fiduciary

Author Topic: Arduino as RGBx PWM controller and Soundcard interface  (Read 7042 times)

0 Members and 1 Guest are viewing this topic.

Offline TroyO

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 39
Arduino as RGBx PWM controller and Soundcard interface
« on: February 13, 2010, 10:33:32 PM »
The Arduino is an open source Microcontroller and "IDE" (Independant Development Evironment)

That means it's hardware board and a code compiler that you can use to program in your own code and load it to the chip. It sounds scary, but really it's not that bad.. LOL. In reality, if you are just using code and not writing it, it could be as easy as:
Load the software
Plug in the Arduino
Install the drivers (Like any other USB device)
Run the software
Paste the code
Hit the "Upload" button

Really... that's it.

Right now I am using an Arduino Duemilinove (I bet I misspelled that) which is too large for a Saber, but I will be using an Arduino Nano... it's one of the smaller models of the Arduino at .7" x 1.7" (But not the smallest.. there's a smaller one but it doesn't plug in to USB so its harder to use and I'm lazy.)

Anyway... on to what's going on.

Over at the Open Source Saber Project (OSSP) we are working on creating an open source option for soundcards. Someday, that hopefully means we will have a full on sound card that people can make themselves using off the shelf electronics and things like the ARduino. (Or a PIC, or.... whatever works really.)

We aint there (yet). LOL.

For now we do have some usefull bit of kit.  Using the Arduino as a "bridge" between an existing soundcard (a Joe Jedi or MR616 in this case) and a PWM controlled driver (Or 4 of them, in this case) we are able to use the Arduino to kind of manage things... like the light levels of 4 different LED dies on a LEDengin 10W RGBA LED.

Here's a YouTube video of it in action....
http://www.youtube.com/watch?v=YowVHboU-oQ

Hows it work? Well, the PWM outputs of the Arduino hook to the PWM inputs on the driver. You can set 255 levels for each PWM pin so you have 255 levels of control of the brightness for each LED Die. 255x255x255 = 16581375 colors. (Not counting the Amber LED...I'm just using that to flash.)

Before you get too color happy... LOL, I am using 4 levels on each color. LED's aren't even close to being "linear" and the brightness steps aren't even. Still, you could easily do 10 or more per color... I just chose 4 (plus off) because that gives me ~54 or so colors and that's about all I wanted. I really didn't want to click 16 million times to cycle my colors.

The PWM output would work on ANY driver that takes a PWM signal... the new ones at TCSS, good old Buckpucks... whatever. The code might need to be tweaked to match the output to whatever your flavor of PWM driver is.

Anyway... the soundcard side of it. The Arduino is hooked to the soundcard with 3 wires.

1) On/Off
2) Sith/Jedi sound selector
3) Impact sensor

The first is one side of the main switch,... the Arduino sends 5V to it and the ingnition sounds and the card turns "on"

The second is to one of the pads where the color select switch was. The Arduino shoots 5V at it and it changes to the sith Soundbank.

Lastly, one wire of the impact sensor gets 5v whenever the sensor is triggered. That goes to the Joe Jedi board as well as the Arduino, which reads the signal so it knows when a clash is happening.

That's about it really... the rest is just code that glues it together.

Speaking of the Glue.... here's the code. Copy/mangle/adapt/adopt/modify it at your leisure.... (Note that it is by no means complete, effecient, clean or even the final version I will be using in my saber.... but it works and it's a starting point.)

Don't blame me if your refrigerator comes to life and eats off your big toe while you sleep.......

Code: [Select]
/* Lightsaber test sketch controlling a "Joe Jedi" SW616 sound card
 Modified by Troy Ollom
 Feb. 5, 2010
 Original "Four button sketch" by Jeff Saltzman.
 To keep a physical interface as simple as possible, this sketch demonstrates generating three output events from a single push-button.
 1) Click: rapid press and release
 2) Double-Click: two clicks in quick succession
 3) Press and Hold: holding the button down
 */
