Tamiya Gearbox for Obstacle Avoiding Robot

Im working on an obstacle avoiding robot from a sketch I got off a website.

#include <AFMotor.h>
#include <Servo.h> 
#include <NewPing.h>

#define TRIG_PIN A4 // Pin A4 on the Motor Drive Shield soldered to the ultrasonic sensor
#define ECHO_PIN A5 // Pin A5 on the Motor Drive Shield soldered to the ultrasonic sensor
#define MAX_DISTANCE 200 // sets maximum useable sensor measuring distance to 200cm
#define MAX_SPEED 180 // sets speed of DC traction motors to 180/256 or about 70% of full speed - to get power drain down.
#define MAX_SPEED_OFFSET 10 // this sets offset to allow for differences between the two DC traction motors
#define COLL_DIST 10 // sets distance at which robot stops and reverses to 10cm
#define TURN_DIST COLL_DIST+10 // sets distance at which robot veers away from object (not reverse) to 20cm (10+10)
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // sets up sensor library to use the correct pins to measure distance.

AF_DCMotor motor1(1, MOTOR12_1KHZ); // create motor #1 using M1 output on Motor Drive Shield, set to 1kHz PWM frequency
AF_DCMotor motor2(4, MOTOR12_1KHZ); // create motor #2, using M2 output, set to 1kHz PWM frequency
Servo myservo;  // create servo object to control a servo 

int pos = 0; // this sets up variables for use in the sketch (code)
  int maxDist = 0;
  int maxAngle = 0;
  int maxRight = 0;
  int maxLeft = 0;
  int maxFront = 0;
int course = 0;
int curDist = 0;
String motorSet = "";
int speedSet = 0;

