LED Strip + Accelerometer, Stopping & Starting Loop

Hi all, first Arduino project underway here.

I've gotten my UNO to read both the accelerometer and LED strip fine but having a hard time getting the code to reach to my end goal.

  • I want the strip to start blank.
  • When motion is detected, the strip will turn one color and stay that color.
  • After waiting three seconds, if moved again the strip will change to color 2 and stay there.
  • The strip will cycle through about 4 color variations.

Is this possible? Is this post too long? What is even happening?

Thanks for any and all help.

-Matt

Is there a post-of-the-month award?

MattDBC:
Is this possible? Is this post too long? What is even happening?

Thanks for your requirements. Now...

Yes it's possible. No, the post is far too short because it doesn't contain any code for us to help with or any details of what it currently does or of what accelerometer or LED strip you have.

What is happening is that you are asking us to fix something we can't see and have almost no information about.

Steve

Is this possible?

Yes.

Is this post too long?

No.

What is even happening?

Lots of things are happening, most of which do not involve an Arduino. Their is general global unrest and the rise of right wing and religious extremists. However, what this has to do with this forum I don't know.

Please read this:- BEGINNERS: We rarely write code for you, but will help you write it for yourself - General Discussion - Arduino Forum

@Grumpy_Mike -- I KNEW there was something afoot. Someone should get on that? dunno.

@Steve -- Appreciate the headsup

Accelerometer: HiLetgo GY-521 MPU-6050 MPU6050 3 Axis Accelerometer Gyroscope Module 6
LED Strip: MOKUNGIT WS2812B 144Pixels RGB

Current Code:

#include <Adafruit_NeoPixel.h>
#include <Wire.h>

#define PIN 6
#define NUMPIXELS 140

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
int delayval = 1000;
int stillTime = 1000;
const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
char tmp_str[7]; // temporary variable used in convert function
char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
sprintf(tmp_str, "%6d", i);
return tmp_str;
}

void setup() {

pixels.begin();

Serial.begin(9600);
delay(3000);
Wire.begin();
Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
}

void loop() {

for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
pixels.show();
}

if (accelerometer_x > -500 && accelerometer_y > 16000) {
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(150, 0, 0));
pixels.show();
if (accelerometer_x > -10000 && accelerometer_y > 14000) {
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 150, 0));
pixels.show();

Wire.beginTransmission(MPU_ADDR);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
Wire.requestFrom(MPU_ADDR, 7 * 2, true); // request a total of 7*2=14 registers

// "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
accelerometer_x = Wire.read() << 8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
accelerometer_y = Wire.read() << 8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
accelerometer_z = Wire.read() << 8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
temperature = Wire.read() << 8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
gyro_x = Wire.read() << 8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
gyro_y = Wire.read() << 8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
gyro_z = Wire.read() << 8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)

// print out data
Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
// the following equation was taken from the documentation [MPU-6000/MPU-6050 Register Map and Description, p.30]
Serial.print(" | tmp = "); Serial.print(temperature / 340.00 + 36.53);
Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
Serial.println();

}
}
}
}
}

Getting better. Now if you format the code use Ctrl-T and then post it using </> code tags it will be even better.

Oh and you also need to tell us in detail what it actually does that's different from what it's supposed to do. From a quick look it seems to blank the display every time round the loop() and I can't see any attempt at timing a 3 second wait before a colour change.

Steve

You're the man. Knew there had to be a better way to post that code thanks. Full detail mode:

  • The project is that I have a series of old encyclopedias on a bookshelf.
  • For the first volume, willl hollow it out and place the UNO/accelerometer inside.
  • The led strip will be taped to the wall-facing sides of the bookshelf.
  • If the book is pulled out/down (with the movement in the style of a secret compartment latch) the LED Strip will light up .
  • If pulled out again a few seconds later, the strip will change color. Hoping for 4-ish color variations.

Right now, I can only get the strip to change color if I program the accelerometer to recognize movement to a certain x y criteria. So it starts blank, then if I stand my breadboard on it's side it'll turn green.

Again ideally it'll start blank, recognize any movement and change color, and check back every few seconds for movement and cycle through susequent colors.

I've added a 'better' version of the code here.

#include <Adafruit_NeoPixel.h>
#include <Wire.h>

#define PIN 6
#define NUMPIXELS 140

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
int delayval = 5000;
int stillTime = 5000;
bool blinkState = 0;
bool running = false;
bool myOutput = false;
unsigned long loopTime = 0;          // get the time since program started
unsigned long interruptsTime = 0;    // get the time when motion event is detected
const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
char tmp_str[7]; // temporary variable used in convert function
char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
  sprintf(tmp_str, "%6d", i);
  return tmp_str;
}


void setup() {

  pixels.begin();

  Serial.begin(9600);
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN, HIGH);
  digitalWrite(PIN, LOW);
  delay(1000);
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
}

void loop() {

  for (int i = 0; i < NUMPIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.show();
  }
    // This one is breadboard facing left (color should be green)
  if (accelerometer_x > -1000 && accelerometer_y > 8000) {
    for (int i = 0; i < NUMPIXELS; i++) {
      pixels.setPixelColor(i, pixels.Color(150, 0, 0));
      pixels.show();
    }
    delay(5000);
  }

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
  Wire.requestFrom(MPU_ADDR, 7 * 2, true); // request a total of 7*2=14 registers

  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  accelerometer_x = Wire.read() << 8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accelerometer_y = Wire.read() << 8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accelerometer_z = Wire.read() << 8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  temperature = Wire.read() << 8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyro_x = Wire.read() << 8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
  gyro_y = Wire.read() << 8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
  gyro_z = Wire.read() << 8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)

  // print out data
  Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
  Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
  Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
  // the following equation was taken from the documentation [MPU-6000/MPU-6050 Register Map and Description, p.30]
  Serial.print(" | tmp = "); Serial.print(temperature / 340.00 + 36.53);
  Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
  Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
  Serial.println();


  }

