Hackster is hosting Hackster Holidays, Ep. 5: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 5 on Friday!
javier muñoz sáez
Published © GPL3+

20$ RF smart controled RGB LEDS, for bikes

RGB coloured wheels with three different control modes. -analogRead 3 potentiometers -random smooth changing colours -copycat colour

IntermediateFull instructions provided10 hours4,352
20$ RF smart controled RGB LEDS, for bikes

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
ATMEGA168 do just fine, we will use half of the memory
×3
lipo battery 3S 11,1v
(i use 2200mah (overkill))
×2
lipo battery 2S 7,4V
for the emmiter, a 500mah will do, you can also use 3s 11,1v
×1
rgb stripes (the lenght you need, use your rusty calculus skills )
mines are 12v common cathode
×1
433mhz emitter and receiver couple
well use one transmitter and two receivers
×2
Power MOSFET N-Channel
Power MOSFET N-Channel
3 each stripe you need to control, i need 3 for each wheel
×6
Resistor 221 ohm
Resistor 221 ohm
for handling the current drain on the gate of the mosfets
×6
circuit plates
buy some of this, they will save your ass with your cool projects
×2
Rotary potentiometer (generic)
Rotary potentiometer (generic)
i used some of 100k at first, i was wrong, use 10k at least better
×3
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
with latching
×2
RGB Diffused Common Cathode
RGB Diffused Common Cathode
for copycat
×1
light sensor
cheapest variable resistor by light
×1

Software apps and online services

Arduino IDE
Arduino IDE
we all love you arduino ide

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
ffssssshh

Story

Read more

Schematics

Transmitter module

receiver module

i have two of this , one for each wheel

Code

RX, receiver on the weels

C/C++
to upload into an arduino (nano in my case)
its reads an specific datagram with this concrete sintaxis
MaRRRRaGGGGaBBBB;

M->mode , 0 for waving colours, 1 for analog transmitted from the TX unit
RRRR-> RED VALUE
GGGG->GREEN VALUE
BBBB->BLUE VALUE
a->for separate the data
#include <VirtualWire.h>
//pin map, RX and pwm analogOutupts to PNP transistors
#define RX 3
#define pwmledRED 5
#define pwmledGREEN 6
#define pwmledBLUE 11

//arrays of data for build the final message
char datarraycharred  [(sizeof(int)*4+1)];
char datarraychargreen[(sizeof(int)*4+1)];
char datarraycharblue [(sizeof(int)*4+1)];
char datarraymodo     [(sizeof(int)*4+1)];
char datarrayclear    [(sizeof(int)*4+1)]={"FFFF"};//tricky thing to reorder the data
char datatotal        [(sizeof(int)*4+1)*4+4];

int datared =0;
int datagreen =0;
int datablue =0;
int bandera=0;
int i=0,j=0,index=0;
int indexchill=0;
int datamodo=3;//initialice with idle state all LED turned off

int ired=0,igreen=0,iblue=0;

void setup() {
  Serial.begin(9600);
  
    
    // VirtualWire 
    // Initialise the IO and ISR
    // Required for DR3100
    vw_set_rx_pin(RX);       //Config pin as RX
    vw_set_ptt_inverted(true); 
    // Bits per sec
    vw_setup(2000);         
    // Start the receiver PLL running
    vw_rx_start();  
    pinMode(pwmledRED,OUTPUT); //trt--->leds outuput
        pinMode(pwmledGREEN,OUTPUT);
            pinMode(pwmledBLUE,OUTPUT);    

} 