void setup() {
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 (SERVO_2 on the Motor Drive Shield to the servo object 
  delay(2000); // delay for two seconds
  myservo.write(90); // Face Forward
  checkPath(); // run the CheckPath routine to find the best path to begin travel
  motorSet = "FORWARD"; // set the director indicator variable to FORWARD
  moveForward(); // run function to make robot move forward
}

void loop() {
  checkForward(); // check that if the robot is supposed to be moving forward, that the drive motors are set to move forward - this is needed to overcome some issues with only using 4 AA NiMH batteries
  checkPath(); // set ultrasonic sensor to scan for any possible obstacles
}

void checkPath() {
  Serial.println("Checking path...");
  int curLeft = 0;
  int curFront = 0;
  int curRight = 0;
  int curDist = 0;
  myservo.write(144); // set servo to face left 54-degrees from forward
  delay(120); // wait 120milliseconds for servo to reach position
  for(pos = 144; pos >= 36; pos-=18)     // loop to sweep the servo (& sensor) from 144-degrees left to 36-degrees right at 18-degree intervals. 
  {
    myservo.write(pos);  // tell servo to go to position in variable 'pos' 
    delay(90); // wait 90ms for servo to get to position   
    checkForward(); // check the robot is still moving forward
    curDist = readPing(); // get the current distance to any object in front of sensor
    
    // If distances are too close///objects are nearby!!!
    if (curDist < COLL_DIST) { // if the current distance to object is less than the collision distance
      Serial.println("call checkCourse()");
      checkCourse(); // run the checkCourse function
      break; // jump out of this loop
    }
    if (curDist < TURN_DIST) { // if current distance is less than the turn distance
      Serial.println("call changePath()");
      changePath(); // run the changePath function
    }
    
    //ELSE if curDist !< COLL_DIST then...
    if (curDist > maxDist) {
      maxAngle = pos; 
      maxDist = curDist; 
      Serial.println("curDist > maxDist, maxDist has been set!"); 
    }
// COMMENTED OUT BECAUSE CODE WAS NOT USED ELSEWHERE
//    if (pos > 90 && curDist > curLeft) { 
//      curLeft = curDist; 
//      Serial.println("facing left and curDist > curLeft?");
//    }
//    if (pos == 90 && curDist > curFront) {
//      curFront = curDist; 
//      Serial.println("facing front and curDist > curFront?");
//    }
//    if (pos < 90 && curDist > curRight) {
//      curRight = curDist; 
//      Serial.println("facing left and curDist > curRight?");
//    }
  }
//  maxLeft = curLeft;
//  maxRight = curRight;
//  maxFront = curFront;
  Serial.println("Done checking path...");
}

void setCourse() { // set direction for travel based on a very basic distance map, simply which direction has the greatest distance to and object - turning right or left? 
    Serial.println("Setting course...");
    if (maxAngle < 90) {turnRight();}
    if (maxAngle > 90) {turnLeft();}
    maxLeft = 0;
    maxRight = 0;
    maxFront = 0;
}

void checkCourse() { // we're about to hit something so move backwards, stop, find where the empty path is.
  Serial.println("Checking course...");
  moveBackward();
  delay(500);
  moveStop();
  setCourse();
}

void changePath() {
  Serial.println("Changing path...");
  if (pos < 90) {veerLeft();} // if current pos of sensor is less than 90-degrees, it means the object is on the right hand side so veer left
  if (pos > 90) {veerRight();} // if current pos of sensor is greater than 90-degrees, it means the object is on the left hand side so veer right
}

int readPing() { // read the ultrasonic sensor distance
  Serial.println("Reading ping...");
  delay(70);
  unsigned int uS = sonar.ping();
  int cm = uS/US_ROUNDTRIP_CM;
  Serial.println(cm);
  return cm;
}

void checkForward() { Serial.println("Checking forward..."); if (motorSet=="FORWARD") {motor1.run(FORWARD); motor2.run(FORWARD); } }     // make sure motors are going forward

void checkBackward() { Serial.println("Checking backward..."); if (motorSet=="BACKWARD") {motor1.run(BACKWARD); motor2.run(BACKWARD); } } // make sure motors are going backward

void moveStop() { Serial.println("Move stopping..."); motor1.run(RELEASE); motor2.run(RELEASE);}  // stop the motors.

void moveForward() {
  Serial.println("Moving forward...");
    motorSet = "FORWARD";
    motor1.run(FORWARD);      // turn it on going forward
    motor2.run(FORWARD);      // turn it on going forward
  for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2) // slowly bring the speed up to avoid loading down the batteries too quickly
  {
    motor1.setSpeed(speedSet+MAX_SPEED_OFFSET);
    motor2.setSpeed(speedSet);
    delay(5);
  }
}

void moveBackward() {
  Serial.println("Moving backward...");
    motorSet = "BACKWARD";
    motor1.run(BACKWARD);      // turn it on going forward
    motor2.run(BACKWARD);     // turn it on going forward
  for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2) // slowly bring the speed up to avoid loading down the batteries too quickly
  {
    motor1.setSpeed(speedSet+MAX_SPEED_OFFSET);
    motor2.setSpeed(speedSet);
    delay(5);
  }
}  

void turnRight() {
  Serial.println("Turning right...");
  motorSet = "RIGHT";
  motor1.run(FORWARD);      // turn motor 1 forward
  motor2.run(BACKWARD);     // turn motor 2 backward
  delay(400); // run motors this way for 400ms
  motorSet = "FORWARD";
  motor1.run(FORWARD);      // set both motors back to forward
  motor2.run(FORWARD);      
}  

void turnLeft() {
  Serial.println("Turning left...");
  motorSet = "LEFT";
  motor1.run(BACKWARD);     // turn motor 1 backward
  motor2.run(FORWARD);      // turn motor 2 forward
  delay(400); // run motors this way for 400ms
  motorSet = "FORWARD";
  motor1.run(FORWARD);      // turn it on going forward
  motor2.run(FORWARD);      // turn it on going forward
}  

