Tuesday, February 22, 2011

Relay driver circuit

I had a couple of goals for my circuit:
  • Be able to drive 32 channels
  • Use LEDs to indicate which lights are turned on

The heart of this circuit is the transistor (labeled 2N2222).  A transistor, like a relay, uses a small amount of electricity to switch a larger amount of electricity.  Current from the Arduino is used to switch on the current flowing through the transistor.  The Arduino is connected to the transistor's base (labeled B) and allows current to flow from the collector (labeled C) the the emitter (labeled E).

I added a resistor (R2) to the circuit.  The resistor reduces the current flowing from the Arduino.  I selected R2 using Ohms Law.  V=IR (Voltage = Current * Resistance).  By definition, the diode drop from the transistor Base to Emitter is going to be approximately 0.7V.  Since the Arduino will output 5V, I knew there would be 4.3V across R2.  I picked a fairly large resistor, 4.7K, and used Ohms Law to see how much current would flow.  V=IR can be rearranged to I=V/R.  Substituting, I=4.3V/470K.  I=0.9mA.  That's perfect.  The Arduino will have absolutely no problem, even if 32 separate pins are supplying 0.9mA each.  

The 2N2222 has a current gain of about 100.  That means that 0.9mA at the Base will allow 90mA to pass from the Collector to Emitter.  Next, I needed to see if that would work for the top half of the circuit.
The top half of the circuit can't do anything when the transistor is turned off (no current can pass).  When the transistor passes current, there will be 5V across the LED+R1, as well as 5V across the relay.  Let's take the LED+R1 first.  From the LED's specs, I knew there would be 2V across the LED at it's ideal 13.6mA.  So, of the original 5V, 2V will dissipate across the LED, and 3V will dissipate across R1.  Again, using Ohms Law, R=V/I.  Substituting, R=3.0V/13.6mA.  R=220.  So, a 220 ohm resistor will limit the current and keep the LED happy.

When connecting a relay, a diode needs to be wired backwards across the relay coil.  This protects the transistor from the brief high voltage produced when the relay coil is switched off.  

The relay needs 5V to activate it, so no resistor is needed there.  From the data sheet, I expected approximately 60mA to pass through the relay.  The 60mA through the relay, combined with the 13.6mA through the LED+resistor (plus zero mA through the diode) came to 73.6mA through the top part of the circuit.  So, the transistor circuit should allow enough current through the top half.

An Arduino can briefly supply 40mA per pin.  It certainly can't supply 73.6mA times 32 pins (that's over 2 Amps), so I need a power supply separate from the Arduino.  I used a power supply from an old PC.  It's not very difficult to do, and it's a fun project on its own.
I really enjoyed the next step.  I needed to turn the schematic/breadboard circuit into the physical circuit.  I found a circuit board at Radio Shack, and figured out how to scrunch the circuit into the minimum amount of space.
Then, I started soldering.  The red LEDs are easy to see.  Just below the LED is the 2N2222 transistor.  Next to the transistor are the two tan resistors with the diode sandwiched in between.  The relays are off in the high-voltage area of the project.
In my next blog entry I'll show how I hooked the driver circuits to the Arduino and to the relays.

Monday, February 21, 2011

Relays

The heart of the project is the relay.  A relay is an electrically operated switch.  In this case, I'm using a relay that allows me to use 5V (from the Arduino) to switch 110V (to run the XMas lights).

I picked up my relays from eBay.  Just search for "5V power relay".  I bought a quantity of them for about 50 cents each.  They will switch up to 10 Amps of 125V AC.
 
The relay has five terminals on it.  Two connections energize an electromagnet.  In my relay, it requires 5 Volts.  The other three terminals switch the high voltage.  When the electromagnet is not energized, B and C are connected.  When the electromagnet is energized, the switch is pulled over to connect A and C.

You connect the hot (110V) to terminal C, and then connect either A or B to the hot terminal of the outlet.  I chose to connect B to the outlet.  This way, the switch is "on" (outlet is active) even when the Arduino isn't turned on.  If I were to connect A to the outlet, the outlet would be off unless the Arduino was supplying 5V to the relay.