#include <EEPROM.h> // Set up the EEPROM library so I can read/write from permenant memory
#define buttonPin 2 // analog input pin to use as a digital input
#define redPin 3 // digital output pin for Red LED 1
#define sndOnPin 4// Digital out to turn on soundcard
#define grnPin 5 // digital output pin for Green LED 2
#define bluPin 6// digital output pin for Blue LED 3
#define impactPin 7// Input pin for impact sensor
#define sndSelectPin 8// Digital out to select sound True is Sith, False is Jedi
#define flashPin 9 // FoC LED Pin
// RGB LED variables
byte rgbArray [54][3]={//RGB Array 3 wide 54 tall, stores RGB values (There's gotta be a prettier way to do this!)
{100,0,0},{100,15,0},{100,40,0},{100,60,0},{100,100,0}
,
{60,100,0},{40,100,0},{15,100,0},{0,100,0},{0,100,15}
,
{0,100,40},{0,100,60},{0,100,100},{0,60,100},{0,40,100}
,
{0,15,100},{0,0,100},{15,0,100},{40,0,100},{60,0,100}
,
{100,0,100},{100,0,60},{100,0,40},{100,0,15}
,
//Hue one, a lighter starts at Array pointer 40100
{100,15,15},{100,40,15},{100,60,15},{100,100,15}
,
{60,100,15},{40,100,15},{15,100,15},{15,100,40}
,
{15,100,60},{15,100,100},{15,60,100},{15,40,100}
,
{15,15,100},{40,15,100},{60,15,100},{100,15,100}
,
{100,15,60},{100,15,40}
,
//Hue two, Lightest starts at Array pointer 10040
{100,40,40},{100,60,40},{100,100,40},{60,100,40}
,
{40,100,40},{40,100,60},{40,100,100},{40,60,100}
,
{40,40,100},{60,40,100},{100,40,100},{100,40,60}
,
};
byte rgbFactor = 100;          // Value to factor by.. IE, 100 would provide 100 steps 255 is Max
byte randFlicker = 41;
int fadeValue = 0;             //tracks the current state of the fade value
boolean fadeDirection = false; // in this case, true means fade up, false means fade down
byte colorMode = 0;             // Stores the current color
byte sndMode = 0;               // Store the current sound mode
byte menuMode = 0;               // Stores the current menuMode
byte impactRead = 0;             // Place to store the last read of the impactPin
byte flashOn = 0;               // Place to store the count for flashOn
//=================================================
// RGB Timing Variables
long rgbMillis = 0;      // Store millis to keep track of the last time rgb was updated
int rgbInterval = 30;    // How often to update the rgb values
//==========================================
void setup()
{
                                    // Set button input pin
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH );
  pinMode(impactPin, INPUT);
  digitalWrite(impactPin, LOW);
                                    // Set LED output pins
  pinMode(redPin, OUTPUT);
  digitalWrite(redPin, 0);
  pinMode(grnPin, OUTPUT);
  digitalWrite(grnPin, 0);
  pinMode(bluPin, OUTPUT);
  digitalWrite(bluPin, 0);
  pinMode(flashPin, OUTPUT);
  digitalWrite(flashPin, 0);
  colorMode = EEPROM.read(0);              // Read in the stored colorMode
  sndMode = EEPROM.read(1);               // Read in the stored sndMode
  digitalWrite (sndSelectPin,sndMode);    // Use the stored sndMode to set the sndSelectPin
}
void loop()
{
                                            // Get button event and act accordingly
  int b = checkButton();
  if (b == 1) clickEvent();
  if (b == 2) doubleClickEvent();
  if (b == 3) holdEvent();
  impactRead = digitalRead (impactPin);           // Read the impact pin and dump it in to impactRead
  if (fadeDirection == true && impactRead == HIGH && flashOn == 0){ // Three way check, see if the LED's are on if we have an impact and that we aren't already in impact mode//
    flashOn = 10;                                 // if all those conditions are true set flashOn to 10. flashOn * 30 MS = total flash time
  }
  // Main LED ramp/fade routine
  if (millis () - rgbMillis >= rgbInterval){             // if it's been 30 ms since last time, lets update the LED
    rgbMillis = millis ();                               // reset so we know the last time
    Serial.println (colorMode);
    if (fadeDirection == true){                          // This is gonna happen if we are fading UP
      if (fadeValue <=250) {                             // If fadeValue is less than or equalls 250
        fadeValue = fadeValue +5;                        // Lets add 6 to it
      }
      else {
        randFlicker = random(30);           
        fadeValue = 255 - randFlicker;                  // or else if it's already there, just make it 255 and flicker it there
      }
    }
    if (fadeDirection == false){                         //This is gonna happen if we are fading down
      if (fadeValue >=8) {                               // if its over or = to 7
        fadeValue = fadeValue - 8;                       // subtract 7 from it
      }
      else {
        fadeValue = 0;                                   // if it's less than 5 hold it at zero
      }
    }
    if (flashOn >= 1){                                  // If we have a flashOn value lets do some flashing
      analogWrite (flashPin, 255 -randFlicker * 8);     // Write the flashPin high and 9X the flicker for crazy flicker madness
      flashOn --;                                       // Decrement by one so we only do this 10 times in a row
    }
    else{
      analogWrite (flashPin, 0);
    }
    updateLED ();
  }
}
// Main LED update routine
void updateLED (){
  analogWrite(redPin, fadeValue * rgbArray[colorMode][0] / rgbFactor);   //Now that the math has been done, update the LED
  analogWrite(bluPin, fadeValue * rgbArray[colorMode][1] / rgbFactor);
  analogWrite(grnPin, fadeValue * rgbArray[colorMode][2] / rgbFactor);
}
//=================================================
// Events to trigger by click and press+hold
void clickEvent() {
  if (menuMode == 0){              //0 is normal on/off saber mode
    fadeDirection = true;           // Set fadeDirection and let the Mian ramp routine take care of it. True fades UP
    digitalWrite (sndOnPin,true);       //Turns on the soundcard
  }
  else
    if (menuMode == 1){                 //1 is Color setting mode
      colorMode++;                       // Add 1 to the colormode
      if (colorMode >=54){               // If colorMode is over 53 loop it back to 0
        colorMode = 0;
      }
      updateLED ();                       // Update the LED with the current colorMode selected
    }
    else
      if (menuMode == 2){
        sndMode=0;
        digitalWrite (sndSelectPin,sndMode);      // Set the soundbank. 0 is the Jedi soundbank
        delay (10);                               // A little wait to let it get active
        digitalWrite (sndOnPin,true);             // Turn the sound card on (briefly) as an audible indicator
        digitalWrite (redPin,0);                   // Turn off active colors so you can see the Blue flash
        digitalWrite (grnPin,0);
        digitalWrite (bluPin,0);                   // Flash the Blue LED a couple of times as a visual indicator
        delay (300);
        digitalWrite (bluPin,1);
        delay (300);
        digitalWrite (bluPin,0);
        delay (300);
        digitalWrite (bluPin,1);
        delay (300);
        digitalWrite (bluPin,0);
        digitalWrite (sndOnPin,false);               // Turn off the sound card
      }
}
void doubleClickEvent() {
  if (menuMode == 0){                               //0 is normal on/off saber mode
    fadeDirection = false;                           // Set fadeDirection and let the Mian ramp routine take care of it. False fades DOWN
    digitalWrite (sndOnPin,false);                   // Turns off the soundcard
  }
  if (menuMode == 1){
    if (colorMode <= 23){
      colorMode=24;
    }
    else if (colorMode <=41){
      colorMode=42;
    }
    else {
      colorMode=0;
    }
  }
  if (menuMode == 2){                         //2 is Sound setting mode.
    sndMode = 1;
    digitalWrite (sndSelectPin,sndMode);     // Set the soundbank. 1 is the Sith soundbank
    delay (10);                                // A little wait to let it get active
    digitalWrite (sndOnPin,true);            // Turn the sound card on (briefly) as an audible indicator
    digitalWrite (redPin,0);                 // Turn off active colors so you can see the Red flash
    digitalWrite (grnPin,0);                 // Flash the Red LED a couple of times as a visual indicator
    digitalWrite (bluPin,0);
    delay (300);
    digitalWrite (redPin,1);
    delay (300);
    digitalWrite (redPin,0);
    delay (300);
    digitalWrite (redPin,1);
    delay (300);
    digitalWrite (redPin,0);
    digitalWrite (sndOnPin,false);              // Turn off the sound card
  }
}
void holdEvent() {                             //Triggered with 3 second press hold
  menuMode++;                                   //increment menuMode
  if (menuMode >= 3){                           //If it's over 2 loop it back to 0
    menuMode = 0;
  }
  if (menuMode == 0){
    fadeDirection = false;
    digitalWrite (sndOnPin,false);                // Turn off the sound card
    digitalWrite (redPin,0);
    digitalWrite (grnPin,0);
    digitalWrite (bluPin,0);
    EEPROM.write(1,sndMode);                       // Save the selected sndMode... good place to do it sice we are just going to delay anyway and it takes a few MS
    delay (100);
    digitalWrite (redPin,1);                           // fast-Flash red pin to show we are going back to normal.
    delay (100);
    digitalWrite (redPin,0);
    digitalWrite (grnPin,1);
    delay (100);
    digitalWrite (grnPin,0);
    digitalWrite (bluPin,1);
    delay (100);
    digitalWrite (bluPin,0);
  }
  if (menuMode == 1){                                 // Cycle through R G and B to show we are in color mode
    digitalWrite (sndOnPin,false);                    // Turn off the sound card
    digitalWrite (redPin,0);                          //All off but red pin
    digitalWrite (grnPin,0);
    digitalWrite (bluPin,0);
    delay (300);
    digitalWrite (grnPin,0);                            //All off but red pin
    digitalWrite (bluPin,0);
    digitalWrite (redPin,1);
    delay (300);
    digitalWrite (redPin,0);                            // A little Green pin love
    digitalWrite (grnPin,1);
    delay (300);
    digitalWrite (grnPin,0);                              // How 'bout some for the Blue already!
    digitalWrite (bluPin,1);
    delay (300);
    digitalWrite (redPin,0);                            //All off
    digitalWrite (grnPin,0);
    digitalWrite (bluPin,0);
    fadeDirection = true;                                   //Ramp up that LED
  }
  if (menuMode == 2){
    digitalWrite (sndOnPin,false);                        // Turn off the sound card
    fadeDirection = false;
    fadeValue = 0;
    digitalWrite (redPin,0);
    digitalWrite (grnPin,0);
    digitalWrite (bluPin,0);
    EEPROM.write(0,colorMode);                           // Save the selected colorMode... good place to do it sice we are just going to delay anyway and it takes a few MS
    delay (100);
    digitalWrite (grnPin,1);                             // Flash the green pin to show we are in sound mode.
    delay (300);
    digitalWrite (grnPin,0);
    delay (300);
    digitalWrite (grnPin,1);
    delay (300);
    digitalWrite (grnPin,0);
  }
}
/*
MULTI-CLICK: One Button, Multiple Events
 
 Run checkButton() to retrieve a button event:
 Click
 Double-Click
 Hold
 */