void veerRight() {Serial.println("Veering right..."); motor2.run(BACKWARD); delay(400); motor2.run(FORWARD);} // veering right? set right motor backwards for 400ms

void veerLeft() {Serial.println("Veering left..."); motor1.run(BACKWARD); delay(400); motor1.run(FORWARD);} // veering left? set left motor backwards for 400ms

The code seems fine, I've made one modification based on suggestions I got in these forums about commenting a few lines in the loop() because they werent really being used in the code.

What I would like to know is what is the best way to debug a sketch like this since so many things happen so fast repeatedly. Im used to adding serial prints but in this case they dont work well. From the video of the rig operating you can see the left engine works better than the right engine which seems to stop and sputter at times. Im guessing that is a gearbox issue.

But it also seems the logic is not working as intended since there is nothing in front of the sensor during the run and at times the motors run backwards. At least the left one seems to.

Here is the link to the video:
Imgur

Marciokoko:
What I would like to know is what is the best way to debug a sketch like this since so many things happen so fast repeatedly.

One thing to do is to isolate the particular aspect of the program you're testing.

If you're testing how the motors run, set the motors to run at a set speed and delete the rest of the code. As the code is currently written it's hard to know why the motors are behaving as they are.

Reduce the number of variables you're testing to as few as possible.

There are certainly other things to help with debugging the above would be a good start.

What are you using as a power supply to the motor?

For testing I'm using the USB plug. I do have a lipo battery pack for the motor shield and a 9v battery for the Arduino for running it autonomously.

Ok I tried 2 things:

  1. I just made the motors run forward by calling only the moveForward() function. This made the motors run fine, continuously. It works fine even with my LiPo battery pack powering the shield and the 9V powering the arduino.

  2. I gutted the moving around code and just left this code:

#include <AFMotor.h>
#include <Servo.h> 
#include <NewPing.h>

#define TRIG_PIN A4 // Pin A4 on the Motor Drive Shield soldered to the ultrasonic sensor
#define ECHO_PIN A5 // Pin A5 on the Motor Drive Shield soldered to the ultrasonic sensor
#define MAX_DISTANCE 200 // sets maximum useable sensor measuring distance to 200cm
#define MAX_SPEED 180 // sets speed of DC traction motors to 180/256 or about 70% of full speed - to get power drain down.
#define MAX_SPEED_OFFSET 10 // this sets offset to allow for differences between the two DC traction motors
#define COLL_DIST 10 // sets distance at which robot stops and reverses to 10cm
#define TURN_DIST COLL_DIST+10 // sets distance at which robot veers away from object (not reverse) to 20cm (10+10)
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // sets up sensor library to use the correct pins to measure distance.

AF_DCMotor motor1(1, MOTOR12_1KHZ); // create motor #1 using M1 output on Motor Drive Shield, set to 1kHz PWM frequency
AF_DCMotor motor2(4, MOTOR12_1KHZ); // create motor #2, using M2 output, set to 1kHz PWM frequency
Servo myservo;  // create servo object to control a servo 

int pos = 0; // this sets up variables for use in the sketch (code)
  int maxDist = 0;
  int maxAngle = 0;
  int maxRight = 0;
  int maxLeft = 0;
  int maxFront = 0;
int course = 0;
int curDist = 0;
String motorSet = "";
int speedSet = 0;

//-------------------------------------------- SETUP LOOP ----------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  myservo.attach(9);  // attaches the servo on pin 9 (SERVO_2 on the Motor Drive Shield to the servo object 
  delay(2000); // delay for two seconds
  myservo.write(90); // Face Forward
  checkPath(); // run the CheckPath routine to find the best path to begin travel
  motorSet = "FORWARD"; // set the director indicator variable to FORWARD
  moveForward(); // run function to make robot move forward
}

