What happened?
Recently, I got an unusual task: bring an old
So the solution was to redesign the controller from scratch using an Arduino.
That’s where my embedded systems journey started...
The task...
The device itself was pretty unusual.
Its job was to move tissue samples through a sequence of chemical tanks, where each tank contained a different substance used during processing.
Our machine had 12 tanks in total.
The first 10 tanks required the tissue to remain submerged for one hour each. The last two tanks were different: they contained paraffin wax, so the samples had to stay there for two hours.
Those final stages were especially sensitive because the paraffin had to be completely melted before the tissue could enter the tank. Otherwise, the sample could be damaged.
The original machine already had:
- wax temperature sensors for the paraffin tanks
- two heating elements
- vibration motor that used to shake the samples while they were inside the tanks.
- a bottom sensor to detect when the sample holder was fully submerged
- a top sensor to detect when the mechanism was preparing to move the samples to the next tank
- a motor controlling the movement mechanism
The movement itself was surprisingly primitive.
The main motor only knew how to perform a fixed sequence:
down → up → move → down → up...
There was no position control, no direction switching, and no speed adjustment. We could only turn the motor on or off and trust the mechanical system to complete the cycle correctly.
At first glance, it sounded simple.
Then came the real problems:
- handling power outages
- detecting damaged sensors
- recovering from interrupted cycles
- allowing operators to skip tanks safely
- preventing samples from being destroyed by overheated or unmelted paraffin
Sometimes I defended those decisions, and sometimes I simply noted the possible consequences of a particular implementation.
After many meetings and countless hours spent searching the internet and asking LLMs for reliable descriptions of how these machines actually worked, the technical requirements were finally ready... 😊😯
Implementation... First Round :)
Here we go. I implemented the code using an FSM (Finite State Machine), and everything seemed to be working well.
Then I heard the electrical engineer say:
"Okay, we think it should handle power outages too..."
If you could have seen my face ):
Because the machine was built around isolated states, I could simply add a recovery mode. If the sample holder was down, everything was normal and the machine continued as usual. If it was up or somewhere in between, the software tried to figure out its position and recover safely from there.
One more point for FSMs. 😄
Example of My Mess...)
Let's look at one of the methods responsible for moving the samples to the next tank:
// Finite State Machine Transition Configuration
{
verifyingPredicate, // Condition check
S_IDLE, // Next state if false
S_UNKNOWN_DIRECTION_RECOVERY, // Next state if true
verifyingProcess, // State body logic
verifyingActionChanged, // UI/Side-effects hook
VERIFICATION_DELAY_MS, // State stabilization timeout
PREDIC_TIMER // Timer configuration
},
First, it’s an array of transitions, so each transition includes the previous one. Don’t ask me how I ended up with this architecture—it actually comes from the
We spent a huge amount of time testing different situations and edge cases:
- Processor timeouts
- Thermostats
- Sensor failures
- Tank identification
- Recovery scenarios
As with most embedded development, and especially in medical-related systems, testing often takes more time than development itself.
The real world is much less predictable than the development environment.
So, in the end, I can say that I really enjoyed working on this project with the team. If I sounded a little annoyed in some parts of the article, that's just because I wanted to share the reality of the development process. 😄
As a small gift for reading this article, you can check out the GitHub repository with the full source code and all commits.
Bye! :)
SOCIAL SHARE CARD GENERATOR