void loop(){
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    
    // Non-blocking
    if (vw_get_message(buf, &buflen)) 
    {
    int i;

           // Message with a good checksum received, dump it. 
        for (i = 0; i < buflen; i++)
    {            
          // Fill Sensor1CharMsg Char array with corresponding 
          // chars from buffer.   
          datatotal[i] = char(buf[i]);
    }
        
        datatotal[buflen] = '\0';
        
 // Convert Sensor1CharMsg Char array to TRUE integer, not the direct ASCII equivalent shit
chartointconvert();
}


  if(datamodo==0)// chill wabing colour mode
 modochill();



//write outupts
analogWrite(pwmledRED,datared);
analogWrite(pwmledGREEN,datagreen);
analogWrite(pwmledBLUE,datablue);



            // DEBUG 
        Serial.print(datatotal);
        Serial.print("      ");
        Serial.print(datarraymodo);
        Serial.print("  ");
        Serial.print(datarraycharred);
        Serial.print("  ");
        Serial.print(datarraychargreen);
        Serial.print("  ");
        Serial.print(datarraycharblue);
        Serial.print("     ");
        Serial.print(datamodo);
        Serial.print("  ");
        Serial.print(datared);
        Serial.print("  ");
        Serial.print(datagreen);
        Serial.print("  ");
        Serial.println(datablue);
        delay(50);

}










void chartointconvert(){
bandera=0;
strcpy (datarraymodo,datarrayclear);
strcpy (datarraycharred,datarrayclear);
strcpy (datarraychargreen,datarrayclear);
strcpy (datarraycharblue,datarrayclear);


  index=0;
  for(i=0;datatotal[i]!='a';i++)
  {
    datarraymodo[index]=datatotal[i];
    index++;
  }
  i++;
  j=i;
  index=0;

  for(i=j;datatotal[i]!='a';i++)
  {
    datarraycharred[index]=datatotal[i];
    index++;
  }
  i++;
  j=i;
  index=0;
  
   for(i=j;datatotal[i]!='a';i++)
  {
    datarraychargreen[index]=datatotal[i];
    index++;
  }
  i++;
  j=i;
   index=0;
  
   for(i=j;datatotal[i]!='a';i++)
  {
    datarraycharblue[index]=datatotal[i];
    index++;
  }

////arranging the char array
//WE NEED TRUE INTEGER DATA
for(i=0;i<4;i++)
{
if (datarraymodo[3]=='F')
{
datarraymodo[3]=datarraymodo[2];
datarraymodo[2]=datarraymodo[1];
datarraymodo[1]=datarraymodo[0];
datarraymodo[0]='0';
}
}

for(i=0;i<4;i++)
{
if (datarraycharred[3]=='F')
{
datarraycharred[3]=datarraycharred[2];
datarraycharred[2]=datarraycharred[1];
datarraycharred[1]=datarraycharred[0];
datarraycharred[0]='0';
}
}

for(i=0;i<4;i++)
{
if (datarraychargreen[3]=='F')
{
datarraychargreen[3]=datarraychargreen[2];
datarraychargreen[2]=datarraychargreen[1];
datarraychargreen[1]=datarraychargreen[0];
datarraychargreen[0]='0';
}
}

for(i=0;i<4;i++)
{
if (datarraycharblue[3]=='F')
{
datarraycharblue[3]=datarraycharblue[2];
datarraycharblue[2]=datarraycharblue[1];
datarraycharblue[1]=datarraycharblue[0];
datarraycharblue[0]='0';
}
}

 datamodo = atoi(datarraymodo);
 if(datamodo!=0)
 {
 datared = atoi(datarraycharred);
 datagreen = atoi(datarraychargreen);
 datablue = atoi(datarraycharblue);
datared=map(datared,0,1023,0,255);
datagreen=map(datagreen,0,1023,0,255);
datablue=map(datablue,0,1023,0,255);
 }
}


void modochill()
 {
//when first time on chill mode, set random numbers
      if(indexchill==0){
  datared=random(170, 255); 
    datagreen=random(85, 170); 
      datablue=random(0, 85); 
      indexchill=1;

    }

  //after first time just wave the values
  if(datared>=250)
  {ired=1;}
  if(datared<=3)
  {ired=0;}
  if(ired==0)
  {datared=datared+3;}
  if(ired==1)
  {datared=datared-3;}
  
  if(datagreen>=240)
  {igreen=1;}
  if(datagreen<=3)
  {igreen=0;}
  if(igreen==0)
  {datagreen=datagreen+3;}
  if(igreen==1)
  {datagreen=datagreen-3;}
  
  
  if(datablue>=240)
  {iblue=1;}
  if(datablue<=3)
  {iblue=0;}
  if(iblue==0)
  {datablue=datablue+3;}
  if(iblue==1)
  {datablue=datablue-3;}


 
  }

