Have robot, won't travel? (solved)

Hello all

I have ventured off into autonomous robot territory. Figured I would start off with a project that seemed pretty standard intro to robotics kind of stuff. I grabbed a small RC car, stripped it down to frame and motors, and hooked it up to an arduino through the Arduino Motor Shield R3.
I found a pretty basic sketch to run it, and haven't really even taken the time to modify it, though I do plan to add some bells and whistles, and see if I can't make it a little smarter :slight_smile:

Here is the sketch I am using now.

/*
RC Car to Robot Conversion
by Randy Sarafan

Used to convert an RC car into a robot that uses a PING sensor to avoid obstacles,
and an Arduino motor shield for motor control.

For more information see:
http://www.instructables.com/id/RC-Car-to-Robot/

Built atop Ping example code by Tom Igoe
*/

// this constant won't change.  It's the pin number
// of the sensor's output:
const int pingPin = 7;

void setup() {
  
  //establish motor direction toggle pins
  pinMode(12, OUTPUT); //drive motor -- HIGH = forwards and LOW = backwards
  pinMode(13, OUTPUT); //turn motor -- HIGH = left and LOW = right
  
  //establish motor brake pins
  pinMode(9, OUTPUT); //brake (disable) the drive motor
  pinMode(8, OUTPUT); //brake (disable) the turn motor

  //Turns brake off for drive motor
  digitalWrite(9, LOW); 

  //Turns brake on for turn motor
  digitalWrite(8, HIGH); 

  //Sets initial speed of drive motor
  analogWrite(3, 200);
  
  //Sets initial direction of drive motor
  digitalWrite(12, HIGH);
}

void loop()
{
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, inches, cm;

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // 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 of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);

  //
  //if objects are less than 12 inches away
  //the robot reverses and turns to the right
  //for 2 seconds
  //
  
  if (inches < 12){
    
    //brake drive motor and pause 1/10 second
    digitalWrite(9, HIGH);
    delay(100);

    //
    //setting turn motor
    //
    
    //turn off brake for turn motor 
    digitalWrite(8, LOW);

    //set turn motor direction
    digitalWrite(13, HIGH);

    //activate turn motor
    analogWrite(11, 255);
    
    //
    //setting drive motor
    //
    
    //turn off brake of drive motor
    digitalWrite(9, LOW); 
    
    //set drive motor backwards direction
    digitalWrite(12, LOW);
    
    //activate the drive motor
    analogWrite(3, 200);

    
    //backup for 2 seconds
    delay(2000);
    
    //
    //stopping
    //
    
    //brake both motors
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    
    
  }
  
  //
  //when nothing is within 12" 
  //the robot simply drives forwards
  //
  
  else{
    
    //
    //Setting drive motor
    //
    
    //set drive motor forward direction
    digitalWrite(12, HIGH);
    
    //turn off brake of drive motor
    digitalWrite(9, LOW);    
    
    //activate drive motor
    analogWrite(3, 200);
  
  
  }
  
  delay(100);
}

long microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

I haven't really even looked through the code yet, but I don't think my problem is in the code, I just posted it in case there was anything in there that might help.

My issue is, the code works perfectly, as long as the car isn't on the ground. I can hold it up in the air, and the drive motor does what it is supposed to, and the turn motor works when it is supposed to. But when I put it down, it works on a nice flat surface for a few minutes, then it seems to run out of power. It wont move much at all on carpet.

The car originally ran on 3 AA batteries, though I never even turned it on before I tore it apart. It was pretty light weight, and with all the Arduino gear on top, it does have a bit more load to move, but I would think the difference would be negligible.

The car uses one DC motor to drive the rear wheels, and one DC motor to turn the front wheels. When the car needs to back up and turn, it has noticeably less power, and is usually the first direction to stop working. I have tried 3 AA's and 4AA's to drive the motors. I tried using a 9V to power the arduino, and the motors through the shield, which is how it is set up to work. No matter how I configure the power in, I don't get enough drive, and it dies after only a few minutes.

Does anyone have any idea how I might fix this? The inscrutable where I got the code worked on just the 9V supplying the arduino, and used the Vin pin to supply power to the shield. His seemed to work just fine, and I have a nearly identical RC car, the same motor shield and PING sensor. Not sure where I am loosing so much energy, and it has me stumped.

Any suggestions would be greatly appreciated!
Thanks
N8

If I'm reading the datasheet correctly, the L298P will drop the voltage to the motors between 1.8V to 3.2V at 1A of current.

Use more batteries.

Thank you Chagrin :slight_smile:

That was more or less what I thought was needed, but wanted to fish for the answer a bit before I strap more power to this thing. If there was something in the code I wasn't seeing that was draining power, I didn't want to add more juice only to burn out a component with a bad line of code.

Thank you for the reply, Looks like I might need to pick up a regular RC car battery. It should run off a 9V battery with more available amp hours.
I don't think I should need to go the 12V route. It was already moving pretty fast for the PING sensor for the few minutes it would drive off a fresh set of 4AA powering the motor.
Don't mind me, just thinking "out loud" now
off to ponder
Thanks
N8

Exactly the problem I had a while back with the 298 based MotoMama as discussed here.... The 298 is a veritable voltage sponge.

I've since got a Pololu 2130

Thanks for the tip JimboZA

I will have to check that out. I was pretty surprised that this thing wouldn't run on a 9V or 4AAs because it ran on 3AAs with the original circuit. I figured it was the motor driver gobbling up power, but wanted to be sure.

I went and did a dumb thing, not paying attention, and smoked my PING sensor, so this project is on the shelf until I get a new set of eyes....
Might try a IR distance sensor this time, or maybe two, give me a wider range of view and more options.
I have lots of ideas for this project, cool ways to take this very simple code and make a really nice driving automaton out of it. Pretty bummed I burned out the distance sensor just as I was getting things to work....
That's what I get for trying to run a test in a hurry before I have to leave for work.
Live and learn eh?