// Button timing variables
int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250; // max ms between clicks for a double click event
int holdTime = 2000; // ms hold period: how long to wait for press+hold event
int longHoldTime = 5000; // ms long hold period: how long to wait for press+hold event
// Other button variables
boolean buttonVal = HIGH; // value read from button
boolean buttonLast = HIGH; // buffered value of the button's previous state
boolean DCwaiting = false; // whether we're waiting for a double click (down)
boolean DConUp = false; // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true; // whether it's OK to do a single click
long downTime = -1; // time the button was pressed down
long upTime = -1; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false; // when held, whether to wait for the up event
boolean holdEventPast = false; // whether or not the hold event happened already
int checkButton()
{
  int event = 0;
  // Read the state of the button
  buttonVal = digitalRead(buttonPin);
  // Button pressed down
  if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce) {
    downTime = millis();
    ignoreUp = false;
    waitForUp = false;
    singleOK = true;
    holdEventPast = false;
    if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
    else DConUp = false;
    DCwaiting = false;
  }
  // Button released
  else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce) {
    if (not ignoreUp) {
      upTime = millis();
      if (DConUp == false) DCwaiting = true;
      else {
        event = 2;
        DConUp = false;
        DCwaiting = false;
        singleOK = false;
      }
    }
  }
  // Test for normal click event: DCgap expired
  if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true) {
    event = 1;
    DCwaiting = false;
  }
  // Test for hold
  if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
    // Trigger "normal" hold
    if (not holdEventPast) {
      event = 3;
      waitForUp = true;
      ignoreUp = true;
      DConUp = false;
      DCwaiting = false;
      //downTime = millis();
      holdEventPast = true;
    }
  }
  buttonLast = buttonVal;
  return event;
}