In my next blog entry, I'll discuss the circuit I used to drive these relays.

Centipede shield

I originally started designing my project using 74HC595 shift registers.  There are some great tutorials, and the 74HC595 really isn't very difficult to use.  I was able to get a prototype working pretty easily, but 32 channels of output would have required four 8-bit shift registers, and the code would have been a little bit messy.  Then, I found the Centipede shield.  
I'm pretty impressed by this little guy.  It uses the I2C (inter IC communication) Wire interface to individually control the 64 individual inputs/outputs.  

"Hello world" for the Centipede is pretty simple:

#include <Wire.h>
#include <Centipede.h>

Centipede CS; //create Centipede object
int i;  //general loop variable

void setup() {
  Wire.begin(); //start I2C
  CS.initialize(); //set all registers to default

  for (i=0;i<32;i++) {  //set first 32 channels to output
   CS.pinMode(i, OUTPUT); 
   }

  for (i=0;i<32;i++) {  //set first 32 channels to HIGH
   CS.digitalWrite(i, HIGH);
   }
}

The library is exceptionally easy to use.
  • Include the Wire.h library and Centipede.h library.
  • Create the Centipede object
  • Initialize I2C and Centipede
  • Set the pinmode of each pin
  • And then you can read/write each individual pin
I use an inexpensive breakout board and connect it to the Centipede shield using a 2x10 connector (20 conductor) ribbon cable.
I had some difficulty building my cable.  You buy the connectors and ribbon cable separately.  To build the cable, you basically squish the connector pins through the cable and they are supposed to make a good connection.  Well, mine didn't.  I ended up buying a couple 12 inch cables on eBay for the same amount I could have bought a couple new connectors.

I still don't know what I did wrong.  I tried squishing the connector using a big book.  Maybe a vice would have provided more force without any twisting.  Oh, well.  eBay to the rescue.

In my next blog entry I'll look at the relays I'm using to switch the XMas lights on and off.

Sunday, February 20, 2011

Rogue MP3 shield

The Rogue MP3 shield from RogueRobotics.com is a central to my project.  The shield has a slot for an SD card (you can see it sticking out the right side of the board).  On the SD card are the MP3 files, and the data files containing the instructions for turning on and off the lights.
This shield is really easy to use, and the code examples are very helpful.  There were some reports of problems with the libraries, but I found that upgrading to Arduino 022 solved it.


#include <RogueMP3.h>
#include <NewSoftSerial.h>


NewSoftSerial rmp3_s(6, 7);
RogueMP3 rmp3(rmp3_s);


void setup()
{
  rmp3_s.begin(9600); 
  rmp3.sync();
  rmp3.playfile("/ump3test.mp3");
}


Playing an MP3 can be done in just 7 lines of code.  I guess they had to update the serial library with their own NewSoftSerial library.  When initializing the NewSoftSerial, you can choose the pins to use (in case the default conflicts with the pins you are already using on the Arduino).

The Rogue MP3 library can be downloaded from their web site, and documentation can be found in their wiki.  Overall, the documentation is good, but it would benefit from Arduino examples.

The only criticism I have of the shield/library is the with the playback status.  For my project, it would have been very helpful if the current time position in the file were returned in milliseconds.  Unfortunately, the Rogue MP3 only returns position in whole seconds.

Overall, it's a fantastic shield.  I can definitely see myself using this again in other projects.

In my next blog entry, I'll look at another Arduino shield I'm using; the Centipede shield.

Arduino application

The Arduino application is fairly straightforward, even if the implementation took a little effort to make it work.

To get the Arduino to play MP3 files, I'm using the Rogue MP3 shield.  This shield does double duty.  It provides storage on an SD card (for the MP3s and "piano scroll" files), and it decodes/plays the music files.  The card comes with nicely written libraries (SD library / MP3 library) to get access to the functionality.  I'll talk more about the Rogue MP3 more in my next blog entry.

#include <NewSoftSerial.h>
#include <RogueMP3.h>
#include <RogueSD.h>