TX, transmitter with three different functions

C/C++
mode 0 0
just chill, the receiver waves the colours slowly

mode 1 0
read and send analog values

mode 0 1
read colours with rgb sensor

mode 1 1
calibrate rgb sensor
#include <VirtualWire.h>
#define LEDRED A0
#define LEDGREEN A1
#define LEDBLUE A2
#define LIGHTSENSOR A3
#define TX 10
#define buttonA 5
#define buttonB 6
//variables TX - RX
char separador [2] = {"a"};
char datarraycharred[(sizeof(int)*4+1)];
char datarraychargreen[(sizeof(int)*4+1)];
char datarraycharblue[(sizeof(int)*4+1)];
char datamodo[(sizeof(int)*4+1)];
char datatotal[(sizeof(int)*4+3)*3];


int index=0,ired=0,igreen=0,iblue=0;
int datared=0,datagreen=0,datablue=0 ; //cm/seg 
int modo=0;

//for led copycat
int ledArray[] = {2,3,4};
int red = 0;
int green = 0;
int blue = 0;
int avgRead;
float colourArray[] = {0,0,0};
float whiteArray[] = {0,0,0};
float blackArray[] = {0,0,0};


void setup() {
  pinMode(LEDRED,OUTPUT);
  pinMode(LEDGREEN,OUTPUT);
  pinMode(LEDBLUE,OUTPUT);
    pinMode(LIGHTSENSOR,INPUT);
  pinMode(buttonA,INPUT);
  pinMode(buttonB,INPUT);
  pinMode(TX,OUTPUT);
  //ledarray copycat
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
   digitalWrite(2,HIGH);
   digitalWrite(3,HIGH);
   digitalWrite(4,HIGH);
  
  Serial.begin(9600);
  pinMode(TX, INPUT);
   pinMode(TX, OUTPUT);
  vw_set_tx_pin(TX);          // Configura el pin  como TX
  vw_set_ptt_inverted(true);  // Requerido para DR3100
  vw_setup(2000);             // Bits por segundo
  

}

void loop() {
if(digitalRead(buttonA)==0&&digitalRead(buttonB)==0)
modochill();
  
  
if(digitalRead(buttonA)==1&&digitalRead(buttonB)==0)
modoanalogico();

if(digitalRead(buttonB)==1)
modoLEDcopycat();
 

//construccion del array de datos a enviar
strcpy (datatotal,datamodo);
strcat (datatotal,separador);
strcat (datatotal,datarraycharred);
strcat (datatotal,separador);
strcat (datatotal,datarraychargreen);
strcat (datatotal,separador);
strcat (datatotal,datarraycharblue);
strcat (datatotal,separador);



//DEBUG
//Serial.print(datatotal);
Serial.print("  ");
Serial.println(datatotal);



  
//ENVIO RX
 
 digitalWrite(13, HIGH); // Turn on a light to show transmitting
 vw_send((uint8_t *)datatotal, strlen(datatotal));
 vw_wait_tx(); // Wait until the whole message is gone
  delay(50); 
 digitalWrite(13, LOW); // Turn off a light after transmission

}







//mode chillout defined at receiver, just freeze the dataflow and send modo=0
void modochill(){
  modo=0;
  itoa(modo,datamodo,10);//10--> base decimal
  }


