Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Sunday, April 15, 2012

Mood Lamp Touch Version 1.0



Horse of a different colour

The finishing touches on this touchy project ended up taking longer than I expected, leaving me with much less time (and patience) to blog about it.



Alterations

Since the last post on it, I modified the touch lamp code to change colours on tap-and-hold. It was a little less error-prone and far more intuitive than detecting fingers at a distance from the touch area.


[ I hate vero board... yes, I still hate it... ]

Frustrations

Moving it to the vero board was relatively painless. What really caused me headaches was the reassembly of the lamp itself. When using capacitive detection, all wires must be very well insulated and accounted for.

Version Cutoff

After having to assemble, test, disassemble, solder, un-solder, assemble, ad-nauseum for a few hours I gave up on trying to fix all of the bugs or not-so-great features of it and called it “Version 1.0”. Eventually the state of it will bug me enough to make version 2. Until then, at least I have my fancy mood lamp touch with colour therapy to relax with.

Alpha Bugs/Shortcomings

  1. The emitter is far too high in the lamp diffuser, creating a bright band of light in the middle of the lamp instead of at the base.
  2. A single RGB module is far too weak to produce enough light to fill a room. More will need to be added.
  3. Occasionally, due to either the vero board wiring or the internal wire arrangement or some other variable in the sensitivity of the code, the lamp will turn itself off instead of change colours when touched and held. It’s not too frequent so it should be ok for now.
  4. The project severely underuses the Atmega328P. Don’t know what I can do about this one, really. Smaller chips could be bought and used but it’s more effort and time (hence more cost). I optimised a bunch of the HSV to RGB code to produce a hex file that was about half the size that it started at… If you’re interested in recreating this, it’s worth mentioning that the hex is under 8K and would easily fit on an ATtiny85 (slightly less wasteful).

Code

Should you want to make this project yourself, here’s the sketch for it. It was thrown together pretty quickly so I apologise for the many ragged edges. You’ll first need to install the CapSense library by Paul Badger.

Note: Because it was easier on the vero, I changed D4 and D5 to D6 and D7. Be sure to change it back if you follow the schematic to the letter.

#include <CapSense.h>

/* colours */

const long cRed     = 0xFF0000;
const long cGreen   = 0x00FF00;
const long cBlue    = 0x0000FF;

const long cYellow  = cRed | cGreen;
const long cCyan    = cGreen | cBlue;
const long cMagenta = cRed | cBlue;

/* shifts */

const short cRedShift   = 16;
const short cGreenShift = 8;
const short cBlueShift  = 0;

int CKI = 2;
int SDI = 3;

boolean touchPresent = false;

boolean isOn = true;

long toggledFromTouchAtTime = 1L;

long touchesBeganAtTime = 1L;
long currentTouchHoldTime = 1L;
long lastTouchHoldTime = 1L;

CapSense   cs_4_5 = CapSense(6,7); 

#define STRIP_LENGTH 1 // Number of RGBLED modules connected
long currentColor = 0L;
long lastColor = 0L;

void setup() {
  pinMode(SDI, OUTPUT);
  pinMode(CKI, OUTPUT);
  cs_4_5.set_CS_AutocaL_Millis(0xFFFFFFFF);
}

void touchesDidBegin()
{
  touchPresent = true;
  touchesBeganAtTime = millis();
  currentTouchHoldTime = 0;
}

void touchesDidContinue()
{
  currentTouchHoldTime = millis() - touchesBeganAtTime;
}

void touchesDidEnd()
{
  touchPresent = false;
  lastTouchHoldTime = millis() - touchesBeganAtTime;
  currentTouchHoldTime = 0;
}

long highestVal = 0;
long red = 0x00;
long green = 0xFF;
long blue = 0x00;
long *modColor = NULL;
boolean addColor;

void updateCurrentColor()
{
  currentColor = (red << cRedShift) + (green << cGreenShift) + (blue << cBlueShift);
}

void changeColor()
{
  switch(currentColor){

      case cRed:
        // add green
        modColor = &green;
        addColor = true;
      break;

      case cYellow:
        // subtract red
        modColor = &red;
        addColor = false;
      break;

      case cGreen:
        // add blue
        modColor = &blue;
        addColor = true;
      break;

      case cCyan:
        // subtract green
        modColor = &green;
        addColor = false;
      break;

      case cBlue:
        // add red
        modColor = &red;
        addColor = true;
      break;

      case cMagenta:
        // subtract blue
        modColor = &blue;
        addColor = false;
      break;

      default:
      break;
    }

    // modify the colour
    if (addColor){
      *modColor = *modColor + 1;
    } else {
      *modColor = *modColor - 1;
    }

    updateCurrentColor();
}

void loop() {

  long total1 =  cs_4_5.capSense(30);

  // calibrate

  if (highestVal == 0){
    for (int i = 0; i < 100; i++){
      if (highestVal < total1){
        highestVal = total1;
      }
      total1 = cs_4_5.capSense(30);
      delay(10);
    }
  }

  // touch recognition

  if (total1 >= highestVal + 30){
    if (!touchPresent){
      touchesDidBegin();
    } else {
      touchesDidContinue();
    }
  } else if (touchPresent){
    touchesDidEnd();
  }

  // and the colour bit

  if (isOn && currentTouchHoldTime > 500){
    changeColor();
  } else if ((!isOn || (!touchPresent && lastTouchHoldTime < 500)) && (touchesBeganAtTime > toggledFromTouchAtTime + 200)) {
    toggledFromTouchAtTime = touchesBeganAtTime;
    isOn = !isOn;
  }

  if (isOn) {
    updateCurrentColor();
  } else {
    currentColor = 0;
  }

  if (currentColor != lastColor) {
    post_frame(currentColor);
    lastColor = currentColor;
  }

  delay(50);
}

void post_frame (long led_color) {
  for(int LED_number = 0; LED_number < STRIP_LENGTH; LED_number++)
  {
    long this_led_color = led_color; //24 bits of color data

    for(byte color_bit = 23 ; color_bit != 255 ; color_bit--) {
      //Feed color bit 23 first (red data MSB)

      digitalWrite(CKI, LOW); //Only change data when clock is low

      long mask = 1L << color_bit;
      //The 1'L' forces the 1 to start as a 32 bit number, otherwise it defaults to 16-bit.

      if(this_led_color & mask) 
        digitalWrite(SDI, HIGH);
      else
        digitalWrite(SDI, LOW);

      digitalWrite(CKI, HIGH); //Data is latched when clock goes high
    }
  }

  //Pull clock low to put strip into reset/post mode
  digitalWrite(CKI, LOW);
  delayMicroseconds(500); //Wait for 500us to go into reset
}

Monday, March 5, 2012

Dual Battery Monitor Adapter

This is a design I sketched up tonight for a compact in-line dual battery monitor adapter for Arduino. Those of you who have looked into battery monitoring for Arduino will know that the maximum voltage that the Arduino's ADC pins can handle is 5v.

Here's a simple design (5 solder points) that will take your servo battery (~6v) and your Arduino battery (~9v) and reduce the voltage from them to safely measurable levels. I wouldn't push this design past measuring two 9v sources as it gets a bit close to the maximum.


Assuming you are using the voltages specified, the power usage is 58.5 microWatts. If you use 10M resistors instead, you can reduce that by a factor of 10 (und so weiter...).

I will be making one of these for ABE and a half-one for the WRPC so that they can monitor their own battery levels.