I'm also using a Centipede shield to give me more digital output pins.  Instead of the usual 14 on an Arduino board, the Centipede gives you 64!  Just like the Rogue MP3 shield, the card comes with nicely written libraries to access the functionality.  I'll talk more about the Centipede shield in a future blog entry.

#include <Wire.h>
#include <Centipede.h>

The setup() and loop() routines are straightforward.  I suppose I could have used more complex logic to find and loop through all the MP3 files on the SC card.  Maybe I'll do that in a future iteration.


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


  //initialize RogueSD
  filecommands.sync();  //initialize RogueSD
  filecommands.closeall();  //initialize RogueSD


  //initialize RogueMP3
  rmp3.sync();  //initialize RogueMP3
  rmp3.setvolume(50);  //smaller numbers are louder


  //initialize Centipede shield
  Wire.begin();  //start I2C for Centipede shield
  CS.initialize(); //set all registers to default
  for (i=0;i<32;i++) {  //set first 32 channels to output
    CS.pinMode(i, OUTPUT); 
  }
}


void loop()
{
  playSong("/test.mp3", "/test.data");
  delay(5000);
  playSong("/Let_It_Snow.mp3", "/Let_It_Snow.data");
  delay(5000);
}


The only real logic in the Arduino application happens in the playSong routine.  The "while" loop continues as long as the MP3 status=='P' (play).  Each time through the loop, I check to see if we've arrived at the time (currentTime-startTime) to display the next set of lights (it's after waitForTime).  I added 200 ms to the time to adjust for a slight timing difference between the Arduino sketch execution time and the MP3 play time.


void playSong(char* SongFile, char* DataFile) {
  loadSong(SongFile, DataFile);
  readLine (); 
  while (rmp3.getplaybackstatus()=='P') {
    currentTime=millis();
    if((currentTime-startTime+200) >= waitForTime) {
      setLights();
      readLine ();
    } 
  }
  filecommands.closeall();
}

After displaying a set of lights (setLights), the next line in the piano scroll is read (readLine) from the SD card, and the loop is repeated.  The last line of the file has a waitForTime of 999999, which is never reached, so there is no need to worry about end-of-file type errors.

The RogueRobotics.com site has a cool demo showing how they synchronized a song to the lyrics coming from a standard LRC file.  The example is great, but overkill for my purpose.  Because I controlled the input file, I was able to assume some things (6 digits for the waitForTime, 5 digits for value1, and 5 digits for value2).  This simplified the way I was able to read from my data file.

void readLine () {
  readStatus = filecommands.readln(fileHandle, 20, lineBuffer);
  waitForTime=getNumber(lineBuffer[0],100000)+
    getNumber(lineBuffer[1],10000)+
    getNumber(lineBuffer[2],1000)+
    getNumber(lineBuffer[3],100)+
    getNumber(lineBuffer[4],10)+
    getNumber(lineBuffer[5],1);
 lights1=getNumber(lineBuffer[7],10000)+
    getNumber(lineBuffer[8],1000)+
    getNumber(lineBuffer[9],100)+
    getNumber(lineBuffer[10],10)+
    getNumber(lineBuffer[11],1);
 lights2=getNumber(lineBuffer[13],10000)+
    getNumber(lineBuffer[14],1000)+
    getNumber(lineBuffer[15],100)+
    getNumber(lineBuffer[16],10)+
    getNumber(lineBuffer[17],1);
}

I knew that position [0] is the 100,000's digits, position [1] is the 10,000's digit, etc.  I didn't have to look for brackets or commas to parse the file.

