Obstacle avoidance with Analog motors

Hello,

I'm new to all of this and have read through a few posts, and am trying to learn coding for the Arduino.

I have to admit, I'm still using a good bit of cut and paste and then modification for my hardware.

I think I have obstacle avoidance working on my tamiya tankbot but I'm sure there may be more efficient ways to write this and/or more effective.

This is what I have so far, and it seems to work semi-OK. I think I may need to lift the Parallax Ping up higher as it may be getting ground noise.

Any comments or advice would be appreciated at this point.

// TurtleDuino Obstacles Avoiding Robot By:RobDavinci Modified for Analog motors by ShawnPconst
int pingPin = 7; // pin for ping input
const int dangerThresh = 10; //threshold for obstacles (in cm)
int leftDistance, rightDistance; //distances on either side
long duration; //time it takes to recieve PING))) signal


void setup() {
   // initialize serial communication:
  Serial.begin(9600);
  
   //Setup Channel A
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin

  //Setup Channel B
  pinMode(13, OUTPUT); //Initiates Motor Channel B pin
  pinMode(8, OUTPUT);  //Initiates Brake Channel B pin
}

void loop()
{
  int distanceFwd = ping(); //set distance ahead to ping distance
  if (distanceFwd > dangerThresh) //if path is clear
  {
   //MOVE FORWARD
   //Motor A forward
  digitalWrite(12, HIGH); //Establishes forward direction of Channel A
  digitalWrite(9, LOW);   //Disengage the Brake for Channel A
  analogWrite(3, 255);   //Spins the motor on Channel A
  
    //Motor B Forward
  digitalWrite(13, HIGH);  //Establishes backward direction of Channel B
  digitalWrite(8, LOW);   //Disengage the Brake for Channel B
  analogWrite(11, 255);    //Spins the motor on Channel B
  }
  else //if path is blocked
  {
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);

   //MOVE BACK TURNING FIRST WAY
   //Motor A Backwards
   digitalWrite(12, LOW); //Establishes backward direction of Channel A
   digitalWrite(9, LOW);   //Disengage the Brake for Channel A
   analogWrite(3, 175);   //Spins the motor on Channel A
   delay(1000);

   rightDistance = ping(); //scan to the right
   delay(1000);

   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);

   //return to center
   //Motor B backwards
   digitalWrite(13, LOW);  //Establishes backward direction of Channel B
   digitalWrite(8, LOW);   //Disengage the Brake for Channel B
   analogWrite(11, 175);    //Spins the motor on Channel B
   delay(1000);
   
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);
   
   //MOVE BACK TURNING SECOND WAY
   //Motor B Backwards
   digitalWrite(13, LOW);  //Establishes backward direction of Channel B
   digitalWrite(8, LOW);   //Disengage the Brake for Channel B
   analogWrite(11, 175);    //Spins the motor on Channel B
   delay(1000);
   
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);
   
   leftDistance = ping(); //scan to the left
   delay(1000);

   //RETURN TO CENTER
   //Motor A forward
   digitalWrite(12, LOW); //Establishes backward direction of Channel A
   digitalWrite(9, LOW);   //Disengage the Brake for Channel A
   analogWrite(3, 175);   //Spins the motor on Channel A
   delay(1000);
   compareDistance();
  }
}
 
  void compareDistance()
 {
   if (leftDistance>rightDistance) //if left is less obstructed
  {
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);

  //Motor A backwards
    digitalWrite(12, LOW); //Establishes backward direction of Channel A
    digitalWrite(9, LOW);   //Disengage the Brake for Channel A
    analogWrite(3, 100);   //Spins the motor on Channel A
    delay(2000);
  }
   else if (rightDistance>leftDistance) //if right is less obstructed
  {
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);

    //Motor B backwards
    digitalWrite(13, LOW);  //Establishes backward direction of Channel B
    digitalWrite(8, LOW);   //Disengage the Brake for Channel B
    analogWrite(11, 100);    //Spins the motor on Channel B
    delay(2000);
  }
   else //if they are equally obstructed
  {
   digitalWrite(9, HIGH);  //Engage the Brake for Channel A
   digitalWrite(8, HIGH);  //Engage the Brake for Channel B
   delay(1000);

   //Motor A forward
   digitalWrite(12, LOW); //Establishes backward direction of Channel A
   digitalWrite(9, LOW);   //Disengage the Brake for Channel A
   analogWrite(3, 100);   //Spins the motor on Channel A
   //Motor B Forward
   digitalWrite(13, HIGH);  //Establishes backward direction of Channel B
   digitalWrite(8, LOW);   //Disengage the Brake for Channel B
   analogWrite(11, 100);    //Spins the motor on Channel B
   delay(2000);
  }
 }
 // establish variables for duration of the ping, 
 // and the distance result in inches and centimeters:
long ping()
{
  // 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);
 
  // 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 travelled.
  return duration / 29 / 2;

Hi Murphyslaww,

Welcome to the wonderful world of Arduino!

I looked over your code and it looks pretty good, here are just a few quick comments to consider:

  • Excellent comments
  • Your indentation is inconsistent
  • Use meaningful constants for all of your GPIO pins, like you did with pingPin
  • Consider creating functions for actions such as moveForward, etc...

Pat.

Thanks for the comments.

I did clean it up a bit. There was a comment or two that were incorrect as to what was actually happening as well. I don't know how to code, so I'm going to be going off of constructive criticism for a while.

I'm not sure I know what you mean by separate functions. I picked up a few errors while coding that I wasn't sure what they referred to as far as what seemed to mean a variable wasn't called out in a "scope" which is something I couldn't figure out exactly the meaning of.

As for the GPIO pins, which ones would those be ? The pins that actually take the motor initiation function (direction/PWM/Brake) on the Motor Shield ?

This is run on a Mega ADK, and eventually it will be getting a wifi built-in-webserver cam to run around the house with, but I'll need more robust motors, and/or a larger chassis.

Murphyslaww:
Thanks for the comments.

I did clean it up a bit. There was a comment or two that were incorrect as to what was actually happening as well. I don't know how to code, so I'm going to be going off of constructive criticism for a while.

Well, for someone who is learning, you did a great job! Accept the criticism as guidance and "free" instruction.

I'm not sure I know what you mean by separate functions. I picked up a few errors while coding that I wasn't sure what they referred to as far as what seemed to mean a variable wasn't called out in a "scope" which is something I couldn't figure out exactly the meaning of.

If you find that you are writing duplicate code for the same action over and over again, consider making some utility functions so you only have to write them (and test them) once. Candidates for you are moveForward. You'll probably want other movement control utilities too. Look up functions, they aren't as hard as they may seem.

Scope is a little different. It refers to what variables can be accessed by functions. Global variables can be accessed by all functions. Alternatively, if you declare a variable in setup, it is out of scope (not visible, not accessible) in loop:

void setup() {
  int x = 12;
}

void loop() {
  ... x ...          <<< loop can't see it

As for the GPIO pins, which ones would those be ? The pins that actually take the motor initiation function (direction/PWM/Brake) on the Motor Shield ?

Yes, name each of the pins so you (or a reader) won't confuse them. Hard-coded values are a huge source of errors.

Something like:
digitalWrite(channel_B_brake, HIGH); //Engage the Brake for Channel B

This is run on a Mega ADK, and eventually it will be getting a wifi built-in-webserver cam to run around the house with, but I'll need more robust motors, and/or a larger chassis.

Sounds like a great project. You're doing the right thing by breaking it down into smaller chunks and building in per-planned improvements.

I can't wait to see it in action.

You are using a lot of delay()'s, so in the end you will need to scrap your code!. Take a look at "blink without delay" now. Learn to do all your timing this way.

Mark

Thanks for the help. I'll look into all of that.

I initially used the delays, because I wanted to be able to hopefully see that what I had coded was actually happening. Giving it a little more time for the events to happen, and me to notice they were happening seemed to accomplish that. Basically, as Pat said, breaking the parts of the code down.

I seem to be getting a lot of false positives on the Ping reading that there is a clear path when there is a clear path. It will roll forward on the clear path for a second or two, then react as if it's seeing a blocked path. Might be that it's too low on the chassis.

If anyone is interested in keeping up with a noob Arduino-er, it'll be here. I'm becoming a serial blogger...