Trying to make 2 patterns on one Neopixel chain

Hi,
I'm trying, and failing, to do something that should be simple: run two independent lighting patterns on different zones of 30 neopixels. I have potentiometers that control the speed and direction that the LEDs light in a theatre strip pattern. I can get LEDs 0-17 working the way I want, but not 18-30. I am sure I'm doing something simple wrong, and I have a feeling it's to do with conflicting calls to pixels.show(), but I am stumped. Any helpful pointers welcome!!! Here's the code...

I'm running this on a Teensy 3.2

#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#define PIN 3
#define NUMPIXELS   30
#define CALIBRATIONTIME 20000
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int rotationDirectionY = 0;
int rotationDirectionX = 0;
const int xPot = A7;
const int yPot = A8;
const int zPot = A9;
const int xAxisMotorEnable = 1;
const int xAxisMotorPin1  = 4;  // Pin 14 of L293
const int xAxisMotorPin2  = 5;  // Pin 10 of L293
const int zAxisMotorEnable = 2;
const int zAxisMotorPin1  = 6;  // Pin 14 of L293
const int zAxisMotorPin2  = 9;  // Pin 10 of L293
unsigned long pixelsIntervalY = 0; // the time we need to wait
unsigned long pixelsIntervalX = 0; // the time we need to wait
unsigned long theaterChaseYPreviousMillis = 0;
unsigned long theaterChaseXPreviousMillis = 0;
int theaterChaseY = 0;
int theaterChaseX = 0;
int timingData[6];
//uint16_t currentPixelY = 0;// what pixel are we operating on
//uint16_t currentPixelX = 0;// what pixel are we operating on

void setup() {
  //  currentPixelY = 0;
  //  currentPixelX = 18;
  Serial.begin(9600);
  Wire.begin(); //try this as the master device, with the audio board as a slave on channel 8
  pinMode(xAxisMotorEnable, OUTPUT);
  pinMode(xAxisMotorPin1, OUTPUT);
  pinMode(xAxisMotorPin2, OUTPUT);

  pinMode(zAxisMotorEnable, OUTPUT);
  pinMode(zAxisMotorPin1, OUTPUT);
  pinMode(zAxisMotorPin2, OUTPUT);
  pixels.begin();
  pixels.setBrightness(80);
  pixels.show(); // Initialize all pixels to 'off'
}

