CarBot - My first Robot

I was looking around for a basis for a wall-follower and I came across a battery operated car that originally had a wire-attached controller with two C-cells in it. Much dicking around later I present... CarBot.

The original motors are being driven by a little motor-driver board from robotshop which is sitting on a proto-shield on top of my arduino. There's a seeed studio ultrasonic rangefinder up front for object avoidance.

Once I had built and programmed the thing I discovered that it was very similar in intent and components to "Makey" from Make magazine. I quickly ripped off the software and changed the pins etc to suit my details.

/*
 * CarBot roams around, while avoiding objects
 * sensed with the Seeed ultrasonic rangefinder.
 * Thanks to:
 * Makey Robot, MAKE Magazine, Volume 19, p. 77
 * Created: June 2009 Kris Magri
  adapted from the program 06_Object_Avoidance
 */
#include <Streaming.h>
#define cout Serial
#define endl '\n'
  #define pingPin       4      // Seeed ultrasonic sensor on pin D4.
  #define leftSpeedPin 10      // Left motor speed control, to PWM_A
  #define leftDir1      18      // Left motor direction 1, to AIn1
  #define leftDir2      17      // Left motor direction 2, to AIn2
  #define rightDir1     15      // Right motor direction 1, to BIn1
  #define rightDir2     16      // Right motor direction 2, to BIn2
  #define rightSpeedPin 11      // Right motor speed control, to PWM_B 
  #define basespeed     92      //default speed
  #define BOUNDARY     30      // (cm) Avoid objects closer than 30cm.
  #define INTERVAL     25      // (ms) Interval between distance readings.
                               // at 250 cm/s that's 6 cm
volatile unsigned long notstalled; // last time we know the robot was moving

void setup()                                                 
{
  pinMode(leftDir1, OUTPUT);        // Set motor direction pins as outputs.
  pinMode(leftDir2, OUTPUT);      
  pinMode(rightDir1, OUTPUT);      
  pinMode(rightDir2, OUTPUT); 

  analogWrite(leftSpeedPin,basespeed); //limit the speed of CarBot
  analogWrite(rightSpeedPin,basespeed);
  attachInterrupt(0,stallchecker,FALLING);
  Serial.begin(19200); //just what my xbees are set to

}
void stallchecker(){ //check to see if the robot is stuck
notstalled=millis(); //record the time of the wheelpass
}

// Main program
// Roam around while avoiding objects.
// 
// Set motors to move forward,
// Take distance readings over and over, 
// as long as no objects are too close (determined by BOUNDARY).
// If object is too close, avoid it -- back up and turn.
// Repeat.

void loop()                     
{
  long distance;                    // Distance reading from rangefinder.
  
  forward();                        // Robot moves forward continuously.
  do 
  {
   delay(INTERVAL);                // Delay between readings.
    distance = readDistance();      // Take a distance reading.
    cout <<" f"<<distance;
    Serial.println(distance);       // Print it out.             
   }
  while((distance >= BOUNDARY)&& //loop til an object is sensed
       ((millis()-notstalled)<1000)); //or the wheels stop moving     

  if ((millis()-notstalled)<=1000){ //if it's just an object
    cout <<endl<<"bkp "<<endl;
    backward();                       // Move backward 750ms.
    delay(750);               
    leftTurn(300);}                   // Turn left 300ms.
  else{ //robot has stalled
      cout<< '\n' <<"stalled" << '\n';
      backward(); delay(1000); //longer backup
      leftTurn(500);                   // bigger turn
  }
}// end Main program


// forward
//
// Move robot forward by setting both wheels forward.
// Will persist until something else changes the
// motors' directions.

void forward() //designations confirmed dec 4
{
  digitalWrite(leftDir1, LOW);      // Left motor forward.             
  digitalWrite(leftDir2, HIGH);
  digitalWrite(rightDir1, LOW);     // Right motor forward.
  digitalWrite(rightDir2, HIGH);
}  


// backward
//
// Move robot backward by setting both wheels backward.
// Will persist until something else changes the
// motors' directions.

void backward()
{
  digitalWrite(leftDir1, HIGH);     // Left motor backward.
  digitalWrite(leftDir2, LOW);
  digitalWrite(rightDir1, HIGH);    // Right motor backward.
  digitalWrite(rightDir2, LOW);
}


// leftTurn
//
// Turn robot to left by moving wheels in opposite directions.
// Amount of turning is determined by duration argument (ms).

void leftTurn(int duration)
{
  digitalWrite(leftDir1, HIGH);     // Left motor backward.
  digitalWrite(leftDir2, LOW);
  digitalWrite(rightDir1, LOW);     // Right motor forward.
  digitalWrite(rightDir2, HIGH);
  delay(duration);                  // Turning time (ms).
}


// readDistance
// Take a distance reading from Ping ultrasonic rangefinder.
// from http://arduino.cc/en/Tutorial/Ping?from=Tutorial.UltrasoundSensor
 
long readDistance()
{
  long duration, inches, cm;

  // The sensor is triggered by a HIGH pulse of 2 or more microseconds.
  // We give a short LOW pulse beforehand to ensure a clean HIGH pulse.
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(15);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(20);

  // The same pin is used to read the signal from the Ping: a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // Convert the time into a distance.
  cm = microsecondsToCentimeters(duration);
  return(cm);
}

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

Hardly a harbinger of the robot apocalypse but I've learned a lot. I'm planning to install a second sensor to make a wall racer and build another version with a servo to scan with the sensor. I also got a pololu baby orangutan controller which, incredibly to me, should replace the arduino, proto-shield and motor driver board. With this I can either have CarBot regain his wheelie capabilities or simplify my next platform.

This was my original inspiration: http://letsmakerobots.com/node/928

and here's makey, my accidental software developer: Make: Projects

Nice car. It's good to see Makey getting some love. I still use the PING sweep out of that sketch all of the time.

Nice work dude!