It has been a while since my last log, this was not entirely intentional as I was hard at work refactoring the Aruna library with the architecture described in my previous post. And I thought posting updates on the software would be boring. Therefore, I was planning to post an update after the refactoring was done. But this took way longer than expected. Well that time has finally come, the refactoring of all the lower layers is as good as done. Just a few tweaks left (like a missing IO abstraction and one module still in FreeRTOS), but those can be kinked out later.
Architecture
The abstraction layers of Aruna are now looking really nice. When adding a new driver, sensor of actuator you only need to focus on the part that makes it different from other drivers or sensors and can easily inherit existing logic. Lets for example look at the `Rain40x16` sensor driver, this is a sensor that is normally used to measure rainfall in a 40 mm by 16 mm grid, but I use it measure leaks in the ROV.
The driver for this sensor is used as a `SIS::Performer`, SIS stands for Safety instrumented system and is used to keep a system (the ROV) safe. A SIS::Performer in Aruna performs safety checks, so that other SIS modules like the SIS::Watcher (bad name) and SIS::Reporter can report the problem to the user, so they can take action. I am also planning to add an automated response (SIS::Response ?) so that the ROV will try to get itself back to a safe state if compromised.
It is of course out of the scope of the rain sensor driver to know anything about SIS, moreover do actions based on the water level. The water level report should be the same for all water sensors, be it a rain sensor as described above or a humidity sensor. The driver should only focus on the part that makes them unique, which in this case is the way of measuring water. The Rain40x16 driver therefore inherits `sensor::Water` to create a standardized interface for water sensors. `sensor::Water` in their turn inherits `SIS::Performer` (can also be used for other task than SIS) and handles all the reporting logic for ROV safety. What also can be seen in this diagram is the use of `driver::ADC`. This is also (like `sensor::Water`) a standardized interface for analogue digital converts.
The great thing about this architecture is that the Rain40x16 driver is hardware dependent (it needs a specific sensor) but is also cross-platform because it does not handle any device specific things itself. But instead relies on the `driver::ADC` that can be implemented for any platform.
//
// Created by noeel on 22-12-20.
//
#include <math.h>
#include "aruna/sensor/Rain40x16.h"
aruna::sensor::Rain40x16::Rain40x16(aruna::driver::ADC *adc): adc(adc) {
}
aruna::err_t aruna::sensor::Rain40x16::get_water_level(uint16_t &water_level_in_mm) {
int16_t mV;
err_t e;
e = adc->read_voltage(mV);
water_level_in_mm = voltage_to_mm(mV);
return e;
}
int16_t aruna::sensor::Rain40x16::voltage_to_mm(uint16_t mV) {
// TODO vcc etc as parameters
const int16_t sensor_length_mm = 40;
const int16_t max_voltage_when_dry = 20;
const int16_t voltage_at_min = 1000;
const int16_t voltage_at_max = 3300;
const int16_t voltage_diff = voltage_at_max - voltage_at_min;
if (mV < max_voltage_when_dry)
return 0;
if (mV < voltage_at_min) {
// voltage is in grey space.
return 1;
}
// TODO this conversion is linear while in real-life it is not
return ceilf(((float) mV - (float) voltage_at_min) * ((float) sensor_length_mm / (float) voltage_diff));
}
Above is all the code in `Rain40x16.cpp`. The only function it needs to override is `get_water_level(uint16_t &water_level_in_mm)` from `sensor::Water`
The refactoring and redesign of Aruna has so far caused: 78 files changed, 3154 insertions and 2218 deletions. (17 Oct 2020 - 4 Jan 2021). With refactoring of the top layer and documentation of all the modules is still to be done.
Workflow
In other news I have now started to work on unit tests. These buggers can take a while to get right but have filtered some bugs already. Previously I had experimented with Catch2, but that turned out to be too big to run on an STM32F103. And I want to keep a window open to run Aruna on lower end chips (including the unit tests). So now I have written some unit tests in Gtest and Gmock for Actuator(Set) and Link, and I'm going to experiment to run these natively on ESP32 and STM32F103 (they of course already run on X86 GCC Linux).
For a while now I have worked on Aruna in sprints. These sprints always have a (major) goal and are either electrical, mechanical of software oriented. Like the previous sprint was making the Apsu PCB. For months, I have worked on this problem, some times doing nothing else then browse parts and reading my eyes dry on data sheets. I barely touched any software or mechanical aspects of Aruna during that sprint. Because that sprint was electrical oriented, and required my full focus to create a PCB. I remembered that at times I was completely bored by the project and that it felt more like work than a fun hobby learning project. But still I pressed on and got great results as reward. And now I'm facing the same issue with software, in the beginning it was hella fun but after doing the same thing for months its becomes tedious again. I originally used sprint to keep my focus and not wander off-topic, but now it seems that I work less on the project if a boring task is at hand. Therefore, I have decided to do my planning differently from now on. Instead of focusing on one major problem I'm going to cut it in tiny pieces. So I can get more diversity. One of the reasons I like this project so much is because of the diversity in EE (electrical engineering), CS (computer science) and ME (mechanical engineering). But doing only one of these for months make it not so diverse anymore. So next I will be working on some small ME and EE parts before going back to CS, and try to alternate between tasks more.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Yeah, I think it's important for a personal project to kept it flexible and work on whatever you feel like. On #BlueRetro early on I made the mistake to very rigidly follow my original roadmap. That was fine for around 6 month until I got to an item I didn't feel like doing and on top of it my initial design didn't work at all. This resulted in me not touching the project for 3 months. Now I keep a list of task in a spreadsheet with a gross estimate of which order things should be but in the end I don't stop myself swaping around the priority to whatever I feel like doing. I try as much as possible to end a task before starting another one but sometimes it's not bad to start another one when your are out of idea.
Are you sure? yes | no
Thanks for commenting Jacques, I was wondering if anyone was even reading these logs. Well now I know :)
I keep a task list in "Getting Things Gnome", If you're on Linux and a fan of FOSS it may be worth to check out (there is also a Windows port)!
-edit: links: https://wiki.gnome.org/Apps/GTG win port https://launchpad.net/gtg-win
Are you sure? yes | no