• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

Would you buy a new, somewhat unique lighting kit?

Would you buy this?

  • Not really interested in it

    Votes: 0 0.0%
  • Shutup and take my money

    Votes: 3 50.0%
  • I have questions, but might want one

    Votes: 3 50.0%

  • Total voters
    6
  • Poll closed .

floz

New member
#1
It's a small board that plugs into a spare channel on your radio and gives you multifunction LED lighting controlled from your radio?
  • wingtip FAA nav lights
  • FAA strobes
  • machineguns for warbirds
  • landing lights
  • multirotor UFO patterns
  • lighting for terrestrial vehicles (if you have such in your fleet)
  • etc
I've finally gotten around to doing some more CAD work and got the board design sent off to fab. I should have first-run boards in a week or two, and all of the components to make three first-run prototypes. After that, I may be going to a production house to have the design finalized and put into their SKU catalog, just so I don't lose all my free time soldering kits.
top.png
Board design with OSH Park

Final price point is looking like around $35 USD + shipping for a "basic" kit, which is the controller board, several (2 or 3) LED modules, and leads. Probably about $10 less for an unassembled kit (flashed MCU, breakout board, pin headers, connectors, wire... basically a bag of loose parts). Obviously this may change depending on what exactly changes in the project.

You can absolutely order these and assemble yourself through OSH Park if you're so inclined.
 
Last edited:

mrjdstewart

Well-known member
#2
i would be interested, PM me with details when you are ready to make available. i will take a fully assembled one. i have a wing that i have been waiting to build as a night flyer and would love to have some control over the lights.

thanks,

me :cool:
 

floz

New member
#3
The first-run boards arrived. I made a goof, not something critical to stop testing and development, but not something I would let beta testers use.
first_run_boards.png
Notice the difference in diameter for the holes? The sets of three marked D + - are smaller than the others. :oops:
It's something I can and will fix in the next revision, but it reduces mechanical strength at those connections. As these are the user-accessible "plugs" for radio and lights, it's a pretty big fail.

EDIT: I tried a little harder and managed to push pin headers through, I think without damaging any traces or vias.
headers.png


https://oshpark.com/shared_projects/fFcqOtyw is the updated design (totally untested yet)
flightlights_v0.2.png
The new layout moves the 3-pin connectors for RX and LED to the backside of the board, slimming it by quite a bit. I'm not certain how well this will work in practice during assembly yet, but a small run of boards is cheap. Bonus, it should shave about 2-3g off the assembly.

Bonus points again to OSHpark, these came in as an exact match to the Eagle design in a week + 1 day for less than treating three people to starbucks! The hole-diameter goof is totally on me and my noob-like flailing at Eagle.

Once I have some more time to work on the board design, I'll fix this glaring issue and work on any other improvements I want to make. It's kind of bulky still, about the footprint of a FlySky 6ch receiver, so slimming the board down is definitely on the list of changes as I better learn to navigate Eagle.
 
Last edited:

floz

New member
#5
So for unassembled kits, I'm probably going to add a few silkscreen marks on the board to indicate which pin-headers are required. Instead of putting all 20+ pins in and soldering, you can get away with the required power/data lines and maybe 1 extra for mechanical stability. This actually adds up to about 0.5g (give or take) of weight savings.

I'm also looking into additional drilling on the PCB. If I can remove sufficient material without impacting the strength or circuit functionality at the board-fab step, I will.

The firmware for these boards is still kind of in it's infancy, and I only have a FlySky 6ch to test with. So far it expects a standard hobby-servo PWM type signal, which determines what the state-machine does. I've got some additional dev work to do on it now that the first-run boards are here.

On the todo list

(hardware):
test/validate circuit in v0.1 board
test/validate circuit & fit in v0.2 board
finalize led module 'potting' process
--two 0.5W RGB LEDs are paired to make a module, then potted in epoxy for durability.

