Need help! LED 2812 on a quadcopter project Work in Progress

Hi I would like to start this WIP thread on a quadcopter/led project.

Basically I will be placing 2812' programmable LED's to a quadcopter for display and entertainment purposes (for now) ;).

I will be programming and adapting some LED sequences that I wish to toggle through my taranis radio. Preferably 6-8 sequences (rainbow, blinking, etc).

I already managed to get ppm input from my radio thanks to the help of UKHeliBob

Initially to make things simple I am testing the code with only two sequence:

  1. off state/no lights/color

  2. rainbow sequence from the strandtest of neopixels.

I would like to seek help on these problems.

  1. I cannot turn it off. I thought strip.show will turn it "off" according to the neopixel library but turns out it does not do that, not unless my coding is wrong. Anybody has an idea how to do this?

  2. I noticed that the code I made is implemented in a such a way that the sequence currently selected should finish first before it can read the other or next PPM input to change the display/sequence. What I want to happen is the ability to change the sequence/display anytime I want to with just toggling a switch in my radio.

Here is the code I wrote any constructive input is appreciated. Thanks in advance. Please note I am a noob in arduino coding :smiley:

#include <Adafruit_NeoPixel.h>

#define PIN 6
int signalPin = 9;
int signal;


Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  pinMode (signalPin, INPUT);
  Serial.begin(9600);
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  
} 
  void loop () {
     signal = pulseIn(signalPin, HIGH);
     Serial.println(signal);
     switch (signal) {
     case (982):
     strip.show();// turn off the pixels
     break;
     case (1489):
     rainbowCycle(20);
     break;
  }
  }
  void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else if(WheelPos < 170) {
    WheelPos -= 85;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
}

RainbowCycle_Test.ino (1.15 KB)

You rang ?

I can't help with the strip.show() function as I have no experience of the hardware.

As to the need to wait until the sequence is finished you need to get rid of the for loop and use a technique other than delay(). Here is a program that I wrote to control LEDs on a quad.

#define ON HIGH
#define OFF LOW

#define DOUBLE_FLASH 0
#define ALL_OFF 1
#define LEFT_RIGHT 2
#define IN_OUT 3
#define ALL_ON 4
#define RANDOM 5

#define LEDS_ON_1 0
#define LEDS_OFF_1 1
#define LEDS_ON_2 2
#define LEDS_OFF_2 3
#define WAIT_1 1

byte receiverPin = 11;
unsigned long duration;
byte inputState = LOW;
byte prevInputState = LOW;
int pattern = 1;
unsigned long rearLedStateInterval;
unsigned long frontLedStateInterval;
int frontLedState = ON;

byte rearLedPins[] = {
  A0, A1, A2, A3};

byte frontLedPins[] = {
  8, 9};

void setup() 
{
  Serial.begin(115200);
  for (int pin = 0; pin < 4; pin++)
  {
    pinMode(rearLedPins[pin], OUTPUT);
  }
  
    for (int pin = 0; pin < 2; pin++)
  {
    pinMode(frontLedPins[pin], OUTPUT);
  }
  
  delay(1000);
}

