panning a PING: code check!

OBJECTIVE: pan a servo smoothly from 0 to 140 degrees, while taking readings from a sonar sensor (PING).

PROBLEM: the servo moves in choppy movements and because of the pulseIn command used for the PING, the servo moves faster/slower at certain points in the turn. Also, sometimes the ping and servo stop all together at random intervals in the rotation.

CODE:

#include <Servo.h>

Servo scanServo;
int pos = 0;

int ledPin = 13;
int pingPin = 8;
long duration, distance;

void setup ()
{
  scanServo.attach(7);
  Serial.begin(9600);
}

void loop()
{
 scan();
 if (distance < 10)  {
   digitalWrite(ledPin, HIGH);  }
 else {
   digitalWrite(ledPin, LOW);  }
}

long ping()
{
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);
  distance = duration / 29 / 2;
  Serial.print("PING = ");
  Serial.println(distance);
  delay(100);
}

void scan()
{
  for(pos = 0; pos < 140; pos += 2)  {
  scanServo.write(pos);
  ping();
  delay(15);  }
for(pos = 140; pos > 0; pos -= 2)  {
  scanServo.write(pos);
  ping();
  delay(15);  }
}
Serial.print('PING = ');

That doesn't look right - has something automatically changed your double quotes to singles?

Can you detach the servo before pinging, and reattach it after pinging?

Why are you delaying some more after pinging? Doesn’t ping delay enough?

Changed the Serial.print, now that is working.

Got rid of the delay(15), and the servo started to move very irregularly. I think the problem is that the PING is waiting to get an input, but the servo moves out of the way. The delays are helping the PING so that it takes readings every time, but it is also hindering the servo from moving in a smooth way. Is there maybe a different command, other than pulseIn, to use with the PING?

Also, What do you mean detach the servo before pinging? Is that what you were saying about the delay command?

What do you mean detach the servo before pinging?

Call "scanServo.detach()" Then call "scanServo.attach (whatever_pin);" before moving it again.

I think the problem is that the PING is waiting to get an input, but the servo moves out of the way.

Shouldn't happen - it's all synchronous.

Ok, so maybe my explanation wasn't correct, but is there any other reason that the servo would be moving so "choppily"?

I guess what im asking is can i sweep the servo from 0 to 140 without using steps (this way it wont be jerky) and at the same time fire the PING? So doing them both at the same time, but not intertwined in the code so that the servo turns, ping fires, servo turn, ping fires, etc....

You kinda have to do those steps, because it takes a certain amount of time for the sensor to fire and receive a return (speed of sound); you can't move the sensor before it gets the return echo back.

Maybe you could approach this another way:

  1. Fire the ping; on the return echo activate an interrupt.

  2. In the interrupt, store the value, rotate the servo a little.

  3. If at the "end of travel" (whatever that means to you), reverse the direction of the servo or position it back "home" (whereever that is).

  4. Go back to step 1

This way you would only be moving the servo on receipt of the echo, running the system as fast as the ping sensor will go, not as fast as the servo will go.

It will still be choppy, but hopefully less so.

You might also mount the ping on a stepper, instead of a servo (but you will need some other kind of position feedback); you might be able to get better angular resolution this way.

If none of that works to your satisfaction, then you may want to look into a custom "flying spot" LIDAR (http://en.wikipedia.org/wiki/LIDAR) system (not cheap, not easy, but definitely homebrew-able!).

Something I had thought about my reply: what happens if the ping isn't received back? You essentially get stuck. What you would probably want to do is somehow implement a timer that is started when the ping is sent out, then checked periodically and if the time elapsed is greater than say what the time it would take to cover 30 feet or so (or whatever your max sense distance is), count it as "no object" and move on.

Sorry about the oversight...

:)

Thanks! That is really helpful, because that is one of the problems I was running into. I didnt think of that. Thanks so much for all your help!