void loop() {

  timingData[0] = theaterChaseY;
  timingData[1] = theaterChaseX;
  timingData[2] = rotationDirectionY;
  timingData[3] = rotationDirectionX;
  timingData[4] = pixelsIntervalY;
  timingData[5] = pixelsIntervalX;
  Wire.beginTransmission(4); // transmit to device #4
  for (int i = 0; i < 6; i++) {
    Wire.write(timingData[i]);
  }

  Wire.endTransmission();    // stop transmitting
  //OUTER led ring timer Y Axis
  if ((unsigned long)(millis() - theaterChaseYPreviousMillis) >= pixelsIntervalY) {
    theaterChaseYPreviousMillis = millis();
    yAxisNeopixel(pixels.Color(255, 255, 255), rotationDirectionY); // White

  }

  //  INNER led Spiral timer X Axis
  if ((unsigned long)(millis() - theaterChaseXPreviousMillis) >= pixelsIntervalX) {
    theaterChaseXPreviousMillis = millis();
    xAxisNeopixel(pixels.Color(255, 255, 255), rotationDirectionX); // White
  }
  int xPotVal = analogRead(xPot);
  int yPotVal = analogRead(yPot);
  int zPotVal = analogRead(zPot);
  /*
      X axis (INNER) motor speed and direction controls
  */
  if ((xPotVal > 0) && (xPotVal < 85)) {

    int xLedAntiClockwise = map(xPotVal, 0, 95, 40, 300);
    rotationDirectionX = 0;
    pixelsIntervalX = xLedAntiClockwise;

    int xAntiClockwise = map(xPotVal, 0, 84, 255, 0);
//    digitalWrite(xAxisMotorEnable, HIGH);
//    digitalWrite(xAxisMotorPin1, LOW);
//    analogWrite(xAxisMotorPin2, xAntiClockwise);
  }
  if ((xPotVal > 85) && (xPotVal < 129)) {

    rotationDirectionX = 2;

    digitalWrite(xAxisMotorEnable, LOW);
    analogWrite(xAxisMotorPin1, 0);
    analogWrite(xAxisMotorPin2, 0);
  }
  if ((xPotVal > 130) && (xPotVal < 200)) {

    int xLedClockwise = map(xPotVal, 110, 200, 300, 40);
    rotationDirectionX = 1;
    pixelsIntervalX = xLedClockwise;

    int xClockwise = map(xPotVal, 130, 200, 0, 255);
//    digitalWrite(xAxisMotorEnable, HIGH);
//    analogWrite(xAxisMotorPin1, xClockwise);
//    digitalWrite(xAxisMotorPin2, LOW);
  }

  /*
         Y axis (OUTER RING) neopixel direction and speed controls
  */
  if ((yPotVal > 0) && (yPotVal < 95)) {
    int yAntiClockwise = map(yPotVal, 0, 95, 20, 300);
    rotationDirectionY = 0;
    pixelsIntervalY = yAntiClockwise;
  }
  if ((yPotVal > 95) && (yPotVal < 125)) {
    rotationDirectionY = 2;
  }
  if ((yPotVal > 125) && (yPotVal < 200)) {
    rotationDirectionY = 1;
    int yClockwise = map(yPotVal, 110, 200, 300, 20);
    pixelsIntervalY = yClockwise;
    //need to use a inverse function to decrement to reverse direction
  }

  /*
         Z axis ring motor direction and speed controls
  */

  // Serial.println(zPotVal);
  if ((zPotVal > 0) && (zPotVal < 85)) {
    int zAntiClockwise = map(zPotVal, 0, 85, 255, 0);
    digitalWrite(zAxisMotorEnable, HIGH);
    digitalWrite(zAxisMotorPin1, LOW);
    analogWrite(zAxisMotorPin2, zAntiClockwise);
  }
  if ((zPotVal > 85) && (zPotVal < 130)) {
    digitalWrite(zAxisMotorEnable, LOW);
    analogWrite(zAxisMotorPin1, 0);
    analogWrite(zAxisMotorPin2, 0);
  }
  if ((zPotVal > 130) && (zPotVal < 200)) {
    int zClockwise = map(zPotVal, 130, 200, 0, 255);
    digitalWrite(zAxisMotorEnable, HIGH);
    analogWrite(zAxisMotorPin1, zClockwise);
    digitalWrite(zAxisMotorPin2, LOW);
    //need to use a inverse function to decrement to reverse direction
  }
}





// OUTER LED ring LEDs 0 - 17
void yAxisNeopixel(uint32_t c, int dir) {
 // Serial.println(dir);
  // anticlockwise direction
  if (dir == 0) {
    //Serial.println("Y axis anticlockwise");
    for (int i = 18; i >= 0; i = i - 18) {
      pixels.setPixelColor(i + theaterChaseY, c); 
    }
    pixels.show();
    for (int i = 18; i >= 0; i = i - 18) {
      pixels.setPixelColor(i + theaterChaseY, 0);     
    }

    theaterChaseY--;
    //  Serial.println(theaterChaseY);
    if (theaterChaseY <= -1) theaterChaseY = 18;
  }


  // clockwise direction
  if (dir == 1) {
    for (int i = 0; i < 18; i = i + 18) {
      pixels.setPixelColor(i + theaterChaseY, c);  
    }
    pixels.show();
    for (int i = 0; i < 18; i = i + 18) {
      pixels.setPixelColor(i + theaterChaseY, 0);    
    }
    theaterChaseY++;
    if (theaterChaseY >= 18) theaterChaseY = 0;
  }


  // turn all of
  if (dir == 2) {
    for (int i = 0; i < 18; i++) {
      pixels.setPixelColor(i + theaterChaseY, 0);      //turn every third pixel off
    }
    pixels.show();
    theaterChaseY++;
    if (theaterChaseY >= 18) theaterChaseY = 0;
  }
}



