Servo plus Sonar--Solved

Hello,

I am trying to build a robot that uses a compass for navigation, and a sonar mounted on a rotating servo for object avoidance.When I tried to call the sonar ( ) function under void loop ( ), the program ran very slowly; the servo would increment its position about every second, instead of 70 milliseconds. The robot is using Arduino UNO, a PING))) Ultrasonic Distance Sensor, a HMC5883L compass, and an Airtronics Servo #94322. Below is a abridged version of the code with only the sonar and servo function. Also, I've noticed that the code seems to run faster when compiled in Arduino 0022, instead of 1.01.

#include "Servo.h"
const int servoMin = 35;
const int servoMax = 145;

int servo_counter = servoMin;
int servo_direction = 1;

Servo head;
unsigned long headMillis; //used for the Millis servo timer

const int pingPin = 7;
const int minDist = 42; //minimum distance between sonar and obstacle

void setup ( )
{  
  head.attach(4);

  // initialize serial communication for sonar
  Serial.begin(9600); 
}

void loop ( )
{
  sweep ( );
  long cm = sonar ( );   
  Serial.println (cm);

  if (cm <= minDist);
  {
    Serial.println ("too close");
  } 
}

void sweep () 
{

  if (millis() - headMillis > 15) //15 in millaseconds
  {
    headMillis = millis();
    head.write(servo_counter);
    //1 = backwards, 2 = forwards

    if (servo_direction == 1)
    {
      servo_counter += 2;
    }
    else 
    {
      servo_counter -= 2;
    }

    if (servo_counter > servoMax)
    {
      servo_counter = servoMax;
      servo_direction = 2; 
    } 
    else if (servo_counter < servoMin) 
    {
      servo_counter = servoMin;
      servo_direction = 1; 
    }

  }
}

long sonar ( )
{
  long duration, 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
  cm = MicrosecondsToCM(duration);

  return cm;
}

long MicrosecondsToCM(long microseconds)
{
  /*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 microseconds / 29 / 2;
}

Thank you for any help. :slight_smile:

    head.write(servo_counter);

While this line of code may seem perfectly obvious to you, it is not to me. Counters count things. I can't really imagine the number of servos changing, or how the number of servos changing has any bearing on sweeping one particular servo.

A more meaningful name for the servo position variable is in order.

Is the value returned by sonar() consistent with the distance between the sensor and the sensed object? Or, are there a lot of meaningless times returned?

The symptoms suggest that something in loop() is taking significantly longer than 15ms to execute. That call to pulseIn() would be my first suspect, but you should be able to narrow it down by seeing how long it takes to execute sonar() and then see where the time is going. (I'd just write a sketch to call it a load of times and see how long it took, then chop out parts of it and see where the performance changed. For example if you replace the call to MicrosecondsToCM() with a constant value, you could see whether that took longer than you expected. (Well, that function doesn't actually seem likely to be the problem, but you get the idea.)

Thank you for your responses. PaulS and PeterH -- I was implementing your suggestions into the code today, and I noticed something weird. When I run the full program, without attaching the servo to ground on my breadboard, the sonar returns valid distances. However, when I attach the servo, the sonar returns erratic distances. I'm not sure what causes this problem. Also, the if (cm <= minDist) continues to print out "too close" regardless of the distance. I've included an image of the problem below.

Thank you :).

Valhalah:
when I attach the servo, the sonar returns erratic distances.

Perhaps you have some electrical interference, or the power supply is being affected by the servo and your distance sensor is being affected by power fluctuations. How are they wired up?

Valhalah:
Also, the if (cm <= minDist) continues to print out "too close" regardless of the distance.

The image doesn't show any "too close" messages.

I think the problem might be the wiring. Before, the servo would increment its position every second. Now, the servo will sweep and the sonar will read distances for a short period, then turn off for about a second.

The image doesn't show any "too close" messages.

Sorry, I commented out that section of the code before I took the screenshots.

Here is a picture of the wiring:

I switched out the servo, and now it seems to behave randomly: http://www.youtube.com/watch?v=Lu9hNrfGfag&feature=youtu.be
Thank you for your help, PeterH.

You may well have power issues. Generally, it's better to have a separate power supply for the servo - just don't forget to connect the grounds. I think there was a thread like this a week or two back with the same issue - each component worked with the Arduino on its own, but things went haywire when both were powered from the Arduino.

wildbill, you are right. I connected a 7.2V battery to the breadboard with a 5V regulator, and everything worked great. Thanks for your reply :)!