Arduino, BOE Shield, PING, and a servo

The video above is in two parts: first with a crawler kit and then with wheels. Switching back to wheels required a code modification to change the time it takes to turn. 
All the parts in the video were released for the original STAMP/Propeller chips, but the code below will get you off and running on the Arduino shield. Only digital pins 10, 11, 12, and 13 are used, so any shield that does not require those pins is available for use. 
// BOE Shield code from "Robotics with the BOE Bot"
// Roaming With Whiskers source, modified to use a PING)))
// sensor on the PING))) servo bracket.
// Using code from the Ping))) example sketch.
#include <Servo.h>                           // Include servo library
Servo servoLeft;                             // Declare left, right and Ping))) servos
Servo servoRight;
Servo PingServo;
int minSafeDist = 11 ;                        // Minimum distance in inches
int pingPin = 10;                             // PING input on 10 so the last servo port is used.
int centerDist, leftDist, rightDist;          // Define distance variables
long duration, inches, cm;                    // Define variables for Ping)))
void setup()                                 // Built-in initialization block
  tone(4, 3000, 1000);                       // Play tone for 1 second
  delay(1000);                               // Delay to finish tone
  servoLeft.attach(13);                      // Attach left signal to pin 13 
  servoRight.attach(12);                     // Attach right signal to pin 12
  PingServo.attach(11);
}  
void loop(){
  LookAhead();
  if(inches >= minSafeDist) /* If the inches in front of an object is greater than or equal to the minimum safe distance (11 inches), react*/
  {
    forward (121); //Go Forward
    delay(110); // Wait 0.11 seconds
  }
  else // If not:
  {
    servoLeft.writeMicroseconds(1500);
    servoRight.writeMicroseconds(1500);
    LookAround(); // Check your surroundings for best route
    if(rightDist > leftDist) // If the right distance is greater than the left distance , turn right
    {
      turnRight (250); // Turn Right      
    }
    else if (leftDist > rightDist) // If the left distance is greater than the right distance , turn left
    {
      turnLeft (250); // Turn Left
    }
    else
    {
      backward (250); // Go Backward
    }
    delay (250);
  }
}
void forward(int time)                       // Forward function
{
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
}
void turnLeft(int time)                      // Left turn function
{
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
}
void turnRight(int time)                     // Right turn function
{
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
}
void backward(int time)                      // Backward function
{
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
}
unsigned long ping() {
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW); //Send a low pulse
  delayMicroseconds(2); // wait for two microseconds
  digitalWrite(pingPin, HIGH); // Send a high pulse
  delayMicroseconds(5); // wait for 5 micro seconds
  digitalWrite(pingPin, LOW); // send a low pulse
  pinMode(pingPin,INPUT); // switch the Pingpin to input
  duration = pulseIn(pingPin, HIGH); //listen for echo
  /*Convert micro seconds to Inches
   -------------------------------------*/
  cm = microsecondsToCentimeters(duration);
  inches = microsecondsToInches(duration);
}
long microsecondsToInches(long microseconds) // converts time to a distance
{
  return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds) // converts time to a distance
{
  return microseconds / 29 / 2;
}
void LookAhead() {
  PingServo.write(90);// angle to look forward
  delay(175); // wait 0.175 seconds
  ping();
}
void LookAround(){
  PingServo.write(20); // 20° angle
  delay(320); // wait 0.32 seconds
  ping();
  rightDist = inches; //get the right distance
  PingServo.write(160); // look to the other side
  delay(620); // wait 0.62 seconds
  ping(); 
  leftDist = inches; // get the left distance
  PingServo.write(90); // 90° angle
  delay(275); // wait 0.275 seconds
}

 

Parallax BOE Shield for Arduino: First Look

I'm a big fan of Parallax and adafruit industries, so was glad to learn that they are now stocking the Parallax BOE Shield for Arduino. I already owned this kit but have yet to have time to play with it. The video above is an unboxing of the BOE Shield, PING))) sensor mounting bracket, and crawler kit. 
The original Parallax BOE-Bot uses Propeller controller and is very good for learning robotics in that environment. The lessons, documentation, and examples are quite detailed. With a focus on education, Parallax wisely decided to expand this platform into Arduino territory. The only "required" pins for the shield are two of 10, 11, 12, and 13. You can choose which two in your Arduino code. The rest can be used with your normal stackable Arduino shields.
To get a general idea of the BOE Shield and completed robot in action, take a look at adafruit's new product announcement.
Here's a photo of the crawler kit sitting on an original BOE bot (borrowed from Parallax's site) that I intend to use with the BOE Shield.
I'll be posting all my source code and a bunch of pictures or videos, but it will all pale in comparison to the online book from Parallax.
Stay tuned for more!

 