(software):
build "config" state into state-machine
--use radio to set parameters for model as installed
-LED1 and CH1 on board used as output/input respectively
-flashing/color coded menu system similar to the tone system used to configure ESCs.
--save to ROM
correct logical positioning of LED modules to simplify wiring
simplified wiring.png
This is how it should be laid out in a fixed-wing aircraft.
Red = controller
Green = cables
Blurple(bluish purple) = LED modules
However, my cub (the original testbed for this idea) is wired very differently from this... since these LEDs daisy-chain serially, the software has to change to match the change in circuit. As a result the cub is hefting around an additional wingspan worth of cable, because I just slapped together the very first prototype with no consideration to weight.
 
Last edited:

kilroy07

Well-known member
#6
Ah, I LOVE IT when someone is already halfway through something I planned on doing myself!! (y)

My project is a lot less ambitious. I just want to control the light on my night raidan a bit better! But I would certainly be up for a diy kit or two! (I actually like to solder, I know... weird, right?!!) 😛
 

floz

New member
#7
Sorry for the lack of updates/progress. We (the family) got a nasty bug that hopped person to person to person over the last couple of weeks.

Incidentally, if you're so inclined, the entire project is open-source (hardware and software/firmware). I'll make sure to get the code published sometime soon! In a nutshell though, it's an arduino nano (or micro) 5v mcu and "neopixels".
 

floz

New member
#8
As promised... here's the alpha source. I have some vaca time coming soon, so I might get the chance to clean this up and release a new version soon.

Code:
/*
flightlights - fixed wing

This version of flightlights includes configurations for fixed-wing aircraft.  red/green FAA, landing lights, and
machine-guns are included.  Feel free to edit this source and re-burn it to your board.

 -floz

TODO:

!!clean everything up
!select functions to actually burn to new kits
!fine-tune anything else that's left
!!!develop "interactive" programming mode - done via flashes to set
battery timeout in mins.

*/

#include <Adafruit_NeoPixel.h> // include the NeoPixel library.  super handy, that.

#ifdef __AVR__          //some magic sauce for AVR microcontrollers?
#include <avr/power.h>  //some magic sauce for AVR microcontrollers?
#endif                  //some magic sauce for AVR microcontrollers?

//data-pin for the neopixel LEDs (output)
#define LED_PIN 6

//channel on your hobby receiver connects to this digital pin (input)
#define PWM_SOURCE 5

//how many LEDs in the chain?
#define NUM_PIXELS 2

#define VERSION 1.2
//how long between strobe flashes/battery checks
const long interval = 5050;

// how long until battery warning?
const long battery_timeout = 420000; 

//not really .45, 45ms maximum random on for machinegun fire effect
const long gun_caliber = 45; 

//timer var
unsigned long previousMillis = 0;

//serial console input
String inputString = "";         // a String to hold incoming data

//flag (is input string done?)
boolean stringComplete = false;  // whether the string is complete

// el togglodyte supremo!
// vars used when performing strobe
int MaxLightState = 6;// one over the total number of choices you have.
int LightState = 0; //pick one start with (0 = navlights, 1 = landing lights, 4 = machinegun)

int LastLightState = 0;

//magic sauce for neopixel/ws2812b LEDs
//check strandtest or other examples for further info
//you can instantiate multiples, define a new pin for each.
Adafruit_NeoPixel leds = Adafruit_NeoPixel(NUM_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ400);


void setup() 
{
    //this should be the first void ____ () function in this program
    randomSeed(analogRead(0)); //random seed for machine-gun flash effect (works on rf/emf noise, funnily enough)
    leds.begin(); // init the LED strand instance
    leds.setPixelColor(0,255,0,0);
    leds.setPixelColor(1,255,0,0);
    leds.show(); // Initialize all pixels
    delay(250);
    leds.setPixelColor(0,0,255,0);
    leds.setPixelColor(1,0,255,0);
    leds.show(); // Initialize all pixels
    delay(250);
    leds.setPixelColor(0,0,0,255);
    leds.setPixelColor(1,0,0,255);
    leds.show(); // Initialize all pixels
    delay(250);
    leds.setPixelColor(0,0,0,0);
    leds.setPixelColor(1,0,0,0);
    leds.show(); // Initialize all pixels
    // chose to add color by color init to ensure LED is functional on boot
    Serial.begin(9600); // start serial output
    inputString.reserve(200);
    Serial.print(" flightlights fixed wing ver: ");
    Serial.print(VERSION);
    Serial.println(" boot complete!");
}

