• Ambilamp code

    Date: 2010.04.22 | Category: Ambilamp | Tags:

    There it goes. v0.1 of the Ambilamp code.

    Basically, the lamp changes it’s color randomly, choosing a random target value for red, other for green and other for blue (yes, I’m using RGB leds :-) It then roams between the current value of each color to the target value. The colors are represented as hexadecimal numbers in RGB, so FF0000 is red, 00FF00 is green and 0000FF is blue, and so on…

    I mainly adapted the code from Devon D. Jones from evilsoft. His code provides a way of sending external commands to command the color you want to display, roam randomly, blink, etc… I’m only using the random roam (at least in v0.1, there are important additions in v0.2, not released yet). The code is easy to understand, so I won’t explain it here, I added a few modifications, though:

    - I forced using “stepmax” instead of a random number between stepmax and stepmin. This makes the transition between colors always as slow as possible.
    - When receiving a command for displaying a specific color, I prefer a transition to it instead of just displaying it inmediately.
    - I added a delay (5 seconds) after reaching the target color, to wait there for a while before roaming again.
    - To get better random numbers, I used as seed the value of an unconnected analog input pin, as using millis() as seed makes random numbers that repeat among restarts.

    
    /*
     * Adapted 15 June 2009
     * modification copyleft 2009 Enrique Jorreto
     * quercus [at] nosomos.org
     * http://projects.nosomos.org
     * Adapted 14 April 2007
     * modifications copyleft 2007 Devon D. Jones soulcatcher [at] evilsoft.org
     * http://www.evilsoft.org
     * Adapted from Serial RGB LED TOO
     * Created 18 October 2006
     * copyleft 2006 Tod E. Kurt tod [at] todbot.com
     * http://todbot.com/
     */
    
    /*
     * This program can take a number of inputs on the serial port:
     * 1) #[HHHHHH] where H = Hex.  Example: #FF6666.  This will set the orb to the color that is declared.
     * 2) roam.  This will cause the orb to float between colors
     * 3) %[HHHHHH] where H = Hex.  Examples: %, %00FF00.  This will put the orb into alert mode, where
     *    it will flash between the color (or FF0000 if no color is passed in) and a very dim version of the color
     */
    #define slen 7        // 7 characters, e.g. '#ff6666'
    #define maxCommandLength 16
    // For random colors, this is the lower & upper bound.
    // The result is multiplied by 16, and then normalized to 0-255
    // we start at -3 and go to 20 to bias the randomness towards 0 and 255
    // because it results in generally better colors
    #define randmin -3
    #define randmax 20
    // For color transition we use varied transition speed,
    // this is the lower & upper bound.
    #define stepmin 16
    #define stepmax 1
    
    char serInStr[slen];  // array to hold the incoming serial string bytes
    
    struct led {
      int curr; // Current brightness
      int dest; // Next intended brightness
      int step; // If transitioning from one brightness to another, this is the amount to step by
    }; // Struct representing a single led
    struct ledcolors { led red; led green; led blue; }; // Struct representing the 3 leds
    ledcolors colors;
    
    int roam = 0; // 0 roam off, 1 roam on
    int roamTo=0;
    
    int alert = 0; // 0 alert off, 1 alert off
    unsigned long alertMillis = 0; // used to determine when to swap colors
    int alertInterval = 300; // interval used between swap requests
    
    int gndPin   = 12;  // Ground pin.  We use this instead of gnd so that we can get 4 pins in a row.
                        //   Pin 13 has a resistor, so it is not a good pin for us to use.
                        //   as either gnd or vcc for an LED
    int redPin   = 11;  // Red LED,   connected to digital pin 11
    int greenPin = 10;  // Green LED, connected to digital pin 10
    int bluePin  = 9;   // Blue LED,  connected to digital pin 9
    
    void roamToColor(int red, int green, int blue);
    
    void setup() {
      // sets the pins as output
      pinMode(gndPin,   OUTPUT);
      digitalWrite(gndPin, LOW);
      pinMode(redPin,   OUTPUT);
      pinMode(greenPin, OUTPUT);
      pinMode(bluePin,  OUTPUT);
    
      Serial.begin(9600);
      roam = 1; // start off roaming
    }
    
    void loop () {
      //read the serial port and create a string out of what you read
      int spos = readSerialString();
    
      if(spos == slen && serInStr[0] == '#') {
        roam = 0;
        alert = 0;
        long colorVal = strtol(serInStr + 1, NULL, 16);
        decodeColor(colorVal);
        //displayColor(colors.red.curr, colors.green.curr, colors.blue.curr);
        roamToColor(colors.red.dest, colors.green.dest, colors.blue.dest);
        roam=1;
        roamTo=1;
        memset(serInStr,0,slen);      // indicates we've used this string
      }
      else if(spos != -1 && strncmp(serInStr, "roam", 4) == 0) {
        alert = 0;
        roam = 1;
        roamTo=0;
        initStruct();
        prepRoam();
      }
      else if(spos != -1 && serInStr[0] == '%') {
        roam = 0;
        alert = 1;
        initStruct();
        if(spos == slen) {
          long colorVal = strtol(serInStr + 1, NULL, 16);
          decodeColor(colorVal);
        }
        else {
          colors.red.curr = 255;
        }
        prepAlert();
      }
    
      if(roam == 1) {
        int ret = doRoam();
        displayColor(colors.red.curr, colors.green.curr, colors.blue.curr);
        if(ret > 0 && roamTo==0) {
          delay(5000);
          prepRoam();
        }
    
      }
    
      if(alert == 1) {
        doAlert();
        displayColor(colors.red.curr, colors.green.curr, colors.blue.curr);
      }
    
      delay(100);  // wait a bit, for serial data
    }
    
    // Takes in a string in ?000000 - ?FFFFFF format (Ex: #FFAA33)
    // and sets the curr color to the value
    void decodeColor(long colorVal) {
      colors.red.dest = (colorVal&0xff0000) >> 16;
      colors.green.dest = (colorVal&0x00ff00) >> 8;
      colors.blue.dest = (colorVal&0x0000ff) >> 0;
    }
    
    void displayColor(int red, int green, int blue) {
      analogWrite(redPin, red);
      analogWrite(greenPin, green);
      analogWrite(bluePin, blue);
    }
    
    //read a string from the serial and store it in an array
    int readSerialString () {
      int i = 0;
      if(!Serial.available()) {
        return -1;
      }
      while (Serial.available() && i < maxCommandLength) {
        int c = Serial.read();
          serInStr[i++] = c;
      }
      //Serial.println(serInStr);
      return i;
    }
    
    void initStruct() {
      colors.red.curr = 0;
      colors.red.dest = 0;
      colors.red.step = 0;
      colors.green.curr = 0;
      colors.green.dest = 0;
      colors.green.step = 0;
      colors.blue.curr = 0;
      colors.blue.dest = 0;
      colors.blue.step = 0;
    }
    
    //------------------------------
    //ALERT
    //------------------------------
    void doAlert() {
      if (millis() - alertMillis > alertInterval) {
        alertMillis = millis();
        int tmp = 0;
        tmp = colors.red.curr;
        colors.red.curr = colors.red.dest;
        colors.red.dest = tmp;
        tmp = colors.green.curr;
        colors.green.curr = colors.green.dest;
        colors.green.dest = tmp;
        tmp = colors.blue.curr;
        colors.blue.curr = colors.blue.dest;
        colors.blue.dest = tmp;
      }
    }
    
    void prepAlert() {
      colors.red.dest = colors.red.curr / 8;
      colors.green.dest = colors.green.curr / 8;
      colors.blue.dest = colors.blue.curr / 8;
    }
    
    //------------------------------
    //ROAMING
    //------------------------------
    int doRoam() {
      colors.red.curr = roamColor(colors.red.curr, colors.red.dest, colors.red.step);
      colors.green.curr = roamColor(colors.green.curr, colors.green.dest, colors.green.step);
      colors.blue.curr = roamColor(colors.blue.curr, colors.blue.dest, colors.blue.step);
      if((colors.red.curr == colors.red.dest)
          && (colors.green.curr == colors.green.dest)
          && (colors.blue.curr == colors.blue.dest)) {
        return 1;
      }
      else
      {
        // For some debugging
        /*
        Serial.print("#");
        Serial.print(colors.red.curr);
        Serial.print(" ");
        Serial.print(colors.green.curr);
        Serial.print(" ");
        Serial.print(colors.blue.curr);
        Serial.print(" -> #");
        Serial.print(colors.red.dest);
        Serial.print(" ");
        Serial.print(colors.green.dest);
        Serial.print(" ");
        Serial.println(colors.blue.dest);
        */
      }
      return 0;
    }
    
    int roamColor(int curr, int dest, int step) {
      int diff = curr - dest;
      if(diff < 0) {
        diff = diff * -1;
      }
    
      if(curr == dest) {
        return dest;
      }
      else if(curr < dest) {
        if(diff <= step) {
          return dest;
        }
        return curr + step;
      }
      else {
        if(diff <= step) {
          return dest;
        }
        return curr - step;
      }
    }
    
    void prepRoam() {
      randomSeed(analogRead(1));
      colors.red.dest = getRandomColor();
      // I prefer using stepmax for lower gradient
      //colors.red.step = random(stepmin, stepmax);
      colors.red.step = stepmax;
      colors.green.dest = getRandomColor();
      //colors.green.step = random(stepmin, stepmax);
      colors.green.step = stepmax;
      colors.blue.dest = getRandomColor();
      //colors.blue.step = random(stepmin, stepmax);
      colors.blue.step = stepmax;
    }
    
    void roamToColor(int red, int green, int blue) {
      colors.red.dest = red;
      // I prefer using always stepmax for lower gradient
      //colors.red.step = random(stepmin, stepmax);
      colors.red.step = stepmax;
      colors.green.dest = green;
      //colors.green.step = random(stepmin, stepmax);
      colors.green.step = stepmax;
      colors.blue.dest = blue;
      //colors.blue.step = random(stepmin, stepmax);
      colors.blue.step = stepmax;
    }
    
    int getRandomColor() {
      int color = (random(randmin, randmax) * 16) -1;
      if (color < 0) color = 0;
      if (color > 255) color = 255;
      return color;
    }