The specification is a bit unclear. The LEDs start off blank. Then when you detect movement they come on with a colour. They stay that way for 5 seconds. After 5 seconds you wait for another movement and when one is detected they change colour. They keep doing this, cycling round several different colours. Is that correct?

So once a movement is detected the LEDs will stay on for ever, just changing colour? Or should they ever go blank again? If so what causes them to blank?

Either way start by moving the blanking code out of the top of loop() and put it in setup(). Otherwise you'll blank the LEDs every time no movement is detected.

Steve

Ideally-- when the power is turned on the strip starts blank. If movement is detected, it turns to white LEDs and will stay that color. The LEDs cannot change for three seconds (as I reset the 'book' the accelerometer is in).

If, movement is detected again after that buffer three seconds, the LEDs change to green and stay that way. And so on through a few color options. So i can basically control whatever lighting is in my bookshelf by pulling on a book.

The code is a hodgepodge at this point from different tutorials so it's probably pretty broke-ass. Right now the code looks like I'm giving the accelerometer x & y specifications and still tinkering away with this approach---which I don't think the easiest?

Again, huge thanks.

-matt

Hi Forum just following up here.

I couldn't find a way for the accelerometer to just detect any motion, so I decided to use x,y,z coordinates instead. Which was a bit of a pain but hey good practice.

So when the book housing the UNO/accelerometer is stationary the LED strip is green. When tilted to about a 20 degree angle it turns purple, and then at about 60 degrees it'll go rainbow.

The only issue so far is that my three RGB LED strips connected together (432 LEDs total) can't show the color white. Which makes my rainbow setting janky as shit. Doing some digging on this site think that might be a power issue. Right now I have a 9v charger going into 12v-->5v converter. I have a 12v adapter on the way and hopefully that'll remedy it. If not, whatever.

Long story longer here's the code I'm rolling with now.

<
#include <Adafruit_NeoPixel.h>
#include <Wire.h>

#define PIN 6                                             
#define COLOR_ORDER GRB                                      
#define LED_TYPE WS2812B                                      
#define NUMPIXELS 400   




Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
int delayval = 2000;
int stillTime = 2000;
bool blinkState = 0;
bool running = false;
bool myOutput = false;
unsigned long loopTime = 0;          
unsigned long interruptsTime = 0;   
const int MPU_ADDR = 0x68; 
int16_t accelerometer_x, accelerometer_y, accelerometer_z; 
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; 
char tmp_str[7]; 
char* convert_int16_to_str(int16_t i) {
 sprintf(tmp_str, "%6d", i);
 return tmp_str;
}


void setup() {
 pixels.begin();

 Serial.begin(9600);
 pinMode(PIN, OUTPUT);
 digitalWrite(PIN, HIGH);
 digitalWrite(PIN, LOW);
 delay(1000);
 Wire.begin();
 Wire.beginTransmission(MPU_ADDR); 
 Wire.write(0x6B); 
 Wire.write(0); 
 Wire.endTransmission(true);

} 

 

void loop() {


   if (accelerometer_x > 15000 && accelerometer_y < -200 && accelerometer_y > -2200) {
   for (int i = 0; i < NUMPIXELS; i++) {
     pixels.setPixelColor(i, pixels.Color(0, 5, 200));
     pixels.show();
   }
   delay(2000);
 }
     if (accelerometer_x > 15000 && accelerometer_y < -3200 && accelerometer_y > -5000) {
   for (int i = 0; i < NUMPIXELS; i++) {
     pixels.setPixelColor(i, pixels.Color(150, 8, 0));
     pixels.show();
   }
   delay(2000);
 }
     if (accelerometer_x > 15000 && accelerometer_y < -5600 && accelerometer_y > -8000) {
   for (int i = 0; i < NUMPIXELS; i++) {
     (rainbow(1));
     pixels.show();
   }
   delay(2000);
     }  
 
 Wire.beginTransmission(MPU_ADDR);
 Wire.write(0x3B); 
 Wire.endTransmission(false); 
 Wire.requestFrom(MPU_ADDR, 7 * 2, true); 

 // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
 accelerometer_x = Wire.read() << 8 | Wire.read(); 
 accelerometer_y = Wire.read() << 8 | Wire.read(); 
 accelerometer_z = Wire.read() << 8 | Wire.read();
 temperature = Wire.read() << 8 | Wire.read(); 
 gyro_x = Wire.read() << 8 | Wire.read(); 
 gyro_y = Wire.read() << 8 | Wire.read(); 
 gyro_z = Wire.read() << 8 | Wire.read(); 

 Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
 Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
 Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
 Serial.print(" | tmp = "); Serial.print(temperature / 340.00 + 36.53);
 Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
 Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
 Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
 Serial.println();

}



void rainbow(uint8_t wait) {
 uint16_t i, j;

 for(j=0; j<256; j++) {
   for(i=0; i<pixels.numPixels(); i++) {
     pixels.setPixelColor(i, Wheel((i*1+j) & 255));
   }
   pixels.show();
   delay(2000);
 }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
 if(WheelPos < 85) {
   return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
 } 
 else if(WheelPos < 170) {
   WheelPos -= 85;
   return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
 } 
 else {
   WheelPos -= 170;
   return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
 }
}

>

Cheers,
Matt

432 LEDs total

It is not a matter of voltage but of current. That many will require a current of 25 Amps, each LED requires 60mA.