void loop() {
  checkForward(); // check that if the robot is supposed to be moving forward, that the drive motors are set to move forward - this is needed to overcome some issues with only using 4 AA NiMH batteries
  checkPath(); // set ultrasonic sensor to scan for any possible obstacles
}
//-------------------------------------------------------------------------------------------------------------------------------------
void checkPath() {
  Serial.println("Checking path...");
  int curLeft = 0;
  int curFront = 0;
  int curRight = 0;
  int curDist = 0;
  myservo.write(144); // set servo to face left 54-degrees from forward
  delay(120); // wait 120milliseconds for servo to reach position
  for(pos = 144; pos >= 36; pos-=18)     // loop to sweep the servo (& sensor) from 144-degrees left to 36-degrees right at 18-degree intervals. 
  {
    myservo.write(pos);  // tell servo to go to position in variable 'pos' 
    delay(90); // wait 90ms for servo to get to position   
    checkForward(); // check the robot is still moving forward
    curDist = readPing(); // get the current distance to any object in front of sensor
    
    // If distances are too close///objects are nearby!!!
    if (curDist < COLL_DIST) { // if the current distance to object is less than the collision distance
      Serial.println("call checkCourse()");
      checkCourse(); // run the checkCourse function
      break; // jump out of this loop
    }
    if (curDist < TURN_DIST) { // if current distance is less than the turn distance
      Serial.println("call changePath()");
      changePath(); // run the changePath function
    }
    
    if (curDist > maxDist) {
      maxAngle = pos; 
      maxDist = curDist; 
      Serial.println("curDist > maxDist, maxDist has been set!"); 
    }
  }

  Serial.println("Done checking path...");
}
//-------------------------------------------------------------------------------------------------------------------------------------
void setCourse() { // set direction for travel based on a very basic distance map, simply which direction has the greatest distance to and object - turning right or left? 
    Serial.println("Setting course...");
    if (maxAngle < 90) {turnRight();}
    if (maxAngle > 90) {turnLeft();}
    maxLeft = 0;
    maxRight = 0;
    maxFront = 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------
void checkCourse() { // we're about to hit something so move backwards, stop, find where the empty path is.
  Serial.println("Checking course...");
  moveBackward();
  delay(500);
  moveStop();
  setCourse();
}
//-------------------------------------------------------------------------------------------------------------------------------------
void changePath() {
  Serial.println("Changing path...");
  if (pos < 90) {veerLeft();} // if current pos of sensor is less than 90-degrees, it means the object is on the right hand side so veer left
  if (pos > 90) {veerRight();} // if current pos of sensor is greater than 90-degrees, it means the object is on the left hand side so veer right
}

int readPing() { // read the ultrasonic sensor distance
  Serial.println("Reading ping...");
  delay(70);
  unsigned int uS = sonar.ping();
  int cm = uS/US_ROUNDTRIP_CM;
  Serial.println(cm);
  return cm;
}
void checkForward() { Serial.println("Checking forward..."); }     // make sure motors are going forward
void checkBackward() { Serial.println("Checking backward..."); } // make sure motors are going backward

void moveStop() { Serial.println("Move stopping..."); }  // stop the motors.
void moveForward() {
  Serial.println("Moving forward...");
}
void moveBackward() {
  Serial.println("Moving backward...");
}  
void turnRight() {
  Serial.println("Turning right...");
}  
void turnLeft() {
  Serial.println("Turning left...");     // turn it on going forward
}  
void veerRight() {Serial.println("Veering right..."); } // veering right? set right motor backwards for 400ms
void veerLeft() {Serial.println("Veering left..."); } // veering left? set left motor backwards for 400ms

I got this in the monitor. It seems fine. It reads the ping then checks forward. :

Checking path...
Checking forward... // these are called from setup
Reading ping... //probably from the setup() call of checkPath()
54
curDist > maxDist, maxDist has been set!
Checking forward...

Reading ping...
55
Checking path...
Checking forward...

Reading ping...
57
curDist > maxDist, maxDist has been set!
Checking forward...

Reading ping...
54
Checking forward...

Reading ping...
56
Checking forward...

Reading ping...
36
Checking forward...

Reading ping...
33
Checking forward...

Reading ping...
31
Checking forward...

Reading ping...
32
Done checking path... // this would be the end of the first loop
Moving forward...
Checking forward...
Checking path...
Checking forward...

Reading ping...
38
Checking forward...

Reading ping...
55
Checking forward...

Reading ping...
56
Checking forward...

Reading ping...
200
curDist > maxDist, maxDist has been set!
Checking forward...

Reading ping...
33
Checking forward...

Reading ping...
29
Checking forward...

Reading ping...
32
Done checking path... // this would be the end of the second loop
Checking forward...
Checking path...
Checking forward...

Reading ping...
44
Checking forward...

Reading ping...
56
Checking forward...

Reading ping...
58
Checking forward...

Reading ping...
35
Checking forward...

Reading ping...
33
Checking forward...

Reading ping...
30
Checking forward...

Reading ping...
32
Done checking path...// this would be the end of the third loop
Checking forw //i unplugged it after about 3 loops/sweeps of the sensor

Marciokoko:
It works fine even with my LiPo battery pack powering the shield and the 9V powering the arduino.

As you satisfied the motors are working okay?

So do you think the problem lies with the code you originally posted?

BTW, I suggest you make sure you're using a powered USB hub if you're powering motors from USB. Running motors or servos from USB can damage the computer (I've done this myself).

Here isa sorta decision tree I made...btw, is there a software to model this kinda thing?

Basically on every loop, it makes the map. I made a sample map as represented by a black rectangle as the robot, red rectangles as close obstacles (because the sketch calls for <10 objects and <20 objects) and yellow rectangles as far away objects.

Im confused because it seems that when it does find that curDist < COLL_DIST (when it finds a <10 close obstacle (red rectangle), the robot turnsLeft and then veersRight???

It doesnt make sense on 2 levels:

  1. Why if the object is on the left @8, why does it turn left?

  2. Why does it then veer right?

bump :slight_smile:

The latest code is in reply #3?

I'm a sucker for trying other people's code if I have the same sort of hardware, but I don't don't have the same setup as you and the code is more complex than I'd like to inspect for the fun of it.

Maybe someone else will feel inclined to peruse your code.

if not, I suggest simplifying the code as much as possible. Can you get the robot to stop when there's an obstacle? Can you have the robot drive in a circle?

It looks like you have debug statements but do you have enough to find the problem? When I have a bug in my code, I keep adding debug statements until I can identify the exact location in code where something unexpected occurs.

Yes I understand. I will try to make it run and stop when it finds an obstacle or make it go around in a circle.

I guess I wanted to know if my excel diagram does what the code says and specifically why I think there would be an issue with the code.

The specific point is here:

For pos 144 and 126 there are no obstacles within 20cm (turn distance) or 10cm (collision distance). Then in C, it finds an obstacle at 8 cm, so it goes into the if block and calls checkCourse() which itself reverses, stops and calls setCourse(). At this point maxAngle is still 144, it's the angle with the farthest clearance. So when setCourse() is called, maxAngle is > 90 so it turnsLeft, but the obstacle WAS at the left. And since curDist is also < turn_distance, it then calls to veerRight!? This doesn't make sense to me. Am I interpreting this correctly?

Ok I commented out everything and just left the first if from the checkPath() method which checks to see if curDist in < Coll_dist.

It would run very slowly and stop even with the LiPo battery pack. So I tested with a voltmeter and discovered the terminals for ext power of the shield were getting about 5-6V, Im using a 3.7V battery with a 5V stepup booster. But the motors at the shield terminals were only getting about 0.2-0.5V intermittently of course.

I plugged the unit into the laptop usb and the terminals at the shield were getting about 3.5V but one motor gets 1.1V and the other gets 0.5V. It seems there is a difference between what one motor gets vs the other.

I guess I need to get a NiMH pack from somewhere.

Bump