R2-D2 Laser Robot for Cats

This is an expanded modification for the Laser ToyBot for Cats to fit into an R2-D2 toy. The entire project can be built with significantly less work without using the R2-D2, but the astromech droid had a lot more flair. First: How to make it work from scratch:

The first revision was just an Ardweeny on a proto board with some hot-glue attaching the continuous rotation servo horn to a project box. It spins in horizontal circles, randomly changing directions while also randomly changing vertical angle. The vertical servo must be "tuned" so it is consistently pointing toward the ground unless you enjoy having your cats climb the walls. 

Simple parts:

  1. Ardweeny (Maker Shed)
  2. Adafruit 1/2 Size Perma-Proto Board (adafruit)
  3. Micro Servo and perhaps some 10uF capacitors to clean up the noise (adafruit)
  4. Sparkfun TTL Laser and 10k resistor (Sparkfun) 
  5. Continuous Rotation Servo (adafruit)
  6. 3xAAA battery holder (adafruit)

Advanced/Optional parts:

  1. RobotShop pan kit for either Futaba or Hitec servos. I went with the Hitec version and modified a Hitec HS-422 servo for continuous rotation. Futaba continuous rotation servos are more widely available without modification, but the Futaba pan kit is more expensive. The servo I linked above is a Futaba servo.
  2. R2-D2 model. I used a Diamond Select bank I found on Amazon but can't find it anymore.
  3. Shape Lock molding plastic. (Maker Shed)
  4. On-Off button and LED. This beauty from adafruit does both

Simple assembly:

In my non-Droid version, I simply sandwiched the servos between the proto board and the battery holder then used hot glue to affix the continuous rotation servo to a project enclosure. It worked fine, but was not sturdy. The switch to the Perma-Proto board was ideal as shown here:

Pin assignment:

  • Vertical (standard) servo: 10
  • Horizontal (continuous rotation) servo: 9
  • Laser diode: 8  (The diode is TTL controlled and uses a 10k resistor to ground)
  • Power LED: 7

That's all that is needed to get a basic laser toy running. Fitting it into the R2-D2 robot was a bit more challenging. I needed to find a way to allow the entire R2-D2 head to spin freely without tangling wires and I didn't have a slip ring (but adafruit does now) so I decided to make the entire electronic device rotate. Finding the DDP155 Pan System from RobotShop and mounting it upside down solved that for me. I screwed in a few risers to the rotating plate to lift it higher into the droid model. 

 

When working with ShapeLock, be aware that the hot plastic will bond to other plastics. To get a very close form, insulate other plastic areas with aluminum foil until the cooling completes. ShapeLock can be cut with a Dremel rotary tool with a plastic or wood cutting bit at 5-8k RPM. Going over 10k causes the plastic to melt. USE SAFETY GLASSES when using a rotary tool. Little bits of white plastic in the eye are not fun.

The most difficult part of the R2-D2 enclosure was the centering and balancing of the head on the RobotShop pan kit. This took several tries. Thankfully ShapeLock can simply be melted down and re-molded. 

That's it for the construction. The rest is just source code. Enjoy!

 

/* Arduino laser cat toy
 
 2012 Daniel Gentleman
 thoughtfix.com
 Creative Commons Attribution license
 
 Laser diode attached to a standard servo for vertical movement
 Continuous rotation servo for horizontal spinning
 Power LED (optional) 
 
 */
