Before adding new features and drivers to the Aruna library I thought it would be wise to do some household and refactor the library a bit. The current architecture consist of 2 layers. One for logic and the other for hardware interfacing.
In the image above contains the architecture for the control module. All the PCA9685 specific code rests inside the PCA9685 class that is inherited from Actuator.
A rather simple approach that worked fine in the beginning. But as more and more features get added it becomes repetitive. There are two main problems with this architecture:
- PCA9685 is forced to always be an Actuator, if this same chip is be used for PWM of a LED for example it would result in poor code.
- PCA9685 class needs to be rewritten for every platform I²C driver, despite the PCA9685 driver logic staying the same.
To mitigate these problems extra abstraction layers are added between the Actuator and the I²C code resulting in 4 layers:
- Control logic
- PWM Actuator
- PCA9685 driver
- I²C driver
With the addition of the high level driver layer the PCA9685 driver is now free from hardware specific I²C code because that now rests in the I2C_master implementation. Instead of being hardcoded to an Actuator object the PCA driver is now a PWM object and free to be implemented in any module being an Actuator as shown above or an LED or what not.
A new implementation of PWM (for example the ESP32 native PWM) can easily replace the PCA driver and the layers above would function as if nothing happened. Also porting to a new platform is easier as only the I2C_master class has to be written, all the other code is portable (given an POSIX OS).
I have not yet written the PWM_Actuator code but while making this graph I thought to maybe let PWM inherit Actuator. That makes things easier when using the code, and we are not limited to one parent because C++ supports multiple inherits. So any module abstraction can be added later when needed. But it might make PWM bloated, not sure yet what to do. Atlas I'm first going to focus on more refactoring because although the architecture is now much more flexible this is not yet the case for the other modules (comm and blinky). And some internal structures like `direction_t` for given direction feel redundant because I much rather make use of a singed integer.
I have also been looking into ROS 2, I might make an Aruna ROS package. But that's all in the far future. Nevertheless, I really like their pub/sub model and I might implement something similar for the comm module. I also think that using a simulator could really benefit the development of the project. But I'm indecisive about Gazebo or Webots. Unit tests and better code quality will be worked on first though.