Roving robot

I built a roving robot, I call it "Marvin" since it just drives around and not do anything apart from occasionally colliding into stuff.

It uses a ultrasonic sensor for distance, two converted servos for driving the wheels, and another servo for rotating the sensor.

Here's a picture:

And a video clip of it in action with an old navigation algorithm:

http://video.google.com/videoplay?docid=-3503512249544932125

Hi i need your help ... do u have any example codes to move a servo up n down ? like if i press A the servo will go UP n when i press S the servo will go down ... Thnx

I can give you the code, but I think this explains it better than my uncommented code:

I also read somewhere in the forum that someone posted a way of driving two servos with the PWM pins, but I can't seem to find the post. Search servo in the forum see if you can find it.

-Z-

Could you give more information about the servors and the sensor that you use for your robot ?

Yeah! Nice work man! Im building robots aswell so it's great to see someone else that does here too. I like how the robot feels so alive and active when it moves. It's not a rigid kind of movement.

Could you give more information about the servors and the sensor that you use for your robot ?

Lets see if i can help you...

The sensor is an ultrasonic sensor. It provides the robot a range sensing and gives a higher input the farer away the detected oblect is.

The servos seems to be of standard size, where the two driving servos have been modified to be continous driving. An unmodified servo is restricted to about 180 degrees movement and can be positioned in a specific degree.

What else do you need to know?

Lets see if i can help you...

The sensor is an ultrasonic sensor. It provides the robot a range sensing and gives a higher input the farer away the detected oblect is.

The servos seems to be of standard size, where the two driving servos have been modified to be continous driving. An unmodified servo is restricted to about 180 degrees movement and can be positioned in a specific degree.

What else do you need to know?

It should be ok. I will try to do that and I will post the result later.

Sorry I've been too busy with my uni project to browse the arduino forums lately.

Fredrik, thanks for the answer, you are exactly right!

I bought my ultrasonic sensor here:

I've connected the analog output directly to an analog-in to read the distance.

Good luck!

-Z-

The ultrasonic sensor on a servo is an awesome idea. I just my steal it someday :-*

The ultrasonic sensor on a servo is an awesome idea. I just my steal it someday :-*

It wasn't my idea, I stole it from someone else :).

what is the type of servo motor ? Do you have the schema of your circuit ? What is the goal of the capacitor ?

#define LeftWheelPin 6
#define RightWheelPin 5
#define ArmServoPin 4
#define SonarPin 0

#define runningLED 2
#define errorLED 7

short ArmAngle, dAngleMax,dAngleMin, dAngleMaxTemp, dAngleMinTemp;
short ArmAngleRange, ArmAngleTarget;
short LeftSpeed;
short RightSpeed;
short ArmTrim = 0;
int distance, dmax, dmin, dmaxtemp, dmintemp;

unsigned long lastPulseL;
unsigned long lastPulseR;
unsigned long lastPulseA;

int i, k;
unsigned short refreshTime = 15;
unsigned long timeLast, timeLastFast;
unsigned long timeLastSlow;
unsigned int timeStart;

// --------------------------------------------------- LED flashing 
void flashLED(short pin, short times) {
  for (i = 0; i<=times; i++) {
    digitalWrite(pin, HIGH);
    delay(100);
    digitalWrite(pin, LOW);
    delay(500);  
  }
} 

// ---------------------------------------------------- Refreshes all servo pulses
void updateServos() {

  if (millis() - lastPulseL >= refreshTime) {
    digitalWrite(LeftWheelPin, HIGH);
    delayMicroseconds((LeftSpeed+90)*11+500);
    digitalWrite(LeftWheelPin, LOW);
    lastPulseL = millis();
  }

  if (millis() - lastPulseR >= refreshTime) {
    digitalWrite(RightWheelPin, HIGH);
    delayMicroseconds((-RightSpeed+90)*11+500);
    digitalWrite(RightWheelPin, LOW);
    lastPulseR = millis();
  }

  if (millis() - lastPulseA >= refreshTime) {
    digitalWrite(ArmServoPin, HIGH);
    delayMicroseconds((ArmAngle+ArmTrim+90)*11+500);
    digitalWrite(ArmServoPin, LOW);
    lastPulseA = millis();
  }

} // end updateServos