//INNER LED Spiral
void xAxisNeopixel(uint32_t c, int dir) {
      //Serial.println(dir);
  if (dir == 0) { // anticlockwise direction

    for (int i = 30; i > 19; i = i - 12) {
      pixels.setPixelColor(i + theaterChaseX, c);  //turn every third pixel on
    }
    pixels.show();
    for (int i = 30; i > 19; i = i - 12) {
      pixels.setPixelColor(i + theaterChaseX, 0);      //turn every third pixel off
    }
    theaterChaseX--;
   // Serial.println(theaterChaseX);
    if (theaterChaseX <= 19) theaterChaseX = 30;
  }
  if (dir == 1) { // clockwise direction
    for (int i = 19; i <= 30; i = i + 12) {
      pixels.setPixelColor(i + theaterChaseX, c);  //turn every third pixel on

    }
    pixels.show();
    for (int i = 19; i <= 30; i = i + 12) {
      pixels.setPixelColor(i + theaterChaseX, 0);      //turn every third pixel off

    }
  pixels.show();
    theaterChaseX++;
    if (theaterChaseX >= 30) theaterChaseX = 19;
  }

  if (dir == 2) { // turn all off
    for (int i = 19; i < 30; i++) {
      pixels.setPixelColor(i + theaterChaseX, 0);      //turn every third pixel off
    }
    theaterChaseX++;
    pixels.show();
    if (theaterChaseX >= 30) theaterChaseX = 19;
  }
}
for (int i = 19; i <= 30; i = i + 12) {

How many times do you expect this loop to iterate? It will only do the loop once.

Hi Mike,

As the pot is being monitored constantly in the main loop, this returns a number between 0-2 indicating which direction the LEDs should light in (for context, it's a gyroscope type light installation, with LEDs 0-17 arranged in a ring, 18-30 in a line but angled to make a spiral). So the ring uses a for loop in the same way you highlighted but loops constantly as the condition is met. So maybe not the best way to implement it but that part at least seems to work...

The function controlling the ring will work alone just fine, but the other group (18-30) will only work if the ring group is turned on.

I don’t think you understand what I am saying. The comments in that loop say that it will turn on every third LED, that is not what the code will do. Because after the first time round the loop with i being 19, i gets changed to be 32 and so stops.

Ah right. I copied a piece of code that turned on every third led but changed it so they'd go on one after another... Is there a neater way of doing this?

I don’t know because you haven’t posted that bit of code. But I would suggest changing that function to


for (int i = 19; i <= 30; i = i + 3 {
      pixels.setPixelColor(i + theaterChaseX, 0);      //turn every third pixel off
} 

Why were you doing

  i = i + 12

Hi Mike,

the comment "turn every third pixel on/off" is from the original code I copied and adapted, I simply hadn't changed it to reflect what the code was actually doing. Sorry if that confuses my query. With LEDs 0-17, in order to turn one on, then turn it off, and turn the next one in the chain on in sequence, I adapted this to be
for (int i = 0; i <= 18; i = i + 18){
...which works perfectly. I will attach a video of this to illustrate tomorrow. The issue is using this same approach with the next set of leds, 18-29, where adding 12 to i doesn't work in the same way as with the other range.

So all I want to do is to be able to turn one led on while simultaneously turning off the previous LED. The way I'm using from the example code is not the most obvious way to me to do this, but it worked for the first set of leds at least.

Confused it! It totally screwed it up. Thanks.
Without accurate comments you have no idea what the section of code is supposed to do. As it is a nonsense thing to write how on earth is anyone supposed to read your mind?

for (int i = 0; i <= 18; i = i + 18){

…which works perfectly.

That also runs only once. It is exactly the same as writing:-

for (int i = 0; i <= 18; i = i + 18000){

Which also is a nonsense thing to write. The fact it did what you wanted it to do was a pure fluke. You do it again and you don't win the lottery twice. Surprised?

teach me, master. Seriously, if you can even hint at a better way I'll look into figuring it out for myself. Evidently the code is rubbish, and a fluke that it worked at all. I get that, but would love to move on from that towards something that might help me to fix it.

Well the first thing would be to update your comments.

Then try to tackle just one pattern in one section of the strip and get that working.

Once one is working then try and get the other pattern working in the other part of the strip. Finally combine them when you have an overall pattern of what you are doing.

There is no such thing as conflicting .show calls, you can call this method as much as you want and it will just show the latest state of the pixel buffer.

Will do when I'm on that computer again. To be clear though, I have already got one of the sections working as I want it to. It's only when I try the same approach with the second section that things don't go as planned.

Good to know it's not pixels.show(), thanks for eliminating that from the mix.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.