<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Project Lab</title>
	<atom:link href="http://nootropicdesign.com/projectlab/feed/" rel="self" type="application/rss+xml" />
	<link>http://nootropicdesign.com/projectlab</link>
	<description></description>
	<lastBuildDate>Fri, 05 Mar 2010 03:50:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Wireless Robotics Platform: Cheap R/C Vehicle + Arduino + XBee + Processing</title>
		<link>http://nootropicdesign.com/projectlab/2010/03/04/wireless-robotics-platform/</link>
		<comments>http://nootropicdesign.com/projectlab/2010/03/04/wireless-robotics-platform/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 03:47:05 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[Robotics]]></category>
		<category><![CDATA[XBee]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=87</guid>
		<description><![CDATA[I built a wireless robotics platform from a cheap R/C car, an Arduino with XBee shield, small microswitch sensors, and a Processing program running on a remote computer to control the vehicle.  The vehicle is completely controlled by the code running on the remote computer which allows very rapid prototyping of the code to [...]]]></description>
			<content:encoded><![CDATA[<p>I built a wireless robotics platform from a cheap R/C car, an Arduino with XBee shield, small microswitch sensors, and a <a href="http://processing.org">Processing</a> program running on a remote computer to control the vehicle.  The vehicle is completely controlled by the code running on the remote computer which allows very rapid prototyping of the code to tell the vehicle what to do and how to react to the sensor events received from the vehicle.  I&#8217;m hoping this is a good way to teach my 9-year old son about programming.</p>
<div id="attachment_91" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverLeftFront1.jpg"><img class="size-full wp-image-91" title="roverLeftFront1_m" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverLeftFront1_m.jpg" alt="" width="640" height="480" /></a><p class="wp-caption-text">Wireless computer-controlled robotics platform built on cheap RC vehicle, Arduino microcontroller, and XBee radios</p></div>
<p>Before I get into details, here&#8217;s an overview of the features:</p>
<ul>
<li>All logic controlling the vehicle is performed in a Processing program running on remote computer.  The Arduino program listens for commands from the remote computer.</li>
<li>Bi-directional wireless communication over XBee radios with (theoretical) 1-mile range.  I&#8217;ve accomplished 1/4 mile range with these radios.</li>
<li>Sensor events are transmitted from the vehicle to the controlling computer.  This vehicle has 3 microswitches &#8211; two on front bumper and one at the rear.</li>
<li>Original circuitry of vehicle replaced with dual H-Bridge circuit to control drive motor and turn motor.  Drive motor is controlled with variable speed.</li>
<li>Power: Vehicle motors powered by 4 AA batteries.  Arduino with XBee shield powered by 9V battery mounted at front of vehicle.</li>
<li>Simple communications protocol: 2 byte commands from controller to vehicle, one byte sensor readings from vehicle to controller.</li>
</ul>
<p></p>
<h3>The Hardware</h3>
<p>There&#8217;s nothing special about the configuration of the XBee radios.  They are running the AT firmware (&#8220;transparent mode&#8221;) which allows them to simply exchange serial data.  The Libelium XBee shield on top of the Arduino makes it easy to read/write serial data from Arduino code.<br />
<div id="attachment_90" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverTopView.jpg"><img class="size-full wp-image-90" title="roverTopView_m" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverTopView_m.jpg" alt="" width="640" height="480" /></a><p class="wp-caption-text">Arduino and XBee shield on top of the vehicle</p></div></p>
<p></p>
<p>Inside the vehicle is a simple circuit board with an L293 quadruple half-H driver to drive the motors.  The drive motor and turn motor are connected.  I had to rip out the original circuit board (but I saved it!).<br />
<span id="more-87"></span><br />
<div id="attachment_102" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/motorController.jpg"><img class="size-full wp-image-102" title="motorController" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/motorController.jpg" alt="" width="640" height="480" /></a><p class="wp-caption-text">Small circuit board with dual H-Bridge chip connected to drive motor and turn motor</p></div></p>
<p></p>
<p>The controller computer connects to an XBee radio via a Sparkfun FTDI USB breakout board.  This is just a simple perf-board circuit connecting the USB interface to the XBee.  It&#8217;s as simple as connecting the RX/TX pairs together, and giving it power.<br />
<div id="attachment_100" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/transmitter.jpg"><img class="size-full wp-image-100" title="transmitter" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/transmitter.jpg" alt="" width="640" height="460" /></a><p class="wp-caption-text">Transmitter on controller computer.  FTDI USB board and XBee radio.</p></div></p>
<p></p>
<p>Here&#8217;s a view of a microswitch collision sensor on the back of the vehicle.   It&#8217;s mounted on a small piece of wood (yes, wood) glued to the chassis.<br />
<div id="attachment_86" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverRearSensor-e1263768084116.jpg"><img class="size-full wp-image-86" title="roverRearSensor" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/roverRearSensor-e1263768084116.jpg" alt="" width="640" height="480" /></a><p class="wp-caption-text">Rear collision sensor microswitch</p></div></p>
<p></p>
<h3>The Code</h3>
<p>This is a listing of the Arduino code.  It is fairly simple and self-explanatory because the Arduino just listens for commands and sends sensor readings.  A BEGIN_COMMAND delimiter indicates that the next two bytes are a command.  The first byte of a command is a bit pattern telling the Arduino whether to go forward, backward, turn left, or turn right.  There is one bit assigned to each of those 4 directions (4 bits are unused and reserved for future functions).  The second byte represents speed.  By using PWM on the H-bridge enable pin, the speed of the vehicle can be controlled.<br />
If a sensor switch is closed, then a byte with the appropriate bit is sent back to the controlling computer.  There is logic to debounce the switches.  Studying this code is left as an exercise for the reader.  Feel free to <a href="/projectlab/downloads/XBeeVehicleController.pde">download the Arduino sketch</a>.</p>
<pre class="codeblockscroll">

// Pin assignments
#define LEFT_PIN 13         // red/black
#define TURN_ENABLE_PIN 12  // white
#define DRIVE_ENABLE_PIN 11 // white/black
#define RIGHT_PIN 10        // red
#define BACKWARD_PIN 9      // yellow/black
#define FORWARD_PIN 8       // yellow

#define LEFT_FRONT_BUMPER_PIN 7     // white
#define RIGHT_FRONT_BUMPER_PIN 6    // yellow
#define REAR_BUMPER_PIN 5           // red

// Input Commands
#define BEGIN_COMMAND 0x7F
#define FORWARD 0x1
#define BACKWARD 0x2
#define LEFT 0x4
#define RIGHT 0x8

// Sensor Data
#define LEFT_FRONT_BUMPER 0x1
#define RIGHT_FRONT_BUMPER 0x2
#define REAR_BUMPER 0x4
#define DEBOUNCE_THRESHOLD 50

int sensorData = 0;
int lastSensorData = 0;
int lastLeftFrontBumperReading;
int lastRightFrontBumperReading;
int lastRearBumperReading;
int leftFrontBumperReadingTime;
int rightFrontBumperReadingTime;
int rearBumperReadingTime;
int command[2];

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

  pinMode(DRIVE_ENABLE_PIN, OUTPUT);
  pinMode(TURN_ENABLE_PIN, OUTPUT);
  pinMode(LEFT_PIN, OUTPUT);
  pinMode(RIGHT_PIN, OUTPUT);
  pinMode(BACKWARD_PIN, OUTPUT);
  pinMode(FORWARD_PIN, OUTPUT);

  pinMode(LEFT_FRONT_BUMPER_PIN, INPUT);
  digitalWrite(LEFT_FRONT_BUMPER_PIN, HIGH);
  pinMode(RIGHT_FRONT_BUMPER_PIN, INPUT);
  digitalWrite(RIGHT_FRONT_BUMPER_PIN, HIGH);
  pinMode(REAR_BUMPER_PIN, INPUT);
  digitalWrite(REAR_BUMPER_PIN, HIGH);

}

void loop() {

  // Read sensors and transmit
  readSensors();
  if (sensorData != lastSensorData) {
    Serial.write(sensorData);
    lastSensorData = sensorData;
  }

  // listen for wireless commands
  if (Serial.available() > 0) {
    if (readCommand() > 0) {
      executeCommand();
    }
  }
}

void readSensors() {
  int s;

  s = digitalRead(LEFT_FRONT_BUMPER_PIN);
  if (s != lastLeftFrontBumperReading) {
    leftFrontBumperReadingTime = millis();
  }
  if ((millis() - leftFrontBumperReadingTime) > DEBOUNCE_THRESHOLD) {
    if (s == LOW) {
      sensorData |= LEFT_FRONT_BUMPER;
    } else {
      sensorData &#038;= ~LEFT_FRONT_BUMPER;
    }
  }
  lastLeftFrontBumperReading = s;

  s = digitalRead(RIGHT_FRONT_BUMPER_PIN);
  if (s != lastRightFrontBumperReading) {
    rightFrontBumperReadingTime = millis();
  }
  if ((millis() - rightFrontBumperReadingTime) > DEBOUNCE_THRESHOLD) {
    if (s == LOW) {
      sensorData |= RIGHT_FRONT_BUMPER;
    } else {
      sensorData &#038;= ~RIGHT_FRONT_BUMPER;
    }
  }
  lastRightFrontBumperReading = s;

  s = digitalRead(REAR_BUMPER_PIN);
  if (s != lastRearBumperReading) {
    rearBumperReadingTime = millis();
  }
  if ((millis() - rearBumperReadingTime) > DEBOUNCE_THRESHOLD) {
    if (s == LOW) {
      sensorData |= REAR_BUMPER;
    } else {
      sensorData &#038;= ~REAR_BUMPER;
    }
  }
  lastRearBumperReading = s;
}

int readCommand() {
  int b = Serial.read();
  if (b == BEGIN_COMMAND) {
    command[0] = readByte();
    command[1] = readByte();
    return 1;
  } else {
    return 0;
  }
}

// blocking read
int readByte() {
  while (true) {
    if (Serial.available() > 0) {
      return Serial.read();
    }
  }
}

void executeCommand() {
  int c = command[0];
  int speed = command[1];

  digitalWrite(DRIVE_ENABLE_PIN, LOW);
  if (c &#038; FORWARD) {
    digitalWrite(BACKWARD_PIN, LOW);
    digitalWrite(FORWARD_PIN, HIGH);
  }
  if (c &#038; BACKWARD) {
    digitalWrite(FORWARD_PIN, LOW);
    digitalWrite(BACKWARD_PIN, HIGH);
  }
  if (c &#038; (FORWARD | BACKWARD)) {
    analogWrite(DRIVE_ENABLE_PIN, speed);
  }

  digitalWrite(TURN_ENABLE_PIN, LOW);
  if (c &#038; LEFT) {
    digitalWrite(RIGHT_PIN, LOW);
    digitalWrite(LEFT_PIN, HIGH);
  }
  if (c &#038; RIGHT) {
    digitalWrite(LEFT_PIN, LOW);
    digitalWrite(RIGHT_PIN, HIGH);
  }
  if (c &#038; (LEFT | RIGHT)) {
    digitalWrite(TURN_ENABLE_PIN, HIGH);
  }
}
</pre>
<p></p>
<p>Now let&#8217;s look at the <a href="http://processing.org">Processing</a> code that really controls the vehicle from afar.  I used Procesing because it&#8217;s easy for beginners, has an IDE that is familiar to Arduino coders, and hides a lot of complexity.  And I&#8217;ve been coding in Java since last century &#8212; Processing is just Java simplified, so it&#8217;s second-nature for me.</p>
<p>This Processing sketch doesn&#8217;t actually have a visual interface at all.  It just communicates with the transmitter via the USB serial interface.  Before I show the entire Processing sketch, I just want to show you the part of the code you write in the <span class="code">draw()</span> method that controls the vehicle.  The <span class="code">draw()</span> method is the same concept as the <span class="code">loop()</span> method in Arduino.  This is how you tell the vehicle what to do:</p>
<pre class="codeblock">
void draw() {

   ...

  speed = 9;  // set speed value.  Valid values are 0-9.
  forward(1000);  // go forward for 1000ms (one second)
  stop();
  right();  // turn wheels
  backward(500);  // backward for half a second
  left();
  speed = 5;
  backward(500);
  stop();
  forward(2000);
  //  you get the idea...

  straight();  // wheels straight
  end();  // end the program.  Without this, it repeats.
}
</pre>
<p>
What about sensor events that we receive from the vehicle?  We handle those by writing methods for each event.  These methods will be called as soon as the sensor reading is received.  The currently running program (like above) will be terminated immediately and the appropriate method below will run.  It looks like we&#8217;re only checking for collision events at the beginning of the <span class="code">draw()</span> method, but when an event happens, the program instructions stop and we come back to the beginning of the <span class="code">draw()</span> immediately so we can handle the event.  Here&#8217;s the full <span class="code">draw()</span> method and the event handling methods:</p>
<pre class="codeblock">
void draw() {

  if (rightFrontBumper) {
    println(timestamp() + " ----RIGHT FRONT IMPACT!----");
    rightFrontBumper();
  }
  if (leftFrontBumper) {
    println(timestamp() + " ----LEFT FRONT IMPACT!-----");
    leftFrontBumper();
  }
  if (rearBumper) {
    println(timestamp() + "-------REAR IMPACT!--------");
    rearBumper();
  }

  speed = 9;  // set speed value.  Valid values are 0-9.
  forward(1000);  // go forward for 1000ms (one second)
  stop();
  right();  // turn wheels
  backward(500);
  left();
  speed = 5;
  backward(500);
  stop();
  forward(2000);
  //  you get the idea...

  straight();  // wheels straight
  end();  // end the program.  Without this, it repeats.
}

void leftFrontBumper() {
  leftFrontBumper = false;
  running = true;
  left();
  speed = 9;
  backward(800);
  straight();
  end();
}

void rightFrontBumper() {
  rightFrontBumper = false;
  running = true;
  right();
  speed = 9;
  backward(800);
  straight();
  end();
}

void rearBumper() {
  rearBumper = false;
  running = true;
  right();
  speed = 9;
  forward(1000);
  straight();
  end();
}
</pre>
<p></p>
<p>You can start your program again by pressing the &#8217;s&#8217; key.  Also, after a program is done running, you can control the vehicle with the arrow keys.  For example, if you want to position the vehicle for another run.</p>
<p>The whole idea here is that this provides a platform for programming the vehicle to do whatever you wish, and dealing with collisions however you want.  There&#8217;s a lot of potential here for more sensors and more commands to the vehicle (How about a robotic arm?  Infrared sensors?).</p>
<p>There&#8217;s a lot more code in the Processing sketch that handles the communication, etc.  Here is an entire listing with simple code for the program to run, and simple event handling methods for collisions.  I won&#8217;t explain every bit of the code, but if you like code, you&#8217;ll be able to understand it.  Feel free to <a href="/projectlab/downloads/XBeeVehicleRemoteControl.pde">download the entire Processing sketch that implements the remote vehicle controller</a>.</p>
<pre class="codeblockscroll">
import processing.serial.*;

Serial port = null;
String portName;
int lastInput = 0;
int[] command = new int[2];
int[] lastCommand = new int[2];
int speed = 9;
int lastSpeed = 0;
int speedStep = (255 - 130) / 8;
boolean running = true;
boolean leftFrontBumper = false;
boolean rightFrontBumper = false;
boolean rearBumper = false;

int DIR_FORWARD = 0x1;
int DIR_BACKWARD = 0x2;
int DIR_LEFT = 0x4;
int DIR_RIGHT = 0x8;
int BEGIN_COMMAND = 0x7F;

// Sensor Data
int LEFT_FRONT_BUMPER = 0x1;
int RIGHT_FRONT_BUMPER = 0x2;
int REAR_BUMPER = 0x4;

SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss.SSS");

void setup() {
  size(1, 1);

  portName = Serial.list()[0];
  try {
    port = new Serial(this, portName, 9600);
  } catch (Exception e) {
    e.printStackTrace();
  }
}

String timestamp() {
  return df.format(new Date());
}

void draw() {

  if (rightFrontBumper) {
    println(timestamp() + " ----RIGHT FRONT IMPACT!----");
    rightFrontBumper();
  }
  if (leftFrontBumper) {
    println(timestamp() + " ----LEFT FRONT IMPACT!-----");
    leftFrontBumper();
  }
  if (rearBumper) {
    println(timestamp() + " -------REAR IMPACT!--------");
    rearBumper();
  }

  speed = 9;
  left();
  forward(1200);
  right();
  forward(800);
  stop();

  left();
  backward(1200);
  stop();
  right();

  forward(2500);
  stop();

  left();
  backward(4000);

  end();
}

void leftFrontBumper() {
  leftFrontBumper = false;
  running = true;

  left();
  speed = 9;
  backward(800);
  straight();
  end();
}

void rightFrontBumper() {
  rightFrontBumper = false;
  running = true;

  right();
  speed = 9;
  backward(800);
  straight();
  end();
}
void rearBumper() {
  rearBumper = false;
  running = true;

  speed = 9;
  forward(1000);
  straight();
  end();
}

void end() {
  if (!running) return;
  stop();
  straight();
  println(timestamp() + " -----------END------------");
  println("Press 's' to restart program or use arrow keys to control vehicle.");
  running = false;
}

void interruptibleDelay(int millis) {
  int start = millis();
  int d;
  while (running) {
    int timeLeftToWait = millis-(millis()-start);
    d = min(10, timeLeftToWait);
    if (d <= 0) return;
    delay(d);
  }
}

void forward(int millis) {
  if (!running) return;
  forward();
  interruptibleDelay(millis);
  stop();
}

void forward() {
  if (!running) return;
  doForward();
}

void doForward() {
  command[0] = command[0] &#038; ~DIR_BACKWARD;
  command[0] = command[0] | DIR_FORWARD;
  sendCommand();
}

void backward(int millis) {
  if (!running) return;
  doBackward();
  interruptibleDelay(millis);
  stop();
}

void backward() {
  if (!running) return;
  doBackward();
}

void doBackward() {
  command[0] = command[0] &#038; ~DIR_FORWARD;
  command[0] = command[0] | DIR_BACKWARD;
  sendCommand();
}

void left() {
  if (!running) return;
  doLeft();
}

void doLeft() {
  command[0] = command[0] &#038; ~DIR_RIGHT;
  command[0] = command[0] | DIR_LEFT;
  sendCommand();
}

void right() {
  if (!running) return;
  doRight();
}

void doRight() {
  command[0] = command[0] &#038; ~DIR_LEFT;
  command[0] = command[0] | DIR_RIGHT;
  sendCommand();
}

void straight() {
  if (!running) return;
  doStraight();
}

void doStraight() {
  command[0] = command[0] &#038; ~DIR_RIGHT;
  command[0] = command[0] &#038; ~DIR_LEFT;
  sendCommand();
}

void stop() {
  if (!running) return;
  doStop();
}
void doStop() {
  command[0] = command[0] &#038; ~DIR_BACKWARD;
  command[0] = command[0] &#038; ~DIR_FORWARD;
  sendCommand();
}

void serialEvent(Serial p) {
  int input = p.read();
  lastInput = input;
  processInput(input);
} 

void processInput(int input) {
  if ((input &#038; LEFT_FRONT_BUMPER) != 0) {
    stop();
    leftFrontBumper = true;
    running = false;
  }

  if ((input &#038; RIGHT_FRONT_BUMPER) != 0) {
    stop();
    rightFrontBumper = true;
    running = false;
  }

  if ((input &#038; REAR_BUMPER) != 0) {
    stop();
    rearBumper = true;
    running = false;
  }
}

void sendCommand() {
  if (!isNewCommand()) {
    return;
  }
  if (port != null) {
    port.write(BEGIN_COMMAND);
    port.write(command[0]);
    command[1] = 255 - ((9 - speed) * speedStep);
    port.write(command[1]);
    if ((command[0] &#038; DIR_FORWARD) > 0) {
      print(timestamp() + " FORWARD\t");
    }
    if ((command[0] &#038; DIR_BACKWARD) > 0) {
      print(timestamp() + " BACKWARD\t");
    }
    if (((command[0] &#038; DIR_FORWARD) == 0) &#038;&#038; ((command[0] &#038; DIR_BACKWARD) == 0)) {
      print(timestamp() + " STOP\t");
    }
    if ((command[0] &#038; DIR_LEFT) > 0) {
      print("LEFT\t");
    }
    if ((command[0] &#038; DIR_RIGHT) > 0) {
      print("RIGHT\t");
    }
    if (((command[0] &#038; DIR_LEFT) == 0) &#038;&#038; ((command[0] &#038; DIR_RIGHT) == 0)) {
      print("STRAIGHT\t");
    }
    println("SPEED=" + speed);

    lastCommand[0] = command[0];
    lastCommand[1] = command[1];
    lastSpeed = speed;
  }
}

boolean isNewCommand() {
  return ((command[0] != lastCommand[0]) || (command[1] != lastCommand[1]) || (speed != lastSpeed));
}

void keyPressed() {
  if (key == CODED) {
    if (keyCode == UP) {
      doForward();
    }
    if (keyCode == DOWN) {
      doBackward();
    }
    if (keyCode == LEFT) {
      doLeft();
    }
    if (keyCode == RIGHT) {
      doRight();
    }
  }
  if ((key >= '1') &#038;&#038; (key <= '9')) {
    speed = 9 - ('9' - key);
    println("set speed = " + speed);
  }
  if (key == 's') {
    running = true;
  }
}

void keyReleased() {
  if (key == CODED) {
    if (keyCode == UP) {
      doStop();
    }
    if (keyCode == DOWN) {
      doStop();
    }
    if (keyCode == LEFT) {
      doStraight();
    }
    if (keyCode == RIGHT) {
      doStraight();
    }
  }
}
</pre>
<h3>Demo</h3>
<p>Here's a demo where I tried to program the vehicle to negotiate an obstacle course.  This is the instructions and the sensor event handling code:</p>
<pre class="codeblockscroll">
void draw() {

  if (rightFrontBumper) {
    println(timestamp() + " ----RIGHT FRONT IMPACT!----");
    rightFrontBumper();
  }
  if (leftFrontBumper) {
    println(timestamp() + " ----LEFT FRONT IMPACT!-----");
    leftFrontBumper();
  }
  if (rearBumper) {
    println(timestamp() + " -------REAR IMPACT!--------");
    rearBumper();
  }

  speed = 9;
  left();
  forward(1200);
  right();
  forward(800);
  stop();

  left();
  backward(1200);
  stop();
  right();

  forward(2500);
  stop();

  left();
  backward(4000);

  end();
}

void leftFrontBumper() {
  leftFrontBumper = false;
  running = true;

  left();
  speed = 9;
  backward(800);
  straight();
  end();
}

void rightFrontBumper() {
  rightFrontBumper = false;
  running = true;

  right();
  speed = 9;
  backward(800);
  straight();
  end();
}

void rearBumper() {
  rearBumper = false;
  running = true;

  speed = 9;
  forward(1000);
  straight();
  end();
}
</pre>
<p>Let's see how well it worked.  I tried to navigate through the cones without hitting them.  The wheels skidded a bit when changing direction on the smooth floor.  At the end, I purposefully ran into something backwards to demonstrate a sensor event.  See if you can match up the vehicle's actions with the code above.<br />
<object width="640" height="480"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=8937750&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=8937750&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="480"></embed></object></p>
<p>Finally, here's a screenshot of the Processing console that shows everything that happened.  Notice the rear impact event at the end.<br />
<a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/vehicleControllerConsole.jpg"><img src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/vehicleControllerConsole.jpg" alt="" title="vehicleControllerConsole" width="640" height="297" class="alignnone size-full wp-image-122" /></a></p>
<p>Hope you enjoyed reading about this project.  It was a lot of work and I hope that it can be the basis for future robotics experimentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2010/03/04/wireless-robotics-platform/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>EZ-Expander Shield for Arduino</title>
		<link>http://nootropicdesign.com/projectlab/2010/03/03/ez-expander/</link>
		<comments>http://nootropicdesign.com/projectlab/2010/03/03/ez-expander/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 02:21:57 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=133</guid>
		<description><![CDATA[I&#8217;m happy to finally announce my new product, the EZ-Expander shield.  After several months of hard work of sourcing parts, designing the PCB, and setting up a store, my first product is now available for purchase in the nootropic design store! 
For all the technical details, go to the EZ-Expander page.
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to finally announce my new product, the EZ-Expander shield.  After several months of hard work of sourcing parts, designing the PCB, and setting up a store, my first product is now available for purchase in the <a href="http://nootropicdesign.com/store/">nootropic design store</a>! </p>
<p><a href="http://nootropicdesign.com/ez-expander/">For all the technical details, go to the EZ-Expander page.</a></p>
<div id="attachment_136" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/03/ez-expander-assembled-640x480.jpg"><img src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/03/ez-expander-assembled-640x480.jpg" alt="" title="EZ-Expander shield" width="640" height="480" class="size-full wp-image-136" /></a><p class="wp-caption-text">EZ-Expander shield</p></div><br />
<div id="attachment_137" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/03/ez-expander-arduino-640x480.jpg"><img src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/03/ez-expander-arduino-640x480.jpg" alt="" title="EZ-Expander on Arduino" width="640" height="480" class="size-full wp-image-137" /></a><p class="wp-caption-text">EZ-Expander on an Arduino</p></div>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2010/03/03/ez-expander/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino Police Lights</title>
		<link>http://nootropicdesign.com/projectlab/2010/01/08/arduino-police-lights/</link>
		<comments>http://nootropicdesign.com/projectlab/2010/01/08/arduino-police-lights/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 04:03:23 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=70</guid>
		<description><![CDATA[This is an amusing project inspired by flashing blue and red lights on police cars, ambulances, etc.  This is a perf board Arduino with 5 blue and 5 red LEDs, and the Arduino code lights them up in a pattern similar to police lights.
First, the Arduino built on a perf board.  It&#8217;s not hard to [...]]]></description>
			<content:encoded><![CDATA[<p>This is an amusing project inspired by flashing blue and red lights on police cars, ambulances, etc.  This is a perf board Arduino with 5 blue and 5 red LEDs, and the Arduino code lights them up in a pattern similar to police lights.</p>
<p>First, the Arduino built on a perf board.  It&#8217;s not hard to build your own Arduino.  I use a real Arduino board to upload code to the ATMega328 chip, then just move it to the project board.</p>
<div id="attachment_73" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/policeLights.jpg"><img class="size-full wp-image-73" title="policeLights" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2010/01/policeLights.jpg" alt="" width="640" height="480" /></a><p class="wp-caption-text">Perfboard Arduino with blue and red LEDs for police lights mini-project</p></div>
<p>Now here it is in action &#8212; I really think if you don&#8217;t know what you&#8217;re looking at, it looks realistic in the dark.</p>
<p><object width="640" height="480"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=8628039&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=8628039&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="480"></embed></object></p>
<p>Here&#8217;s the code that makes it work.  Notice that some of the LEDs are controlled using PWM; the second and fourth LED in each of the blue and red groups.  I would invite people to build something similar and tweak this to get the most realistic effect possible!</p>
<pre class="codeblockscroll">
#define NUM_OFF 3
#define DELAY 50
#define PWM_MIN 10
#define PWM_MAX 128

int blue[5];
int red[5];

void setup()
{
  blue[0] = 19;
  blue[1] = 5;
  blue[2] = 18;
  blue[3] = 6;
  blue[4] = 17;
  red[0] = 13;
  red[1] = 11;
  red[2] = 12;
  red[3] = 10;
  red[4] = 9;

  for(int i=0;i<5;i++) {
    pinMode(blue[i], OUTPUT);
    pinMode(red[i], OUTPUT);
  }
  randomSeed(analogRead(0));
}

void loop()
{
  allOn();
  analogWrite(blue[1], random(PWM_MIN, PWM_MAX));
  analogWrite(blue[3], random(PWM_MIN, PWM_MAX));
  analogWrite(red[1], random(PWM_MIN, PWM_MAX));
  analogWrite(red[3], random(PWM_MIN, PWM_MAX));

  for(int i=0;i&lt;NUM_OFF;i++) {
    digitalWrite(blue[random(5)], LOW);
    digitalWrite(red[random(5)], LOW);
  }
  delay(DELAY);
}

void allOn() {
  for(int i=0;i&lt;5;i++) {
    digitalWrite(blue[i], HIGH);
    digitalWrite(red[i], HIGH);
  }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2010/01/08/arduino-police-lights/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino-Controlled Lock with Keypad</title>
		<link>http://nootropicdesign.com/projectlab/2009/11/23/arduino-controlled-coded-lock/</link>
		<comments>http://nootropicdesign.com/projectlab/2009/11/23/arduino-controlled-coded-lock/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 13:51:54 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=39</guid>
		<description><![CDATA[After tearing down an old CD player, I was inspired by the CD laser scanning assembly to build a door lock for my subterranean lab.  The assembly has two motors: one for turning the CD (I&#8217;m not using this one) and one for slowly moving the laser across the CD&#8217;s surface.  This second [...]]]></description>
			<content:encoded><![CDATA[<p>After tearing down an old CD player, I was inspired by the CD laser scanning assembly to build a door lock for my subterranean lab.  The assembly has two motors: one for turning the CD (I&#8217;m not using this one) and one for slowly moving the laser across the CD&#8217;s surface.  This second motor provides a nice linear motion that I wanted to use to build an electronically-controlled dead bolt lock for my lab.</p>
<p>Here&#8217;s the assembled lock.  The circuit board in the middle is an H-bridge circuit I built to allow the motor to move in both directions.  There are two position sensing switches so the Arduino senses when the motor has reached its limit in either direction.  A 9V power supply powers the Arduino board, and a separate 5V supply drives the motor through the H-bridge.  The dead bolt is <em>literally</em> a bolt &#8212; connected to the assembly with a piece of scrap circuit board &#8212; that travels through the door jamb and into the door.</p>
<div id="attachment_44" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/lockClosed.jpg"><img class="size-full wp-image-44" title="lockClosed-sm" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/lockClosed-sm.jpg" alt="The lock in the closed (locked) position." width="640" height="853" /></a><p class="wp-caption-text">The lock in the closed (locked) position.</p></div>
<p>The black CAT5 cable connected to pins 2-8 goes through a small hole in the wall (under a desk) to the keypad on the outside of the lab (I wasn&#8217;t sure I wanted to permanently mount the keypad in the wall).  The user types in the correct code and presses the # key to open or close the lock.  The green LED indicates the door is unlocked.  Red indicates locked.  </p>
<div id="attachment_29" class="wp-caption alignnone" style="width: 650px"><a href="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/keypad.jpg"><img class="size-full wp-image-29" title="keypad" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/keypad.jpg" alt="Lock keypad - green indicates that it's unlocked, red indicates locked." width="640" height="480" /></a><p class="wp-caption-text">Lock keypad - green indicates that it&#39;s unlocked, red indicates locked.</p></div>
<p>Let&#8217;s see the lock in action.  (While recording, I gave instructions to my son to lock and unlock using the keypad off camera.)<br />
<object width="640" height="480"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=7504447&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=7504447&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="480"></embed></object></p>
<p><span id="more-39"></span><br />
Reading the keypad is by far the most complicated thing in the Arduino code below.  They keypad has 12 keys but only 10 wires.  Reading the keypad is not as simple as checking to see which of the 12 switches is closed.  The keys must be constantly scanned to see which if any keys are depressed.   Scanning the keypad is done by multiplexing through 6 of the wires on the keypad, alternately setting them LOW and then checking the other 4 wires (blue, green, yellow, red) on the keypad to see if a button is pressed.  </p>
<p>A shift register on the keypad lets me control 8 outputs with only 3 Arduino pins: the latch pin, clock pin and data pin.  The eight outputs are 6 multiplexed wires of the keypad plus one for each LED.  The total number of wires running to the keypad is 3 for the output (latch, clock, data), 4 inputs, 5V, and GND.  That&#8217;s 9 total, and since CAT5 has only 8 wires, I have the 9th wire (GND) taped to the CAT5.  Hey, it got the job done.</p>
<pre class="codeblockscroll">
#define LATCH_PIN 2
#define CLOCK_PIN 3
#define DATA_PIN 4

// Keypad inputs (colors are keypad wires, not cat5 wires)
#define BLUE_PIN 5
#define GREEN_PIN 6
#define YELLOW_PIN 7
#define RED_PIN 8

// PNP transistors.  LOW to activate.
#define Q1 17
#define Q2 19

// NPN transistors.  HIGH to activate.
#define Q3 16
#define Q4 18

#define LOCK_LIMIT_SWITCH_PIN 15  // long wires
#define UNLOCK_LIMIT_SWITCH_PIN 14

#define LOCKED 0
#define UNLOCKED 1
#define LOCKING 2
#define UNLOCKING 3

#define NO_SCAN 0xFC
#define BLACK 0x80
#define WHITE 0x40
#define GRAY 0x20
#define PURPLE 0x10
#define ORANGE 0x8
#define BROWN 0x4
#define GREEN_LED_ON 0x2
#define RED_LED_ON 0x1

#define NO_KEY -1
#define STAR 10
#define POUND 11

int state;
byte greenLED = 0;
byte redLED = RED_LED_ON;
int lastKey = -1;

#define MAX_GUESS 10
#define COMBO_LENGTH 4

int code[COMBO_LENGTH] = {5, 6, 1, 8};
int guess[MAX_GUESS];
int guessIndex = 0;

void setup() {
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);

  pinMode(BLUE_PIN, INPUT);
  digitalWrite(BLUE_PIN, HIGH); // set pull-up resistor
  pinMode(GREEN_PIN, INPUT);
  digitalWrite(GREEN_PIN, HIGH); // set pull-up resistor
  pinMode(YELLOW_PIN, INPUT);
  digitalWrite(YELLOW_PIN, HIGH); // set pull-up resistor
  pinMode(RED_PIN, INPUT);
  digitalWrite(RED_PIN, HIGH); // set pull-up resistor

  pinMode(Q1, OUTPUT);
  pinMode(Q2, OUTPUT);
  pinMode(Q3, OUTPUT);
  pinMode(Q4, OUTPUT);

  pinMode(UNLOCK_LIMIT_SWITCH_PIN, INPUT);
  digitalWrite(UNLOCK_LIMIT_SWITCH_PIN, HIGH); // set pull-up resistor

  pinMode(LOCK_LIMIT_SWITCH_PIN, INPUT);
  digitalWrite(LOCK_LIMIT_SWITCH_PIN, HIGH); // set pull-up resistor

  unlock();

}

void loop() {
  if ((isUnlocked()) &amp;&amp; (state == UNLOCKING)) {
    stop();
    state = UNLOCKED;
  }
  if ((isLocked()) &amp;&amp; (state == LOCKING)) {
    stop();
    state = LOCKED;
  }

  if ((state != UNLOCKING) &amp;&amp; (state != LOCKING)) {
    int n = scanKeypad();
    if (n != lastKey) {
      // something changed
      if (n == NO_KEY) {
        // key released
        processKey(lastKey);
      }
      lastKey = n;
    }
  }
}

int scanKeypad() {

  writeData((NO_SCAN ^ BLACK) | redLED | greenLED);
  if (digitalRead(BLUE_PIN) == LOW) {
    return POUND;
  }
  if (digitalRead(GREEN_PIN) == LOW) {
    return 0;
  }
  if (digitalRead(YELLOW_PIN) == LOW) {
    return STAR;
  }

  writeData((NO_SCAN ^ WHITE) | redLED | greenLED);
  if (digitalRead(BLUE_PIN) == LOW) {
    return 9;
  }
  if (digitalRead(GREEN_PIN) == LOW) {
    return 8;
  }
  if (digitalRead(YELLOW_PIN) == LOW) {
    return 7;
  }

  writeData((NO_SCAN ^ GRAY) | redLED | greenLED);
  if (digitalRead(YELLOW_PIN) == LOW) {
    return 4;
  }

  writeData((NO_SCAN ^ PURPLE) | redLED | greenLED);
  if (digitalRead(BLUE_PIN) == LOW) {
    return 6;
  }
  if (digitalRead(GREEN_PIN) == LOW) {
    return 5;
  }
  if (digitalRead(YELLOW_PIN) == LOW) {
    return 2;
  }

  writeData((NO_SCAN ^ ORANGE) | redLED | greenLED);
  if (digitalRead(RED_PIN) == LOW) {
    return 3;
  }

  writeData((NO_SCAN ^ BROWN) | redLED | greenLED);
  if (digitalRead(RED_PIN) == LOW) {
    return 1;
  }

  return NO_KEY;
}  

void processKey(int k) {
  if ((k != POUND) &amp;&amp; (k != STAR)) {
    guess[guessIndex++] = k;
    if (guessIndex == MAX_GUESS) {
      clearGuess();
      blinkRed(3);
    }
  }
  if (k == POUND) {
    if (guessIsCorrect()) {
      if (state == LOCKED) {
        greenLED = GREEN_LED_ON;
        redLED = 0;
        unlock();
      } else {
        if (state == UNLOCKED) {
          greenLED = 0;
          redLED = RED_LED_ON;;
          lock();
        }
      }
      blinkGreen(3);
      clearGuess();
    } else {
      clearGuess();
      blinkRed(3);
    }
  }
}

void clearGuess() {
  guessIndex = 0;
  for(int i=0; i &lt; MAX_GUESS; i++) {
    guess[i] = -1;
  }
}

boolean guessIsCorrect() {
  for(int i=0; i &lt; COMBO_LENGTH; i++) {
    if (guess[i] != code[i]) {
      return false;
    }
  }
  return true;
}

void blinkRed(int n) {
  for(int i=0; i &lt; n; i++) {
    writeData(NO_SCAN);
    delay(100);
    writeData(NO_SCAN | RED_LED_ON);
    delay(100);
  }
}

void blinkGreen(int n) {
  for(int i=0; i &lt; n; i++) {
    writeData(NO_SCAN);
    delay(100);
    writeData(NO_SCAN | GREEN_LED_ON);
    delay(100);
  }
}

void writeData(byte data) {
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, data);
  digitalWrite(LATCH_PIN, HIGH);
}

boolean isUnlocked() {
  return (digitalRead(UNLOCK_LIMIT_SWITCH_PIN) == LOW);
}

boolean isLocked() {
  return (digitalRead(LOCK_LIMIT_SWITCH_PIN) == LOW);
}

void unlock() {
  digitalWrite(Q2, HIGH);  // OFF
  digitalWrite(Q3, LOW);   // OFF
  digitalWrite(Q1, LOW);   // ON
  digitalWrite(Q4, HIGH);  // ON
  state = UNLOCKING;
}

void lock() {
  digitalWrite(Q1, HIGH);  // OFF
  digitalWrite(Q4, LOW);   // OFF
  digitalWrite(Q2, LOW);   // ON
  digitalWrite(Q3, HIGH);  // ON
  state = LOCKING;
}

void stop() {
  digitalWrite(Q1, HIGH);  // OFF
  digitalWrite(Q2, HIGH);  // OFF
  digitalWrite(Q3, LOW);   // OFF
  digitalWrite(Q4, LOW);   // OFF
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2009/11/23/arduino-controlled-coded-lock/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wireless Temperature Sensor</title>
		<link>http://nootropicdesign.com/projectlab/2009/11/01/wireless-temperature-sensor/</link>
		<comments>http://nootropicdesign.com/projectlab/2009/11/01/wireless-temperature-sensor/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 18:50:49 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[XBee]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=14</guid>
		<description><![CDATA[I decided to explore the more advanced features of XBee radios by building a remote temperature sensor.  You can get quite a bit of control over an XBee radio without a microcontroller at all.  You can configure the radio to send sensor readings at particular intervals when it detects changes on certain input [...]]]></description>
			<content:encoded><![CDATA[<p>I decided to explore the more advanced features of <a href="http://www.digi.com/products/wireless/zigbee-mesh/">XBee</a> radios by building a remote temperature sensor.  You can get quite a bit of control over an XBee radio without a microcontroller at all.  You can configure the radio to send sensor readings at particular intervals when it detects changes on certain input pins.  For the details on configuring XBee radios, see the <a href="http://ftp1.digi.com/support/documentation/90000982_B.pdf">documentation at Digi International</a>.</p>
<p>For this project, I configured the radio at the sensor end to read the analog input of pin 19 every 4 seconds and to send a sensor reading packet.  Both the sender and receiver radios should be running the API firmware.  Input pin 19 on my sensor radio is configured (parameter D1) with value &#8216;2&#8242; which means that it will read analog input, and the IO sampling rate (parameter IR) is set to &#8216;1000&#8242; which sends a sample every 4096ms.</p>
<p>An LM34 temperature sensor outputs a variable voltage depending on the temperature.  The mapping is extremely simple: 10mV for every Fahrenheit degree.  So, at 72 degrees F, the output is 720mV.</p>
<p>Why did I choose pin 19?  I started with pin 20, but I burned it out.  The pins can only handle an analog input of up to 1.2V, and I <em>think</em> I may have sent too much into the pin.  How?  Well, let&#8217;s say it involved holding a cold Pepsi can on the circuit to cool off the temperature sensor, and I shorted out a connection with the can.  Oops.  I&#8217;m lucky I didn&#8217;t burn out the entire XBee chip.</p>
<div id="attachment_5" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-5" title="sensor" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/sensor.jpg" alt="Remote temperature sensor" width="640" height="480" /><p class="wp-caption-text">Remote temperature sensor</p></div>
<p>Here is the circuit for the remote sensor:</p>
<div id="attachment_6" class="wp-caption alignnone" style="width: 623px"><img class="size-full wp-image-6" title="sensorSchematic" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/sensorSchematic1.png" alt="Schematic for remote sensor circuit" width="613" height="481" /><p class="wp-caption-text">Schematic for remote sensor circuit</p></div>
<p>For the receiving side, I used an Arduino with an XBee shield and a two digit LED display:<br />
<span id="more-14"></span></p>
<div id="attachment_7" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-7" title="display" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/display.jpg" alt="Arduino with XBee shield and LED display" width="640" height="480" /><p class="wp-caption-text">Arduino with XBee shield and LED display</p></div>
<p>Here&#8217;s the Arduino code for reading incoming packets from the XBee and displaying the received analog sample on the LED display.  Parsing an XBee packet is quite complex, unfortunately.  But after studying the documentation for a while, it isn&#8217;t that hard.</p>
<pre class="codeblockscroll">#define NUM_DIGITAL_SAMPLES 12
#define NUM_ANALOG_SAMPLES 4

int groundPins[7] = {8, 2, 3, 4, 5, 9, 7};
int digitPins[2] = {11, 10};
int ON = HIGH;
int OFF = LOW;
int number[10][7];
int digit[2];
int TOP = 0;
int UPPER_L = 1;
int LOWER_L = 2;
int BOTTOM = 3;
int LOWER_R = 4;
int UPPER_R = 5;
int MIDDLE = 6;

int index;
int n = 0;

int packet[32];
int digitalSamples[NUM_DIGITAL_SAMPLES];
int analogSamples[NUM_ANALOG_SAMPLES];

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

  for(int i=0;i&lt;7;i++) {
    pinMode(groundPins[i], OUTPUT);
  }
  for(int i=0;i&lt;2;i++) {
    pinMode(digitPins[i], OUTPUT);
  }
  initNumber();

  setDigit(n);
}

void loop() {
  readPacket();
  drawDisplay();
}

void readPacket() {
  if (Serial.available() &gt; 0) {
    int b = Serial.read();
    if (b == 0x7E) {
      packet[0] = b;
      packet[1] = readByte();
      packet[2] = readByte();
      int dataLength = (packet[1] &lt;&lt; 8) | packet[2];

      for(int i=1;i&lt;=dataLength;i++) {
        packet[2+i] = readByte();
      }
      int apiID = packet[3];
      packet[3+dataLength] = readByte(); // checksum

      printPacket(dataLength+4);

      if (apiID == 0x92) {
        int analogSampleIndex = 19;
        int digitalChannelMask = (packet[16] &lt;&lt; 8) | packet[17];
        if (digitalChannelMask &gt; 0) {
          int d = (packet[19] &lt;&lt; 8) | packet[20];
          for(int i=0;i &lt; NUM_DIGITAL_SAMPLES;i++) {
            digitalSamples[i] = ((d &gt;&gt; i) &amp; 1);
          }
          analogSampleIndex = 21;
        }

        int analogChannelMask = packet[18];
        for(int i=0;i&lt;4;i++) {
          if ((analogChannelMask &gt;&gt; i) &amp; 1) {
            analogSamples[i] = (packet[analogSampleIndex] &lt;&lt; 8) | packet[analogSampleIndex+1];
            analogSampleIndex += 2;
          } else {
            analogSamples[i] = -1;
          }
        }
      }
    }

    int reading = analogSamples[1];  // pin 19
    // convert reading to millivolts
    float v = ((float)reading/(float)0x3FF)*1200.0;

    // convert to Fahrenheit.  10mv per Fahrenheit degree
    float f = v / 10.0;

    // round to nearest int
    n = (int)(f+0.5);
    setDigit(n);
  }
}

void drawDisplay() {
  for(int g=0;g&lt;7;g++) {
    digitalWrite(groundPins[g], LOW);
    for(int i=0;i&lt;2;i++) {
      if (digit[i] &lt; 0) {
        continue;
      }
      digitalWrite(digitPins[i], number[digit[i]][g]);
    }
    delay(0);  // for some reason, this is required even if the value is 0
    digitalWrite(groundPins[g], HIGH);
  }
}

void setDigit(int n) {
  n = n % 100;
  digit[0] = n % 10;
  digit[1] = (n / 10) % 10;
  if ((digit[1] == 0) &amp;&amp; (n &lt; 10)) {
    digit[1] = -1;
  }
}

void initNumber() {
  number[0][0] = ON;
  number[0][1] = ON;
  number[0][2] = ON;
  number[0][3] = ON;
  number[0][4] = ON;
  number[0][5] = ON;
  number[0][6] = OFF;

  number[1][0] = OFF;
  number[1][1] = OFF;
  number[1][2] = OFF;
  number[1][3] = OFF;
  number[1][4] = ON;
  number[1][5] = ON;
  number[1][6] = OFF;

  number[2][0] = ON;
  number[2][1] = OFF;
  number[2][2] = ON;
  number[2][3] = ON;
  number[2][4] = OFF;
  number[2][5] = ON;
  number[2][6] = ON;

  number[3][0] = ON;
  number[3][1] = OFF;
  number[3][2] = OFF;
  number[3][3] = ON;
  number[3][4] = ON;
  number[3][5] = ON;
  number[3][6] = ON;

  number[4][0] = OFF;
  number[4][1] = ON;
  number[4][2] = OFF;
  number[4][3] = OFF;
  number[4][4] = ON;
  number[4][5] = ON;
  number[4][6] = ON;

  number[5][0] = ON;
  number[5][1] = ON;
  number[5][2] = OFF;
  number[5][3] = ON;
  number[5][4] = ON;
  number[5][5] = OFF;
  number[5][6] = ON;

  number[6][0] = ON;
  number[6][1] = ON;
  number[6][2] = ON;
  number[6][3] = ON;
  number[6][4] = ON;
  number[6][5] = OFF;
  number[6][6] = ON;

  number[7][0] = ON;
  number[7][1] = OFF;
  number[7][2] = OFF;
  number[7][3] = OFF;
  number[7][4] = ON;
  number[7][5] = ON;
  number[7][6] = OFF;

  number[8][0] = ON;
  number[8][1] = ON;
  number[8][2] = ON;
  number[8][3] = ON;
  number[8][4] = ON;
  number[8][5] = ON;
  number[8][6] = ON;

  number[9][0] = ON;
  number[9][1] = ON;
  number[9][2] = OFF;
  number[9][3] = ON;
  number[9][4] = ON;
  number[9][5] = ON;
  number[9][6] = ON;
}
void printPacket(int l) {
  for(int i=0;i &lt; l;i++) {
    if (packet[i] &lt; 0xF) {
      // print leading zero for single digit values
      Serial.print(0);
    }
    Serial.print(packet[i], HEX);
    Serial.print(" ");
  }
  Serial.println("");
} 

int readByte() {
    while (true) {
      if (Serial.available() &gt; 0) {
      return Serial.read();
    }
  }
}</pre>
<p>Here&#8217;s how I wired the back of the LED display.  The code displays each digit separately to save Arduino pins but toggles between the digits so fast you can&#8217;t see any flicker.</p>
<div id="attachment_8" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-8" title="displayCircuit" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/displayCircuit.jpg" alt="Back of LED display.  The pin positions are designed to fit the XBee shield." width="640" height="480" /><p class="wp-caption-text">Back of LED display.  The pin positions are designed to fit the XBee shield.</p></div>
<p>Here&#8217;s how it looks in the dark!</p>
<div id="attachment_9" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-9" title="display-dark" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/display-dark.jpg" alt="In the dark!" width="640" height="480" /><p class="wp-caption-text">In the dark!</p></div>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2009/11/01/wireless-temperature-sensor/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Hack-a-Sketch</title>
		<link>http://nootropicdesign.com/projectlab/2009/10/31/hack-a-sketch/</link>
		<comments>http://nootropicdesign.com/projectlab/2009/10/31/hack-a-sketch/#comments</comments>
		<pubDate>Sat, 31 Oct 2009 13:45:28 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Processing]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=12</guid>
		<description><![CDATA[Here is a device I call the Hack-a-Sketch.  The screen is a normal laptop (an old one), but it has real knobs which control the stylus on the screen.
An Arduino board reads the inputs from two potentiometers (the knobs), and sends the information via USB to a Processing sketch which displays the path of [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a device I call the Hack-a-Sketch.  The screen is a normal laptop (an old one), but it has real knobs which control the stylus on the screen.</p>
<div id="attachment_3" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-3" title="hackasketch" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/hackasketch.jpg" alt="The Hack-a-Sketch" width="640" height="480" /><p class="wp-caption-text">The Hack-a-Sketch</p></div>
<p>An <a href="http://www.arduino.cc/">Arduino</a> board reads the inputs from two potentiometers (the knobs), and sends the information via USB to a <a href="http://processing.org/">Processing</a> sketch which displays the path of the stylus on the screen.  This was extremely easy to build because the Arduino is just running the StandardFirmata firmware.  No custom code on the board.  The Processing sketch was surprisingly easy to write.  Using this really did feel like using an Etch-a-Sketch.</p>
<p>Here&#8217;s the Hack-a-Sketch in action.  Wait for the big finish where I erase the image&#8230;</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="480" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=7367464&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="640" height="480" src="http://vimeo.com/moogaloop.swf?clip_id=7367464&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>How did I erase the drawing by shaking the computer?  There&#8217;s a mercury switch hidden behind the panel holding the knobs.  When the code senses shaking, the image is slowly erased.  More shaking = more erasure.<br />
<span id="more-12"></span></p>
<div id="attachment_4" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-4" title="disassembled" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/disassembled.jpg" alt="Disassembled Hack-a-Sketch exposing mercury switch to sense movement." width="640" height="480" /><p class="wp-caption-text">Disassembled Hack-a-Sketch exposing mercury switch to sense movement.</p></div>
<p>Finally, here&#8217;s the Processing code that does all the work:</p>
<pre class="codeblockscroll">import processing.serial.*;

import processing.core.*;
import cc.arduino.Arduino;

PImage backgroundImage;
Arduino arduino;
int STYLUS_X_PIN = 0;
int STYLUS_Y_PIN = 1;
int MERCURY_SWITCH_LEFT_PIN = 8;
int MERCURY_SWITCH_RIGHT_PIN = 9;
// Origin is lower left corner of screen.
int originX = 146;
int originY = 673;
int width = 740;
int height = 530;
int PEN_COLOR = 50;
int GRAY = 217;
int GRAY_ALPHA = 80;
int lastX, lastY;
int SMOOTH_BUFFER_SIZE = 2;
int[] smoothBufferX = new int[SMOOTH_BUFFER_SIZE];
int[] smoothBufferY = new int[SMOOTH_BUFFER_SIZE];
int smoothBufferXSum = 0;
int smoothBufferYSum = 0;
int LEFT = 0;
int RIGHT = 1;
int SHAKE_SPEED_THRESHOLD = 300;
int lastSwitchPosition;
int lastSwitchPositionChange;

void setup() {
    size(1024, 768);
    frameRate(24);
    backgroundImage = loadImage("hackasketch-cropped.jpg");
    background(backgroundImage);

    String[] ports = Arduino.list();
    println(ports[0]);
    println(ports[1]);
    String port = ports[1];
    try {
        arduino = new Arduino(this, port, 115200);
        arduino.pinMode(MERCURY_SWITCH_LEFT_PIN, Arduino.INPUT);
        arduino.pinMode(MERCURY_SWITCH_RIGHT_PIN, Arduino.INPUT);
    } catch (Exception e) {
        println("Failed to find Arduino board");
    }
    stroke(PEN_COLOR);
}

void draw() {
    smooth();
    int x, y;
    if (frameCount == 1) {
        // Give the Arduino some time to initialize so we can get a good first
        // reading from the potentiometers.
        delay(2000);
        lastX = readStylusX();
        lastY = readStylusY();
        for(int i=0;i &lt; SMOOTH_BUFFER_SIZE;i++) {
            smoothBufferX[i] = lastX;
            smoothBufferXSum += lastX;
            smoothBufferY[i] = lastY;
            smoothBufferYSum += lastY;
        }
        point(originX+lastX, originY-lastY);
    }

    x = smoothX(readStylusX());
    y = smoothY(readStylusY());
    if ((x != lastX) || (y != lastY)) {
        line(originX+lastX, originY-lastY, originX+x, originY-y);
    }
    lastX = x;
    lastY = y;

    if (shake()) {
        erase();
    }
}

boolean shake() {
    boolean left = (arduino.digitalRead(MERCURY_SWITCH_LEFT_PIN) == Arduino.HIGH);
    if (left &amp;&amp; (lastSwitchPosition != LEFT)) {
        lastSwitchPosition = LEFT;
        if ((millis() - lastSwitchPositionChange) &lt; SHAKE_SPEED_THRESHOLD) {
            lastSwitchPositionChange = millis();
            return true;
        }
        lastSwitchPositionChange = millis();
    }
    boolean right = (arduino.digitalRead(MERCURY_SWITCH_RIGHT_PIN) == Arduino.HIGH);
    if (right &amp;&amp; (lastSwitchPosition != RIGHT)) {
        lastSwitchPosition = RIGHT;
        if ((millis() - lastSwitchPositionChange) &lt; SHAKE_SPEED_THRESHOLD) {
            lastSwitchPositionChange = millis();
            return true;
        }
        lastSwitchPositionChange = millis();
    }
    return false;
}

void keyPressed() {
    if (key == ' ') {
        erase();
    }
}

void erase() {
    fill(GRAY, GRAY_ALPHA);
    noStroke();
    rect(originX, originY-height, width+1, height+1);
    stroke(PEN_COLOR);
}

// Read current stylus X position relative to the origin.
int readStylusX() {
    int reading = arduino.analogRead(STYLUS_X_PIN);
    return (int)map((float)reading, 0f, 1023f, 0f, (float)width);
}

int smoothX(int v) {
    int index = frameCount % SMOOTH_BUFFER_SIZE;
    smoothBufferXSum -= smoothBufferX[index];
    smoothBufferXSum += v;
    smoothBufferX[index] = v;
    return (int)(smoothBufferXSum / SMOOTH_BUFFER_SIZE);
}

// Read current stylus Y position relative to the origin.
int readStylusY() {
    int reading = arduino.analogRead(STYLUS_Y_PIN);
    return (int)map((float)reading, 0f, 1023f, 0f, (float)height);
}

int smoothY(int v) {
    int index = frameCount % SMOOTH_BUFFER_SIZE;
    smoothBufferYSum -= smoothBufferY[index];
    smoothBufferYSum += v;
    smoothBufferY[index] = v;
    return (int)(smoothBufferYSum / SMOOTH_BUFFER_SIZE);
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2009/10/31/hack-a-sketch/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>LED Clock</title>
		<link>http://nootropicdesign.com/projectlab/2009/10/25/led-clock/</link>
		<comments>http://nootropicdesign.com/projectlab/2009/10/25/led-clock/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 03:53:10 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Arduino]]></category>

		<guid isPermaLink="false">http://nootropicdesign.com/projectlab/?p=30</guid>
		<description><![CDATA[I harvested this LED clock display from an ancient VCR and wrote an Arduino sketch to drive the display.  First I experimented with the leads to understand which leads controlled what behavior.  There are 4 digits on the display and there are 4 corresponding leads for positive voltage to drive them (the Arduino [...]]]></description>
			<content:encoded><![CDATA[<p>I harvested this LED clock display from an ancient VCR and wrote an Arduino sketch to drive the display.  First I experimented with the leads to understand which leads controlled what behavior.  There are 4 digits on the display and there are 4 corresponding leads for positive voltage to drive them (the Arduino pins connected with the resistors).  Then there are 7 ground pins (the yellow wires) that correspond to the seven segments on each digit (well, the leftmost digit only has 2 segments).  There&#8217;s also a pin for the colon but one of the LEDs is burned out.</p>
<div id="attachment_23" class="wp-caption alignnone" style="width: 650px"><img class="size-full wp-image-23" title="clockShield" src="http://nootropicdesign.com/projectlab/wp-content/uploads/2009/11/clockShield.jpg" alt="ClockShield!" width="640" height="480" /><p class="wp-caption-text">ClockShield!</p></div>
<p>This display is driven in a typical manner by multiplexing between the 7 segments of each digit.  The display is driven by sinking current on each of the seven segments in sequence, and sending current into the leads for any digit that needs to display that segment.  Ouch, that&#8217;s confusing, so I&#8217;ll give an example.  The first display ground pin (connected to pin 2 on the Arduino) is for the horizontal middle segment.  Some numbers need the horizontal middle segment turned on, right?  Numbers &#8216;0&#8242;, &#8216;2&#8242;, &#8216;3&#8242;, &#8216;4&#8242;, &#8216;5&#8242;, &#8216;6&#8242;, &#8216;8&#8242;, and &#8216;9&#8242;.  So, the code sets the ground pin for this segment to LOW (to sink current), and for each of the four digits that need that segment, we set the digit pin to HIGH.  If the number to display is &#8216;1027&#8242;, then when Arduino pin 2 is LOW (for the horizontal middle segment), we set the digit pins HIGH for the two middle digits (the &#8216;0&#8242; and the &#8216;2&#8242;).  Then we repeat this process for each of the 7 segments.  If we do it fast enough, then persistence of vision makes it look like the LEDs are all on at the same time.</p>
<p>If you are unfamiliar with this multiplexing I&#8217;ve tried to explain, then study the code for the sketch.  The array &#8216;number&#8217; contains the information about what segments need to be on for each number.  This might seem hard to understand at first, but I can guarantee an &#8220;ah ha!&#8221; moment when you get it.</p>
<pre class="codeblockscroll">// These are indexes into the groundPins array
#define MIDDLE 0
#define UPPER_L 1
#define LOWER_L 2
#define BOTTOM 3
#define LOWER_R 4
#define UPPER_R 5
#define TOP 6

int groundPins[7] = {2, 3, 4, 5, 6, 7, 8};
int digitPins[4] = {9, 10, 11, 12}; // positive voltage supply for each of the 4 digits
int ON = HIGH;
int OFF = LOW;
int number[10][7]; // holds information about which segments are needed for each of the 10 numbers
int digit[4]; // holds values for each of the 4 display digits

int hours = 12;
int minutes = 8;
int elapsedMinutes = 0;
int seconds = 0;

void setup()
{
  initNumber();

  for(int i=0; i &lt; 7; i++) {
    pinMode(groundPins[i], OUTPUT);
    digitalWrite(groundPins[i], HIGH);
  }
  for(int i=0; i &lt; 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], LOW);
  }
}

void loop() {
  int n = 0;
  unsigned long time = millis() - (elapsedMinutes * 60000);
  seconds = (time / 1000);
  if (seconds &gt; 60) {
    seconds = 0;
    minutes++;
    elapsedMinutes++;
    if (minutes &gt;= 60) {
      minutes = 0;
      hours++;
      if (hours &gt; 12) {
        hours = 1;
      }
    }
  }

  n = (hours * 100) + minutes;
  setDigit(n);

  for(int g=0; g &lt; 7; g++) {
    digitalWrite(groundPins[g], LOW);
    for(int i=0; i &lt; 4; i++) {
      if (digit[i] &lt; 0) {
        continue;
      }
      digitalWrite(digitPins[i], number[digit[i]][g]);
    }
    delay(getDelay());
    digitalWrite(groundPins[g], HIGH);
  }
}

void setDigit(int n) {
  n = n % 2000;
  digit[0] = n % 10;
  digit[1] = (n / 10) % 10;
  if ((digit[1] == 0) &amp;&amp; (n &lt; 10)) {
    digit[1] = -1;
  }
  digit[2] = (n / 100) % 10;
  if ((digit[2] == 0) &amp;&amp; (n &lt; 100)) {
    digit[2] = -1;
  }
  digit[3] = (n / 1000) % 10;
  if (digit[3] == 0) {
    digit[3] = -1;
  }
}

int getDelay() {
  if (millis() &gt; 10000) {
    return 0;
  } else {
    return (int) (((10000 - millis()) / 10000.0) * 125);
  }
} 

void initNumber() {
  number[0][MIDDLE]  = OFF;
  number[0][UPPER_L] = ON;
  number[0][LOWER_L] = ON;
  number[0][BOTTOM]  = ON;
  number[0][LOWER_R] = ON;
  number[0][UPPER_R] = ON;
  number[0][TOP]     = ON;

  number[1][MIDDLE]  = OFF;
  number[1][UPPER_L] = OFF;
  number[1][LOWER_L] = OFF;
  number[1][BOTTOM]  = OFF;
  number[1][LOWER_R] = ON;
  number[1][UPPER_R] = ON;
  number[1][TOP]     = OFF;

  number[2][MIDDLE]  = ON;
  number[2][UPPER_L] = OFF;
  number[2][LOWER_L] = ON;
  number[2][BOTTOM]  = ON;
  number[2][LOWER_R] = OFF;
  number[2][UPPER_R] = ON;
  number[2][TOP]     = ON;

  number[3][MIDDLE]  = ON;
  number[3][UPPER_L] = OFF;
  number[3][LOWER_L] = OFF;
  number[3][BOTTOM]  = ON;
  number[3][LOWER_R] = ON;
  number[3][UPPER_R] = ON;
  number[3][TOP]     = ON;

  number[4][MIDDLE]  = ON;
  number[4][UPPER_L] = ON;
  number[4][LOWER_L] = OFF;
  number[4][BOTTOM]  = OFF;
  number[4][LOWER_R] = ON;
  number[4][UPPER_R] = ON;
  number[4][TOP]     = OFF;

  number[5][MIDDLE]  = ON;
  number[5][UPPER_L] = ON;
  number[5][LOWER_L] = OFF;
  number[5][BOTTOM]  = ON;
  number[5][LOWER_R] = ON;
  number[5][UPPER_R] = OFF;
  number[5][TOP]     = ON;

  number[6][MIDDLE]  = ON;
  number[6][UPPER_L] = ON;
  number[6][LOWER_L] = ON;
  number[6][BOTTOM]  = ON;
  number[6][LOWER_R] = ON;
  number[6][UPPER_R] = OFF;
  number[6][TOP]     = ON;

  number[7][MIDDLE]  = OFF;
  number[7][UPPER_L] = OFF;
  number[7][LOWER_L] = OFF;
  number[7][BOTTOM]  = OFF;
  number[7][LOWER_R] = ON;
  number[7][UPPER_R] = ON;
  number[7][TOP]     = ON;

  number[8][MIDDLE]  = ON;
  number[8][UPPER_L] = ON;
  number[8][LOWER_L] = ON;
  number[8][BOTTOM]  = ON;
  number[8][LOWER_R] = ON;
  number[8][UPPER_R] = ON;
  number[8][TOP]     = ON;

  number[9][MIDDLE]  = ON;
  number[9][UPPER_L] = ON;
  number[9][LOWER_L] = OFF;
  number[9][BOTTOM]  = ON;
  number[9][LOWER_R] = ON;
  number[9][UPPER_R] = ON;
  number[9][TOP]     = ON;
}</pre>
<p>Now for the fun.  The <span class="code">getDelay()</span> method returns a delay based on how long the sketch has been running.  First we start with a longer delay (125ms) between each segment so you can see visually how the digits are being rendered.  Over the course of 10 seconds, we reduce the delay to 0.  This way you can see exactly how quickly rendering the display causes you to see the digits without ficker even though each segment is being displayed separately!  Cool, huh?</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="480" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=7495527&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="640" height="480" src="http://vimeo.com/moogaloop.swf?clip_id=7495527&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=ff9933&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><a href="http://vimeo.com/7495527">LEDClock</a> from <a href="http://vimeo.com/user2564885">nootropicdesign</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nootropicdesign.com/projectlab/2009/10/25/led-clock/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
