Sunday, January 30, 2011

VibraMotor as a Cat Toy

If you have an old cellphone lying around that doesn't work anymore or that you would have thrown away anyway, you might want to think about taking it apart for spare parts or looking inside to understand how it works.

Yesterday I disassembled an old cellphone to look for some parts which I could use. Besides some buttons, a microphone and a speaker, one particular component caught my attention. I extracted a small vibra motor. Vibra motors are responsible for the vibrating notification your cellphone can alert you with. In general they are just small DC motors. At the top of their shaft they have a weight in the form of a half circle. When the motor spins the weight, it gets out of balance and you experience a vibration.

You also can order those motors online if you don't have a cellphone lying around.

With the motor and an additional LED, I decided to build a toy for my cat.

Usually those little motors work with a 3V power supply. I used a coin cell battery holder for my circuit so I could keep the project really small. The only thing left to do was to attach a 150Ω resistor with a red LED to the circuit. Now the circuit can be placed in a casing. I used a surprise egg plastic casing. Make sure that you seal the casing or stand by when your cat plays with it, so your cat can't accidentally break it open and swallow the parts.

Let's have look at the setup:

Vibra Motor

Parts (150Ω resistor and LED are missing on that photo)

Assembled Circuit

Circuit in Casing




Here is the circuit diagram of the project:







If you assembled everything correctly, the result should look like this:

video

Friday, January 28, 2011

Capacitive Touch Sensor on Arduino

If you ever wanted to integrate touch sensitivity into your project, this board could just do the trick. It's a capacitive touch sensor. These sensors are used in our everyday consumer electronics like notebook trackpads, video game consoles, touchscreens...just to name a few.

They work on the principle of alteration of the electrostatic field. The sensor builds up an electrostatic field which will be altered if conductive objects get in contact with the field. In this case your finger is the conductive object which triggers the change in the field. For detailed information about capacitive sensing have a look here.

The board works in I2C mode and needs pull-up resistors for the SDA and SCL pins. The operating voltage range is from 2.7V to 5.25V, so you can use either the 3.3V or 5V socket of the Arduino.

The setup is pretty easy. I attached two LEDs to indicate if the sensor plate was touched.




Figuring out the communication with the device is a little bit tricky. I found a really good blog post from Marcus Nowotny who provides a sample code, so you don't have to get a headache while trying to understand the datasheet.

If you hooked up everything correctly, you can enjoy capacitive sensing in your project.

video

Wednesday, January 26, 2011

RFID with Arduino

If you ever wanted to integrate RFID functionality into your project, this small tutorial might help you accomplish that. I used the RDM630 module from seeedstudio in its UART version. It comes on a small board with presoldered connectors which fits perfectly on a breadboard. You only need to connect the antenna to the two pin socket. You also can connect a LED to indicate if the antenna picks up a signal. The signal output can be easily read by using the NewSoftSerial library and assigning the RX TX ports.

Here are the setup schematics:


The signal readings are transmitted in byte blocks. The first byte (02) is the start of text byte in HEX-ASCII format. Then following is the 10 byte data for the ID which has been recognized. After that a 2 byte checksum is transmitted. Followed by the last byte (03).
To translate the 10 byte HEX-ASCII data to the unique ID, you only have to map the bytes to the according ASCII character. For details have a look into the datasheet.

This is an example code which checks if the data was received correctly. It prints the ID and checks if the transmitted checksum is equal to the calculated checksum of the ID.
#include "NewSoftSerial.h"
#define stx 2
#define etx 3

NewSoftSerial mySerial(6, 7);
int counter;
byte data[14];
byte hexBlock1,hexBlock2,hexBlock3,hexBlock4,hexBlock5;
byte hexCalculatedChecksum,hexChecksum;

void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
}

void loop() {
  if (mySerial.available() > 0) {
    data[counter] = mySerial.read();
    counter++;
    if(counter > 13) {
      //we read the whole message, so reset counter
      counter = 0;
      //check if start of text and end of text is correct
      if(data[0] == stx && data[13] == etx) {
        Serial.println("Start of text and end of text correctly received.");
        Serial.print("ID: ");
        //show ID
        for(int x = 1; x < 11; x++) {
          Serial.print(data[x], BYTE);
        }
        Serial.println("");
        Serial.print("Checksum: ");
        //show checksum
        Serial.print(data[11], BYTE);
        Serial.println(data[12], BYTE);

        //Hex ID blocks. Two transmitted Bytes form one Hex ID block.
        //Hex ID blocks:      6   2  |  E   3  |  0   8  |  6   C  |  E   D
        //Transmitted Bytes: 36H 32H | 45H 33H | 30H 38H | 36H 43H | 45H 44H
        hexBlock1 = AsciiCharToNum(data[1])*16 + AsciiCharToNum(data[2]);
        hexBlock2 = AsciiCharToNum(data[3])*16 + AsciiCharToNum(data[4]);
        hexBlock3 = AsciiCharToNum(data[5])*16 + AsciiCharToNum(data[6]);
        hexBlock4 = AsciiCharToNum(data[7])*16 + AsciiCharToNum(data[8]);
        hexBlock5 = AsciiCharToNum(data[9])*16 + AsciiCharToNum(data[10]);
       
        //Transmitted checksum.
        hexChecksum = AsciiCharToNum(data[11])*16 + AsciiCharToNum(data[12]);

        //XOR algorithm to calculate checksum of ID blocks.
        hexCalculatedChecksum = hexBlock1 ^ hexBlock2 ^ hexBlock3 ^ hexBlock4 ^ hexBlock5;
        if ( hexCalculatedChecksum == hexChecksum )
        {
          Serial.println("Calculated checksum matched transmitted checksum.");
        }
        else {
          Serial.println("Calculated checksum didn't match transmitted checksum. Corrupt data!");
        }
      }
    }
  }
}