#include <Servo.h> 
Servo myservoh;  // Horizontal servo - continuous rotation
Servo myservov; // Vertical servo - standard 
unsigned int duration = 0;
int lasttime1 = 0;
int lasttime2 = 0;
int randstart = 0;
int randend = 0;
int pos = 0;
int laser = 8; // TTL laser diode on pin 8
int vpos = 80; 
int powerLed = 7; // Power LED on pin 7
void setup()
{
  myservoh.attach(9); // Continuous rotation servo on pin 9
  myservov.attach(10); // Standard servo on pin 8
  pinMode(laser, OUTPUT);
  pinMode(powerLed, OUTPUT);
  digitalWrite(laser, LOW);  // Turn ON the laser 
  digitalWrite(powerLed, HIGH); // Turn ON the power LED
}
void loop()
{
  int vaxis = random(50,120); // Range of vertical movement (50-120 here)
  myservov.write(vaxis);
  lasttime1 = millis();
  randstart =  random(200, 19990); // Tune these for your preferred random behavior
  randend =  random(2000, 2400);
  while(pos <= randend) // Random horizontal spinning 
  {
    pos += 1;
    myservoh.writeMicroseconds(pos); 
    delay(1);
  }
  vaxis = random(70,100);
  myservov.write(vaxis); // Random vertical movement
  duration = millis() - lasttime1;
  lasttime2 = millis();
  while(pos >= randstart)
  {
    pos-=1;
    myservoh.write(pos);
    delay(1);
  }
  vaxis = random(70,100);
  delay(500);
  duration = millis() - lasttime2;
  duration = millis() - lasttime1;
}  

 

Sparkfun RGB LED and RGB Light Sensor

I can't quite figure this one out: it's VERY delicate and I can't get consistant color results with the built-on LED on or off. I know if it gets a UV light, it shows a lot of purple and if it gets hit with a red laser it maxes out the red LED. Anyhow... Video and code! 

 

 

