Using a Servo Dev Board for NeoPixel LED Control
The Kitronik Simply Servos Board (Figure 1) solves the problem of providing an adequate 3 V – 12 V power rail when using multiple servos in a project. The built-in 3 V power regulation and pin headers provide a quick way to add a Raspberry Pi Pico to operate the servos. But what about a different device that has a three-wire lead, needs 5 V power, and can have significant current draw? Like Adafruit’s NeoPixel LED strips!
Figure 1: The Kitronik Simply servos board. (Image source: Kitronik)
Recently, I had the idea of creating a night flyer out of one of my R/C combat planes. I could throw in just about any microcontroller and find a way to connect the NeoPixel strips to a power supply but, what if it could be done quickly using servo leads and be easily serviceable? The Simply Servos Board is not just for servos. Choosing this platform streamlined this project and minimized the need for custom wiring and a host of connectors.
The details of the flying platform and a fun video of how the combat plane is converted are presented in blog and video links provided at the end of this article. The Arduino IDE was used to program the Pico to run the NeoPixels based on input from the R/C transmitter. The plan is to use a marquee function on the sides of the plane body that chases faster with increased throttle. As the evening gets darker, the Neopixels can be hard on the eyes due to excessive brightness. An auxiliary channel is used to dim the LEDs. Lastly, when landing the aircraft in the dark, landing lights would be handy. Rather than add another channel, the bottom NeoPixels turn bright white when the throttle is at or below landing speed. I used basic programming but there is room for improvement or additional features to explore.
CopyArduino IDE Code:
//Rx throttle as LED speed control. Rx Aux 2 as dimmer. Channels 1 and 2 as inputs on Simply Servos.
//Remaining servo ports on board (channels 3-8, pins 4-9) used as NeoPixel outputs.
#include <neopixelconnect.h>
//Number of NeoPixels in each string
#define FIN_LEN 34 //Number of NeoPixels on each fin
#define BOT_LEN 28 //Number of NeoPixels on each bottom skid
#define AUX_LEN 61 //Number of NeoPixels on each auxiliary location
#define THRESH 60 //Landing versus flight throttle threshold
//Rx channel Pico GPIO inputs
#define THROT 2
#define AUX2 3
// Create an instance of NeoPixelConnect and initialize it for each strand of NeoPixels
// (pin, number of pixels in string, programmable IO location (0 or 1), programmable IO state machine usage (0-3))
NeoPixelConnect R_Aux(4, AUX_LEN, pio0, 0);
NeoPixelConnect L_Aux(5, AUX_LEN, pio1, 0);
NeoPixelConnect R_Bot(6, BOT_LEN, pio0, 1);
NeoPixelConnect L_Bot(7, BOT_LEN, pio1, 1);
NeoPixelConnect R_Fin(8, FIN_LEN, pio0, 2);
NeoPixelConnect L_Fin(9, FIN_LEN, pio1, 2);
uint8_t AuxSingLED; //Single LED variable on auxiliary string
//Function - Get intensity level from Rx Aux2 output
uint8_t get_pixel_intensity() {
return map(pulseIn(AUX2, HIGH), 900, 2200, 0, 255);
}
//Function - Get speed level from Rx Throttle output
uint8_t get_pixel_speed() {
return map(pulseIn(THROT, HIGH), 990, 1902, 100, 0);
}
void setup() {
pinMode(THROT, INPUT); //Set Pico GPIO pin 2 as input
pinMode(AUX2, INPUT); //Set Pico GPIO pin 3 as input
}
void loop() {
uint8_t LEDInten = get_pixel_intensity(); //Get NeoPixel intensity value
uint8_t LEDSpeed = get_pixel_speed(); //Get NeoPixel speed value
if (LEDSpeed < 10) LEDSpeed = 0; //Dampen lower speed limit
if (LEDSpeed < THRESH) { //Throttle high color
R_Bot.neoPixelFill(LEDInten, 0, 0, true); //Fill string with red
L_Bot.neoPixelFill(LEDInten, 0, 0, true); //Fill string with red
} else { //Throttle low color
R_Bot.neoPixelFill(LEDInten, LEDInten, LEDInten, true); //Fill string with white
L_Bot.neoPixelFill(LEDInten, LEDInten, LEDInten, true); //Fill string with white
}
R_Fin.neoPixelFill(0, LEDInten, 0, true); //Fill string with green
L_Fin.neoPixelFill(0, LEDInten, 0, true); //Fill string with green
R_Aux.neoPixelFill(0, 0, LEDInten, false); //Fill string with blue
R_Aux.neoPixelSetValue(AuxSingLED, LEDInten, 0, 0, false); //Set a NeoPixel to red
R_Aux.neoPixelSetValue(AuxSingLED - 1, LEDInten / 10, 0, 0, false); //Set trailing NeoPixel to dimmed red
R_Aux.neoPixelSetValue(AuxSingLED + 1, LEDInten / 10, 0, 0, true); //Set leading NeoPixel to dimmed red
L_Aux.neoPixelFill(0, 0, LEDInten, false); //Fill string with blue
L_Aux.neoPixelSetValue(AuxSingLED, LEDInten, 0, 0, false); //Set a NeoPixel to red
L_Aux.neoPixelSetValue(AuxSingLED - 1, LEDInten / 10, 0, 0, false); //Set trailing NeoPixel to dimmed red
L_Aux.neoPixelSetValue(AuxSingLED + 1, LEDInten / 10, 0, 0, true); //Set leading NeoPixel to dimmed red
AuxSingLED = AuxSingLED + 3; //Marquis - move R_Aux and L_Aux red LEDs along NeoPixel string 3 pixels at a time.
if (AuxSingLED >= AUX_LEN) AuxSingLED = 0; //If at end of string, return to start.
delay(LEDSpeed); //Set how long to delay code execution cycle depending upon throttle level.
}
Arduino IDE Code END:
</neopixelconnect.h>
Listing 1: Arduino IDE code for controlling the NeoPixel strips.
The entire program will benefit from elimination of any delay functions and LEDs can run faster by manipulating the input value from the throttle or the input value mapping. The rest of the strips are open for whatever pattern or color is desired. Keep in mind that the pilot relies on a recognizable pattern of lights to determine aircraft orientation and heading. Night flying is fun and challenging at the same time. Practice night flying in the early evening when you can still see the plane and its LEDs at the same time.
Additional Resources:
Have questions or comments? Continue the conversation on TechForum, Digi-Key's online community and technical resource.
Visit TechForum