ProtoCylon: It’s ALIVE
By Bobby Neal Winters
I wasn’t exactly in a laboratory over a cadaver coaxing the lightning to come it; I didn’t exactly have a hunchback named Igor by my side; but I do have some idea of the elation Dr. Frankenstein may have felt in those first few moments.
It he hadn’t been a fictional character, that is.
Along the way in this adventure, I continually referred to the simple-sounding model that organizes my thought so well: Input, Processing, and Output. The processing consists of writing computer programs and that scares a lot of people, but throughout my adventure--for that is what is has been, an adventure--the Input and Output have been the most difficult. And of those two, Input has been by far the harder.
In Muscles on the Beast, I had put my robot body together and it would roll, but only with a preprogrammed script. It had null input; it simply had processing and output. At that time, I was debating whether to have it process input from ultrasonic sensors or to make it into a line following robot.
I decided to do the easiest; big surprise there. I made into a bat. It receives input from ultrasonic sensors. The heuristic for this robot is for it to go straight ahead until it runs into a wall and then to turn until it gets free. It tries turning one direction three times and if it is still caught it will try the other. It will continue in this way until it is either free or its batteries run out.
#include
#define FULL_SPEED 256
#define TRAPPED_DIST 10
// motor pins
int speed1=3;
int speed2=11;
int direction1=12;
int direction2=13;
//distance Sensor pins
const int pingPin =4;
int inPin=2;
//variables concerning distance
int myDist;
boolean trapped;
void setup(){
setMotorPins();
setSensorPins();
}
void loop(){
//How far is the next obstacle?
myDist=getDistance();
//If it is too close, I am trapped
trapped=(myDist
switch(trapped){
case true:
//If I am trapped, begin the struggle
getFree();
case false:
//If I am not trapped, then quarter speed ahead
goStraight(0.25,0.5);
break;
}
}
void setMotorPins(){
pinMode(speed1,OUTPUT);
pinMode(speed2,OUTPUT);
pinMode(direction1,OUTPUT);
pinMode(direction2,OUTPUT);
return;
}
void setSensorPins(){
pinMode(pingPin,OUTPUT);
return;
}
long getDistance(){
long duration, cm;
digitalWrite(pingPin,LOW);
delayMicroseconds(2);
digitalWrite(pingPin,HIGH);
delayMicroseconds(5);
digitalWrite(pingPin,LOW);
pinMode(inPin, INPUT);
//How long does it take for my pings to get back.
duration=pulseIn(inPin,HIGH);
//How far is the next obstacle?
cm=microsecondsToCentimeters(duration);
return cm;
}
void goStraight(float prop, float seconds){
//prop is the proportion of full speed
int rate=prop*FULL_SPEED;
//Convert to microseconds
int duration=1000*seconds;
//Use both wheels
digitalWrite(direction1,HIGH);
digitalWrite(direction2,HIGH);
analogWrite(speed1,rate);
analogWrite(speed2,rate);
//Run awhile before we do anything else.
delay(duration);
return;
}
void goTurn(int dir, float seconds){
//We will only turn at half speed
float prop=0.5;
int rate=prop*FULL_SPEED;
//How long will we turn?
int duration=1000*seconds;
//Switch between the various directions.
switch(dir){
case 1:
digitalWrite(direction1,HIGH);
digitalWrite(direction2,LOW);
analogWrite(speed1,rate);
analogWrite(speed2,0);
break;
case 2:
digitalWrite(direction1,LOW);
digitalWrite(direction2,HIGH);
analogWrite(speed1,0);
analogWrite(speed2,rate);
break;
default:
return;
}
delay(duration);
return;
}
void stopMotor(int seconds){
analogWrite(speed1,0);
analogWrite(speed2,0);
delay(1000*seconds);
return;
}
long microsecondsToCentimeters(long microseconds)
{
return microseconds / 29 / 2;
}
void getFree(){
//First try one direction
int sense=0;
int count=0;
//Struggle until no longer trapped.
while(trapped){
++count;
goTurn(sense+1,1);
if(count>3){
count=0;
//Struggle in one direction three times and then try the other.
++sense;
sense=sense % 2;
}
myDist=getDistance();
trapped=(myDist < TRAPPED_DIST);
}
return;
}