Timing Problem

NOTE: READ THE BELOW POST FIRST I MESSED UP AND WENT OVER ON CHARACTERS

Here'e the code (ignore any commented-out code and subroutines that are not called upon):

int servoturretPin = 3;
int pulses = 0;
int sensVal[10];
int prevSensVal[10];
int ultraSoundSignal = 7; // Ultrasound signal pin
int val = 0;
int ultrasoundValue = 0;
int timecount = 0; // Echo counter
int ledPin = 8; // LED connected to digital pin 13
boolean increment;
int i;
int prevcnt;
int newcnt;
int done;
int a;
int x;
int prevtime;
int delaytime;

void setup() {
  Serial.begin(9600);
  pinMode(servoturretPin, OUTPUT);
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  Scan();
}

void Scan() {
  
  if(done == 2) {                     // This if for debugging; it scans as much as it needs to to get results, then shows you them
    printVals();
  }
  if(pulses >= 2100)                     // Starting here is the code for handling the back-and-forth of the servo
  {  pulses = 2100;   
     increment = true;
    while(pulses >= 1100) 
    {
      prevtime = millis();              // Here I TRIED to fix the timing problem; it doesn't work, though
      readPing();                         // read the ultrasonic rangefinder
      pulses = pulses - 50;                  // Speed
      digitalWrite(servoturretPin, HIGH);
      delayMicroseconds(pulses);
      digitalWrite(servoturretPin, LOW);
      delay(delaytime);                             // Speed
    }
    if(millis() > 10000) {
      done = done + 1;
    }
    a = 0;
  } 
  else if(pulses <= 1100)  
  {  pulses = 1100;  
     increment = false;
    while(pulses <= 2100)
    {
      prevtime = millis();
      readPing();                                // read it again in reverse direction
      pulses = pulses + 50;                  // Speed
      digitalWrite(servoturretPin, HIGH);
      delayMicroseconds(pulses);
      digitalWrite(servoturretPin, LOW);
      delay(delaytime);                             // Speed
    } 
    if(millis() > 10000) {
      done = done + 1;
    }
    a = 0;
  }
}                                               // (end of code for handling servo)
void readPing() {
 timecount = 0;
 val = 0;
 pinMode(ultraSoundSignal, OUTPUT); // Switch signalpin to output

/* Send low-high-low pulse to activate the trigger pulse of the sensor
 * -------------------------------------------------------------------
 */

digitalWrite(ultraSoundSignal, LOW); // Send low pulse
delayMicroseconds(2); // Wait for 2 microseconds
digitalWrite(ultraSoundSignal, HIGH); // Send high pulse
delayMicroseconds(5); // Wait for 5 microseconds
digitalWrite(ultraSoundSignal, LOW); // Holdoff

/* Listening for echo pulse
 * -------------------------------------------------------------------
 */

pinMode(ultraSoundSignal, INPUT); // Switch signalpin to input
val = digitalRead(ultraSoundSignal); // Append signal value to val
while(val == LOW) { // Loop until pin reads a high value
  val = digitalRead(ultraSoundSignal);
}

while(val == HIGH) { // Loop until pin reads a high value
  val = digitalRead(ultraSoundSignal);
  timecount = timecount +1;            // Count echo pulse time
}

/* Writing out values to the serial port
 * -------------------------------------------------------------------
 */

ultrasoundValue = timecount; // Append echo pulse time to ultrasoundValue
Serial.println(ultrasoundValue);

if(pulses == 1100 || pulses == 1200 || pulses == 1300 || pulses == 1400 || pulses == 1500 || pulses == 1600 || pulses == 1700 || pulses == 1800 || pulses == 1900 || pulses == 2000 || pulses == 2100 && millis() > 10000 ) {
  if(increment == true) {                         // The function of the above 'if' is to ONLY store new values every time pulses is 100 more 
    prevSensVal[a] = ultrasoundValue;     // ...(store a total of 10 values in each direction)
    a++;
  }       // The above 'if' is for storing the first set of values
  if(increment == false) {   // and <---- this one if for storing the next set (after reversing direction)
    sensVal[a] = ultrasoundValue;
    a++;
  }
}
for(x = 0; x < 9; x++) {      // For debugging
  if(prevSensVal[x] > 0) {
    prevcnt = prevcnt + 1;
  }
  if(sensVal[x] > 0) {
    newcnt = newcnt + 1;
  }
}
delaytime = 150 - (millis() - prevtime);
}
void printVals() {
  Serial.println("Counters: ");
  Serial.println(prevcnt);
  Serial.println(newcnt);
  Serial.println("Previous");
  for(i = 0; i < 10; i++) {
    Serial.println(prevSensVal[i]);
  }
  Serial.println("Newest");
  for(i = 0; i < 10; i++) {
    Serial.println(sensVal[i]);
  }
  end();
}
void end() {                  // ignore
  delay(500);
  end();
}

