{"id":87,"date":"2010-03-04T21:47:05","date_gmt":"2010-03-05T03:47:05","guid":{"rendered":"http:\/\/nootropicdesign.com\/projectlab\/?p=87"},"modified":"2018-11-02T09:22:47","modified_gmt":"2018-11-02T14:22:47","slug":"wireless-robotics-platform","status":"publish","type":"post","link":"https:\/\/nootropicdesign.com\/projectlab\/2010\/03\/04\/wireless-robotics-platform\/","title":{"rendered":"Wireless Robotics Platform: Cheap R\/C Vehicle + Arduino + XBee + Processing"},"content":{"rendered":"<p><strong><em>Difficulty Level = 8<\/em><\/strong>  <a href=\"\/projectlab\/difficulty-levels\/\">[What&#8217;s this?]<\/a><\/p>\n<p><span class=\"highlight\">UPDATE: <\/span><a href=\"https:\/\/nootropicdesign.com\/projectlab\/2012\/02\/18\/xbee-robotics-platform\/\">Check out the new robotics platform project!<\/a><\/p>\n<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>\n<div id=\"attachment_91\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverLeftFront1.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-91\" class=\"size-full wp-image-91\" title=\"roverLeftFront1_m\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverLeftFront1_m.jpg\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverLeftFront1_m.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverLeftFront1_m-300x225.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-91\" class=\"wp-caption-text\">Wireless computer-controlled robotics platform built on cheap RC vehicle, Arduino microcontroller, and XBee radios<\/p><\/div>\n<p\/>\n<p\/>\nBefore I get into details, here&#8217;s an overview of the features:<\/p>\n<ul>\n<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>\n<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>\n<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>\n<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>\n<li>Power: Vehicle motors powered by 4 AA batteries.  Arduino with XBee shield powered by 9V battery mounted at front of vehicle.<\/li>\n<li>Simple communications protocol: 2 byte commands from controller to vehicle, one byte sensor readings from vehicle to controller.<\/li>\n<\/ul>\n<p><\/p>\n<h3>The Hardware<\/h3>\n<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 \/>\n<div id=\"attachment_90\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverTopView.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-90\" class=\"size-full wp-image-90\" title=\"roverTopView_m\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverTopView_m.jpg\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverTopView_m.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverTopView_m-300x225.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-90\" class=\"wp-caption-text\">Arduino and XBee shield on top of the vehicle<\/p><\/div><\/p>\n<p\/>\n<p\/>\nInside the vehicle is a simple circuit board with an SN754410 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 \/>\n<!--more--><br \/>\n<div id=\"attachment_102\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/motorController.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-102\" class=\"size-full wp-image-102\" title=\"motorController\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/motorController.jpg\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/motorController.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/motorController-300x225.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-102\" class=\"wp-caption-text\">Small circuit board with dual H-Bridge chip connected to drive motor and turn motor<\/p><\/div><\/p>\n<p\/>\n<p\/>\nThe 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 \/>\n<div id=\"attachment_100\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/transmitter.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-100\" class=\"size-full wp-image-100\" title=\"transmitter\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/transmitter.jpg\" alt=\"\" width=\"640\" height=\"460\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/transmitter.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/transmitter-300x215.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><p id=\"caption-attachment-100\" class=\"wp-caption-text\">Transmitter on controller computer.  FTDI USB board and XBee radio.<\/p><\/div><\/p>\n<p\/>\n<p\/>\nHere&#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 \/>\n<div id=\"attachment_86\" style=\"width: 650px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverRearSensor-e1263768084116.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-86\" class=\"size-full wp-image-86\" title=\"roverRearSensor\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/roverRearSensor-e1263768084116.jpg\" alt=\"\" width=\"640\" height=\"480\" \/><\/a><p id=\"caption-attachment-86\" class=\"wp-caption-text\">Rear collision sensor microswitch<\/p><\/div><\/p>\n<p><\/p>\n<h3>The Code<\/h3>\n<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 \/>\nIf 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>\n<pre class=\"codeblockscroll\">\r\n\r\n\/\/ Pin assignments\r\n#define LEFT_PIN 13         \/\/ red\/black\r\n#define TURN_ENABLE_PIN 12  \/\/ white\r\n#define DRIVE_ENABLE_PIN 11 \/\/ white\/black\r\n#define RIGHT_PIN 10        \/\/ red\r\n#define BACKWARD_PIN 9      \/\/ yellow\/black\r\n#define FORWARD_PIN 8       \/\/ yellow\r\n\r\n#define LEFT_FRONT_BUMPER_PIN 7     \/\/ white\r\n#define RIGHT_FRONT_BUMPER_PIN 6    \/\/ yellow\r\n#define REAR_BUMPER_PIN 5           \/\/ red\r\n\r\n\/\/ Input Commands\r\n#define BEGIN_COMMAND 0x7F\r\n#define FORWARD 0x1\r\n#define BACKWARD 0x2\r\n#define LEFT 0x4\r\n#define RIGHT 0x8\r\n\r\n\/\/ Sensor Data\r\n#define LEFT_FRONT_BUMPER 0x1\r\n#define RIGHT_FRONT_BUMPER 0x2\r\n#define REAR_BUMPER 0x4\r\n#define DEBOUNCE_THRESHOLD 50\r\n\r\n\r\nint sensorData = 0;\r\nint lastSensorData = 0;\r\nint lastLeftFrontBumperReading;\r\nint lastRightFrontBumperReading;\r\nint lastRearBumperReading;\r\nint leftFrontBumperReadingTime;\r\nint rightFrontBumperReadingTime;\r\nint rearBumperReadingTime;\r\nint command[2];\r\n\r\nvoid setup() {\r\n  Serial.begin(9600);\r\n\r\n  pinMode(DRIVE_ENABLE_PIN, OUTPUT);\r\n  pinMode(TURN_ENABLE_PIN, OUTPUT);\r\n  pinMode(LEFT_PIN, OUTPUT);\r\n  pinMode(RIGHT_PIN, OUTPUT);\r\n  pinMode(BACKWARD_PIN, OUTPUT);\r\n  pinMode(FORWARD_PIN, OUTPUT);\r\n\r\n  pinMode(LEFT_FRONT_BUMPER_PIN, INPUT);\r\n  digitalWrite(LEFT_FRONT_BUMPER_PIN, HIGH);\r\n  pinMode(RIGHT_FRONT_BUMPER_PIN, INPUT);\r\n  digitalWrite(RIGHT_FRONT_BUMPER_PIN, HIGH);\r\n  pinMode(REAR_BUMPER_PIN, INPUT);\r\n  digitalWrite(REAR_BUMPER_PIN, HIGH);\r\n\r\n}\r\n\r\nvoid loop() {\r\n\r\n  \/\/ Read sensors and transmit\r\n  readSensors();\r\n  if (sensorData != lastSensorData) {\r\n    Serial.write(sensorData);\r\n    lastSensorData = sensorData;\r\n  }\r\n\r\n\r\n  \/\/ listen for wireless commands\r\n  if (Serial.available() > 0) {\r\n    if (readCommand() > 0) {\r\n      executeCommand();\r\n    }\r\n  }\r\n}\r\n\r\n\r\nvoid readSensors() {\r\n  int s;\r\n\r\n  s = digitalRead(LEFT_FRONT_BUMPER_PIN);\r\n  if (s != lastLeftFrontBumperReading) {\r\n    leftFrontBumperReadingTime = millis();\r\n  }\r\n  if ((millis() - leftFrontBumperReadingTime) > DEBOUNCE_THRESHOLD) {\r\n    if (s == LOW) {\r\n      sensorData |= LEFT_FRONT_BUMPER;\r\n    } else {\r\n      sensorData &= ~LEFT_FRONT_BUMPER;\r\n    }\r\n  }\r\n  lastLeftFrontBumperReading = s;\r\n\r\n  s = digitalRead(RIGHT_FRONT_BUMPER_PIN);\r\n  if (s != lastRightFrontBumperReading) {\r\n    rightFrontBumperReadingTime = millis();\r\n  }\r\n  if ((millis() - rightFrontBumperReadingTime) > DEBOUNCE_THRESHOLD) {\r\n    if (s == LOW) {\r\n      sensorData |= RIGHT_FRONT_BUMPER;\r\n    } else {\r\n      sensorData &= ~RIGHT_FRONT_BUMPER;\r\n    }\r\n  }\r\n  lastRightFrontBumperReading = s;\r\n\r\n  s = digitalRead(REAR_BUMPER_PIN);\r\n  if (s != lastRearBumperReading) {\r\n    rearBumperReadingTime = millis();\r\n  }\r\n  if ((millis() - rearBumperReadingTime) > DEBOUNCE_THRESHOLD) {\r\n    if (s == LOW) {\r\n      sensorData |= REAR_BUMPER;\r\n    } else {\r\n      sensorData &= ~REAR_BUMPER;\r\n    }\r\n  }\r\n  lastRearBumperReading = s;\r\n}\r\n\r\nint readCommand() {\r\n  int b = Serial.read();\r\n  if (b == BEGIN_COMMAND) {\r\n    command[0] = readByte();\r\n    command[1] = readByte();\r\n    return 1;\r\n  } else {\r\n    return 0;\r\n  }\r\n}\r\n\r\n\/\/ blocking read\r\nint readByte() {\r\n  while (true) {\r\n    if (Serial.available() > 0) {\r\n      return Serial.read();\r\n    }\r\n  }\r\n}\r\n\r\nvoid executeCommand() {\r\n  int c = command[0];\r\n  int speed = command[1];\r\n\r\n  digitalWrite(DRIVE_ENABLE_PIN, LOW);\r\n  if (c & FORWARD) {\r\n    digitalWrite(BACKWARD_PIN, LOW);\r\n    digitalWrite(FORWARD_PIN, HIGH);\r\n  }\r\n  if (c & BACKWARD) {\r\n    digitalWrite(FORWARD_PIN, LOW);\r\n    digitalWrite(BACKWARD_PIN, HIGH);\r\n  }\r\n  if (c & (FORWARD | BACKWARD)) {\r\n    analogWrite(DRIVE_ENABLE_PIN, speed);\r\n  }\r\n\r\n  digitalWrite(TURN_ENABLE_PIN, LOW);\r\n  if (c & LEFT) {\r\n    digitalWrite(RIGHT_PIN, LOW);\r\n    digitalWrite(LEFT_PIN, HIGH);\r\n  }\r\n  if (c & RIGHT) {\r\n    digitalWrite(LEFT_PIN, LOW);\r\n    digitalWrite(RIGHT_PIN, HIGH);\r\n  }\r\n  if (c & (LEFT | RIGHT)) {\r\n    digitalWrite(TURN_ENABLE_PIN, HIGH);\r\n  }\r\n}\r\n\r\n<\/pre>\n<p><\/p>\n<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>\n<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>\n<pre class=\"codeblock\">\r\nvoid draw() {\r\n\r\n   ...\r\n\r\n  speed = 9;  \/\/ set speed value.  Valid values are 0-9.\r\n  forward(1000);  \/\/ go forward for 1000ms (one second)\r\n  stop();\r\n  right();  \/\/ turn wheels\r\n  backward(500);  \/\/ backward for half a second\r\n  left();\r\n  speed = 5;\r\n  backward(500);\r\n  stop();\r\n  forward(2000);\r\n  \/\/  you get the idea...\r\n\r\n  straight();  \/\/ wheels straight\r\n  end();  \/\/ end the program.  Without this, it repeats.\r\n}\r\n<\/pre>\n<p>\nWhat 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>\n<pre class=\"codeblock\">\r\nvoid draw() {\r\n\r\n  if (rightFrontBumper) {\r\n    println(timestamp() + \" ----RIGHT FRONT IMPACT!----\");\r\n    rightFrontBumper();\r\n  }\r\n  if (leftFrontBumper) {\r\n    println(timestamp() + \" ----LEFT FRONT IMPACT!-----\");\r\n    leftFrontBumper();\r\n  }\r\n  if (rearBumper) {\r\n    println(timestamp() + \"-------REAR IMPACT!--------\");\r\n    rearBumper();\r\n  }\r\n\r\n  speed = 9;  \/\/ set speed value.  Valid values are 0-9.\r\n  forward(1000);  \/\/ go forward for 1000ms (one second)\r\n  stop();\r\n  right();  \/\/ turn wheels\r\n  backward(500);\r\n  left();\r\n  speed = 5;\r\n  backward(500);\r\n  stop();\r\n  forward(2000);\r\n  \/\/  you get the idea...\r\n\r\n  straight();  \/\/ wheels straight\r\n  end();  \/\/ end the program.  Without this, it repeats.\r\n}\r\n\r\nvoid leftFrontBumper() {\r\n  leftFrontBumper = false;\r\n  running = true;\r\n  left();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\n\r\nvoid rightFrontBumper() {\r\n  rightFrontBumper = false;\r\n  running = true;\r\n  right();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\n\r\nvoid rearBumper() {\r\n  rearBumper = false;\r\n  running = true;\r\n  right();\r\n  speed = 9;\r\n  forward(1000);\r\n  straight();\r\n  end();\r\n}\r\n\r\n<\/pre>\n<p><\/p>\n<p>You can start your program again by pressing the &#8216;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>\n<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>\n<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>\n<pre class=\"codeblockscroll\">\r\nimport processing.serial.*;\r\n\r\nSerial port = null;\r\nString portName;\r\nint lastInput = 0;\r\nint[] command = new int[2];\r\nint[] lastCommand = new int[2];\r\nint speed = 9;\r\nint lastSpeed = 0;\r\nint speedStep = (255 - 130) \/ 8;\r\nboolean running = true;\r\nboolean leftFrontBumper = false;\r\nboolean rightFrontBumper = false;\r\nboolean rearBumper = false;\r\n\r\nint DIR_FORWARD = 0x1;\r\nint DIR_BACKWARD = 0x2;\r\nint DIR_LEFT = 0x4;\r\nint DIR_RIGHT = 0x8;\r\nint BEGIN_COMMAND = 0x7F;\r\n\r\n\/\/ Sensor Data\r\nint LEFT_FRONT_BUMPER = 0x1;\r\nint RIGHT_FRONT_BUMPER = 0x2;\r\nint REAR_BUMPER = 0x4;\r\n\r\nSimpleDateFormat df = new SimpleDateFormat(\"hh:mm:ss.SSS\");\r\n\r\nvoid setup() {\r\n  size(1, 1);\r\n\r\n  portName = Serial.list()[0];\r\n  try {\r\n    port = new Serial(this, portName, 9600);\r\n  } catch (Exception e) {\r\n    e.printStackTrace();\r\n  }\r\n}\r\n\r\nString timestamp() {\r\n  return df.format(new Date());\r\n}\r\n\r\nvoid draw() {\r\n\r\n  if (rightFrontBumper) {\r\n    println(timestamp() + \" ----RIGHT FRONT IMPACT!----\");\r\n    rightFrontBumper();\r\n  }\r\n  if (leftFrontBumper) {\r\n    println(timestamp() + \" ----LEFT FRONT IMPACT!-----\");\r\n    leftFrontBumper();\r\n  }\r\n  if (rearBumper) {\r\n    println(timestamp() + \" -------REAR IMPACT!--------\");\r\n    rearBumper();\r\n  }\r\n\r\n  speed = 9;\r\n  left();\r\n  forward(1200);\r\n  right();\r\n  forward(800);\r\n  stop();\r\n\r\n  left();\r\n  backward(1200);\r\n  stop();\r\n  right();\r\n\r\n  forward(2500);\r\n  stop();\r\n\r\n  left();\r\n  backward(4000);\r\n\r\n  end();\r\n}\r\n\r\nvoid leftFrontBumper() {\r\n  leftFrontBumper = false;\r\n  running = true;\r\n\r\n  left();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\n\r\nvoid rightFrontBumper() {\r\n  rightFrontBumper = false;\r\n  running = true;\r\n\r\n  right();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\nvoid rearBumper() {\r\n  rearBumper = false;\r\n  running = true;\r\n\r\n  speed = 9;\r\n  forward(1000);\r\n  straight();\r\n  end();\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\nvoid end() {\r\n  if (!running) return;\r\n  stop();\r\n  straight();\r\n  println(timestamp() + \" -----------END------------\");\r\n  println(\"Press 's' to restart program or use arrow keys to control vehicle.\");\r\n  running = false;\r\n}\r\n\r\nvoid interruptibleDelay(int millis) {\r\n  int start = millis();\r\n  int d;\r\n  while (running) {\r\n    int timeLeftToWait = millis-(millis()-start);\r\n    d = min(10, timeLeftToWait);\r\n    if (d <= 0) return;\r\n    delay(d);\r\n  }\r\n}\r\n\r\n\r\nvoid forward(int millis) {\r\n  if (!running) return;\r\n  forward();\r\n  interruptibleDelay(millis);\r\n  stop();\r\n}\r\n\r\nvoid forward() {\r\n  if (!running) return;\r\n  doForward();\r\n}\r\n\r\nvoid doForward() {\r\n  command[0] = command[0] &#038; ~DIR_BACKWARD;\r\n  command[0] = command[0] | DIR_FORWARD;\r\n  sendCommand();\r\n}\r\n\r\nvoid backward(int millis) {\r\n  if (!running) return;\r\n  doBackward();\r\n  interruptibleDelay(millis);\r\n  stop();\r\n}\r\n\r\nvoid backward() {\r\n  if (!running) return;\r\n  doBackward();\r\n}\r\n\r\nvoid doBackward() {\r\n  command[0] = command[0] &#038; ~DIR_FORWARD;\r\n  command[0] = command[0] | DIR_BACKWARD;\r\n  sendCommand();\r\n}\r\n\r\nvoid left() {\r\n  if (!running) return;\r\n  doLeft();\r\n}\r\n\r\nvoid doLeft() {\r\n  command[0] = command[0] &#038; ~DIR_RIGHT;\r\n  command[0] = command[0] | DIR_LEFT;\r\n  sendCommand();\r\n}\r\n\r\nvoid right() {\r\n  if (!running) return;\r\n  doRight();\r\n}\r\n\r\nvoid doRight() {\r\n  command[0] = command[0] &#038; ~DIR_LEFT;\r\n  command[0] = command[0] | DIR_RIGHT;\r\n  sendCommand();\r\n}\r\n\r\nvoid straight() {\r\n  if (!running) return;\r\n  doStraight();\r\n}\r\n\r\nvoid doStraight() {\r\n  command[0] = command[0] &#038; ~DIR_RIGHT;\r\n  command[0] = command[0] &#038; ~DIR_LEFT;\r\n  sendCommand();\r\n}\r\n\r\nvoid stop() {\r\n  if (!running) return;\r\n  doStop();\r\n}\r\nvoid doStop() {\r\n  command[0] = command[0] &#038; ~DIR_BACKWARD;\r\n  command[0] = command[0] &#038; ~DIR_FORWARD;\r\n  sendCommand();\r\n}\r\n\r\n\r\n\r\nvoid serialEvent(Serial p) {\r\n  int input = p.read();\r\n  lastInput = input;\r\n  processInput(input);\r\n} \r\n\r\n\r\nvoid processInput(int input) {\r\n  if ((input &#038; LEFT_FRONT_BUMPER) != 0) {\r\n    stop();\r\n    leftFrontBumper = true;\r\n    running = false;\r\n  }\r\n\r\n  if ((input &#038; RIGHT_FRONT_BUMPER) != 0) {\r\n    stop();\r\n    rightFrontBumper = true;\r\n    running = false;\r\n  }\r\n\r\n  if ((input &#038; REAR_BUMPER) != 0) {\r\n    stop();\r\n    rearBumper = true;\r\n    running = false;\r\n  }\r\n}\r\n\r\n\r\nvoid sendCommand() {\r\n  if (!isNewCommand()) {\r\n    return;\r\n  }\r\n  if (port != null) {\r\n    port.write(BEGIN_COMMAND);\r\n    port.write(command[0]);\r\n    command[1] = 255 - ((9 - speed) * speedStep);\r\n    port.write(command[1]);\r\n    if ((command[0] &#038; DIR_FORWARD) > 0) {\r\n      print(timestamp() + \" FORWARD\\t\");\r\n    }\r\n    if ((command[0] & DIR_BACKWARD) > 0) {\r\n      print(timestamp() + \" BACKWARD\\t\");\r\n    }\r\n    if (((command[0] & DIR_FORWARD) == 0) && ((command[0] & DIR_BACKWARD) == 0)) {\r\n      print(timestamp() + \" STOP\\t\");\r\n    }\r\n    if ((command[0] & DIR_LEFT) > 0) {\r\n      print(\"LEFT\\t\");\r\n    }\r\n    if ((command[0] & DIR_RIGHT) > 0) {\r\n      print(\"RIGHT\\t\");\r\n    }\r\n    if (((command[0] & DIR_LEFT) == 0) && ((command[0] & DIR_RIGHT) == 0)) {\r\n      print(\"STRAIGHT\\t\");\r\n    }\r\n    println(\"SPEED=\" + speed);\r\n    \r\n\r\n    lastCommand[0] = command[0];\r\n    lastCommand[1] = command[1];\r\n    lastSpeed = speed;\r\n  }\r\n}\r\n\r\nboolean isNewCommand() {\r\n  return ((command[0] != lastCommand[0]) || (command[1] != lastCommand[1]) || (speed != lastSpeed));\r\n}\r\n\r\nvoid keyPressed() {\r\n  if (key == CODED) {\r\n    if (keyCode == UP) {\r\n      doForward();\r\n    }\r\n    if (keyCode == DOWN) {\r\n      doBackward();\r\n    }\r\n    if (keyCode == LEFT) {\r\n      doLeft();\r\n    }\r\n    if (keyCode == RIGHT) {\r\n      doRight();\r\n    }\r\n  }\r\n  if ((key >= '1') && (key <= '9')) {\r\n    speed = 9 - ('9' - key);\r\n    println(\"set speed = \" + speed);\r\n  }\r\n  if (key == 's') {\r\n    running = true;\r\n  }\r\n}\r\n\r\nvoid keyReleased() {\r\n  if (key == CODED) {\r\n    if (keyCode == UP) {\r\n      doStop();\r\n    }\r\n    if (keyCode == DOWN) {\r\n      doStop();\r\n    }\r\n    if (keyCode == LEFT) {\r\n      doStraight();\r\n    }\r\n    if (keyCode == RIGHT) {\r\n      doStraight();\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<h3>Demo<\/h3>\n<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>\n<pre class=\"codeblockscroll\">\r\nvoid draw() {\r\n\r\n  if (rightFrontBumper) {\r\n    println(timestamp() + \" ----RIGHT FRONT IMPACT!----\");\r\n    rightFrontBumper();\r\n  }\r\n  if (leftFrontBumper) {\r\n    println(timestamp() + \" ----LEFT FRONT IMPACT!-----\");\r\n    leftFrontBumper();\r\n  }\r\n  if (rearBumper) {\r\n    println(timestamp() + \" -------REAR IMPACT!--------\");\r\n    rearBumper();\r\n  }\r\n\r\n  speed = 9;\r\n  left();\r\n  forward(1200);\r\n  right();\r\n  forward(800);\r\n  stop();\r\n\r\n  left();\r\n  backward(1200);\r\n  stop();\r\n  right();\r\n\r\n  forward(2500);\r\n  stop();\r\n\r\n  left();\r\n  backward(4000);\r\n\r\n  end();\r\n}\r\n\r\nvoid leftFrontBumper() {\r\n  leftFrontBumper = false;\r\n  running = true;\r\n\r\n  left();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\n\r\nvoid rightFrontBumper() {\r\n  rightFrontBumper = false;\r\n  running = true;\r\n\r\n  right();\r\n  speed = 9;\r\n  backward(800);\r\n  straight();\r\n  end();\r\n}\r\n\r\nvoid rearBumper() {\r\n  rearBumper = false;\r\n  running = true;\r\n\r\n  speed = 9;\r\n  forward(1000);\r\n  straight();\r\n  end();\r\n}\r\n<\/pre>\n<p\/>\nLet'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.<\/p>\n<p\/>\n<iframe loading=\"lazy\" width=\"640\" height=\"505\" src=\"https:\/\/www.youtube.com\/embed\/WPEL6stR_dg\" frameborder=\"0\" gesture=\"media\" allow=\"encrypted-media\" allowfullscreen><\/iframe><\/p>\n<p\/>\nFinally, here's a screenshot of the Processing console that shows everything that happened.  Notice the rear impact event at the end.<\/p>\n<p\/>\n<a href=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/vehicleControllerConsole.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/vehicleControllerConsole.jpg\" alt=\"\" title=\"vehicleControllerConsole\" width=\"640\" height=\"297\" class=\"alignnone size-full wp-image-122\" srcset=\"https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/vehicleControllerConsole.jpg 640w, https:\/\/nootropicdesign.com\/projectlab\/wp-content\/uploads\/2010\/01\/vehicleControllerConsole-300x139.jpg 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p\/>\n<p\/>\nHope 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>\n","protected":false},"excerpt":{"rendered":"<p>Difficulty Level = 8 [What&#8217;s this?] UPDATE: Check out the new robotics platform project! 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 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[3,6,5],"tags":[],"class_list":["post-87","post","type-post","status-publish","format-standard","hentry","category-arduino","category-robotics","category-xbee"],"_links":{"self":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/comments?post=87"}],"version-history":[{"count":52,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/87\/revisions"}],"predecessor-version":[{"id":1975,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/posts\/87\/revisions\/1975"}],"wp:attachment":[{"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/media?parent=87"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/categories?post=87"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nootropicdesign.com\/projectlab\/wp-json\/wp\/v2\/tags?post=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}