/*
Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sending
PWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012
Inherited OSHW license.
Original comments below.
*/
/*
An Arduino code example for interfacing with the 
HDJD-S822-QR999 Color Sensor.  Put an object in front of the
sensor and look at the serial monitor to see the values the sensor
is reading.  Scaling factors and gains may have to be adjusted
for your application.
by: Jordan McConnell
 SparkFun Electronics
 created on: 1/24/12
 license: OSHW 1.0, http://freedomdefined.org/OSHW
 
Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).
Connect the led pin to digital 13.
Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.
*/
// Define pins
const int ledpin = 13;
const int GSR1 = 12;
const int GSR0 = 11;
const int GSG1 = 10;
const int GSG0 = 9;
const int GSB1 = 8;
const int GSB0 = 7;
const int redLed = 3;
const int greenLed = 5;
const int blueLed = 6;
int redpin = A0;
int greenpin = A1;
int bluepin = A2;
// Sensor read values
int red = 0;
int green = 0;
int blue = 0;
int redBright = 0;
int greenBright = 0;
int blueBright = 0;
void setup() 
{
  Serial.begin(9600);
  pinMode(ledpin, OUTPUT);
  pinMode(GSR1, OUTPUT);
  pinMode(GSR0, OUTPUT);
  pinMode(GSG1, OUTPUT);
  pinMode(GSG0, OUTPUT);
  pinMode(GSB1, OUTPUT);
  pinMode(GSB0, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  // Turn on the LED
  digitalWrite(ledpin, LOW);
  
  // Set the gain of each sensor
  digitalWrite(GSR1, LOW);
  digitalWrite(GSR0, LOW);
  digitalWrite(GSG1, LOW);
  digitalWrite(GSG0, LOW);
  digitalWrite(GSB1, LOW);
  digitalWrite(GSB0, LOW);
}
void loop() 
{
  
  // Read sensors
  // On page 7 of the datasheet, there is a graph of the 
  // spectral responsivity of the chip.  Scaling factors were
  // selected based on this graph so that the gain of each 
  // color is closer to being equal
  red = analogRead(redpin) * 10;
  green = analogRead(greenpin) * 14;
  blue = analogRead(bluepin) * 17;
  redBright = red/10;
  greenBright = green/10;
  blueBright = blue/10;
  // Print values to the serial monitor
  Serial.print("Red: ");
  Serial.print(red, DEC);
  analogWrite(redLed, redBright);
  Serial.print("\t\tGreen: ");
  Serial.print(green, DEC);
  analogWrite(greenLed, greenBright);
  Serial.print("\tBlue: ");
  Serial.println(blue, DEC);
  analogWrite(blueLed, blueBright);
  delay(20);
}
/*Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sendingPWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012Inherited OSHW license.Original comments below.*/
/*An Arduino code example for interfacing with the HDJD-S822-QR999 Color Sensor.  Put an object in front of thesensor and look at the serial monitor to see the values the sensoris reading.  Scaling factors and gains may have to be adjustedfor your application.
by: Jordan McConnell SparkFun Electronics created on: 1/24/12 license: OSHW 1.0, http://freedomdefined.org/OSHW Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).Connect the led pin to digital 13.Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.*/

// Define pinsconst int ledpin = 13;const int GSR1 = 12;const int GSR0 = 11;const int GSG1 = 10;const int GSG0 = 9;const int GSB1 = 8;const int GSB0 = 7;const int redLed = 3;const int greenLed = 5;const int blueLed = 6;
int redpin = A0;int greenpin = A1;int bluepin = A2;
// Sensor read valuesint red = 0;int green = 0;int blue = 0;int redBright = 0;int greenBright = 0;int blueBright = 0;
void setup() {  Serial.begin(9600);
  pinMode(ledpin, OUTPUT);  pinMode(GSR1, OUTPUT);  pinMode(GSR0, OUTPUT);  pinMode(GSG1, OUTPUT);  pinMode(GSG0, OUTPUT);  pinMode(GSB1, OUTPUT);  pinMode(GSB0, OUTPUT);  pinMode(redLed, OUTPUT);  pinMode(greenLed, OUTPUT);  pinMode(blueLed, OUTPUT);
  // Turn on the LED  digitalWrite(ledpin, LOW);    // Set the gain of each sensor  digitalWrite(GSR1, LOW);  digitalWrite(GSR0, LOW);  digitalWrite(GSG1, LOW);  digitalWrite(GSG0, LOW);  digitalWrite(GSB1, LOW);  digitalWrite(GSB0, LOW);}
void loop() {    // Read sensors  // On page 7 of the datasheet, there is a graph of the   // spectral responsivity of the chip.  Scaling factors were  // selected based on this graph so that the gain of each   // color is closer to being equal  red = analogRead(redpin) * 10;  green = analogRead(greenpin) * 14;  blue = analogRead(bluepin) * 17;  redBright = red/10;  greenBright = green/10;  blueBright = blue/10;
  // Print values to the serial monitor  Serial.print("Red: ");  Serial.print(red, DEC);  analogWrite(redLed, redBright);  Serial.print("\t\tGreen: ");  Serial.print(green, DEC);  analogWrite(greenLed, greenBright);  Serial.print("\tBlue: ");  Serial.println(blue, DEC);  analogWrite(blueLed, blueBright);  delay(20);}

 

Laser ToyBot for Cats

This is a simple bot that really belongs installed in an R2-D2 toy. It's simply an Ardweeny on a breadboard, a set of AA batteries, a continuous rotation servo, a standard servo, and a laser. If there's a desire for source code, I'll post it here. However, it's simply a matter of random writes to both servos (after calibrating the vertical servo so it doesn't move more than 15 degrees.) 

 

2WD Roving Robot

This is a simple robot using an Adafruit Motor Shield, Arduino Uno, and two motors. The video shows off the sensors and arrangements. The source code is below:

/*
Autonomous roving robot
Parts: 
   -Arduino Uno
   -Parallax PING))) ultrasonic sensor
   -Adafruit motor shield http://www.ladyada.net/make/mshield/
   -2WD Mobile Platform http://www.makershed.com/ProductDetails.asp?ProductCode=MKSEEED7
   -Lever switch (for back bumper)
   -Indicator LED
   -Energizer XPAL XP8000 battery (custom cable and self-built regulator for motors)
Original motion functions and design from Robot Living 8/30/2010 
Code borrowed from example sketches:
   -Ping
Original code created June 2011
by Daniel Gentleman
thoughtfix@gmail.com
http://thoughtfix.com

Additional credits: 
Victor Brilon
Mark Balliet
luckylarry.co.uk for the math on the Sharp sensor
Advice from arduino.cc forum
Advice from from #arduino on irc.freenode.net
Advice from adafruit forums
Further inspiration
      -Adafruit Industries
      -Make Magazine
Adafruit Motor shield library

Wiring (remember, analog 0 is also digital 14) 
- Left motor to Motor 1
- Right motor to Motor 2
- LEDs on digital 15 and 16
- PING))) on digital 17
- Sharp IR sensors on digital 18 and 19
- Lever switch (bumper attached) on digital 14
- USB power (from a USB battery) to the Arduino
- Regulated power (I used an Energizer XPAL XP8000 regulated to +5v) for servos
*/


#include <AFMotor.h>

AF_DCMotor motorL(1, MOTOR12_1KHZ);
AF_DCMotor motorR(2, MOTOR12_1KHZ);


int BSensor = 14; //Back sensor
int FLEDPin = 15; //Forward LED
int BLEDPin = 16; //Backup LED
int pingPin = 17; //Front sensor
int FSensorR = 18; //Front right sensor
int FSensorL = 19;  //Front left sensor
int count = 0;
int b=0;
int bs=0;
int sensorValue;
int forwardSensor;
int sensorValueB=1;
int leftSensor=0;
int rightSensor=0;
int obstacle=0;


void setup() {
  Serial.begin(9600); 
  randomSeed(analogRead(0));
  pinMode(BLEDPin, OUTPUT); 
  pinMode(FLEDPin, OUTPUT);
  pinMode(BSensor, INPUT);
  pinMode(pingPin, INPUT);
  pinMode(FSensorR, INPUT);
  pinMode(FSensorL, INPUT);
  motorL.setSpeed(200);
  motorR.setSpeed(200);
  motorL.run(RELEASE);
  motorR.run(RELEASE);
}

void loop()
{
  uint8_t i;
  Forward();
}

void Forward () // Charge forth!
{
  digitalWrite(FLEDPin, HIGH);                
  digitalWrite(BLEDPin, LOW);
  ForwardSensor ();
  if (obstacle == 0){ //unless something is in the way
  Serial.println("Going forward.");
  motorL.run(FORWARD);
  motorR.run(FORWARD);
  }

}

void ForwardSensor ()
{
  leftSensor = (ForwardSensorLeft());
  rightSensor =(ForwardSensorRight());
  forwardSensor = (getDistance());
  delay(30);
  //  Serial.print(leftSensor);
  //  Serial.println(" left");
  //  Serial.print(rightSensor);
  //  Serial.println(" right");
  //  Serial.print(forwardSensor);
  //  Serial.println(" front");
  if (forwardSensor <=30 || leftSensor <= 30 || rightSensor <= 30 )
  { // I gave 10cm of "wiggle room" so it doesn't turn endlessly. 
    obstacle=1;
    if (ForwardSensorRight() > (ForwardSensorLeft()-10)){
      RightBackward();
    }
    else if (ForwardSensorRight() < (ForwardSensorLeft()-10)){
      LeftBackward();
    }
    else{
      Backward();
    }
  }
  else {
    obstacle = 0;
  }
  sensorValue=0;
  rightSensor=0;
  leftSensor=0;
}

int ForwardSensorRight () 
{ // This function is here so you don't have to re-write code
  // if you use a different sensor.
  sensorValue = irDistance(FSensorR); 
  return sensorValue;
}

int ForwardSensorLeft ()
{ // This function is here so you don't have to re-write code
  // if you use a different sensor.
  sensorValue = irDistance(FSensorL); 
  return sensorValue;
}

void BackwardSensor ()
{
  sensorValueB = digitalRead(BSensor); 
  if (sensorValueB == 1)
  {
    Serial.println("Object detected while going backwards.");
    motorL.run(RELEASE);
    motorR.run(RELEASE);
    for (bs=0; bs <= 3; bs++) // Add blinky lights for personality on detecting object when backing up.
    {
      digitalWrite(FLEDPin, HIGH);                
      digitalWrite(BLEDPin, HIGH);
      delay(5);
      digitalWrite(FLEDPin, LOW);                
      digitalWrite(BLEDPin, LOW);
      delay (5);
    }
    b=31;
    bs=0;
    Forward();

  }
  sensorValueB = 0;
}

void Backward ()
{
  motorL.run(RELEASE);
  motorR.run(RELEASE);
  digitalWrite(FLEDPin, LOW);                
  digitalWrite(BLEDPin, HIGH);
  Serial.println("Going backwards.");

  do
  {
    b++;
    motorL.run(BACKWARD);
    motorR.run(BACKWARD);
    delay(20);
    BackwardSensor ();
  } 
  while (b < 20);

  b=0;
}


void LeftBackward ()
{
  motorL.run(RELEASE);
  motorR.run(RELEASE);
  digitalWrite(FLEDPin, LOW);                
  digitalWrite(BLEDPin, HIGH);
  Serial.println("Going left backwards.");

  do
  {
    b++;
    //    Serial.print("b = ");
    //    Serial.print(b);
    motorL.run(BACKWARD);
    motorR.run(RELEASE);
    BackwardSensor ();
    delay (20);
  } 
  while (b < 20);

  b=0;
}

void RightBackward ()
{
  motorL.run(RELEASE);
  motorR.run(RELEASE);
  digitalWrite(FLEDPin, LOW);                
  digitalWrite(BLEDPin, HIGH);
  Serial.println("Going right backwards.");

  do
  {
    b++;
    //    Serial.print("b = ");
    //    Serial.print(b);
    motorL.run(RELEASE);
    motorR.run(BACKWARD);
    BackwardSensor ();
    delay (20);
  } 
  while (b < 20);

  b=0;
}

int getDistance()

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
reread:  // takes another reading if cm=0
  long duration, cm;
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  cm = microsecondsToCentimeters(duration);
  //  Serial.print(cm);
  //  Serial.print("cm");
  //  Serial.println();
  delay(100);
  //  if (cm == 0) {
  //    goto reread;
  //  }
  return cm;


long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return (microseconds/58);
}

int irDistance(int irPin) {
  float volts = analogRead(irPin)*0.0048828125;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
  int distance = 32.5*pow(volts, -1.10);          // theretical distance 32.5/ (1/Volts)S 
  //  Serial.print(distance);
  //  Serial.print(" from ");
  //  Serial.println(irPin);  
  delay (10);
  return distance;        // print the raw analog value to serial port
}

Arduino Haunted Pumpkin

For the Radio Shack Great Create, I crafted a motion-sensitive haunted pumpkin with pulsing red eyes. When motion was detected, it would blink wildly and issue a wicked laugh. The full how-to with pictures and video is posted on instructables.

Full source code:

 

/*
This is the source code for the motion sensitive
haunted pumpkin built for Radio Shack.
Original code by Daniel Gentleman, thoughtfix.com
*/

// Set up pin assignments
int leftEye = 3; // PWM pin 3
int rightEye = 5; // PWM pin 5
int redBlink1 = 9;
int redBlink2 = 10;
int whiteBlink = 13;
int laughBox = 12; // transistor to voice module
int pirSensor = 7; // passive infrared sensors
int pirState = 0; //Initial IR state

// Setting up pin modes
void setup() {
pinMode(leftEye, OUTPUT);
pinMode(rightEye, OUTPUT);
pinMode(redBlink1, OUTPUT);
pinMode(redBlink2, OUTPUT);
pinMode(whiteBlink, OUTPUT);
pinMode(laughBox, OUTPUT);
pinMode(pirSensor, INPUT);
}

void loop () {
// fade in from min to max in increments of 5 points:
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {
// sets the value (range from 0 to 255):
analogWrite(leftEye, fadeValue);
analogWrite(rightEye, fadeValue);
// wait for 30 milliseconds
delay(30);
}
pirState = digitalRead(pirSensor); // read the state of the pirsensor value:
if (pirState == HIGH){ // If motion is detected
freakout(); // Call the freakout routine
}

// fade out from max to min in increments of 5 points:
for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {
// sets the value (range from 0 to 255):
analogWrite(leftEye, fadeValue);
analogWrite(rightEye, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
pirState = digitalRead(pirSensor); // Same as above
if (pirState == HIGH){
freakout();
}

}

void freakout(){
digitalWrite(laughBox, HIGH); // Send intial ON for all pins
digitalWrite(leftEye, HIGH);
digitalWrite(rightEye, HIGH);
digitalWrite(redBlink1, HIGH);
digitalWrite(redBlink2, HIGH);
digitalWrite(whiteBlink, HIGH);
delay(250);
digitalWrite(laughBox, LOW); // turn off laugh button
for (int i=1; i<=40; i++){ // Start blinking mayhem
digitalWrite(leftEye, HIGH);
digitalWrite(rightEye, HIGH);
digitalWrite(redBlink1, LOW);
digitalWrite(redBlink2, LOW);
digitalWrite(whiteBlink, LOW);
delay(50);
digitalWrite(leftEye, LOW);
digitalWrite(rightEye, LOW);
digitalWrite(redBlink1, HIGH);
digitalWrite(redBlink2, HIGH);
digitalWrite(whiteBlink, HIGH);
delay(50);
} // Finish blinking mayhem, turn everything off
digitalWrite(redBlink1, LOW);
digitalWrite(redBlink2, LOW);
digitalWrite(whiteBlink, LOW);
}

Ethernet enabled server room thermometer

After my first "blinky" thermometer was taken down for looking "too unprofessional," I moved on to craft a more subtle (and functional) way to get the job done. This time,  with an Arduino Uno, an Ethernet Shield, and a DHT11 temperature sensor. The code is a combination of Ladyada's DHT code and the Arduino example Ethernet code with only tiny modifications. The enclosure was purchased at Jameco.

The result is monitored in Nagios and Cacti. If anyone builds one and needs help with Nagios/Cacti implementation, let me know.

The HTML output is intentionally boring so as to be easily readable by monitoring software:

TemperatureC: 28.00
TemperatureF: 82.40
Humidity: 53.00

Code:

/*
  Web  Server Thermometer

A simple web server that shows the value of a DHT11
using an Arduino Wiznet Ethernet shield. 

Circuit:
* DHT11 attached to pin 2
* Ethernet shield attached to pins 10, 11, 12, 13

Web server code: 
created 18 Dec 2009
by David A. Mellis
modified 4 Sep 2010
by Tom Igoe

DHT code written by ladyada
Public Domain

Combining the two by thoughtfix
July, 2011

*/

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

#define DHTTYPE DHT11   // DHT 11 
#define DHTPIN 2     // DHT pin

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4B, 0x21 };
byte ip[] = { 192,168,1, 223 };

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

void setup()
{
  // start the Ethernet connection and the server:

  Ethernet.begin(mac, ip);
  server.begin();
  dht.begin();
}


void loop()
{
  // listen for incoming clients
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = t*1.8+32; 
  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();

          // output the value of each analog input pin
          client.print("TemperatureC: "); 
          client.println(t);
          client.println("<br />");
          client.print("TemperatureF: "); 
          client.println(f);
          client.println("<br />");
          client.print("Humidity: "); 
          client.print(h);
          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();
  }
}

Arduino server room thermometer (Blinky)

This is the first generation of the project with only visual alerts. The second generation was Ethernet enabled.

At my last job, I rarely had to set foot in my server room. The air conditioning unit, however, sometimes falls behind in the summer. I wanted something that would grab the attention of people walking by if it were to go over 80F ambient temperature. Except for a little wiring, the parts list is 100% Adafruit stock:

 


That's $31.75 if you have an UNO handy, $30 more if you don't. 

To build the LCD shield: http://forums.adafruit.com/viewtopic.php?f=31&p=112887#p112887

A long section of ribbon cable (I used 7 wires - more than I need) to go around the door and a little wire, time, and solder to assemble the bits together are all that is left. I have the proto shield's LEDs on pins 12 and 13, the LCD shield exactly how I described it built in a previous thread, and the temperature sensor on (analog 0) pin 14. I have analog 1 and 2 going to the back breadboard too just in case I want to use them.

On the ribbon cable, I am using VIN to power the display. This way the power supply can sit inside the server room and won't be hanging off the wall in the "public area." The barrel jack was perfect for that. 

Make sure to get the required libraries for the temperature sensor and LCD from the product links above or it'll never compile. The code is ugly and poorly commented, but it does the job. I even got lazy and read the temperature through two different functions (one as a string, one as an int) because I hate converting back and forth. 

Code:

// Arduino "FREAK OUT OVER 80F" thermometer

#include <PCD8544.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "String.h"
#include "WProgram.h"



// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 14

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;
PCD8544 nokia = PCD8544(7, 6, 5, 4, 3);
char msg[125];
int flash = 0;
int currTemp;

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");
  // locate devices on the bus
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");
  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();
  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();
  nokia.init();
  nokia.command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYALLON);
  delay(500);
  // back to normal
  nokia.command(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);
  pinMode(13, OUTPUT); // Green  LED
  pinMode(12, OUTPUT); // Red LED 
  digitalWrite(12, HIGH);
}


void loop(void)

  nokia.clear();
  sensors.requestTemperatures(); // Send the command to get temperatures
  String msgHead = "The current   server room   temp is ";
  String termMessage = msgHead + fetchTemp(insideThermometer) + "F " + "\0";
  Serial.println(termMessage);
  int msglen = (termMessage.length()+1); // count the characters, add 3 just in case
  Serial.print(msglen);
  Serial.println(" - message length");
  termMessage.toCharArray(msg,msglen); // Convert it to an array called msg
  Serial.print("Attempted message ");
  Serial.println(msg); 
  nokia.drawstring(0, 0, msg);
  nokia.display();
  if (numTemp(insideThermometer) > 80){
    for (int flash = 1; flash < 10; flash++){
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    delay(60);
    digitalWrite(12, HIGH);
    digitalWrite(13, LOW);
    delay(60);
    }
  }
  else {
  delay(600);
  }
  nokia.clear();

}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