// ----------------------------------------------------- Rover move and turn function
void move(int speed, int turnSpeed) {
  //LeftSpeed = speed - turnSpeed;
  //RightSpeed = speed + turnSpeed;

  if (LeftSpeed < 30 && LeftSpeed < (speed - turnSpeed)) {
    LeftSpeed++;
    //LeftSpeed = ((LeftSpeed*10)+1)/10
  }
  else if (LeftSpeed > -30 && LeftSpeed > (speed - turnSpeed)) {
    LeftSpeed--;
    //LeftSpeed = ((LeftSpeed*10)-1)/10;
  }

  if (RightSpeed < 30 && RightSpeed < (speed + turnSpeed)) {
    RightSpeed++;
  }
  else if (RightSpeed > -30 && RightSpeed > (speed + turnSpeed)) {
    RightSpeed--;
  }

  //if (speed == 0 && turnSpeed == 0) {
  //  LeftSpeed = 0;
  //  RightSpeed = 0;
  //}
}    // End move

// -------------------------------------------------- Update ArmAngle
void armturn() {

  if (ArmAngle < 90 && ArmAngle < ArmAngleTarget) {
    ArmAngle = ArmAngle ++;
  }
  else if (ArmAngle > -90 && ArmAngle > ArmAngleTarget) {
    ArmAngle = ArmAngle --;
  }
}

// ------------------------------------------------- sonar distance function
long ping() {
  long raw;

  raw = analogRead(SonarPin)+analogRead(SonarPin)+analogRead(SonarPin)+analogRead(SonarPin);
  raw = raw/4;
  return raw + raw*123/512;
}


// -------------------------------------------------- Main navigation function 
void roving() {
  int speed, turn;
  randomSeed(millis());
  
  if (dmax > 300 && abs(dAngleMax) < 10) {
    ArmAngleRange = 15;
    speed = 20;
    turn = -dAngleMax;
  }    
  else if (dmax > 60) {
    ArmAngleRange = 60;
    speed = 16;
    turn = -dAngleMax/4;
  }  
  else if (dmax > 30) {
    ArmAngleRange = 70;
    speed = dmax/5 - 6;
    turn = -dAngleMax/24;
  }
  else if (dmax <= 30) {
    ArmAngleRange = 80;
    speed = 0;
    turn = -dAngleMax/20;
    digitalWrite(runningLED, HIGH);
  }
  if ((dmin <= 19)&&(abs(dAngleMin)<60)) {
    ArmAngleRange = 80;
    digitalWrite(errorLED, HIGH);
    speed = -4;
    if (dAngleMin !=0) {
      turn = dAngleMin/20;
    }
    else {
      if (random(0,1)) {
        turn = -2;
      }
      else {
        turn = 2;
      }
    }
  }
  /*
  else {
    move(0,0);
    flashLED(errorLED,5);
  }
  */
  move(speed, turn);
}  


void setup() {
  pinMode(LeftWheelPin, OUTPUT);
  pinMode(RightWheelPin, OUTPUT);
  pinMode(ArmServoPin, OUTPUT);
  pinMode(errorLED, OUTPUT);
  pinMode(runningLED, OUTPUT);
  pinMode(SonarPin, INPUT);
  Serial.begin(9600);

  LeftSpeed = 0;
  RightSpeed = 0;
  ArmAngleRange = 80;
  ArmAngleTarget = 80;
  distance = 50;
  dmaxtemp = 20;
  dmintemp = 1000;

  flashLED(runningLED,5);

  timeStart = millis();

  move(0,0);
}