uint8_t AsciiCharToNum(byte data) {
  //First substract 48 to convert the char representation
  //of a number to an actual number.
  data -= '0';
  //If it is greater than 9, we have a Hex character A-F.
  //Substract 7 to get the numeral representation.
  if (data > 9)
    data -= 7;
  return data;
}
 
An example reading would look like this:
Start of text and end of text correctly received.
ID: 4200442C01
Checksum: 2B
Calculated checksum matched transmitted checksum.
Here is a demonstration of the RFID reader in action:

video

Tuesday, January 25, 2011

Color Wheel with Wii Nunchuck and Arduino

Today I want to show you how to use a Wii nunchuck to control your Arduino projects. In my example I used the nunchuck to simulate a color wheel with a full rgb LED. I connected a WiiChuck board directly to the Arduino using the analog ports. You can use them for the I2C communication and to power the board. There is a blog which already provides a library and some demo code to get you started.

I modified the demo code and had to adjust some coordinate bounds of my nunchuck. There are some formulars for calculating color wheels, but I took an easier approach and just mapped coordinate bounds of the color spectrums to the color wheel.
Note that my mapping is only a rough approximation. You also might need to adjust the bounds because your nunchuck readings could differ just a little bit.

The setup is easy. You just need to connect the WiiChuck board to the analog ports 5-2 and setup a circuit for your rgb LED. I have a rgb LED with 6 pins. Two for GND, two for blue, one for red and one for green. That's why my setup seems a little bit crowded.



The code isn't the prettiest one but it gets the job done for now.
#include <Wire.h>
#include "nunchuck_funcs.h"

//PWM Digital Pin layout for RGB LED
#define greenLED 6
#define blue1LED 9
#define blue2LED 10
#define redLED 11

byte joyx,joyy;
byte redVal,greenVal,blueVal;

void setup()
{
  nunchuck_setpowerpins();
  nunchuck_init(); // send the initilization handshake
}

void loop()
{
  nunchuck_get_data();

  joyx = nunchuck_joyx(); // idle position at approx 133, ranges from approx 31 - 232
  joyy = nunchuck_joyy(); // idle position at approx 130, ranges from approx 33 - 228

  //Red has its full intensity at y = 228 (approx upper bound).
  //When moving in x direction, y will decrease.
  //Red has its lowest intensity when it reaches the full intensity position of green or blue.
  //In my case approx y = 95.
  redVal = map(joyy >= 95 ? joyy : 95, 95, 228, 0, 255);

  //Green has its full intensity at approx x = 217 and approx y = 95.
  //Green has two x ranges. If y is above 95 then the x range is from 133 to 232.
  //If y is below 95 then the x range is from 44 to 217.
  greenVal = joyy >=95 ? map(joyx < 133 ? 133 : joyx, 133, 232, 0, 255) :
  map(joyx > 217 ? 217 : joyx < 44 ? 44 : joyx, 44, 217, 0, 255);

  //Blue has its full intensity at approx x = 44 and approx y = 95.
  //Blue has two x ranges. If y is above 95 then the x range is from 31 to 133.
  //If y is below 95 then the x range is from 44 to 217.
  blueVal = joyy >=95 ? map(joyx > 133 ? 133 : joyx, 133, 31, 0, 255) :
  map(joyx > 217 ? 217 : joyx < 44 ? 44 : joyx, 217, 44, 0, 255);

  //Because I also want to simulate white light I need to determine if the position is roughly in the middle.
  if(joyy > 125 && joyy < 135 && joyx > 125 && joyx < 135) {
    redVal=255;
    greenVal=255;
    blueVal=255;
  } 
  analogWrite(redLED, redVal);
  analogWrite(greenLED, greenVal);
  analogWrite(blue1LED, blueVal);
  analogWrite(blue2LED, blueVal);

  delay(100);
}
This video shows the nunchuck color wheel in action:

video

Saturday, January 22, 2011

DIY Nightlight

Since I became an uncle last year, I thought about building something with electronics for my niece. I already setup a circuit a while ago for pulsating LEDs. I used this circuit for one pulsating blue LED and added another blue LED and a Yellow LED. What I wanted to achieve is that the LEDs illuminate certain parts of an image which is put in front of them. I used a food container where I could put in a mini breadboard and a 9V battery. I searched the web for free images to use and found a clipart page which had just the image I needed.

For the circuit setup please have a look into my old post.

Here is a demo of the nightlight:

video

RGB Color Sensor on Arduino

The next board I want to show you is the ADJD-S371 Color Light Sensor Evaluation Board from sparkfun. It emits light and analyses the reflected color spectrum. The board can be controlled via I2C. The sleep and xclk pins were not used in this example. I found a really nice tutorial describing how to connect the sensor to the Arduino. The example also provided the code to communicate with the sensor. I only had to change minor parts to fit my needs.

My basic setup looks a little bit different because I used a full color rgb LED with six pins. Two for ground, one for red, one for green and two for blue. I also used another schematic this time. What you see here is a software developed by the University of Applied Sciences Potsdam, here in Germany. The software is called Fritzing. You can design your circuit on a protoboard, convert it into a circuit diagram and even into a PCB layout for later manufacturing. It's really nice and easy to use. Thanks for the tip Darsh!

Here is my setup:




As already mentioned I only changed the code from the tutorial a little bit to fit to my rgb LED.
//Configure gain here
//Higher numbers = less sencitive
// 0x00 through 0x0f
int redGain = 0x03;
int greenGain = 0x0;
int blueGain = 0x0f;
int clearGain = 0x01;

//Include the I2C Arduino library
#include <Wire.h>

//7 bit I2C address of this sensor
#define I2C_ADDRESS 0x74

#define REG_CAP_RED    0x06
#define REG_CAP_GREEN     0x07
#define REG_CAP_BLUE     0x08
#define REG_CAP_CLEAR     0x09

#define REG_INT_RED_LO    0x0A
#define REG_INT_RED_HI    0x0B
#define REG_INT_GREEN_LO 0x0C
#define REG_INT_GREEN_HI 0x0D
#define REG_INT_BLUE_LO    0x0E
#define REG_INT_BLUE_HI    0x0F
#define REG_INT_CLEAR_LO 0x10
#define REG_INT_CLEAR_HI 0x11

#define REG_DATA_RED_LO    0x40
#define REG_DATA_RED_HI    0x41
#define REG_DATA_GREEN_LO 0x42
#define REG_DATA_GREEN_HI 0x43
#define REG_DATA_BLUE_LO 0x44
#define REG_DATA_BLUE_HI 0x45
#define REG_DATA_CLEAR_LO 0x46
#define REG_DATA_CLEAR_HI 0x47

//PWM Digital Pin layout for RGB LED
#define greenLED 6
#define blue1LED 9
#define blue2LED 10
#define redLED 11

float redFactor=1;
float blueFactor=1;
float greenFactor=1;

//initial darkLevel;
int calibrationDarkness = 0;
byte calibrationRed = 5;
byte calibrationGreen = 5;
byte calibrationBlue = 5;

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

  // sensor gain setting (Avago app note 5330)
  // CAPs are 4bit (higher value will result in lower output)
  set_register(REG_CAP_RED, redGain);
  set_register(REG_CAP_GREEN, greenGain);
  set_register(REG_CAP_BLUE, blueGain);
  set_register(REG_CAP_CLEAR, clearGain);

  int ledGain = getColorGain();

  set_gain(REG_INT_RED_LO,ledGain);
  set_gain(REG_INT_GREEN_LO,ledGain);
  set_gain(REG_INT_BLUE_LO,ledGain);

  performMeasurement();

  int red=get_readout(REG_DATA_RED_LO);
  int green=get_readout(REG_DATA_GREEN_LO);
  int blue=get_readout(REG_DATA_BLUE_LO);

  int m=2000; //bigger anyway
  m=min(m,red);
  m=min(m,green);
  m=min(m,blue);

  //Serial.print("m - ");
  //Serial.println(m);

  redFactor=((float)m*255.0)/(1000*(float)red);
  greenFactor=((float)m*255.0)/(1000*(float)green);
  blueFactor=((float)m*255.0)/(1000*(float)blue);

}