void(* resetFunc) (void) = 0;
//define each of your effect functions here:

void nav_lights(){
    //red/green FAA style
    leds.setPixelColor(0, 0,255,0);
    leds.setPixelColor(1,255,0,0);
    leds.show();
    
}

void landing_lights(){
       //bright warm white (r,g,b)
      leds.setPixelColor(0, 255,255,196);
      leds.setPixelColor(1, 255,255,196);
      leds.show();
}

void battery_timer(){
   //after x minutes (set above) give the pilot a warning flash
   //and then go to critical flasher after two more minutes

     //two minutes over, go red
     if (millis() >= battery_timeout + 120000){          
        LightState = 5;
        return;                                        
     }   
     
      leds.setPixelColor(0, 255,255,0);
      leds.setPixelColor(1, 0,0,0);
      leds.show();
      delay(150);
      leds.setPixelColor(1, 255,255,0);
      leds.setPixelColor(0, 0,0,0);
      leds.show();
      delay(150);
         
 }
 
void critical_flash(){
      leds.setPixelColor(0, 255,0,0);
      leds.setPixelColor(1, 0,0,0);
      leds.show();
      delay(150);
      leds.setPixelColor(1, 255,0,0);
      leds.setPixelColor(0, 0,0,0);
      leds.show();
      delay(150);  
    
 }
 
void strobe(){
      // added strobe thingie - provides a quick flash and returns to nav red/green cleanly
      leds.setPixelColor(0, 255,255,255);
      leds.setPixelColor(1, 255,255,255);
      leds.show();
      delay(60);
      LightState = LastLightState;
      return;
}

void strobe_loop(){
  // rapid wingtip flashes of white/off (find my crashed plane mode)
      leds.setPixelColor(0, 255,255,255);
      leds.setPixelColor(1, 255,255,255);
      leds.show();
      delay(100);
      leds.setPixelColor(0, 0,0,0);
      leds.setPixelColor(1, 0,0,0);
      leds.show();
      delay(100);
}

void machine_gun_loop(){
       /* rapid fire-like flashes at random intervals
        *  
        * gives a nice random fire effect, provided as a well-documented example
        * of how to write your own functions.
        * 
        * if you had other lights and machineguns, you would need to specify what
        * pixel/LEDs were where by changing the ID
        * for example: leds.setPixelColor(ID,red,green,blue);
         */       
      int randNumber = random(gun_caliber);   //generate a random number 0 to 45
      leds.setPixelColor(0, 255,128,0);        //set a nice orangeish fire color for first pixel
      leds.setPixelColor(1, 0,0,0);            //turn second pixel off
      leds.show();                             // make it so!
      delay(randNumber);                      //wait random amount of milliseconds, see random 0 to 60 above
      randNumber = random(gun_caliber+10);     //get a new random number
      leds.setPixelColor(0, 0,0,0);            //turn first pixel off
      leds.setPixelColor(1, 255,128,0);       //set a nice orangeish fire color for second pixel
      
      leds.show();                              // make it so!
      delay(randNumber);                        //wait random amount of milliseconds again
}

