Why are they blinking?

rusty truck
A 1950 Chevy 3100 truck I built, fully weathered.

One of my hobbies is building models. I remember working on them with my father when I was young, and building some with my daughter when she was old enough. I’m a member of IPMS, which has improved the quality, if not the quantity, of my finished models.

One of my other loves is science fiction, whether in book, movie, or television form. I’ve been a Star Trek fan for years, and my favorite movie is still Star Trek II: The Wrath of Khan (paid link). The call back to the original series, coupled with a great story, great writing, and great effects, makes it the best of the original Trek movies.

Being a modeler, I am very happy that there are numerous Star Trek model kits, including several of the USS Reliant (paid link) which features heavily in that movie. I’ve always wanted to build a version of the Reliant with lighting and sound effects. When displayed, the model would feature lighted warp engines and blinking running lights, and buttons will allow people to fire phasers and trigger sounds like Kirk screaming “KHAAAAAN!”

Now, you can buy full lighting kits for this model, but I had a different plan in mind. You see, I started playing around with an Arduino a few years ago.

These micro-controllers allow a person with some electronic knowledge to directly control the physical world with software. Rather than buy a lighting kit, I decided I wanted to use an Arduino to animate this model. While the sound effects would require some research, making LED’s blink is basically Arduino Tutorial 1.

However, there’s a problem (if there wasn’t, there wouldn’t be a blog post). You see, from a software level, the Arduino only provides two places where you can write code:

  1. There is a setup routine, which is executed once when the device is powered up.
  2. There is also a loop routine, which is executed over and over again as long as the Arduino has power.

Everything you want to do with an Arduino has to fit in these two routines.

My plan for lights includes:

arduino uno
One of my Arduino Uno devices

  • running lights which blink at various rates
  • interior lights which cycle on and off at random intervals to simulate a crew
  • user input via buttons for phasers and such

Since the Arduino only gives me a single loop to work with, how do I provide three different lighting experiences?

I threw away some solutions right away:

  • Use a PC and run three separate programs to handle these scenarios.
    Where would I put a PC or laptop in the model? And how do I run lights from it?
  • Use a PC and run a single program with three separate execution threads.
    This has the same problem as above.
  • Use three separate Arduino’s for each planned circuit.
    This seems like a waste, since the Arduino can handle multiple LED’s easily. Each Arduino also needs a power supply and place to live in the model. Plus, what if I wanted to add something new later, like engine lights or additional sounds? No, the solution I wanted could only use a single Arduino.

Now, the Arduino does have a way to count time. There is a way to get the number of milliseconds which have passed since the Arduino was powered on. Knowing that, I had a glimmer of an idea…

I started talking to a friend who had done something similar. It’s no coincidence that a many solutions come from talking to someone else. I could still use a single Arduino with a single loop, using the basis of a technique I played with years ago called cycle counting. Here’s how my modification works:

In my setup routine, I specify a timing map for each light in my design. The timing map has a few pieces to it:

  1. First, there’s a set of time intervals which tells the Arduino when to turn each light on and off. I can turn the light on or off multiple times in a given map, with any time intervals between changes I choose.
  2. The map also tracks which timing interval is active, which is used to set the lights properly.
  3. Lastly, the map tracks the elapsed time since the active interval was set.

Then, in my loop routine, I count how many milliseconds have passed since the last loop. By convention, this is called delta time.

Now I can look at all my timing maps and do the following:

  1. First, add the delta time to the elapsed time for the current map.
  2. Next, check if the elapsed time is greater than the time specified for the active interval.
    1. If it is, set the active interval to the next one in the sequence, and reset the elapsed time to zero.
    2. If the last interval in the sequence is completely, then set the active interval to the first one to repeat the pattern.

Once all the maps are updated, I can turn the lights on or off based on the current settings.

arduino test rig
Setting up a test of the cycle counting code.

Once I had the basic scheme in place, I started adding code to handle special cases:

  • For button presses, I activate a map with the proper timings, but once the last interval is done, I stop.
  • For randomly shifting lights, I modify the map every time the interval changes.
  • I can even add complexity by specifying the light intensity for each interval, or having a light grow and fade over an interval.

I did a quick test of the basic timing map using some LED’s on a breadboard, and it works like a champ. All it took was thinking about the problem a little differently, and using the tools the Arduino offers instead of trying to invent new ones.

Next stop: sound!

BTW, if you want to play around with an Arduino as well, you can purchase the Elegoo Arduino Uno Super Starter Kit from Amazon, which is what I started with. If you purchase anything from Amazon using the link above, I get a small commission as well.