void loop() {

  //set rgb LED off
  analogWrite(redLED, 0);
  analogWrite(greenLED, 0);
  analogWrite(blue1LED, 0);
  analogWrite(blue2LED, 0);

  int clearGain = getClearGain();
  set_gain(REG_INT_CLEAR_LO,clearGain);
  int colorGain = getColorGain();
  set_gain(REG_INT_RED_LO,colorGain);
  set_gain(REG_INT_GREEN_LO,colorGain);
  set_gain(REG_INT_BLUE_LO,colorGain);

  //reset the RGB (and clear) values
  int cc = 0;
  int red=0;
  int green=0;
  int blue=0;

  // Take 4 samples, and add them together.
  for (int i=0; i<4 ;i ++) {
    performMeasurement();
    cc +=get_readout(REG_DATA_CLEAR_LO);
    red +=get_readout(REG_DATA_RED_LO);
    green +=get_readout(REG_DATA_GREEN_LO);
    blue +=get_readout(REG_DATA_BLUE_LO);
  }

  //now, divide the totals for each by 4 to get their average.
  cc/=4;
  red /=4;
  green /=4;
  blue /=4;

  //take the values mesured from above, and multiply them with the factors to
  //find out what value should be sent to the external RGB LED to reproduce this color
  float redValue = (float)red*redFactor;
  float greenValue = (float)green*greenFactor;
  float blueValue = (float)blue*blueFactor;

  //Print the recognized color to the Serial Monitor and light up rgb LED accordingly.
  if(redValue > 100 && greenValue > 100 && blueValue > 100) {
    Serial.println("White or Clear");
    analogWrite(redLED, 255);
    analogWrite(greenLED, 255);
    analogWrite(blue1LED, 255);
    analogWrite(blue2LED, 255);
  }
  else if(redValue > 100 && greenValue > 100) {
    Serial.println("Yellow");
    analogWrite(redLED, 255);
    analogWrite(greenLED, 255);
  }
  else if(redValue > 100 && blueValue > 100) {
    Serial.println("Magenta");
    analogWrite(redLED, 255);
    analogWrite(blue1LED, 255);
    analogWrite(blue2LED, 255);
  }
  else if(greenValue > 100 && blueValue > 100) {
    Serial.println("Cyan");
    analogWrite(greenLED, 255);
    analogWrite(blue1LED, 255);
    analogWrite(blue2LED, 255);
  }
  else if(redValue > 100) {
    Serial.println("Red");
    analogWrite(redLED, 255);
  }
  else if(greenValue > 100) {
    Serial.println("Green");
    analogWrite(greenLED, 255);
  }
  else if(blueValue > 100) {
    Serial.println("Blue");
    analogWrite(blue1LED, 255);
    analogWrite(blue2LED, 255);
  }

  //Print reflected light spectrum to the Serial Monitor.
  Serial.print("red: ");
  Serial.println(redValue);

  Serial.print("green: ");
  Serial.println(greenValue);

  Serial.print("blue: ");
  Serial.println(blueValue);
  Serial.println("");

  //hold it for one second
  delay(1000);
}

int getClearGain() {
  int gainFound = 0;
  int upperBox=4096;
  int lowerBox = 0;
  int half;

  while (!gainFound) {
    half = ((upperBox-lowerBox)/2)+lowerBox;

    if (half == lowerBox) { //no further halfing possbile
      break; //no further halfing possbile
    }
    else {
      set_gain(REG_INT_CLEAR_LO,half);
      performMeasurement();
      int halfValue = get_readout(REG_DATA_CLEAR_LO);

      if (halfValue > 1000) {
        upperBox=half;
      }
      else if (halfValue<1000) {
        lowerBox = half;
      }
      else {
        break; //no further halfing possbile
      }
    }
  }
  return half;
}

int getColorGain() {
  int gainFound = 0;
  int upperBox=4096;
  int lowerBox = 0;
  int half;
  while (!gainFound) {
    half = ((upperBox-lowerBox)/2)+lowerBox;

    if (half==lowerBox) { //no further halfing possbile
      break; // gain found
    }
    else {

      set_gain(REG_INT_RED_LO,half);
      set_gain(REG_INT_GREEN_LO,half);
      set_gain(REG_INT_BLUE_LO,half);
      performMeasurement();
      int halfValue = 0;

      halfValue=max(halfValue,get_readout(REG_DATA_RED_LO));
      halfValue=max(halfValue,get_readout(REG_DATA_GREEN_LO));
      halfValue=max(halfValue,get_readout(REG_DATA_BLUE_LO));

      if (halfValue>1000) {
        upperBox=half;

      }
      else if (halfValue<1000) {
        lowerBox=half;

      }
      else {
        break; // gain found
      }
    }
  }
  return half;
}

void performMeasurement() {
  set_register(0x00,0x01); // start sensing

  while(read_register(0x00) != 0) {
    // waiting for a result
  }
}

int get_readout(int readRegister) {
  return read_register(readRegister) + (read_register(readRegister+1)<<8);
}

void set_gain(int gainRegister, int gain) {
  if (gain <4096) {
    uint8_t hi = gain >> 8;
    uint8_t lo = gain;

    set_register(gainRegister, lo);
    set_register(gainRegister+1, hi);
  }
}

void set_register(unsigned char r, unsigned char v){

  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(r);
  Wire.send(v);
  Wire.endTransmission();
}

unsigned char read_register(unsigned char r){

  unsigned char v;
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(r); // register to read
  Wire.endTransmission();

  Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
  while(!Wire.available()) {
    // waiting
  }
  v = Wire.receive();
  return v;
}
This is a demo of the sensor in action. It had a really hard time recognizing the green spectrum. It may have been my room lighting though.

video

IR distance sensor on Arduino

The next little device is an IR distance sensor. It comes on a tiny, easy to use board. It operates on 5V and the output voltage which is sent out of the signal pin gets lower the closer an object gets. Theses little sensors are used on robots to measure the distance to an obstacle or to sense edges. The on-board IR LED emits light which is reflected and sensed by an IR sensitive phototransistor. The setup is pretty easy so I don't even need to provide a schematic. Just connect the Vin pin of the board to the 5V port of the Arduino and the GND pin to GND. You can connect the signal pin to any analog port of the Arduino. That's all there is to it.

The source code is straight forward too:
#define signal 0

int adcRawValue;
//You have to determine your normal reflection to set an upper bound.
int normalReflectionValue;

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

void loop() {
  adcRawValue = analogRead(signal);
  //If you get higher values due to interferences, fallback to your upper bound.
  if(adcRawValue > 500) {
    adcRawValue = 500;
  }
  //I mapped my boundaries inverse to a 0-100 scale. (500 = 0; 0 = 100)
  //The closer the Object gets, the lower the ADC value.
  Serial.println(map(adcRawValue, 500, 0, 0, 100));
  delay(50);
}
Here is a demo reading when hovering my finger over the sensor:

video

Thursday, January 20, 2011

7-Segment Display on Arduino

A new package with electronic components arrived today, so let's get busy.

First I want to show you a seven segment display which I hooked up to the Arduino. The display is from sparkfun and it is really easy to connect and to control it. You can control it via SPI or via serial. For more info refer to the datasheet. I used the serial communication, so I only would need one wire to transmit data to the component. You just have to connect the Vcc pin to 5V of the Arduino and the GND pin to GND. Then you only need to connect the RX pin to one of the digital ports of the Arduino. For sending data to the component I used the NewSoftSerial library.

The example program I wrote is a simple seconds counter.
#include "NewSoftSerial.h"

//The second parameter (TX) is the digital port which sends data to the display.
//The first parameter (RX) isn ot used.
NewSoftSerial mySerial(2, 3);
int minutes;
int deciminutes;
int seconds;
int deciseconds;

void setup() {
  Serial.begin(9600);
  // set the data rate for the NewSoftSerial port
  mySerial.begin(9600);
  //all digits off
  mySerial.print("xxxx");
  //activate colon
  mySerial.print(0x77, BYTE);
  mySerial.print(0x10, BYTE);
  //reset display
  mySerial.print(0x76, BYTE);
}

void loop() {
  seconds++;
  if(seconds > 9) {
    seconds = 0;
    deciseconds++;
  }
  if(deciseconds > 5) {
    deciseconds = 0;
    minutes++;
  }
  if(minutes > 9) {
    minutes = 0;
    deciminutes++;
  }
  if(deciminutes > 9) {
    deciminutes = 0;
    mySerial.print("xxxx");
  }
  if(deciminutes > 0) {
    mySerial.print(deciminutes);
    mySerial.print(minutes);
    mySerial.print(deciseconds);
    mySerial.print(seconds);
  } else {
    mySerial.print("x");
    if(minutes > 0) {
      mySerial.print(minutes);
      mySerial.print(deciseconds);
      mySerial.print(seconds);
    } else {
      mySerial.print("x");
      if(deciseconds > 0) {
        mySerial.print(deciseconds);
        mySerial.print(seconds);
      } else {
        mySerial.print("x");
        mySerial.print(seconds);
      }
    }
  }
  delay(1000); 
}
Here is a small demonstration. You could also use the module as a timer, a counter or simply a digital clock.

video

Tuesday, January 18, 2011

Waving Display with Arduino

When I first got my SunSPOT kit two years ago, the first example I ran on it was a demo called AirText. The SPOTs have 8 LEDs aligned in a row on-board. What the example did was to light up the on-board LEDs at a certain frequency. You have to imagine that a character consists of several columns. When displaying one column after another you get the whole character. For example for an 'H' you would set all LEDs of the column to high. Afterwards you would set all LEDs to low except for the middle one. Then again you would set all LEDs to high.

I build a small array of 5 red LEDs and hooked them up to the Arduino board. If I start the program with the board just lying on the table, you would see some flashing LEDs. Nothing fancy so far. But if I pick up the board and wave it continously from left to right at a certain frequency, you can see each column of a character after another "written" into the air, which forms the whole character.

The setup is pretty easy. Here is a simplified schematic:

The source code is easy as well. You can extend it to write new characters. You might need to enhance the LED array or the column count if you want to display special characters, as I only worked with a 3x5 display.

int top = 8;
int topmiddle = 9;
int middle = 10;
int bottommiddle = 11;
int bottom = 12;
int characterDelay = 500;
int columnDelay = 15;

void setup() {
}

void loop() {
  displayH();
  allOff();
  displayE();
  allOff();
  displayL();
  allOff();
  displayL();
  allOff();
  displayO();
  allOff();
}