// -------------------------------------------------- Main Loop
void loop() {

  digitalWrite(errorLED, LOW); 

  if (millis() - timeLast > 100) {
    distance = ping();
    
    
    if (distance < dmintemp) {
      dmintemp = distance;
      dAngleMinTemp = ArmAngle;
    }
    if (distance > dmaxtemp) {
      dmaxtemp = distance;
      dAngleMaxTemp = ArmAngle;
    }
    roving();   
    timeLast = millis();
    updateServos();
  }

  if ((millis() - timeLastSlow > 500) && (abs(ArmAngle) >= abs(ArmAngleTarget))) {
    if (ArmAngleTarget > 0) {    
      ArmAngleTarget = ArmAngleRange*-1;
    }
    else {
      ArmAngleTarget = ArmAngleRange;
    }
    dAngleMax = dAngleMaxTemp;
    dAngleMin = dAngleMinTemp;
    
    dmax = dmaxtemp;
    dmin = dmintemp;
    dmaxtemp = 10;
    dmintemp = 1000;
    
    /*
    Serial.print("Angles: ");
    Serial.print(dAngleMax,DEC);
    Serial.print(", ");
    Serial.print(dAngleMin,DEC);
    Serial.print(" - Distances: ");
    Serial.print(dmax,DEC);
    Serial.print(", ");
    Serial.println(dmin,DEC);
    */
    timeLastSlow = millis();
    updateServos();
  }

  if (millis() - timeLastFast > 4) { 
    armturn();
    timeLastFast = millis();
  }


  //updateServos();
  //Serial.println(distance,DEC); 
  digitalWrite(runningLED, LOW);

  updateServos();
}

This code is more "advanced" than the one used in the video. Basically every time the sonar servo completes a sweep, the angle for the direction with the maximum distance is determined, and the robot tries to turn in that direction. The direction with the minimum distance is also determined, and the rover tries to turn away from that direction.

-Z-

This code is more "advanced" than the one used in the video. Basically every time the sonar servo completes a sweep, the angle for the direction with the maximum distance is determined, and the robot tries to turn in that direction. The direction with the minimum distance is also determined, and the rover tries to turn away from that direction.

-Z-

How do you do to synchronize the servo of your sensor ? After few seconds, the angle of mine is not respected... It starts to go more on the right a little bit and it difficult to calibrate it. After three minutes, it is not anymore in the good direction.

This code is more "advanced" than the one used in the video. Basically every time the sonar servo completes a sweep, the angle for the direction with the maximum distance is determined, and the robot tries to turn in that direction. The direction with the minimum distance is also determined, and the rover tries to turn away from that direction.

-Z-

How do you do to synchronize the servo of your sensor ? After few seconds, the angle of mine is not respected... It starts to go more on the right a little bit and it difficult to calibrate it. After three minutes, it is not anymore in the good direction.

What do you mean? The servo driving the sonar is just a normal servo controlled through PWM, I've never needed to calibrate it. I check the angle of the sonar just by knowing the angle I'm telling the servo to point. The angle is probably not 100% accurate, but the robot only needs a rough idea which direction is clear of stuff.

-Z-

Ok I know why I have a problem with my servo. My servo has a continuous rotation. So it is difficult to know exactly where is the servo after few moments.

The code looks great.
So to build the rover, I will use two continuous servos and one regular servo for the sonic ping. I do not know where the arm fits in. Maybe an updated photo will help.

Q1) The continous servos: Do I need to calibrate them so that they can go forward and backwards? Maybe your code only handles forward.

Answer: Yes, you need to calibrate them for forward and baclword operation

Sorry I've been quite busy lately. The "arm" in the code is just referring to the servo that moves the ultrasonic sensor. And yes, the code will tell the robot to move backwards under certain conditions.

-Z-

Very cool project! I will definitely use some of these ideas for my HummBot project.
My HummBot will start with two IR sensors, but having seen this I will also add a Ultrasonic sensor.
The sensor you used is nice and small and seems pretty accurate.

Thanks, Mega

I know this is an Old topic but this is exactly what im trying to do. I get a "problem uploading to board" error when trying to upload the code from this thread. im using the latrest arduino board and the latest software 0013.

avrdude: stk500_getsync(): not in sync: resp=0x00
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x00

is there any working code to make a robot like this floating around?