Offline TroyO

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 39
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #1 on: February 14, 2010, 10:42:47 AM »
Ohhh... a link to the Arduino website would help... LOL

http://www.arduino.cc/

Offline Salvatore1971

  • Trade Count: (0)
  • Master Force User
  • *****
  • Posts: 684
  • "Yes, I know, I have a toupée on my head!"
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #2 on: February 14, 2010, 12:07:57 PM »
Quote
Right now I am using an Arduino Duemilinove (I bet I misspelled that)

"Duemilanove" is correct, my friend.  ;) (trust me, I'm italian  ;D).

My best wishes for your project!




I'm Italian. Sorry in advance for my bad english! :D

Offline TroyO

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 39
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #3 on: February 24, 2010, 11:11:15 AM »
Trust an Italian? Yeahhhhhh....  ::)

Here's a wiring diagram... kind of... LOL. I figured out which pins to use on the joe Jedi card, and wired them in but wrapped it in ShrinkWrap and didn't take notes. I'll un-wrap it tonight and verify my connections.

Anyway... should give folks an idea of what is involved. I'm adding a fan relay, and a vibe motor to it too... those aren't shown. (Haven't done them yet, LOL.)

Code wise, I'll post the next revision up when it's done... it adds a "Psuedo lockup" function.. hold the button when the saber is on and it tickles the impact sensor and makes it repeatedly do a clash which is sort of like a lockup. (It was Novastar's idea.... maybe I'll call it a NovaLock?)

That code's not done yet, but if I can tidy it up this evening I'll post it.





Offline Salvatore1971

  • Trade Count: (0)
  • Master Force User
  • *****
  • Posts: 684
  • "Yes, I know, I have a toupée on my head!"
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #4 on: February 24, 2010, 12:25:45 PM »
Trust an Italian? Yeahhhhhh....

Did you have problems with italians?  ??? I hope you were joking.

Anyway, I simply was referring to the word "Duemilinove" you used in your first post.  :-\ "Duemilanove" is correct.

Greetings.




I'm Italian. Sorry in advance for my bad english! :D

Offline TroyO

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 39
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #5 on: February 24, 2010, 02:23:00 PM »
LOL, yes I was joking... just being a smart arse. (Movie reference... "Trust me.... esss OK, I'm Italian...")

And thanks on the spelling confirmation... I think I finally got it. I've butchered it a few times and figured I'd never get it without pulling up the page and copying/pasting it.

I even listened to the pronunciation clip they had on there.... it will still be a while before I can SAY it without butchering it... but at least I can type Duelin... Duemununnn...  (Duemilinove)
 ;D

Offline Salvatore1971

  • Trade Count: (0)
  • Master Force User
  • *****
  • Posts: 684
  • "Yes, I know, I have a toupée on my head!"
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #6 on: February 25, 2010, 01:51:44 AM »
LOL, yes I was joking... just being a smart arse. (Movie reference... "Trust me.... esss OK, I'm Italian...")

Oh, Ok, sorry!   :D

...and you're welcome, obviously.  ;D




I'm Italian. Sorry in advance for my bad english! :D

Offline yell0w_lantern

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 29
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #7 on: February 27, 2010, 01:11:16 PM »
I am very intrigued by your project. The PWM hardware looks pretty big; can't wait to see how you squeeze it into a saber hilt.

Offline Luke-SkyMarcher

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 8
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #8 on: February 27, 2010, 03:54:27 PM »
This is most interesting....
Can you give us any idea on what it would take to adjust this for, say, a single-color LED, or for different soundboards?

Offline TroyO

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 39
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #9 on: February 27, 2010, 04:22:20 PM »
Remember that in the Video I am using a prototyping version of the Arduino. It's way bigger and has a breadboard on top of it so I can poke wires in it and such. The "final" version will be installed on an Arduino Nano.... the Nano is .7 inches by 1.7 inches so it's not all that big. The soundcard, the Nano and the PWM driver will all fit in about 3 inches of hilt.

Using it on other soundboards should be pretty easy. If you can control it by sending 5V (@ 40 mA) or connecting it to ground (@60 mA) you can do it directlly from the Arduino pins. If it needs more power than that, you can control a relay directly from a pin, and use the relay to connect/power whatever you want.

In short, you in theory can control any soundboard I've ever seen or heard of and you can have as many or as few colors involved as you'd like.... mostly it's just code.

If anyone wants, they can post up specifics about what they want to do and I can see if i can make up some basic code to match it.


Offline Luke-SkyMarcher

  • Trade Count: (0)
  • No Force
  • *
  • Posts: 8
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #10 on: June 24, 2010, 04:44:58 PM »
Hey TroyO, if you have time I may take you up on that offer. I'm thinking the new hasbro economy board hooked to RGBA. Nothing urgent or anything, but if I were to use arduino at all, that's probably what it would be with.


Offline xl97

  • Trade Count: (0)
  • Force User
  • ***
  • Posts: 228
Re: Arduino as RGBx PWM controller and Soundcard interface
« Reply #11 on: June 26, 2010, 09:12:52 AM »
Is there a reason why you would use it with another card?

you dont need the driver portion of it really..(and doesnt look like you'd be using it anyways)..

and the Arduino 'can' use SD cards to read & write to..

or you could even use an static 'eeprom' type chip to store sounds..

OR.. depending on the Atmel chip you use.. maybe saving the sounds in the chip itself in flash/progmem? (then no SD needed)