After more testing, more writing code and more debugging I have finally managed to call the code inside the Artemis as COMPLETE. The last few bits and pieces came together, so next step will be to work on the higher level software inside the Raspberry Pi.
Artemis has been put through it paces. It all seems to work OK now, Although I did need to make some changes here and there…
Read more: Artemis hard- and software = WORKING!NeoPixel Ledstrip: Working
So The “smart” led strips with the WS2812b smart leds on board refused to work initially. After a lot of debugging I figured out that the first NeoPixel, the onboard ws2812b was the culprit. It just would not work properly, even though it would pass the bitbanged stuff to the rest of the led strip in the correct way.
I ended up soldering the ws2812b from the Artemis PCB, and I replaced it with a ws2812 I took from one of the led strip I own. After that things started to work immediately! Currently using the Adafruit NeoPixel library.
So the neopixel.cpp module inside the Artemis will actually allow you to set all pixels to the color you prefer, and then shoot those colors into the led strip. But it does not end there! You can tell Artemis how much pixels there are in your strip, you can even tell it to draw random stars on there as well. Finally, you can even tell the Artemis to draw sunlight, which takes the number of minutes of daytime as a parameter. Depending on that parameter Artemis will light up 25% of the leds, from reddish to cool white to reddish and going from left to right simulating the sun as it moves across the sky and as it changes the perceived color during the day:
Changed timing of Artemis
Working with the NeoPixels did show a big issue: I was once to happy with the way Artemis would time the entire thing; running on an interrupt for Timer0 I was able to clock the software at exactly 100Hz. Problem though: Arduino’s consider Timer0 as being “theirs”, and most libraries use nasty things like “delay()”… Which also uses Timer0
So in the end I decided to let go of Timer0 altogether, and instead use the provided millis() function. which counts 1/1000th of seconds. So what I do now is:
- Take note of millis()
- Execute the main function that runs basically everything
- Take not of millis() again and see how many [ms] I lost
- Program a delay of (20ms-TimeLost)
This delivers a run of almost exactly 50Hz (so 50 executes per seconds). So all stuff needs to finish executing in 20[ms]. If this overruns, I report this up (but nothing drastic happens except the internal clock will slow down a tiny bit). In normal operation I have not seen an overrun yet, unless I ask Artemis to do a lot of random() stuff or things like a lot of EEPROM.write() statements.
ResetReason – Why Arduino did a RESET
Another thing I’ve been pondering on. Every one that has been working with microcontrollers wil know this: Your MCU resets, and you have no clue why. This especially can happen when the watchdog is active in the system.
I found a solution for Arduino: I reserve two variables that I specifically DO NOT initialize on bootup of the board. Next I check whether one variable contains the exact bit-inverse value of the other. If not, it was a fresh start, so I load the variables with a code which means “Fresh boot” (and off course the bit-reverse in the other variable). After this I always copy the variable into another variable called “ResetReason”. This variable will now always hold the reason for the last reset!
After this, I just add function calls in the code IAM_Doing(SOMETHING); . The “SOMETHING” is a list of defines. This function updates the two variables. If a reset occurs anywhere in the code, the ResetReason will always reflect the last IAM_Doing() code.
LCD 16×2 display added
While I was at it I figured I might add a 16×2 LCD display I had laying around. Not overly important for my use case, but I included the code in case I want to add one. Right now it updates the second line every second. On the left it shows the “ResetReason”. In the below picture that is 0x00 = Fresh boot. So you can always see if the Arduino tripped at some point (and what the reason was). On the right it shows current time as it is counted using millis() (and a slight correction – see below). In case I do not receive any serial commands for over an hour, Artemis assumes the controlling Raspberry Pi has issues, and Artemis will go into “Rescue” mode, controlling the basics in the paludarium looking at the current time. If this happens I will print an “*” behind the time.
On the first row I just spit any of the actions I get through serial. On the image below I just gave the command to WRITE (->) PWM channel 02’s SP (SetPoint) to 1024. Basically this means “PWM02’s target value should be at 25%. Please “walk” towards that value”.
Keeping Time – When Arduino millis() is not enough
With the changed timing I also had to revisit the internal clock. As Artemis does not have a RealTime Clock (RTC) on board, I decided to tune the millis() counter using the Rapsberry Pi.
For this to work, I introduced a “leap seconds” counter. This counter counts to a programmable value in seconds, then leaps a second backward or forward (depending on the counter value that was set- negative numbers for backwards, positive numbers for forward).
The Raspberry Pi can test the internal clock on regular intervals (like hourly or daily). If it discovers the time in Artemis is not the same as its own time (the Raspberry Pi is synced by NTP), it can change the LeapSec value and so adjust the Artemis’s timing.
If the Raspberry then goes offline, the LeapSec value should be optimal and Artemis can happily control in “rescue” mode for the next few days without too much deviation!
Rescue: Check-Engine light for Artemis
And finally, a “check engine” light for Artemis. Who’s not had this happening: Your car shows a “check engine” light. The car still runs, but power out of the engine is horrendous. Why? Well, the “smart” engine controller has some issue (often with a sensor or something) and decides he no longer manage the engine in a smart way. In comes “rescue mode”: The engine still works, but all controls are extremely basic, but at least it still runs.
Similar thing was built for Artemis: If the Artemis does not receive any valid communication on its serial port for more than an hour, it goes into “rescue mode”. This mode is ended as soon as a valid reception of a serial frame occurs.
While in rescue mode, Artemis call the rescue function once per hour. The rescue function determines what need to be set for lighting, fanspeeds, pumps and valves. It is, like the “check engine light” functionality, very basic but at least it will make sure plants and animals don’t die in there.
So what’s next?
Up next is the higher level stuff; now that Artemis is fully functional (apart from the occasional bug that I’m sure will pop up sometime), what is next?
The answer is: The higher level Raspberry Pi coding. So I need to forget “C”, and forget to terminate each line with a “;” character, as I wil be switching gears to Python. The idea is to expand on the microservice design I already have running today. I am still thinking if I’ll jump to containers (K8s or K3s) or just keep running python scripts as “services”; since it is all so closely connected to fixed hardware anyway, K8s might be overkill here.
Still undecided, but stay tuned for the next adventure in software (and a little hardware)!
[…] to the “C”. Today I still program in both “C” and Python for fun (Arduino and Raspberry Pi […]