Caveman Diorama: Quest for Fire - Embedded.com

Caveman Diorama: Quest for Fire

Well, I'm delighted to be able to inform you that things are bouncing along with regard to our Caveman Diorama project. In the case of our Time Portal, for example, we hope to have this little scamp fully up and running in the next few days.


Cardboard prototype of Time Portal (Source: Max Maxfield & Mike Mittlebeeler)

However, we're going to leave the Time Portal for a future column because today we're going to talk about fire. One of the focal points in the cave is going to be a group of cavemen sitting around a fire chatting with yours truly (my presence being explained by the Time Portal, of course). This fire is going to be located close toward the television screen (the diorama will be presented inside an old television cabinet) so we want the effect to look as realistic as possible.

We started off by throwing a crude representation together to get a feel for the overall size of the thing (and also to give us something we could move around the cave to determine the optimum location) as illustrated below:


Getting a feel for the fire pit (Source: Max Maxfield & Mike Mittlebeeler)

Note that the 1/32 soldier is just a figure my partner in crime, Mike Mittlebeeler, happened to have lying around, and it is shown here only to give a sense of scale. In the case of the fire itself, Mike started off by charring the ends of some twigs and arranging them around a fire pit (i.e., a hole in a box with a couple of LEDs inside).


Early prototype of fire pit (Source: Max Maxfield & Mike Mittlebeeler)

You can't really see it here, but the carbonized ends of the twigs glow very realistically in response to the light from the LEDs. Even though Mike was using only three regular LEDs — one each of red, orange, and yellow — as you can see in this video, the resulting effect is really rather tasty.

In order to drive the LEDs, Mike pulled a simple bit of open source Arduino code off the web. I can’t remember exactly how this code went, but — as I recall — the main loop() function looked something like the following:

  void loop() {      int redVal, orangeVal, yellowVal;      redVal    = random(155,255);      orangeVal = random(155,255);      yellowVal = random(155,255);      digitalWrite(redPin,    redVal);      digitalWrite(orangePin, orangeVal);      digitalWrite(yellowPin, yellowVal);      delay( random(1, 100) );  }

On the one hand, I do like the fact that there's lots of “random” with regard to both the intensity and duration. Also, as I mentioned, the end result actually looks quite tasty, but there are a few things we need to consider. The first is that, although this looks great when the main room lights are off, it's almost impossible to see in regular lighting conditions. This means that we need more and brighter LEDs.

Another point to ponder regarding the code snippet above is that the LEDs are always on to some extent. If we have more LEDs, then we'll probably want to increase their dynamic range, possibly to the extent of having them go all the way off sometimes. And one real “biggie” with the above code above is that — even though the delay is random — all of the LEDs change at the same time.

Our next step was to try to visualize what a real camp fire looks like. Obviously there's a lot of red and orange and yellow light and everything is flickering furiously, but on top of all of this there can also be occasional flashes of white and blue and purple light that suddenly flare up and then fade away in the heart of the fire.

We'll return to this point in a moment, but first let's return our attention to the physical implementation of the fire. As noted above, we knew we needed more LEDs, so we created an array of 16 NeoPixels. We also used some clear epoxy to stick a bunch of glass beads together.


Array of NeoPixels with glass bead centerpiece
(Source: Max Maxfield & Mike Mittlebeeler)

We are planning on surrounding the glass centerpiece with burnt twigs, but we have omitted them here for the sake of clarity. Even with a simple flickering algorithm, the end result was quite interesting. The glass beads reflected the light back and forth very nicely, but they are too “regular” if you know what I mean.

This is when we had one of our rare brainwaves. We took a small pane of 1/8″ glass, put it in a Ziploc bag, and hit it repeatedly with a hammer until we had a bunch of small pieces. No, that wasn't the extent of our brainwave; there's more… we then hand-picked the pieces we wanted, mixed them up with some clear epoxy, formed them into a cone shape, waited for them to dry, and placed them on top of our NeoPixel array.


Original glass bead centerpiece (left) vs. crushed glass centerpiece (right)
(Source: Max Maxfield & Mike Mittlebeeler)

This works much better because there are a tremendous number of internal reflections and refractions that really boost the final effect. The big problem now was that our NeoPixel array was too large for the area we had designated for the fire. Of course nothing is set in stone (no pun intended); we could always increase the footprint of the fire, but we're trying to keep everything to scale, and if you have to chop and haul your own wood, you tend to limit yourself to a more reasonable-sized fire.