This little function turns the character into a number (with the right 10's place)

long getNumber(char c, long multiplier) {
  return (int(c)-int('0'))*multiplier;
}

The Centipede shield makes it easy to set the lights, but more about that in a future post.

void setLights () {
  CS.digitalWrite(0, (lights1 & 1)?HIGH:LOW);  //0-LRLeft
  CS.digitalWrite(1, (lights1 & 2)?HIGH:LOW);  //1-RRight
  CS.digitalWrite(2, (lights1 & 4)?HIGH:LOW);  //2-CharlieLeft
  CS.digitalWrite(3, (lights1 & 8)?HIGH:LOW);  //3-CharlieRight
  ...
  CS.digitalWrite(30, (lights2 & 16384)?HIGH:LOW);  //30-Tree7
  CS.digitalWrite(31, (lights2 & 32768)?HIGH:LOW);  //31-Tree8
}


If you'd like my code, just send me an e-mail.  I'd be happy to zip it up and send it to you.


In my next blog entry, I'll discuss the Rogue MP3 Shield.

Friday, February 4, 2011

Creating the piano roll

The instructions for turning off and on the lights is similar to the piano roll on a player piano.  In a player piano, the keys are pneumatically operated by suction when air passes through the paper perforations. Across the width of the roll, each hole represents one key on the piano.  A hole causes a note to be played.  No hole means no note.

015100,04100,00008
015400,16392,00064
015700,32770,00032
016000,08193,00008
016300,04100,00064
016600,16392,00032
016900,32770,00008

The export button generates a text tile.  The text file, just like the piano roll, describes when lights should turn on and off.  Instead of one continuous roll, the text file only describes the times when lights should turn on or off.  In this example, the times are in milliseconds.  The Arduino will wait until 15.1 seconds (015100 milliseconds) into the song and set the first sixteen lights to a value of 4100, and the next sixteen lights to a value of 8.  Then, the Arduino code will wait until 15.4 seconds (015400 milliseconds) into the song, and set the values 16392 and 64.

So, what do these values mean?  Take 8 first.  A value of 8 means the 4th bit is on, and the rest are off.  A value of 4100 means the 13th bit is on, plus the 3rd is on (4096+4=4100).  Any combination of the 16 lights can be represented by summing the values of their corresponding bits.  Basic bitwise operations can be used to encode and decode the values of lights.

In the next blog entry, we'll work on the Arduino application to read the piano roll.

Sunday, January 30, 2011

XMas light simulator application

I created the simulator in Processing with minim library to play music and ControlP5 library for GUI components.

There are couple steps to creating a light show.
1) Mark the beats / add lyrics - I found that keyboard shortcuts work very well.  While playing the song, pressing the <spacebar> adds an asterisk next to the time mark.  It's fairly easy to click the <spacebar> at the start of each word.  Then, I go back and add lyrics at the times marked with asterisks.
2) Turn on/off lights - The right side of the screen shows which lights are on/off, and allows me to switch lights on/off by clicking.  I can play the simulated show, pause, and turn on/off the lights until I get the show just right.
I started by adding GUI buttons for all the functions, and quickly realized that it is much easier keeping my hands on they keyboard.  Navigating up and down the song is accomplished with the arrow keys, Page Up/Down, and Home/End.

I used the minim library Audio Player to play audio.  It's really easy, but I found one feature that causes me a little trouble.  When you get toward the end of the song, and call the audio player Skip method with a negative value (to skip backwards in the song), it takes a long time.  I'm guessing the implementation requires the player to start at the beginning and run through the song to get to the new position.  This is a bit of an annoyance, but really not that big a deal.
The center section of the simulator shows a timeline.  The first column is the time, in seconds.  Next to the time is what I call the beat indicator.  While playing a song, I press the <spacebar> on the words or beats.  This adds the asterisk at that time.  This helps me enter the lyrics (the next column) and synchronize the lights. The last two columns are the values of the lights.  The first number represents the state of the first 16 lights, and the second number represents the state of the next 16 lights.  In my next post, I'll discuss these numbers.
The right side of the screen shows picture(s) of the house.  When playing the song, windows light up simulating the lights.  I can also click the windows to indicate which lights I want turned on.
So, here's the finished XMas lights simulator.  I'm pretty happy with the way it turned out.  If I find some time, I'll probably go back and remove some hard-coded stuff and clean it up, but overall it does the job.

I used a nice piece of open source software called CamStudio to take the movie.  If you're looking to make a video of your screen, I highly recommend it.

In my next blog entry, I'll talk about the output of the simulator, the "piano roll" of instructions for the Arduino.