Practical Arduino Real-Time Control - Part 1

My Arduino Quench program was intended to provide control of the power level of the attached strobe(s). My initial attempt had a few challenges: the majority of them related to timing issues. I had lost my real-time control mojo.

My problems stemmed from a few areas:

  • unfamiliarity with the Arduino runtime environment
  • uncertainty over control timing of the Sea & Sea strobe(s) (see later posts...)

This post will focus on the first issue: real-time Arduino programming.

The Arduino comes with a basic bootstrap framework that allows you to ignore the microcontroller chip details and get started quickly. The framework initializes the chip and then has 2 user hooks: a setup routine and a loop routine. The setup routine is invoked once at program start. The loop routine is then called repeatedly as fast as possible. The framework provides timers and serial communication services (useful for debugging if you are careful...). The runtime is not multi-threaded or multi-tasking. It is simple and only provides a single thread of execution.

There are numerous trivial sample programs that illustrate the use of a single hardware feature. For example, the Blink program consisted of a loop that turns on an LED output, blocks for a time delay, turns off the LED, blocks for another time delay and then returns. The blocking time delay prevents any real-time control ability over multiple inputs / outputs. 

Lack of multi-tasking support meant that I had to design a single monolithic loop routine that would handle everything. This is were things started to get confusing.

In order to monitor and debug my efforts I was dumping (Serial.println) status information to the monitor window connected back to my IDE. As I carried out various experiments I slowly began to realize that things that used to work no longer functioned properly. My program became erratic and undependable. My old stuff was broke. As I added new features (and associated debugging output), features that used to work stopped working. It was time for some cause and effect thinking...

It took several more experiments before I finally realized that as I modified my diagnostic Serial.println calls the behaviour of my program changed. My lazy programming was the source of my problems. My control logic was solid. But its timing was being thrown off due to the delays and overhead of my Serial.println diagnostic output. My monolithic control loop was handling an ever increasing number of inputs and outputs. This meant that the loop needed to execute quickly and consistently.  The Serial.println diagnostic was not suitable for real-time use. A diagnostic report regarding one item would affect the timing of others.

A second issue was framework overhead. There are multiple different Arduino boards. The Arduino framework provided consistent, easy to use, board independent, high level routines to accomplish things like setting an output or reading an input. These routines are portable across boards and safe. They also introduced delay due to execution time overhead. My first approach to reading external camera and strobe signals had been to blindly poll all inputs every loop cycle. The input reading overhead combined with the delay of diagnostic Serial.println meant that my control loop became erratic. It did not execute within a consistent time period. Which destroyed my ability to provide a real-time controller. The loop timing was inconsistent which meant my output controls were inconsistent. I got random strobe behaviour.

Until I fully understood the Arduino timing issue, I was not sure if my program or the creaky ancient YS50 strobe was to blame. Additional research was required...