Okay - so I decided that cool security systems like the ones you see in futuristic sci-fi movies are really cool, so I decided to start making one myself. It may be kind-of ineffective the way I'm doing this, but hey, the thing looks really cool and intimidating when in action. BUT - I've got a timing problem. Basically, the whole setup is a ultrasonic rangefinder mounted on a standard hobby servo, that pans ~ 120 degrees as the ultrasonic ranger (it's a Parallax 'Ping)))') 'scans' the environment. The device checks the ultrasonic rangefinder between every pulse to the servo. Well, little did I know that there's a huge varying delay between the time the ranger sends out an ultrasonic signal, and when it receives that signal (a couple milliseconds). THIS is a problem, because the pulse width is messed up on the servo, and it throws the readings off (it scans 120 degrees in one direction, then reverses direction and scans that 120 degrees, comparing the results from each direction. How can I fix this? Do I need to mess with the 'delayMicroseconcds' part and do some math and make a scale to keep everything even? Or is my claim wrong about the timing problem, and it's in fact something entirely different?

I am not clear on what you are trying to do, but having a separate functions for measuring the range and moving the servo would probably help.

If you want to measure the range over say 12 steps from 0 to 120 degrees and see if the range changes for any of the steps, you could do something like the following in loop:

  • If the servo is at an extreme, toggle the current direction
  • Step the servo 10 degrees in the current direction.
  • Wait for the servo to move and stabilise position (say 50 to 100 ms)
  • Measure the range
  • Compare the range with the previous value in this position and trigger alarm if appropriate

Ok.
I AM stepping 10 degrees (or so I guess)
The servo IS following the 'if at an extreme, toggle direction' rule
BUT--

-The range is being measured AFTER the pulse is sent to the servo, not before.
-It is NOT waiting a few ms for the servo to move and stabilize position

Do you think that could be messing up the results?
When I have the Arduio send the two sets of results to the serial port on my PC, SOME values DO match up, but others may be wayyyy off. This MUST be because it's not taking the readings from one 120 degree sweep in the SAME POSITION as the second set of readings (they should BOTH be taken in the same positions on the servo axis). So this has do do with a timing problem, maybe? Or is it something else? When I get a chance, I'll add in a delay after the servo routine (right after it pulses out the pulse width to the servo), and put the 'readPing()' routine AFTER that delay. Maybe that'll fix it... :-/

Even the fastest servos need a few pulses to move 10 degrees. I suggest you allow at least 100ms (around 5 servo pulses) before taking your sensor readings. You can always speed things up when you have it working.

Mmmkk... But I'm not sure it's moving exactly 10 degrees at a time; the '10' increments in the program are definitely not 10 degrees, now that I think about it; the pulse width extremes that the Arduino sends to this servo are 1100 and 2100, and this servo obviously does not rotate up to 2100 degrees (or even 360 for that matter). So maybe that's not the problem.....?

Its unlikely to move exactly 10 degrees, there is no standardization for how much a servo should move for a given pulse width change. But a decent servo that is not overloaded and not binding should maintain the same position for the same pulse width within a better margin of error than your sensors require. You should be able to see (or hear) if its binding at the extremes

A test you can try to verify the movement is as expected is to attach a pointer to the servo arm and mark the position of each 'step' on some paper under the arm. A light bamboo skewer would work for the pointer and you should be able to see if the position of the pointer is in the same place after each sweep.

Greetings,

You might consider measuring at 10degree intervals going up till you get to the limit and then going all the way back to zero for the next set of measurements instead of doing them in reverse. This would probably simplify you code a lot, and would get rid of the potential problem where lower-limit +10, +10, etc. is not the same position as upper-limit -10, -10, etc...

Regards,
David

Good idea. Tried it; it doesn't work. Thanks, though. I've given up this project because even though it LOOKS cool, it's completely impractical and the code is extremely delicate (easily flawed). It's just not practical for use as an alarm, and it simply doesn't work. :cry: