Accelerometer driving Shift Register LEDs (if/else statement trouble)

Hi all,

I'm trying to help out a buddy with a project he's working on, basically involves having an accelerometer drive a series of 64 LEDs (8 clusters of 8 LEDs), he's using the following equipment:

The basic idea is that the more the accel moves, the "faster" light should travel around the ring (the 8 clusters of 64 LEDs are arranged in a circle)

I came up with a few ideas to get things running smoothly:

  1. polling the current value of accelerometer and comparing to the previous value, using 180 and some absolute value arithmetic to make a shift from 359 to 1 degree or vice versa not so drastic:
void speedcalculate(){
  
  //abs value
  absX[0] = abs(x-180);
  absY[0] = abs(y-180);
  absZ[0] = abs(z-180);


  //acceleration
  accelerationX = (abs(absX[0]-absX[1]));
  
  //velocity
  velocityX[0] = (velocityX[1] + accelerationX);  
  velocityX[0] = constrain(velocityX[0], 0, maxvel);
  velocityX[0] = map_double(velocityX[0], 0, maxvel, 0, 8);
  intVelocityX = (int) velocityX[0];
  1. because we are using the shift registers to control the LEDs, all we can do is run them HIGH or LOW, so instead of controlling PWM values, I am thought we would use an array of 8 values where the index represents the shift register in question, and the value it is storing (a number between 0 and 8) represents how many LEDs should be on in that cluster. I thought I could accomplish this with this bit of code:
//velocity -> LED cup translation 
  for (int i = 0; i < 8; i++) {
    
    if(i == 0) {
        if (ModulePast[i] > 0 && ModulePast[i] >= ModulePast[1] && ModulePast[i] >= ModulePast[2] && ModulePast[i] >= ModulePast[3] && ModulePast[i] >= ModulePast[4] && ModulePast[i] >= ModulePast[5] && ModulePast[i] >= ModulePast[6] && ModulePast[i] >= ModulePast[7]) {
            ModuleNow[i] = ModulePast[i];
            ModuleNow[i] -= intVelocityX;
            ModuleNow[7] += intVelocityX;
            constrain(ModuleNow[i], 0, 8);
            constrain(ModuleNow[7], 0, 8);
        }
    }
       
    else if (ModulePast[i] > 0 && ModulePast[i] >= ModulePast[0] && ModulePast[i] >= ModulePast[1] && ModulePast[i] >= ModulePast[2] && ModulePast[i] >= ModulePast[3] && ModulePast[i] >= ModulePast[4] && ModulePast[i] >= ModulePast[5] && ModulePast[i] >= ModulePast[6] && ModulePast[i] >= ModulePast[7]) {
      ModuleNow[i] = ModulePast[i];
      ModuleNow[i] -= intVelocityX;
      ModuleNow[i-1] += intVelocityX;
      constrain(ModuleNow[i], 0, 8);
      constrain(ModuleNow[i-1], 0, 8);
    }

the if i == 0 part was to compensate for trying to make the loop continuous (IE if there are LEDs on in module 0, they should move to module 7 as they're next to each other in the loop). The long chain boolean AND statements (ModulePast >= ModulePast[1]) was a dumb way of trying to come up with a way where the code would only execute if the value of that register was highest value in the entire array, but I now realize there is even a problem with this, as it would only get to 4 before it would stop executing. <- the basic behavior we are after is that if you think of the 8 LEDs on a single shift register as a cup, they should transfer intVelocityX LEDs to the next module every loop, with intVelocityX being an integer between 0 and 8 which is a number given by the accelerometer/speed calculation.
the last bit of code would take the numbers stored in the array and turn the appropriate pins HIGH based on the value it found for that register:
```
*//write LEDs

shifter.clear();
for (int i = 0; i < 8; i++) {
 for (int j = 0; j <= ModuleNow[i]; j++) {
   ledOn = ((8 * i) + j);
   Serial.println(ledOn);
   shifter.setPin(ledOn, HIGH);
 }
}
shifter.write();*
```
Will post a hypothetical run through of what we want to happen in following post...

So, here is what we would like to happen.

Let's say accelerometer was reporting a value of 255 last loop and is now 268, a difference of 13. This is a pretty good amount of motion, and it runs through our code and dictates that 4 LEDs should move from wherever they are, to the next register.

We then run through the ModulePast[] array one by one, looking for the index which has 8/the most LEDs(trouble here!) and subtract 4 from it, and add 4 to the previous index (not the next one, otherwise this causes it to spread those LEDs on infinitely, as it increments up and finds the 4 it just transferred there). For now we are also constraining the values to an int between 0 and 8 to make things simple, but it would be nice if it had some sort of overfill/underfill protection, IE: current index is only 3, but we subtract 4 from it, and the index that is receiving those 4 is already 5, so it becomes 9. In the current system it's simply chopped off, but it would be nice if something like this happened:

Index : Value | operation
0:0
1:0
2:0 
3:5 | +4  (+4 would results in 9, so any quant. over 8 should immediately acted from this index and added to index 2)
4:3| -4
5:0
6:0
7:0

Does that make any sense? probably not explaining clearly brain is a bit fried with all this simple math/logic hah!

and finally entire code, has some stuff commented out and random Serial.print things sprinkled through that are attempts at diagnosing what is wrong...

//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Simple code for the ADXL335, prints calculated orientation via serial
//////////////////////////////////////////////////////////////////
#include <Shifter.h>

#define SER_Pin 4 //SER_IN
#define RCLK_Pin 3 //L_CLOCK
#define SRCLK_Pin 2 //CLOCK

#define NUM_REGISTERS 8 //how many registers are in the chain

//initaize shifter using the Shifter library
Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); 

//Analog read pins
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

//The minimum and maximum values that came from
//the accelerometer while standing still
//You very well may need to change these
int minVal = 300;
int maxVal = 602;

//to hold the caculated values
double x;
double y;
double z;

//hold absolute values
double absX[2];
double absY[2];
double absZ[2];

//averaged values (accel=erometer)
float avgAccel[2]={0,0};

//speed
float accelerationX; //current accel state(avgAccel[0]) - previous accel state[1])
float accelerationY; //current accel state(avgAccel[0]) - previous accel state[1])
float accelerationZ; //current accel state(avgAccel[0]) - previous accel state[1])

float friction = .9; //rate of natural deceleration
float velocityX[2]={0,0}; //speed of movement, function of friction and any new acceleration
float velocityY[2]={0,0}; //speed of movement, function of friction and any new acceleration
float velocityZ[2]={0,0}; //speed of movement, function of friction and any new acceleration
int maxvel = 200; //used for constraining velocity, adjust to change relative magnitude of vibrations -> acceleration

int intVelocityX;

//REGISTERS/LED

int currentModule;
int ledOn;

//LED Values
int ModuleNow[8] = {0,0,0,0,0,0,0,0};
int ModulePast[8] = {0,0,0,0,8,0,0,0};


void setup() {
  Serial.begin(9600);
}


void loop() {

//  accelerometer();
  
//  speedcalculate();
  intVelocityX = 1;
 
//velocity -> LED cup translation 
  /*
  for (int i = 0; i < 8; i++) {
    
    if(i == 0) {
        if (ModulePast[i] > 0 && ModulePast[i] >= ModulePast[1] && ModulePast[i] >= ModulePast[2] && ModulePast[i] >= ModulePast[3] && ModulePast[i] >= ModulePast[4] && ModulePast[i] >= ModulePast[5] && ModulePast[i] >= ModulePast[6] && ModulePast[i] >= ModulePast[7]) {
            ModuleNow[i] = ModulePast[i];
            ModuleNow[i] -= intVelocityX;
            ModuleNow[7] += intVelocityX;
            constrain(ModuleNow[i], 0, 8);
            constrain(ModuleNow[7], 0, 8);
            Serial.println("IF I = O");
        }
    }
       
    else if (ModulePast[i] > 0 && ModulePast[i] >= ModulePast[0] && ModulePast[i] >= ModulePast[1] && ModulePast[i] >= ModulePast[2] && ModulePast[i] >= ModulePast[3] && ModulePast[i] >= ModulePast[4] && ModulePast[i] >= ModulePast[5] && ModulePast[i] >= ModulePast[6] && ModulePast[i] >= ModulePast[7]) {
      ModuleNow[i] = ModulePast[i];
      ModuleNow[i] -= intVelocityX;
      ModuleNow[i-1] += intVelocityX;
      constrain(ModuleNow[i], 0, 8);
      constrain(ModuleNow[i-1], 0, 8);
      Serial.println("ELSE IF");
    }
        
     
  }
          
delay(1000); 
  
//write LEDs

shifter.clear();
for (int i = 0; i < 8; i++) {
  for (int j = 0; j <= ModuleNow[i]; j++) {
    ledOn = ((8 * i) + j);
    Serial.println(ledOn);
    shifter.setPin(ledOn, HIGH);
  }
}
shifter.write();
Serial.println("Shiftwrite");
*/

  for (int i = 0; i < 64; i++) {
    shifter.clear();
    shifter.setPin(i, HIGH);
    shifter.write();
    Serial.println(i);
    delay(100);
  }

//Move current values to previous values
  velocityX[1] = (velocityX[0] * friction);
  absX[1] = absX[0];
  absY[1] = absY[0];
  absZ[1] = absZ[0];

  for (int i = 0; i < 8; i++) {
    ModulePast[i] = ModuleNow[i];
  }
  
  /*
  //Output the caculations
  Serial.print("A0:");
  Serial.print(analogRead(xPin));
  Serial.print(" | x: ");
  Serial.print(absX[0]);
  Serial.print(" | y: ");
  Serial.print(absY[0]);
  Serial.print(" | z: ");
  Serial.print(absZ[0]);
  Serial.print(" || accelerationX: ");
  Serial.print(accelerationX);
  Serial.print(" | velocityX0: ");
  Serial.print(velocityX[0]);
  Serial.print(" | velocityX1: ");
  Serial.print(velocityX[1]);
  Serial.print(" | intVelocityX: ");
  Serial.println(intVelocityX);
 */

}


float map_double(double x, double in_min, double in_max, double out_min, double out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


void accelerometer(){  //read the analog values from the accelerometer
  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  //convert read values to degrees -90 to 90 - Needed for atan2
  int xAng = map(xRead, minVal, maxVal, -90, 90);
  int yAng = map(yRead, minVal, maxVal, -90, 90);
  int zAng = map(zRead, minVal, maxVal, -90, 90);

  //Caculate 360deg values like so: atan2(-yAng, -zAng)
  //atan2 outputs the value of -? to ? (radians)
  //We are then converting the radians to degrees
  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
  y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
  z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
}

void speedcalculate(){
  
  //abs value
  absX[0] = abs(x-180);
  absY[0] = abs(y-180);
  absZ[0] = abs(z-180);


  //acceleration
  accelerationX = (abs(absX[0]-absX[1]));
  
  //velocity
  velocityX[0] = (velocityX[1] + accelerationX);  
  velocityX[0] = constrain(velocityX[0], 0, maxvel);
  velocityX[0] = map_double(velocityX[0], 0, maxvel, 0, 8);
  intVelocityX = (int) velocityX[0];
}