The software for this project uses the Arduino development environment. If this is your first time using this with Adafruit boards, please see the Feather M0 Setup guide here:

Adafruit Feather M0 Basic Proto: Arduino IDE Setup

Aside from installing the Arduino software, you’ll need to add the Adafruit boards package as mentioned in the guide above.

Other boards…M4, RP2040, ESP32-S3…will have corresponding starter guides to get these going with the Arduino IDE. If it’s your first time using them, use the search field to locate those guides.

Additionally you’ll need a few prerequisite libraries, which can be installed with the Arduino Library Manager (Sketch→Include Library→Manage Libraries…). Search for and install:

  • Adafruit_NeoPixel
  • Adafruit_NeoPXL8
  • Adafruit_ZeroDMA

Then fetch the code for this project, downloadable here:

Select “Feather M0” (or whatever board you’re using) from the Tools→Board menu, compile and verify that you can upload to the board. If so, great! Now we need to fine-tune some settings to match your project…

If using a Feather M4 (with M4 version of the NeoPXL8 FeatherWing), look for this line early in the code:

int8_t pins[8] = { PIN_SERIAL1_RX, PIN_SERIAL1_TX, MISO, 13, 5, SDA, A4, A3 };

Change the list of pins to the following:

int8_t pins[8] = { 13, 12, 11, 10, SCK, 5, 9, 6 };

The above change is only needed for Feather M4; if using Feather M0, you can leave the defaults.

Other boards will use different pins. If you’ve worked through the NeoPXL8 guide and puzzled through the strandtest example, this should all be sorted out by now. If using a Feather RP2040 SCORPIO, the sketch takes care of this part.

Now we can configure some visual things…

Near the top of the code is this line:

#define PIXEL_PITCH (1.0 / 150.0) // 150 pixels/m

This tells the code the “density” of your NeoPixel strip, in LEDs-per-meter. The default, 150.0, corresponds to the density of the ultra-skinny NeoPixel strip. If using different pixels, change this to match…60.0 and 144.0 are both pretty common strip densities. The code needs to know this figure so the drippings fall at a physically plausible speed.

Q: Can I mix and match strip densities?

A: Electronically there’s nothing preventing this, but the code as written works with a single density throughout.

Speaking of physically plausible speed, look for this a few lines further down:

#define G_CONST 9.806 // Standard acceleration due to gravity

Combined with the strip density figure, this makes the drips fall convincingly. 9.806 is the force of gravity on Earth, in m/s2. A little math ties this all together to make the drips and the splats play well together and fool your brain.

The value there…9.086…is convincing enough for a thin liquid like water or blood. If you want something really viscous looking…rather than working viscosity calculations into the code, you can be like Q from Star Trek and just change the gravitational constant of the universe. Try values between 2 and 3 for a nice gravy-like feel.

Then, a short way down, look for this section:

uint8_t palette[][3] = {
  { 0, 255, 0 }, // Bright green ectoplasm

This defines the color of the drippings, as an RGB value. The default, {0,255,0}, is a pure green…good for ectoplasm. But you might want red instead, {255,0,0} for blood, or blue {0,0,255} or white {255,255,255} for something more Christmasy. Later we’ll explain how to use multiple colors.

One more piece to this recipe…a little further along in the code, look for this table of numbers:

  { 16,  7, 0.157, 0, 0 }, // NeoPXL8 output 0: 16 pixels long, drip pauses at index 7, 0.157 meters above ground, use palette colors 0-0
  { 19,  6, 0.174, 0, 0 }, // NeoPXL8 output 1: 19 pixels long, pause at index 6, 0.174 meters up
  { 18,  5, 0.195, 0, 0 }, // NeoPXL8 output 2: etc.
  { 17,  6, 0.16 , 0, 0 }, // NeoPXL8 output 3
  { 16,  1, 0.21 , 0, 0 }, // NeoPXL8 output 4
  { 16,  1, 0.21 , 0, 0 }, // NeoPXL8 output 5
  { 21, 10, 0.143, 0, 0 }, // NeoPXL8 output 6

The table holds information about our NeoPixel strips and real-world distances, to make the physics “actual size.” Each line, one for each drip (up to 7) contains three numbers:

  1. The length of the NeoPixel strip, in pixels.
  2. The pixel index (starting at 0, up to length-1) where the dribble pauses before falling. This can be 0 if you want no dribble.
  3. The distance from the dribble pixel (the one you just provided the index # for) to the splat pixel below, in meters.
  4. A range of color indices to use from the palette[] array. With just one color defined for the default example case, both of these values are 0.

You can have an 8th drip but won’t get splats in that case. Given a choice, I think the splats are way cooler.

Here I’m measuring drip-to-splat length for drip #6. It’s about 143 millimeters, or 0.143 meters as you can see in the table. Not the topmost pixel, not the end of the drip, but the dribble pixel at the tip of the horn.

If measuring in inches, multiply by 0.0254 to convert to meters.

Get all your numbers and measurements in there, save the code (or a copy) and upload to your Halloween prop. If all goes well, the motion should physically correspond to the thing you’ve built! If it’s close but not quite, tweak your table numbers…move the dribble pixel up or down a bit, change distances (or G_CONST) to get the timing right.

This guide was first published on Oct 23, 2019. It was last updated on Jul 24, 2024.

This page (Arduino Code) was last updated on Jul 24, 2024.

Text editor powered by tinymce.