Fortunately, while rooting around the Adafruit.com website, we realized that a 7-NeoPixel Jewel fits exactly inside a 12-NeoPixel Ring. The result is a grouping with more LEDs than our original array (19 versus 16) that occupies a smaller (1.5″ diameter) footprint.


Original array (left) vs. new and improved version (right)
(Source: Max Maxfield & Mike Mittlebeeler)

Now, I don’t know if you remember, but the fact we want a lot of “random” was what sparked off an earlier column: Just how random is the Arduino's random() function? We also wanted each of the pixels in our array to operate independently of each other timewise. I come from a background in digital logic simulation in which we have the concept of an “Event Wheel” whereby things can be scheduled to happen at future times.

We didn’t want to go so far as to create an event wheel, so we opted for a much simpler implementation by creating a two dimensional array of integer variables:

      int g_wheel[NUM_NEOS][NUM_FIELDS];

If we think of this array as columns and rows, then there's a column for each pixel, where each column comprises five fields. The first field is the mode: Glow, Spark, or Dark. The current mode for each pixel is selected randomly, with Glow having the highest weighting. When the Glow mode is selected, the color — red, orange, or yellow — of that pixel is selected randomly, with red having a higher weighting than orange, and orange having a higher weighting than yellow. Also, the intensity of the pixel is determined randomly as is its duration.

By comparison, when the Spark mode is selected, the color of that pixel is again selected randomly, but now we have two extra colors making five — red, orange, yellow, white, and purple — with red having the highest rating and purple having the lowest. In this case, the initial intensity is selected randomly, as is the speed of that pixel's fade. Last but not least, in the case of the Dark mode, the color is set to black and the duration of this off state is determined randomly.

One thing we decided was that we wanted each clock tick (period) of our pseudo-event wheel to take 1 millisecond, but we didn’t know how long all of the calculations would take, so we started off with a delay of 10 microseconds at the end of the loop. We also defined a variable called g_counter . Every time we went around the main loop, we incremented this variable until it reached a value of 10,000, at which point we toggled the state of the Arduino's on-board LED (the one connected to digital pin 13).

When we set things running, we timed how long it took for the on-board LED to toggle some number of times, and from this we determined that the delay at the end of the loop should be increased to 298 microseconds.

The reason we did things in this cheap-and-cheerful manner is that the act of streaming data into the NeoPixels disables interrupts, thereby messing up the Arduinos timers. Also, we didn’t have access to an oscilloscope (we were doing this at the weekend, and all of the test equipment was locked up in another bay).

In anticipation of a future containing oscilloscopes, however, we also assigned digital pin 7 to be our timing pin, and we initialized this pin to a logic 1 state in the setup() function. We subsequently make this pin go to a logic 0 at the beginning of our calculations — we keep it at logic 0 while we're streaming data into the NeoPixels — and then we return it to a logic 1 just prior to starting the delay at the end of the loop.

Later on, when we gained access to an oscilloscope, we measured the logic 0 (calculations) + logic 1 (delay) to give a total of something like 990 microseconds, which is close enough to 1 millisecond for government work, as they say. (We can always fine-tune the delay at the end of the loop again — we just haven’t gotten around to doing this yet.)


Observe the yellow trace: Logic 0 = the calculations, while logic 1 = the delay at the
end of the loop (Source: Max Maxfield & Mike Mittlebeeler)

OK, “The proof of the pudding is in the eating,” as the old saying goes, so take a look at this video. Now, this was taken with a simple camera that finds it difficult to handle the brightness of the pixels forming the fire — the real-world visuals on this are really quite spectacular — but I think it will give you an idea of where we're going with this.

Although this may look a tad over-enthusiastic on the brightness front, remember that the glass centerpiece is going to be surrounded by charred “logs” that will dampen things down a bit. Also, as you'll see in the code (which you can download by clicking here), everything is parameterized and we've only just started to play with the various weighting factors.

The end result is that Mike and I were high-fiving each other this past weekend. If all of the other elements forming the diorama turn out as well as the fire, I'm starting to think we're going to have something spectacular on our hands.

3 thoughts on “Caveman Diorama: Quest for Fire

  1. “Fake cigarettes used copper (the color) metallic paint with most of it covered by something that looks like ash. You could try that kind of upgrade for the matches. Maybe buy a 50 cent fake cig to see how they do it nowadays, in case they got smarter.”

    Log in to Reply
  2. “You mean for the logs — like wrap copper foil around the ends and then add black ash on top — hmm — not a bad idea — we might try that — thanks for the suggestion — I wish you could see it in real life — it really looks pretty amazing.”

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.