String fetchTemp(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  int tempF = DallasTemperature::toFahrenheit(tempC);
  String reportTemp = tempF;
  String reportText = reportTemp + "F";
  return reportTemp;
}

int numTemp(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  int tempF = DallasTemperature::toFahrenheit(tempC);
  return tempF;
}

DFRobotShop Rover example code

A lot of people who submitted to the Adafruit/Instructables "Make it Tweet" challenge also submitted to the RobotShop Microcontroller contest, so many of us got our 50% off coupon codes for a DFRobotShop Rover. I noticed that the documentation on this was a little lacking especially where code is concerned. Even the example code needed some upgrading. 

After poking and prodding around for a while, I think I figured out all the pins, the on-board light sensor, and the on-board temperature sensor. The sketch below turns every operation into a function so it can be called selectively by the user who needs it. I am posting this here in hopes that it helps others with their robot projects:

 

 

/* DFRobotShop Rover bare minimum

Left and right are determined as though driving a car
with the USB and power ports in the rear. If you want
to test code without driving it off your desk, simply
remove the tank treads! 

Board Type: Arduino Duemilanove ATMega328
Motor Drivers: L293B dual H bridge

Motors run at 4.5v nominal, but the whole board can
be powered from 3.78v to 9V. 


pin 5; //Right Speed Control (analogWrite 0-255)
pin 6; //Left Speed Control (analogWrite 0-255)
pin 7; //Right Direction Control  (HIGH=forward, LOW=back)
pin 8; //Left Direction Control (HIGH=forward, LOW=back)

Ambient Light pin on Analog 0
Thermal Sensor (LM35) on Analog 1

*/
int lightPin = A0;
int thermoPin = A1;
int rightMotorPin = 5;
int leftMotorPin = 6;
int rightDirectionPin = 7;
int leftDirectionPin = 8;
int leftspeed = 255; //255 is maximum speed
int rightspeed = 255;