//mode and data rgb analog
void modoanalogico(){
  modo=1;
  itoa(modo,datamodo,10);//10--> base decimal
  //analog read and int to char conversion
datared=analogRead(LEDRED);
itoa(datared,datarraycharred,10);//10--> base decimal
datagreen=analogRead(LEDGREEN);
itoa(datagreen,datarraychargreen,10);
datablue=analogRead(LEDBLUE);
itoa(datablue,datarraycharblue,10);
}



void modoLEDcopycat()
{
      if(digitalRead(buttonA)==1&&digitalRead(buttonB)==1){setBalance();}


 for(int i = 0;i<=2;i++){
     digitalWrite(ledArray[i],LOW);  //turn or the LED, red, green or blue depending which iteration
     delay(100);                      //delay to allow CdS to stabalize, they are slow
     getReading(5);                  //take a reading however many times
     colourArray[i] = avgRead;        //set the current colour in the array to the average reading
     float greyDiff = whiteArray[i] - blackArray[i];                    //the highest possible return minus the lowest returns the area for values in between
     colourArray[i] = (colourArray[i] - blackArray[i])/(greyDiff)*255; //the reading returned minus the lowest value divided by the possible range multiplied by 255 will give us a value roughly between 0-255 representing the value for the current reflectivity(for the colour it is exposed to) of what is being scanned
     digitalWrite(ledArray[i],HIGH);   //turn off the current LED
     delay(100);
     
     }

//rgb con catodo comun , dar la vuelta al valor de intensidad con map
analogWrite(LEDRED,map(colourArray[0],0,255,255,0));
analogWrite(LEDGREEN,map(colourArray[1],0,255,255,0));
analogWrite(LEDBLUE,map(colourArray[2],0,255,255,0));

  
}


//asymetric blink for humans to notice
void piiipipi(){

   digitalWrite(10,LOW);
   digitalWrite(11,LOW);
   digitalWrite(12,LOW);
   delay(1000);
   digitalWrite(10,HIGH);
   digitalWrite(11,HIGH);
   digitalWrite(12,HIGH);
   delay(500);
   digitalWrite(10,LOW);
   digitalWrite(11,LOW);
   digitalWrite(12,LOW);
   delay(500);
   digitalWrite(10,HIGH);
   digitalWrite(11,HIGH);
   digitalWrite(12,HIGH);
   delay(500);
   digitalWrite(10,LOW);
   digitalWrite(11,LOW);
   digitalWrite(12,LOW);
   delay(500);
   digitalWrite(10,HIGH);
   digitalWrite(11,HIGH);
   digitalWrite(12,HIGH);
   delay(1000);   
   
}

//when two buttons pressed, calibrate the rgb readings with white and black objects
void setBalance(){

 piiipipi() ;
                             
  for(int i = 0;i<=2;i++){
     digitalWrite(ledArray[i],LOW);
     delay(100);
     getReading(5);          //number is the number of scans to take for average, this whole function is redundant, one reading works just as well.
     whiteArray[i] = avgRead;
     digitalWrite(ledArray[i],HIGH);
     delay(100);
  }
  //done scanning white, now it will pulse blue to tell you that it is time for the black (or grey) sample.
   //set black balance
 piiipipi() ;
  //go ahead and scan, sets the colour values for red, green, and blue when exposed to black
  for(int i = 0;i<=2;i++){
     digitalWrite(ledArray[i],LOW);
     delay(100);
     getReading(5);
     blackArray[i] = avgRead;
     //blackArray[i] = analogRead(2);
     digitalWrite(ledArray[i],HIGH);
     delay(100);
  }
  //delay another 5 seconds to allow the human to catch up to what is going on
delay(5000);
  }

//get the colour!
  void getReading(int times){
  int reading;
  int tally=0;
  //take the reading however many times was requested and add them up
for(int i = 0;i < times;i++){
   reading = analogRead(LIGHTSENSOR);
   tally = reading + tally;
   delay(10);
}
  }

Credits

javier muñoz sáez

javier muñoz sáez

13 projects • 84 followers
Electronic engineer and sparky person. I make tutorials so my future self doesnt need to remember how he did the thing
Thanks to china people.

Comments