void loop() 
{
  duration = pulseIn(receiverPin, HIGH);
  duration = map(duration, 1080, 1870, 0, 100);

  if (duration > 50)
  {
    inputState = LOW; 
  }
  else
  {
    inputState = HIGH; 
  }
  if (inputState != prevInputState)
  {
    rearAll(OFF);
    pattern++;
    if (pattern > RANDOM)
    {
      pattern = DOUBLE_FLASH;
    }
  }
  prevInputState = inputState;

  switch (pattern)
  {
  case DOUBLE_FLASH:
    {
      static byte state = LEDS_ON_1;

      switch(state)
      {
      case LEDS_ON_1:    //all ON wait 
        rearAll(ON); 
        static unsigned long stateStart = millis();
        rearLedStateInterval = 100;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_OFF_1;
          stateStart = millis();
        }
        break;   //end of LEDS_ON_1 state

      case LEDS_OFF_1:
        rearAll(OFF); 
        rearLedStateInterval = 200;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_ON_2;
          stateStart = millis();
        }      
        break;   //end of LEDS_OFF_1 state

      case LEDS_ON_2:
        rearAll(ON); 
        rearLedStateInterval = 100;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_OFF_2;
          stateStart = millis();
        }
        break;   //end of LEDS_ON_2 state

      case LEDS_OFF_2:      //all OFF wait longer after second flash
        rearAll(OFF); 
        rearLedStateInterval = 500;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_ON_1;
          stateStart = millis();
        }      
        break;   //end of LEDS_OFF_2 state
      }
      break;    //end of DOUBLE_FLASH
    }

  case ALL_OFF:
    {
      rearAll(OFF);    
      break;
    }

  case LEFT_RIGHT:
    {    
      static byte state = LEDS_ON_1;
      switch(state)
      {
      case LEDS_ON_1: 
        left(ON);
        right(OFF); 
        static unsigned long stateStart = millis();
        rearLedStateInterval = 300;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_ON_2;
          stateStart = millis();
        }
        break;    //end of LEDS_ON_1 state

      case LEDS_ON_2:
        left(OFF);
        right(ON); 
        rearLedStateInterval = 300;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_ON_1;
          stateStart = millis();
        }
        break;    //end of LEDS_ON_2 state 
      }
      break;    //end of LEFT/RIGHT states
    }

  case IN_OUT:
    {
      static byte rearLedState = LEDS_ON_1;
      switch(rearLedState)
      {
      case LEDS_ON_1: 
        outers(ON);
        inners(OFF); 
        static unsigned long rearLedStateStart = millis();
        rearLedStateInterval = 300;
        if (millis() - rearLedStateStart >= rearLedStateInterval)
        {
          rearLedState = LEDS_ON_2;
          rearLedStateStart = millis();
        }
        break;      //end of LEDS_ON_1 rearLedState

      case LEDS_ON_2: 
        outers(OFF);
        inners(ON); 
        rearLedStateInterval = 300;
        if (millis() - rearLedStateStart >= rearLedStateInterval)
        {
          rearLedState = LEDS_ON_1;
          rearLedStateStart = millis();
        }
        break;    //end of LEDS_ON_2 rearLedState 
      }    //end of IN/OUT rearLedStates
      break;    //end of IN/OUT case
    }

  case ALL_ON:
    {
      rearAll(ON);
      break;
    }

  case RANDOM:
    {
      static byte rearLedState = LEDS_ON_1;
      switch(rearLedState)
      {
      case LEDS_ON_1: 
        digitalWrite(rearLedPins[random(0, 4)], random(0, 2));
        static unsigned long rearLedStateStart = millis();
        rearLedState = WAIT_1;
        rearLedStateInterval = 50;
        break;

      case WAIT_1:
        if (millis() - rearLedStateStart >= rearLedStateInterval)
        {
          rearLedState = LEDS_ON_1;
          rearLedStateStart = millis();
        }
        break; 
      }  //end of RANDOM rearLedStates
      break;   //end of RANDOM case

    }  
  }    //end of rear leds patterns switch


  switch (frontLedState)
  {
  case ON:
    front(ON);
    frontLedStateInterval = 80;
    static unsigned long frontLedStateStart = millis();
    if (millis() - frontLedStateStart >= frontLedStateInterval)
    {
      frontLedState = OFF;
    frontLedStateStart = millis();
    }
    break;    //end of front leds on

  case OFF:
    front(OFF);
    frontLedStateInterval = 500;
    if (millis() - frontLedStateStart >= frontLedStateInterval)
    {
      frontLedState = ON;
      frontLedStateStart = millis();
    }
    break;    //end of front leds off
  }      //end of front leds switch
  
}      //end of loop()

void rearAll(byte ledState)
{
  outers(ledState);
  inners(ledState);
}

void left(byte ledState)
{
  digitalWrite(rearLedPins[2], ledState);
  digitalWrite(rearLedPins[3], ledState);
}

void right(byte ledState)
{
  digitalWrite(rearLedPins[0], ledState);
  digitalWrite(rearLedPins[1], ledState);
}

void inners(byte ledState)
{
  digitalWrite(rearLedPins[1], ledState);
  digitalWrite(rearLedPins[2], ledState);
}

void outers(byte ledState)
{
  digitalWrite(rearLedPins[0], ledState);
  digitalWrite(rearLedPins[3], ledState);
}

void front(byte ledState)
{
  digitalWrite(frontLedPins[0], ledState); 
  digitalWrite(frontLedPins[1], ledState); 
}

At first sight it will look complicated but take this section and study it. It is actually more complicated than it need be because of the nested switch/cases but that was how I did it at the time to allow the mark/space ratio of the flashes to be uneven.

 case DOUBLE_FLASH:
    {
      static byte state = LEDS_ON_1;

      switch(state)
      {
      case LEDS_ON_1:    //all ON wait 
        rearAll(ON); 
        static unsigned long stateStart = millis();
        rearLedStateInterval = 100;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_OFF_1;
          stateStart = millis();
        }
        break;   //end of LEDS_ON_1 state

      case LEDS_OFF_1:
        rearAll(OFF); 
        rearLedStateInterval = 200;
        if (millis() - stateStart >= rearLedStateInterval)
        {
          state = LEDS_ON_2;
          stateStart = millis();
        }      
        break;   //end of LEDS_OFF_1 state

It uses millis() for timing and switch/case so that only the code for the current state is executed each time through loop(). Because of that this section of code is executes each time through loop()

 duration = pulseIn(receiverPin, HIGH);
  duration = map(duration, 1080, 1870, 0, 100);

  if (duration > 50)
  {
    inputState = LOW; 
  }
  else
  {
    inputState = HIGH; 
  }
  if (inputState != prevInputState)
  {
    rearAll(OFF);
    pattern++;
    if (pattern > RANDOM)
    {
      pattern = DOUBLE_FLASH;
    }
  }
  prevInputState = inputState;

so it can respond to an input without waiting for the current sequence to finish. Replace the for loops in your rainbowCycle() function with counters that are incremented when the timing period ends (millis() - startTime >= requiredPeriod)

One thing I noted is that you are relying on exact values from pulseIn() to activate sequences. This will not be very reliable. I tested the value by using < and > and even mapped the raw small variation on change of switch position to a wider one to make it easier to spot the change.