Generating Random Colours from the Error Signal of the three axis’ of an accelometer.
The arduino nano is connected to the SPI interface. SPI is a serial clocked signal to write the colour values to the RGB strip lights. The accelometer is connected to A5 and A4 ports for the I2C bus.
I use the FASTwire interface as the normal interface does not have error catching. The raw values are read from the MPU6050 directly.
So to get at the error signal, which is as far as I can tell highly random and hence produces the randomness for the RGB lights, I need to create an average over N values. N being 28 in this example. But If you try and increase N it will run out of memory at above 70. From the average I take the difference which produces 3 values dfax,dfay,dfaz. From here I take the minimum value set it to zero and add it to the other values to increase efficiency of the LEDs. I output this difference and spread it out in time along the strip.
Amazing and completely random colours occur along the strip.
See arduino code below
Parts List:
- GY-521 MPU6050
- Arduino Nano
- Adafruit RGB Strip LDP8806
Code:
#include “I2Cdev.h”
#include “MPU6050.h”
#include “Wire.h”
#include “LPD8806.h”
#include “SPI.h” // Comment out this line if using Trinket or Gemma
#ifdef AVR_ATtiny85
#include <avr/power.h>
#endif
// Number of RGB LEDs in strand:
int nLEDs = 28;
// Chose 2 pins for output; can be any valid output pins:
int dataPin = 11;
int clockPin = 13;
// First parameter is the number of LEDs in the strand. The LED strips
// are 32 LEDs per meter but you can extend or cut the strip. Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro2(0x69); / <-- use for AD0 high
////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
Wire.begin();
Fastwire::setup(400, false);
accelgyro.initialize();
if(accelgyro.testConnection()){
}
#if defined(AVR_ATtiny85) && (F_CPU == 16000000L)
clock_prescale_set(clock_div_1); // Enable 16 MHz on Trinket
#endif
// Start up the LED strip
strip.begin();
// Update the strip, to start they are all ‘off’
strip.show();
delay(2000);
}
///////////////////////////////////////////////////////////////////////
#define N 28
int16_t ax, ay, az;
int16_t gx, gy, gz;
uint8_t BUFFER[14];
float farray[N];
float farrayx[N];
float farrayy[N];
float farrayz[N];
int state=0;
float angle1x=0.0;
float angle1y=0.0;
float angle1z=0.0;
float angle2x=0.0;
float angle2y=0.0;
float angle2z=0.0;
float fax=0.0,faz=0.0,fay=0.0,fd=0.0;
float faverage=0.0;
float faveragez=0.0;
float faveragey=0.0;
float faveragex=0.0;
float theta;
#define DUTY_MAX 20
bool tripped=false;
bool flash=true;
unsigned int duty_counter=0,duty_cycleR=0,duty_cycleG=0,duty_cycleB=0;
///////////////////////////////////////////////////////////////////////////
void loop() {
// Serial.print(duty_counter%DUTY_MAX); Serial.print("\t");
duty_counter++;
if(duty_counter==N)duty_counter=0;
//////////////////////////////////////////////
tripped=false;
state=I2Cdev::readBytes(0x68,MPU6050_RA_ACCEL_YOUT_H,2, BUFFER);//
if(state>=0){
ay= (((int16_t)BUFFER[0]) << 8) | BUFFER[1];
}
else{
//Serial.print("FAIL1");
Fastwire::reset();
tripped=true;
// Fastwire::setup(400, false);
}
state=I2Cdev::readBytes(0x68, 0x3F, 2,BUFFER);
if(state>=0){
az= (((int16_t)BUFFER[0]) << 8) | BUFFER[1];
}
else{
// Serial.print("FAIL2");
Fastwire::reset();
tripped=true;
}
state=I2Cdev::readBytes(0x68,MPU6050_RA_ACCEL_XOUT_H,2, BUFFER);//
if(state>=0){
ax= (((int16_t)BUFFER[0]) << 8) | BUFFER[1];
}
else{
// Serial.print("FAIL1");
Fastwire::reset();
tripped=true;
// Fastwire::setup(400, false);
}
if(!tripped){
faz=az;fax=ax;fay=ay;
fd= sqrt(fazfaz+faxfax+fay*fay);
farrayx[duty_counter]=fax;
faveragex=0.0;
for(int i=0;i<N;i++)faveragex+=farrayx[i];
faveragex/=N;
farrayy[duty_counter]=fay;
faveragey=0.0;
for(int i=0;i<N;i++)faveragey+=farrayy[i];
faveragey/=N;
farrayz[duty_counter]=faz;
faveragez=0.0;
for(int i=0;i<N;i++)faveragez+=farrayz[i];
faveragez/=N;
farray[duty_counter]=fd;
faverage=0.0;
for(int i=0;i<N;i++)faverage+=farray[i];
faverage/=N;
//angle1x=atan2(ax,fd)*180/M_PI;
//an/gle1y=atan2(ay,fd)*180/M_PI;
//angle1z=atan2(az,fd)*180/M_PI;
for (int i=0; i < strip.numPixels(); i++) {
float dfax=(farrayx[i]-faveragex);
float dfay=(farrayy[i]-faveragey);
float dfaz=(farrayz[i]-faveragez);
if(dfax<dfay && dfax<dfaz){
dfaz=dfaz-dfax;
dfay=dfay-dfax;
dfax=0.0;
}
else if(dfay<dfax && dfay<dfaz){
dfax=dfax-dfay;
dfaz=dfaz-dfay;
dfay=0.0;
}
else if(dfaz<dfax && dfaz<dfay){
dfax=dfax-dfaz;
dfay=dfay-dfaz;
dfaz=0.0;
}
unsigned int cR=dfax/16.0;
unsigned int cB=dfay/16.0;
unsigned int cG=dfaz/16.0;
//if(cR<cB && cR<cG){cR=0;cB=cB-cR;cG=cG-cR;}
//else if(cB<cR && cB<cG){cB=0;cR=cR-cB;cG=cG-cB;}
// else if(cG<cR && cG<cB){cB=cB-cG;cR=cR-cG;cG=0;}
// theta=atan2(sqrt(fax*fax+faz*faz),fd)*360.0/M_PI;
cR=cR/2;
cG=cG/2;
cB=cB/2;
strip.setPixelColor(i,strip.Color(cR,cG,cB) );
}
strip.show();
//Serial.print(cR); Serial.print("\t");
// Serial.print(cB); Serial.print("\t");
//Serial.print(cG); Serial.print("\t");
// Serial.print( sqrt(faz*faz+fax*fax+fay*fay)); Serial.print("\t\t");
//Serial.print(fd-faverage); Serial.print("\t");
// Serial.print(dfax); Serial.print("\t");
// Serial.print(dfay); Serial.print("\t");
// Serial.print(dfaz); Serial.println("");
}
////////////////////////////////////////////////////////////////////////////////////////////
}