//I found that by displaying the columns from left to right
//and then again from right to left gives a better result.
void displayH() {
    //set left column all high
    digitalWrite(top, HIGH);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(middle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    digitalWrite(bottom, HIGH);
    delay(columnDelay);
    //set all low except middle
    digitalWrite(top, LOW);
    digitalWrite(topmiddle, LOW);
    digitalWrite(bottommiddle, LOW);
    digitalWrite(bottom, LOW);
    delay(columnDelay);
    //set right column all high (middle is still high)
    digitalWrite(top, HIGH);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    digitalWrite(bottom, HIGH);
    delay(columnDelay);
    //second delay so that right column is still high
    delay(columnDelay);
    //set all low except middle
    digitalWrite(top, LOW);
    digitalWrite(topmiddle, LOW);
    digitalWrite(bottommiddle, LOW);
    digitalWrite(bottom, LOW);
    delay(columnDelay);
    //set right column all high (middle is still high)
    digitalWrite(top, HIGH);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    digitalWrite(bottom, HIGH);
    delay(columnDelay);
}

void displayE() {
    digitalWrite(top, HIGH);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(middle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    digitalWrite(bottom, HIGH);
    delay(columnDelay);
    digitalWrite(topmiddle, LOW);
    digitalWrite(bottommiddle, LOW);
    delay(columnDelay);
    delay(columnDelay);
    delay(columnDelay);
    delay(columnDelay);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    delay(columnDelay);
}

void displayL() {
  digitalWrite(top, HIGH);
  digitalWrite(topmiddle, HIGH);
  digitalWrite(middle, HIGH);
  digitalWrite(bottommiddle, HIGH);
  digitalWrite(bottom, HIGH);
  delay(columnDelay);
  digitalWrite(top, LOW);
  digitalWrite(topmiddle, LOW);
  digitalWrite(middle, LOW);
  digitalWrite(bottommiddle, LOW);
  delay(columnDelay);
  delay(columnDelay);
  delay(columnDelay);
  delay(columnDelay);
  digitalWrite(top, HIGH);
  digitalWrite(topmiddle, HIGH);
  digitalWrite(middle, HIGH);
  digitalWrite(bottommiddle, HIGH);
  delay(columnDelay);
}

void displayO() {
    digitalWrite(top, HIGH);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(middle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    digitalWrite(bottom, HIGH);
    delay(columnDelay);
    digitalWrite(topmiddle, LOW);
    digitalWrite(middle, LOW);
    digitalWrite(bottommiddle, LOW);
    delay(columnDelay);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(middle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    delay(columnDelay);
    delay(columnDelay);
    digitalWrite(topmiddle, LOW);
    digitalWrite(middle, LOW);
    digitalWrite(bottommiddle, LOW);
    delay(columnDelay);
    digitalWrite(topmiddle, HIGH);
    digitalWrite(middle, HIGH);
    digitalWrite(bottommiddle, HIGH);
    delay(columnDelay);
}

//set all LEDs off in between characters and provide a bigger delay
void allOff() {
  digitalWrite(top, LOW);
  digitalWrite(topmiddle, LOW);
  digitalWrite(middle, LOW);
  digitalWrite(bottommiddle, LOW);
  digitalWrite(bottom, LOW);
  delay(characterDelay);
}
 
In the video you can see me waving the breadboard continously from left to right varying my waving frequency until you can see the letters a little bit better. I think the result right at the end is the best one.

video

Monday, January 17, 2011

Shell Game Arduino

Since I have no new sensors left to connect to the Arduino for now, I thought about various small experiments I could do with the components I have. One of those experiments is a Shell Game.

You know those shady guys on the street that bet, you can't spot under which cup they put a ball while shuffling them? Well, this is called a shell game, because in the past it was played with walnut shells. Unfortunately those games are fraud and after someone else wins (another con man), you are up to a big loss.

In this experiment you can build your own shell game. Its intended to be used as an eye training and not to rip off your friends. So don't do anything evil with it.

At each round three LEDs are turned on at random for a very short amount of time. At the end you can guess which light flashed last. If you press the correct button, a green LED blinks. If you were wrong, a red LED blinks.

The setup is simple. Here is a schematic on how to connect everything to the Arduino Uno. Note that I left out the resistors in front of each LED so that the image doesn't get too crowded. I used 470Ω resistors. You need the resistors so that the LEDs don't get damaged by too much current.

The source code is pretty simple. You can change the On/Off delays for the LEDs to adjust the difficulty.
int leftLED = 2;
int middleLED = 3;
int rightLED = 4;
int upperLED = 5;
int lowerLED = 6;
int leftButton = 7;
int middleButton = 8;
int rightButton = 9;
int randomLED;
int lastLED;
int answerLED;
int analogReadSum;
boolean answerGiven = false;

void setup() {
  digitalWrite(leftButton, HIGH);
  digitalWrite(middleButton, HIGH);
  digitalWrite(rightButton, HIGH);
}

void loop() {
  answerGiven = false;
  //All analog ports are read, summed up and devided by their count.
  //There are fluctuations on the ports, so we should get a new number in each run.
  for(int x = 0; x < 6; x++) {
    analogReadSum += analogRead(x);
  }
  analogReadSum /= 6;
  //Initialize random sequence by unique number
  randomSeed(analogReadSum);
  analogReadSum = 0;
  for(int x = 0; x < 10; x++) {
    randomLED = random(2,5);
    digitalWrite(randomLED, HIGH);
    delay(15);
    digitalWrite(randomLED, LOW);
    delay(10);
    if(x == 9) {
      lastLED = randomLED;
    }
  }
  while(answerGiven == false) {
    if(digitalRead(leftButton) == LOW) {
      answerLED = 2;
      answerGiven = true;
    } else if(digitalRead(middleButton) == LOW) {
      answerLED = 3;
      answerGiven = true;
    } else if(digitalRead(rightButton) == LOW) {
      answerLED = 4;
      answerGiven = true;
    }
  }
  if(answerLED == lastLED) {
    for(int x = 0; x < 3; x++) {
      digitalWrite(upperLED, HIGH);
      delay(1000);
      digitalWrite(upperLED, LOW);
      delay(500);
    }
  } else {
    for(int x = 0; x < 3; x++) {
      digitalWrite(lowerLED, HIGH);
      delay(1000);
      digitalWrite(lowerLED, LOW);
      delay(500);
    }
  }
}
Here is a small clip of the game:

video

Friday, January 14, 2011

LAN Webserver with Arduino

Just to make things complete, I wanted to show you the alternative to the WiFly shield, the Ethernet shield. It is a heck of a lot easier to work with. There are already some example ethernet sketches available in the Arduino IDE and the board comes preassembled, so you really only have to stack it on top of your Arduino, connect it to your network and define some settings in the code. You could even log some data with the onboard micro SD card slot.

Here is a sample image of the Webserver in action.



The code is pretty much the same as in the example which is provided by the IDE and only differs from my WiFly example in the setup part. You only have to define your network settings accordingly.

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte ip[] = { 127, 0, 0, 1 };

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
Server server(80);

void setup()
{
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          // print something, in HTML format:
          client.print("LAN Webserver Running!");
          client.println("<br />");
          client.print("Visit ");
          client.print("<a href=\"http://marioboehmer.blogspot.com\">marioboehmer.blogspot.com</a>");
          client.print(" for more experiments!");
          client.println("<br />"); 
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

WiFi Webserver with Arduino

Today I want to show you, how to use your Arduino as a webserver or how to transmit data wirelessly. I used the WiFly shield from sparkfun. The only thing I had to do was to solder on some connector pins, so I could stack the module on the Arduino. The module itself works out of the box. You only need some configurations for your network connection. The first thing to do is to connect the board with your Arduino and run a first example sketch to see if works properly. You can find an excellent tutorial for some basic first steps here.

After uploading the first example sketch to the Arduino, open the Serial Monitor and explore some of the commands from the datasheet. One of the most important things you might want to know is the MAC address of your WiFly module. After you switched to the command mode, just enter "get mac". Now you can configure your router to assign a DHCP address for example. For details about all the commands and how the module works look into the datasheet.

One thing to remember is to introduce the module to your network at startup time. So in your setup method you have to send all the necessary information like passphrase, listenport and stuff like that to your module. To communicate easily with the module, I used a high level WiFly Shield library found here.

Source (just insert your configurations where marked with <insert> :
#include "WiFly.h"

Server server(80);

void setup() {
  Serial.begin(9600);
  SpiSerial.begin();
 
  //exit CMD mode if not already done
  SpiSerial.println("");
  SpiSerial.println("exit");
  delay(1000);
 
  //set into CMD mode
  SpiSerial.print("$$$");
  delay(1000);

  //set authorization level
  SpiSerial.println("set w a <insert>");
  delay(1000);

  //set passphrase
  SpiSerial.println("set w p <insert>");
  delay(1000);
 
  //set localport
  SpiSerial.println("set i l 80");
  delay(1000);
 
  //disable *HELLO* default message on connect
  SpiSerial.println("set comm remote 0");
  delay(1000);

  //join wifi network <ssid>
  SpiSerial.println("join <insert>"); 
  delay(5000);
 
  //exit CMD mode
  SpiSerial.println("exit"); 
  delay(1000);  
}


void loop() {
  listenForClients();
}

void listenForClients() {
  // listen for incoming clients
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          // print something, in HTML format:
          client.print("WiFly Webserver Running!");
          client.println("<br />");
          client.print("Visit ");
          client.print("<a href=\"http://marioboehmer.blogspot.com\">marioboehmer.blogspot.com</a>");
          client.print(" for more experiments!");
          client.println("<br />"); 
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}
You can see in the video that the WiFly board is blinking when I send a request to its address.

video

Thursday, January 13, 2011

Motion Sensor on Arduino

I already showed you the example of connecting a radar sensor to the Arduino. While radar sensors are very good at detecting frontal motion, they have their weaknesses when it comes to detecting motion in a wider angle. They are triggered by any object which reflects their radar waves.
For bypassing motion you normally use a passive infrared motion sensor (PIR). They aren't that great when it comes to detecting frontal motion, but they are sensitive to motion in a wider angle. They are called passive infrared motion sensors, because they detect infrared radiation which is emitted by every living person. The hotter your body temperature, the more you emit.

I used the ePIR sensor board from Zilog. You can configure the sensors sensitivity, you can set it to sleep to preserve energy and you can couple it with a light sensor so it won't be triggered at day time. For details on how to configure it, have a look into the datasheet. I used a simple default connection and didn't want to configure anything.

Here is a default setup:



The source code is also pretty simple:
int sleepModePin = 4;
int motionDetectPin = 2;
int alarmLED = 12;
int val;

void setup() {
  //the sleep pin has to be active high to enable detection
  digitalWrite(sleepModePin, HIGH);
}

void loop() {
  val = digitalRead(motionDetectPin);
  //the ePIR sensor is active low so if motion is detected the output is low
  if(val == LOW) {
    digitalWrite(alarmLED, HIGH);
  } else {
    digitalWrite(alarmLED, LOW);
  }
}
Motion sensor in action:

video

Microphone on Arduino

Today I connected a microphone mini board from sparkfun to the Arduino. After soldering on some connector pins you have three connections. Vcc, which works from 2.7V up to 5.5V, GND and the Signal pin. I used 5V for Vcc. I used an additional 4.7kΩ resistor to pull up the ADC value read from the analog port of the Arduino. You might not need it though. As an indicator for signal strength / loudness, I used three LEDs which were triggered if a certain threshold is passed. So it is kind of an equalizer.

Here is the basic setup:


The code is pretty easy. The only thing you might change are the threshold values, because your background noise might differ.
int audioPort = 0;
int val;
int greenLed = 7;
int yellowLed = 4;
int redLed = 2;
int lowThreshold = 780;
int mediumThreshold = 890;
int highThreshold = 1000;

void setup() {
  pinMode(greenLed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(redLed, OUTPUT); 
}

void loop() {
  val = analogRead(audioPort);
  if(val > highThreshold) {
    digitalWrite(redLed, HIGH);
    delay(10);             
    digitalWrite(redLed, LOW);
  } else if(val > mediumThreshold) {
    digitalWrite(yellowLed, HIGH);
    delay(10);             
    digitalWrite(yellowLed, LOW);
  } else if(val > lowThreshold) {
    digitalWrite(greenLed, HIGH);
    delay(10);             
    digitalWrite(greenLed, LOW);
  }
}
I wanted to use one of my favorite songs to demonstrate this experiment, but since I don't want to get into any trouble with the RIAA or the GEMA, I used a recording of me playing my dobro.

video

Wednesday, January 12, 2011

Temperature and Humidity Sensor on Arduino

I already posted about connecting a temperature sensor to the Arduino, but I wanted to use the opportunity to introduce a small combo board. The SHT15 mini board from sparkfun. They made a convenient mini board to easily access the SHT15 sensor from sensirion, which is well documented. After soldering on a connector for the breadboard, I found a blog post which provided a good working source code to access the data. I changed it only slightly because it already provided the access methods to get the data from the sensor.

The setup is trivial but here it is anyway:



All of the credits for the source go to Maurice Ribble:
int gTempCmd  = 0b00000011;
int gHumidCmd = 0b00000101;
int theDataPin  = 10;
int theClockPin = 11;
int temperatureVal;
int currentTemperatureInF;
int currentTemperatureInC;
int humidityVal;
int currentHumidityInPercent;
int ack;
 
int shiftIn(int dataPin, int clockPin, int numBits)
{
   int ret = 0;
   int i;

   for (i=0; i<numBits; ++i)
   {
      digitalWrite(clockPin, HIGH);
      delay(10);  // I don't know why I need this, but without it I don't get my 8 lsb of temp
      ret = ret*2 + digitalRead(dataPin);
      digitalWrite(clockPin, LOW);
   }

   return(ret);
}

void sendCommandSHT(int command, int dataPin, int clockPin)
{
  // Transmission Start
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, LOW);
          
  // The command (3 msb are address and must be 000, and last 5 bits are command)
  shiftOut(dataPin, clockPin, MSBFIRST, command);

  // Verify we get the correct ack
  digitalWrite(clockPin, HIGH);
  pinMode(dataPin, INPUT);
  ack = digitalRead(dataPin);
  if (ack != LOW)
    Serial.println("Ack Error 0");
  digitalWrite(clockPin, LOW);
  ack = digitalRead(dataPin);
  if (ack != HIGH)
     Serial.println("Ack Error 1");
}

void waitForResultSHT(int dataPin)
{
  int i;
 
  pinMode(dataPin, INPUT);
 
  for(i= 0; i < 100; ++i)
  {
    delay(10);
    ack = digitalRead(dataPin);

    if (ack == LOW)
      break;
  }
 
  if (ack == HIGH)
    Serial.println("Ack Error 2");
}

int getData16SHT(int dataPin, int clockPin)
{
  int val;
 
  // Get the most significant bits
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
  val = shiftIn(dataPin, clockPin, 8);
  val *= 256;

  // Send the required ack
  pinMode(dataPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);
          
  // Get the least significant bits
  pinMode(dataPin, INPUT);
  val |= shiftIn(dataPin, clockPin, 8);

  return val;
}

void skipCrcSHT(int dataPin, int clockPin)
{
  // Skip acknowledge to end trans (no CRC)
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);
}

void setup()
{
   Serial.begin(9600); // open serial
}

void loop()
{
  sendCommandSHT(gTempCmd, theDataPin, theClockPin);
  waitForResultSHT(theDataPin);
  temperatureVal = getData16SHT(theDataPin, theClockPin);
  skipCrcSHT(theDataPin, theClockPin);
  Serial.print("Temperature in F:");
  currentTemperatureInF = -40.2 + 0.018 * (float)temperatureVal;
  Serial.println(currentTemperatureInF, DEC);
  Serial.print("Temperature in C:");
  currentTemperatureInC = -40.1 + 0.01 * (float)temperatureVal;
  Serial.println(currentTemperatureInC, DEC); 
 
  sendCommandSHT(gHumidCmd, theDataPin, theClockPin);
  waitForResultSHT(theDataPin);
  humidityVal = getData16SHT(theDataPin, theClockPin);
  skipCrcSHT(theDataPin, theClockPin);
  Serial.print("Humidity in percent:");
  currentHumidityInPercent = -4.0 + 0.0405 * humidityVal + -0.0000028 * humidityVal * humidityVal;
  Serial.println(currentHumidityInPercent, DEC);
  Serial.println("");
}
Here is a small demonstration:

video