void lookupLightState(){
   if (LightState == 0){
      Serial.println("nav lights");
    }
    if (LightState == 1){
      Serial.println("landing lights");
    }
    if (LightState == 2){
      Serial.println("strobe lights");
    }
    if (LightState == 3){
      Serial.println("battery alert");
    }
    if (LightState == 4){
      Serial.println("pewpewpew");
    }                         
    if (LightState == 5){
      Serial.println("critical flash");
    }
}
void loop() {
    
      //serial console - used for debugging/testing porpoises
      // print the string when a newline arrives:
    if (stringComplete) {
    Serial.print("ACK ");
    Serial.print(inputString);
  
  
  //parser starts here   
  
   if (inputString == "test\n"){  //give some diagnostic info
    Serial.print("flightLights - Program version: ");
    Serial.println(VERSION);
    Serial.print("program run time: ");
    Serial.print(millis());
    Serial.println(" ms");
    Serial.print("Current Mode: ");
    lookupLightState();
    int pwmin = pulseIn(PWM_SOURCE, HIGH, 20000);     //read the PWM line (default pin 5)
    Serial.print("PWM input: ");
    Serial.println(pwmin);
   
   }else if(inputString == "change\n"){ //iterate through states
    LightState++;
      if (LightState >= MaxLightState) {
        LightState = 0;
      }
      Serial.print("New Mode: ");
      lookupLightState(); 
     
    }else if(inputString == "reboot\n"){
    Serial.println("rebooting");
    delay(1000);
    resetFunc();
    }else{
    Serial.println("unknown command, valid commands are:"); //return "huh?" catch any non-defined commands this way
    Serial.println("test - show diagnostic data");
    Serial.println("change - change mode");
    Serial.println("reboot - reboot light controller");
    }
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
//end of parser


     //debug output starts here
     /*Serial.println(millis()); //show the counter for rapid pass/fail check that program is running
       uncomment for debugging otherwise the console is spammmmmm  
     */
     
     /*  
      Serial.print("PWM: ");
      Serial.print(pwmin);     
      if (LightState == 0){
      Serial.print(" - nav lights - ");
     }
     
     if (LightState == 1){
      Serial.print(" - landing lights - ");
     }
     
     if (LightState == 2){
      Serial.print(" - strobe lights - ");
     }
     Serial.print(" time: ");
     Serial.println(millis());
     delay(100); 
     */
     
     //uncomment for debugging otherwise the console is spammmmmm  
     //debug output stops here, actual loop code begins

     // how are the lights commanded within this program?
     // LightState is an iterable int that represents individual functions
     // that the lights can perform.  It is used to snap quickly back to FAA red/green
     // after a fast strobe, and just kind of grew from there.
   
    if (LightState == 0){
      nav_lights();
    }
    if (LightState == 1){
      landing_lights();
    }
    if (LightState == 2){
      strobe_loop();
    }
    if (LightState ==3){
      battery_timer();
    }
    if (LightState ==4){      //add extra functions like this.
      machine_gun_loop();     //they can point to any function you want
    }                         //muzzle-flash here
    if (LightState ==5){
      critical_flash();       //alert that something is amiss.
    }



    
  //running timer to check for strobe interval
  //blatantly borrowed from "blink without delay" example for Arduino
 unsigned long currentMillis = millis();
                                                        //someone else's work, from blinkwithoutdelay example.
  if (currentMillis - previousMillis >= interval) {     //has the delay between strobes happened?
  Serial.print("program run time: ");
  Serial.println(millis());
  if (millis() >= battery_timeout){                     //battery timer check
        LightState =3;
        return;                                         //ymmv, comment out?
     }
    previousMillis = currentMillis;
    if (LightState != 0){                               //strobe check, if we're not using nav lights, don't bother
      return;
     }
     LastLightState = LightState;                       //var to return to nav lights after strobe
       strobe();                                        //give us a quick flash
     }



     
      // below this is the PWM input from the hobby receiver
      // any modes you want reachable via your radio must be mapped here.
      // simply add a new case X: / break; statement as shown below
      // and create the function at the top of this program
      
     int pwmin = pulseIn(PWM_SOURCE, HIGH, 20000);     //read the PWM line (default pin 5)
     
     int selection = map(pwmin, 1000,1900,0,4);        //map the value to however many choices you want to have
                                                       //from your radio.  this should match the code below
     
     switch (selection) {  //what mode are we in according to pwm?
     case 0:
     LightState = 0; //nav lights             
     break;
     case 1:
     LightState = 1; //landing lights
     break;
     case 2:
     LightState = 2; // strobes
     break;
     case 3:                                          
     LightState = 3;  //battery flasher
     break;
     case 4:          //add extra functions by adding case 5, case 6, etc.  be sure to change the mapping above.
     LightState = 4;  //machine_gun_loop
     break;
     }
    
      
   }  
   
    /*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}