Since I am now down to buying new parts, might as well give that Pololu 2130 a shot and see if I can't reduce the power pack needed in the first place. Make this thing semi-smart and semi-efficient :stuck_out_tongue:

Thanks again!
N8

Well, I went out and bought a new PING))) sensor, and a 9.6V 1600mAh battery, and just for fun, and seeed studios motor shield.
I now have my robot working, though the code needs tweaked a bit, because once in a while it still hits objects.
I wrote my own code for this one, using the NewPing library and the seeed motor shield.

I wrote the code so the robot first tries to slow down and turn while still driving forward to avoid an obstacle, then if it can't avoid it, it stops and turns a bit then keeps going.

Here is the code as I have it working now...

// Using Seeed Motor Shield with L298 dual H bridge and PING))) distance sensor to drive a converted RC car robot

#include <NewPing.h>  //use NewPing library for the PING))) sensor. 
#define triggerPin 7  // define triggerPin on Arduino Pin 7
#define echoPin 7     // define echoPin on Arduino Pin 7
#define maxDistance 400  // define maxDistance as 400cm
#define Iterations 10   // define Iterations as 10

NewPing sonar(triggerPin, echoPin, maxDistance);  // set sonar with the triggerPin, echoPin, and set maxDistance

const int minDist = 0;  // set minimum distance = 0 for switch case
const int maxDist = 160;  // set maximum distance = 160cm for switch case

const int motorA2 = 8;  // set L298 input 1 as motorA2 on Arduino Pin 8
const int motorA1 = 11; // set L298 input 2 as motorA1 on Arduino Pin 11
const int motorA = 9;   // set L298 output 1 as motorA on Arduino PWM pin 9 (drive motor)
const int motorB2 = 12; // set L298 input 3 as motorB2 on Arduino Pin 12
const int motorB1 = 13; // set L298 input 4 as motorB1 on Arduino Pin 13
const int motorB = 10;  // set L298 output 2 as motorB on Arduino PWM pin 10 (turn motor)

void setup()
{
  pinMode(motorA1, OUTPUT);  // set motor pins as output
  pinMode(motorA2, OUTPUT);
  pinMode(motorA, OUTPUT);
  pinMode(motorB1, OUTPUT);
  pinMode(motorB2, OUTPUT);
  pinMode(motorB, OUTPUT);
}

void loop()
{
  delay(30);  //delay 30 milliseconds 
  //this sets the data coming from the PING))) sensor to integer uSeconds.  This takes 10 readings
  //from the sensor and averages them for better accuracy.
  unsigned int uSeconds = sonar.ping_median(Iterations);
  
  //maps the data coming from the PING))) sensor to one of 4 options to be handled by the switch case
  int Speed = map(uSeconds / US_ROUNDTRIP_CM, minDist, maxDist, 4, 1);
  
  //if statement to handle any sensor readings higher than 160cm
  if(uSeconds / US_ROUNDTRIP_CM >= maxDist)
  {
    analogWrite(motorA, 255);  //Drive forward at full speed
    digitalWrite(motorB, LOW);
    digitalWrite(motorA1, LOW);
    digitalWrite(motorA2, HIGH);
  }
  
  switch(Speed)  //This switch takes the distance readings that were mapped to four options and decides what to
                 //do based on how close the robot is to an object case 1 is farthest away, case 4 is closest.
  {
    case 1:  //drive forward at full speed
    analogWrite(motorA, 255);
    digitalWrite(motorB, LOW);
    digitalWrite(motorA1, LOW);
    digitalWrite(motorA2, HIGH);
    break;
    case 2:  //drive forward, but at a slower speed
    analogWrite(motorA, 200);
    digitalWrite(motorB, LOW);
    digitalWrite(motorA1, LOW);
    digitalWrite(motorA2, HIGH);
    break;
    case 3:  //slow down even more and turn right while still going forward
    analogWrite(motorA, 170);
    analogWrite(motorB, 170);
    digitalWrite(motorA1, LOW);
    digitalWrite(motorA2, HIGH);
    digitalWrite(motorB1, HIGH);
    digitalWrite(motorB2, LOW);
    break;
    case 4:  //stop and back up while turning right for a half second, then stop again
    digitalWrite(motorA, LOW);
    digitalWrite(motorB, LOW);
    delay(100);
    analogWrite(motorA, 200);
    analogWrite(motorB, 170);
    digitalWrite(motorA1, HIGH);
    digitalWrite(motorA2, LOW);
    digitalWrite(motorB1, LOW);
    digitalWrite(motorB2, HIGH);
    delay(500);
    digitalWrite(motorA, LOW);
    digitalWrite(motorB, LOW);
    delay(100);
    break;
  }
}

Just wanted to share the progress I have made with it.

Next I would like to mount the sensor on a servo, and get it to look left and right when it stops, so it can choose if it should turn left or right based on how far away objects are to each side.
Need to figure out an easy way to mount all this up, so it is stable enough to move with the servo, and not fall apart. Not sure how I am going to do that yet, but it should be fun working it out!

I am more than happy to take any suggestions on ways to improve my code as I have it written. I am not married to it, and always welcome advice on how to do things a little bit better.

Thanks for checking it out!
N8

I want to thank you for this code, My car uses an Uno with Seeed motor controller and this gives my project the needed What Next for motion control, now to figure out how to change out the Ping code for the SR04 code.

Have you continued to upgrade this project? The scanning sonic Servo is the next addition to my project also, once I get passed combining my 4 pin sonic code with your driving code.