void setup(){
  pinMode(lightPin, INPUT);
  pinMode(thermoPin, INPUT);
  pinMode(rightMotorPin, OUTPUT);
  pinMode(leftMotorPin, OUTPUT);
  pinMode(rightDirectionPin, OUTPUT);
  pinMode(leftDirectionPin, OUTPUT);
  Serial.begin(9600); // 
}

void loop(){
  // Everything in here is just an example of how to use the functions below.
  forward (leftspeed,rightspeed); //Go Forward
  delay(2500);
  left (leftspeed,rightspeed); // Turn Left
  delay(2500);
  reverse (leftspeed,rightspeed); // Go Backward
  delay(2500);
  right (leftspeed,rightspeed); // Turn Right
  delay(2500);
  stop(); // Full Stop
  delay(2500);
  float TempC = getTemp();
  Serial.print(TempC);
  Serial.println(" degrees C");
  delay(500);
  float light = getLight();
  Serial.print(light);
  Serial.println(" percent readable light"); 
  delay(500);

}

// Everything below this line can be deleted or you can re-use the code

void stop(void) //Stop
{
  digitalWrite(leftMotorPin,LOW);
  digitalWrite(rightMotorPin,LOW);
}

void forward(char a,char b)
{
  analogWrite (leftMotorPin,a);
  digitalWrite(leftDirectionPin,LOW);
  analogWrite (rightMotorPin,b);
  digitalWrite(rightDirectionPin,LOW);
}

void reverse (char a,char b)
{
  analogWrite (leftMotorPin,a);
  digitalWrite(leftDirectionPin,HIGH);
  analogWrite (rightMotorPin,b);
  digitalWrite(rightDirectionPin,HIGH);
}

void left (char a,char b)
{
  analogWrite (leftMotorPin,a);
  digitalWrite(leftDirectionPin,HIGH);
  analogWrite (rightMotorPin,b);
  digitalWrite(rightDirectionPin,LOW);
}

void right (char a,char b)
{
  analogWrite (leftMotorPin,a);
  digitalWrite(leftDirectionPin,LOW);
  analogWrite (rightMotorPin,b);
  digitalWrite(rightDirectionPin,HIGH);
}

float getTemp ()
{
  float sensorRead = analogRead(thermoPin); // Get reading
  float tempRead = (5.0 * sensorRead * 100.0)/1024.0; // 5V
  return tempRead;
}

float getLight()
{
  float lightRead = analogRead(lightPin);
  float lightPercent = map(lightRead, 1024, 0, 0, 100); // to percent of light reading
  return lightPercent;
}