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