Pages: [1]   Go Down
Author Topic: Servo stops working unexpectedly. Seems some code is skipped over.  (Read 594 times)
0 Members and 1 Guest are viewing this topic.
Haverhill, Ma
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone! This sketch is for an obstacle avoiding robot. I just started programming this sketch and already I'm running into a snag. The servo stops responding after the do...while loop in the Full_Scan() function. The servo sweeps from 0 to 180 but does not return back to the midpoint after the sweep. Does anyone have an idea why this happens?

Code:
#include <Servo.h>
#include <NewPing.h>

#define PING_PIN 14  //Analog pin A0
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400.

#define SERVO_DELAY_15 100    //Delay time for servo to travel 15 degrees
#define SERVO_DELAY_90 250   //Delay time for servo to travel 90 degrees

Servo Ping_Servo;
NewPing sonar(PING_PIN, PING_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

long Ping_Array[13];    //Stores all ping distances. Represents Left(0 degrees)--> Forward(90)--> Right(180) in 15 degree increments

void setup()  {
  Serial.begin(57600);
  Serial.println("Ready!");

  Ping_Servo.attach(10);      //Turn on servo by assigning it pin 10. Also set min and max pulse widths
  Ping_Servo.write(90);      //Move servo to midpoint
  delay(SERVO_DELAY_90);     //Give servo time to get to midpoint

  Full_Scan();      //Initialize Ping_Array[]
  Print_Ping_Array();
}

void loop()  {

}

void Full_Scan()  {      //Performs a full sweep with the Ping_Servo and fills Ping_Array[] with distance in centimeters
  int i = 0;      //Counter
  int Degrees = 0;      //Servo position
  long Next_Time = 0;

  Ping_Servo.write(Degrees);      //Get servo in position to start sweep... 0 degrees
  Next_Time = millis() + SERVO_DELAY_90;

  do  {   
      if (millis() >= Next_Time)  {
        Ping_Array[i] = sonar.ping_cm();
        Degrees = Degrees + 15;
        Ping_Servo.write(Degrees);
        Next_Time = millis() + SERVO_DELAY_15;
        i++;
      }
  }
  while (i <= 13);

  //This doesn't work!
  Ping_Servo.write(90);
  delay(SERVO_DELAY_90);     //Give servo time to get to midpoint
}

void Print_Ping_Array()  {
  int i;
  Serial.println("Displaying Ping_Array");
  for (i = 0; i <= 12; i++)  {
    Serial.print("Element "); Serial.print(i, DEC); Serial.print(": "); Serial.print(Ping_Array[i], DEC); Serial.print("cm");
    Serial.println("");
  }
}


I was able to get the servo working using the following code but I'm curious to why the above code doesn't work.

Code:
void Full_Scan()  {      //Performs a full sweep with the Ping_Servo and fills Ping_Array[] with distance in centimeters
  int i = 0;      //Counter
  int Degrees = 0;      //Servo position
  long Next_Time = 0;

  Ping_Servo.write(Degrees);      //Get servo in position to start sweep... 0 degrees
  Next_Time = millis() + SERVO_DELAY_90;

  do  {
    if (i <= 12)  {   
      if (millis() >= Next_Time)  {
        Ping_Array[i] = sonar.ping_cm();
        Degrees = Degrees + 15;
        Ping_Servo.write(Degrees);
        Next_Time = millis() + SERVO_DELAY_15;
        i++;
      }
    }
    else  {
      Ping_Servo.write(90);
      i++;
    }
  }
  while (i <= 14);
}
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8940
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your first code is running off the end of the array:
Code:
long Ping_Array[13];
 int i = 0;      //Counter
  do  {    
        Ping_Array[i] = sonar.ping_cm();
        i++;
  }
  while (i <= 13);

Valid indexes in the Ping_Array are 0 to 12.  You are writing to index 13.


Since Full_Scan() doesn't return until done you can greatly simplify the code:

Code:
void Full_Scan()  {      //Performs a full sweep with the Ping_Servo and fills Ping_Array[] with distance in centimeters
  for (int i=0; i<13; i++) {
        Ping_Servo.write(i*15);
        delay(SERVO_DELAY_15);
        Ping_Array[i] = sonar.ping_cm();
  }

  Ping_Servo.write(90);
  delay(SERVO_DELAY_90);     //Give servo time to get to midpoint
}
« Last Edit: December 02, 2012, 11:17:59 am by johnwasser » Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50123
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using a do/while loop to iterate a fixed number of times is like using a screwdriver for a pry bar. Use the correct construct - a for loop.
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17301
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using a do/while loop to iterate a fixed number of times is like using a screwdriver for a pry bar. Use the correct construct - a for loop.

Which reminds me of the thing a software programmer once told be about screwdrivers, that they come with plus  or negative ends.  smiley-wink

Lefty
Logged

Haverhill, Ma
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your first code is running off the end of the array:
Code:
long Ping_Array[13];
 int i = 0;      //Counter
  do  {    
        Ping_Array[i] = sonar.ping_cm();
        i++;
  }
  while (i <= 13);

Valid indexes in the Ping_Array are 0 to 12.  You are writing to index 13.
I'm pretty sure the last time "i" is used to access Ping_Array it is 12. "i" gets updated afterwards... Am I mistaken?

Also, the reason I used the do..while loop instead of a for loop was because I am trying to avoid using the delay() function. I always read about avoiding the delay function because it makes the sketch unresponsive.

Edit: The for loop definitely makes the code cleaner looking though.
« Last Edit: December 02, 2012, 11:37:19 am by Bill2k » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17301
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Also, the reason I used the do..while loop instead of a for loop was because I am trying to avoid using the delay() function. I always read about avoiding the delay function because it makes the sketch unresponsive.

The delay(x) function can make a sketch unresponsive because it's a 'blocking function' and nothing else in the sketch flow can execute until the delay function 'times out' after x milliseconds. Look at the blink without delay example sketch in the IDE for the best method to time events without blocking program flow.

Lefty

Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 212
Posts: 8940
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm pretty sure the last time "i" is used to access Ping_Array it is 12. "i" gets updated afterwards... Am I mistaken?

You are mistaken.  When element 12 is written and 'i' is incremented to 13 the while loop sees that (i <= 13) is true so it continues to loop and element 13 is written on the next iteration.  Only when 'i' is incremented to 14 does the loop end.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Haverhill, Ma
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Using a do/while loop to iterate a fixed number of times is like using a screwdriver for a pry bar. Use the correct construct - a for loop.

Craftman screwdrivers make excellent pry bars as long as there is a Sears nearby  smiley-wink
Logged

Haverhill, Ma
Offline Offline
Newbie
*
Karma: 0
Posts: 31
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are mistaken.  When element 12 is written and 'i' is incremented to 13 the while loop sees that (i <= 13) is true so it continues to loop and element 13 is written on the next iteration.  Only when 'i' is incremented to 14 does the loop end.
Thanks for pointing that out. I'm not sure why it looked right to me in the first place.

The delay(x) function can make a sketch unresponsive because it's a 'blocking function' and nothing else in the sketch flow can execute until the delay function 'times out' after x milliseconds. Look at the blink without delay example sketch in the IDE for the best method to time events without blocking program flow.

I'm not quite following you here... Are you saying because the function doesn't return till its done, then its ok to use delay. But if other functions had to run also, then used the Blink without delay method?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17301
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are mistaken.  When element 12 is written and 'i' is incremented to 13 the while loop sees that (i <= 13) is true so it continues to loop and element 13 is written on the next iteration.  Only when 'i' is incremented to 14 does the loop end.
Thanks for pointing that out. I'm not sure why it looked right to me in the first place.

The delay(x) function can make a sketch unresponsive because it's a 'blocking function' and nothing else in the sketch flow can execute until the delay function 'times out' after x milliseconds. Look at the blink without delay example sketch in the IDE for the best method to time events without blocking program flow.

I'm not quite following you here... Are you saying because the function doesn't return till its done, then its ok to use delay. But if other functions had to run also, then used the Blink without delay method?

 I'm saying that any use of delay() can be a killer in sketches where you want multiple independent tasks to do their thing without having to wait for the individuals tasks to complete their functions. Use of the millis() and micros() functions and keeping 'time stamps' variables and flags for each individual task updated is a way to have your main loop function continue to loop through all the individual tasks to see if something needs to be done in them or not in each pass of the main loop, therefore always having time to keep up with the needs of each individual task. An airline traffic controller can keep track of and service many planes in the air at the same time. He does not just work with just one plane and only service the next plane when finished with the first one. Your sketch can operate just as well as that air traffic controller does.

Lefty
Logged

Pages: [1]   Go Up
Jump to: