How to prevent stall on servo when returning to position 0

So to begin I'm using the sweep sketch found here

After uploading, when it gets to position 180, its a smooth return the other way heading toward position 0. But when it gets to position 0 it stalls/hangs like its being forced past and then turns around to 180.

Id like to see if its possible to do away with that and how I can add to the sketch to trigger the moving based on other conditions..

thanks..

I have the Motor Control Shield v1.0 (DK Electronics)

Most servos cannot do anything like 180 degrees, typically 120--150 degrees of movement only.
If you command them out of the mechanical range they hit the endstop and stall, which will
overheat them if left for any length of time. Overheated servo will cook and become useless.
A smart servo will detect continuous stall and/or over temperature and protect itself.

so what would be safe ranges to use to test position of the servo?
I tried smaller rotations like 150 and 5(instead of 0) and still ran into slight stall..

there has to be something else im missing..

Hi,

Can you please post a copy of your sketch, using code tags?
They are made with the </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

Thanks.. Tom... :slight_smile:

this is the original code:

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int pos = 0;    // variable to store the servo position

void setup() {
   myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
   for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
     // in steps of 1 degree
     myservo.write(pos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
   for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
     myservo.write(pos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
}

cubangt:
After uploading, when it gets to position 180, its a smooth return the other way heading toward position 0. But when it gets to position 0 it stalls/hangs like its being forced past and then turns around to 180.

Not 100% sure what you mean from the above, as the description could have been a bit rushed.

But what I normally do is to just write a script that slowly and gradually increases the PWM pulse width in steps.... such as in steps of 50. eg... 0, 50, 100, 150 etc. And, initially the servo will not move until the pulse width gets large enough.... such as when it reaches 650 or 700. That's when you record the value (at which the pulse width is wide enough to get things moving). The script should write messages to Serial Monitor - so that the test results can be monitored.

Then the stepping continues. eg... 2000, 2050, 2100 etc. Eventually it'll get to a point where the pulse width is too large and the servo won't do anything. So I record the very last/highest 'workable' value.

That gets you your range of pulse width (at least roughly) for which the motor will respond to workable pulse widths.

From that point on, it is necessary to use only the workable values of pulse width. Don't use values that the motor doesn't respond to (or responds incorrectly to).

So, you might end up with a range of pulse widths from 700 to 2100. The two end-points (700 and 2100) would then correspond roughly to minimum and maximum workable angle that your motor will allow.

Since I'm kinda new to the servo controlling portion of Arduino, how would you gradually increase the PWM pulse? if the code provided above is based on position? is there a change I would need to make in order to control it more gradually?

The simplest approach is to just keep editing the servo sweep example until everything works properly.

When done, write the min and max endpoints on the servo with indelible ink.

cubangt:
Since I'm kinda new to the servo controlling portion of Arduino, how would you gradually increase the PWM pulse? if the code provided above is based on position? is there a change I would need to make in order to control it more gradually?

Here's some code that I used with a MEGA2560 and a typical servo motor MG966R. I modified someone's code (that I found on the internet). It requires the arduino 'Servo' library.

While I used a MEGA2560, it should work on UNO too. If it doesn't work immediately for UNO, then might need to change the code to use a different pin number ..... such as use digital pin 6 (INSTEAD of digital pins 9 or 10).

When it says 'press a key' (in serial monitor), it usually means something like pressing the space bar ONCE, or pressing a button on the keyboard (such as pushing the 'a' key), FOLLOWED BY pushing the ENTER button.

/*
 * Simple Arduino sketch to find the full pulsewidth range of a servo
 *
 * INSTRUCTIONS
 *
 * Watch the serial port, and press a key each time the servo starts/stops moving regularly.
 * 
 * If you're using the Arduino IDE "Serial Monitor", you'll need to type something into the 
 * text field and then press "Send"
 *
 * When you're done, the sketch will output the low and high pulse widths, a sample attach() line, and then
 * start sweeping from top to bottom so you can check it works and/or measure the total angle.
 *
 * Ignore any massive jumping movements when searching, servos often seem to move to a random angle when
 * you send a really out-of-range signal to them.
 *
 *
 * This sketch is released under the GNU General Public License v2, (C) 2009 Angus Gratton 
 */

// Assuming the angle position servo motor is already powered, and digital pin 10 arduino is connected to the servo's PWM control signal INPUT line.
// Use the serial communications monitor. The software starts with pulse width modulation using short pulse-width duration, eg 100 microsecond width to start with.
// No motor response expected due to widths being outside the active range. Iteratively increase the pulse width (increments of +64 microseconds)...eg 164, 228 microseconds etc.
// Eventually the servo will move. This is when we need to press a key (or type a letter in the serial monitor, and press ENTER). This stores the minimum duration required to make the servo respond.
// The ramping continues until we get to a width level where the motor stops responding. At this point, press a key again. This stores the maximum pulse width.

// MG966R angle servos typically have pulse width 1.5 millisecond (1500 MICROsecond) for a mid-angle position 

#include <Servo.h>
#include <stdio.h>

char buffer[128]; // This wastes a bunch of RAM, but we don't need it for this sketch
#define printfLn(format, args... ) \
  snprintf(buffer, sizeof(buffer), format, ## args); \
  Serial.println(buffer);


/*
 * Set this to the pin your servo is hooked to (9 or 10.)
 */
const int servopin = 10;

Servo myservo;

void setup() 
{ 
  int del = 64;
  Serial.begin(9600);
  
  Serial.println("Searching for low pulse width");
  int low = search_low(100, del);  //starting pulse duration, incremental additive value, boolean value to trigger a print statement word
  
  Serial.println("Got low pulse width...");
  delay(2000);
  
  Serial.println("Searching for high pulse width");
  int high = search_high(low, del) - del;  //the minus is for removing the latest recorded value, as the latest one is invalid.

  Serial.println();
  Serial.println();
  printfLn("Got low pulse width of %d", low);
  printfLn("Got high pulse width of %d", high);
  Serial.println();
  printfLn("Example code: myservo.attach(%d, %d, %d);", servopin, low, high);
  
  Serial.println();
  Serial.println("Done (sweeping.)");
  
  myservo.attach(servopin, low, high);
} 

int search_low(int value, int delta)  //
{
   Serial.println("Press any key when the servo %s moving starts"); 
   delay(5000);
   value = sweep(value, delta);  // this is a looping function
   return value;
   delay(5000);  
}

int search_high(int value, int delta)  //
{
   Serial.println("Press any key when the servo %s moving stops - ie when it doesn't respond to the most recent pulse width command"); 
   delay(5000);
   value = sweep(value, delta);  // this is a looping function
   return  value;
   delay(5000);
}

int sweep(int value, int delta)
{
   int value_store = value;
   value = value - delta;
   while(Serial.available()<=0)
   {
     value = value + delta;
     myservo.attach(servopin);
     myservo.writeMicroseconds(value);
     Serial.println(value);
     delay(5000);   // put the delay here.... not after the detach line, since it is important to attach servos before they move, and to detach after they have finished moving.... ie.. not during transitions or activity...otherwise leads to operating problems.
     myservo.detach(); 


     if (value >= 3000) {  // start the pulse width ramping cycle again once we've gone past a certain level.
      value = value_store;
     }
   }
   while(Serial.available()>0)
     Serial.read();
  return value;
} 

void loop() 
{ 
   // Just loop through a few working values
   while(true)
   {
     myservo.writeMicroseconds(700);
     delay(4000);
     myservo.writeMicroseconds(1500);
     delay(4000);
     myservo.writeMicroseconds(2400);
     delay(4000);
     myservo.writeMicroseconds(1500);
     delay(4000);
   }
}

So I finally got around to working on this again, I ran the provided sketch, got the low and high pulse for the servo and with that sketch, its working without stalling..

But id like to update my simple sketch to use these new values and wanted to know what I need to focus on changing within this sketch?

This is the results provided by the above sketch:

Got low pulse width of 740
Got high pulse width of 2468

Example code: myservo.attach(9, 740, 2468);

Done (sweeping.)

Here is my simple sketch with the new values, just by adding the values into the attach the below code isn't stalling like before.. is it really that simple?

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int pos = 0;    // variable to store the servo position

void setup() {
   //myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  myservo.attach(9, 740, 2468);

}

void loop() {
   for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
     // in steps of 1 degree
     myservo.write(pos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
   for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
     myservo.write(pos);              // tell servo to go to position in variable 'pos'
     delay(15);                       // waits 15ms for the servo to reach the position
   }
}

I think the main thing to think about (about these servos) are ---- one method for controlling the shaft-position is by changing a 'pulse width' setting. Eg.... a pulse width of 740 microseconds.

Usually..... 1500 microseconds would correspond to the mid-point position of a SERVO. That might be the '90 degree' position. However, it is just an assumption. But - usually, we assume that 1500 microseconds (general case) corresponds to a 90 degree position.

So 740 microseconds would correspond to some other position. And 2468 microseconds would correspond another position.

The only way we'll know what those exact positions are, will be to "measure" the angles associated with those positions. How to measure? Maybe a rotary encoder of some sort. If we do the angle measurements, then at least we know the relation between pulse width and actual shaft-angle.

Otherwise, if no measurements are done, then the only thing would could do is to 'assume' that the relationship between angle and pulse width is linearly proportional. But we'd only know for sure after angle measurements are done anyway.

Hello,
I will soon play with an Arduino UNO and different type of servos, to meet the demand of teenagers that I try to occupy outside school periods.
I discover that along with them.
I'm trying to understand your codes. Excuse me for my ignorance.
From what I understood the different positions (angles) from 0 to 180 are declared in degrees!
Beyond these values the positions will be interpreted in microseconds (544 to 2400).
A question that comes up often is: How to set the minimum and maximum limits of a servo.
The code posed by "Southpark" seems to help that, but I do not understand the final loop

void loop()
{
   // Just loop through a few working values
   while(true)
   {
     myservo.writeMicroseconds(700);
     delay(4000);
     myservo.writeMicroseconds(1500);
     delay(4000);
     myservo.write(2400);
     delay(4000);
     myservo.write(1500);
     delay(4000);
   }
}

Why use write (x) and writeMicroseconds (x) in the same loop on values in microseconds?
Thank you for your explanations.
Best regards

Hello,
@ Southpark
In your version of the code you say:

Southpark:
// Use the serial communications monitor. The software starts with pulse width modulation using short pulse-width duration, eg 100 microsecond width to start with.
// No motor response expected due to widths being outside the active range. Iteratively increase the pulse width (increments of +64 microseconds)...eg 164, 228 microseconds etc.

You have chosen 100 as the starting value.
Do you have a technical reason for this choice?
Why not choose a multiple of 64 to start (64 or 128) since the incrementation is 64?
Does the difference have a real impact?

100 => 128
164 => 192
228 => 256
292 => 320
356 => 384 ....

Hi,
Welcome to the Forum.

I don't think you will get an instant reply to your posts here.
This thread was last posted in Sept 2016.

If you have a problem, I would suggest you start your own thread.

Tom.... :slight_smile:

Hello TomGeorge,
Thank you for your welcome, my presentation seems to have been unnoticed, embedded in the flow of messages.
There is no real problem with the "Southpark" sketch, I'm just trying to understand.

  1. The choice of the starting pulse width (100 microseconds).
    I understood that she had to be small, to be outside the active beach, but what guided this choice?

  2. +64 microsecond increments, for finding low servo motion.
    There too I try to understand why 64 microseconds?

Thank you for your explanations.
Best regards.

nerixs ..... in general, it's best to start a new thread and then ask your question in the new thread. Maybe you have done that already by now.

the writeMicroseconds function takes in a value between say 1000 and 2000, with the middle position between 1500. The units of these values are in microseconds. If the typical servo has 90 degrees as the middle position, then put in a value of '1500'. If you put in a value of 2000 instead, then the servo would move to one of the max limits .... possibly 180 degree. And putting in 1000 would move to the other limit...such as 0 degree.

The actual 'physical' angle that the servo shaft will move may depend on the quality and type of servo. A super cheap 'toy' servo might not 'actually' move to 180 degree if you write '2000' microseconds. Instead....it might move to some angle below 180 degree. Whereas a relatively more expensive servo may move really close to 180 degree if you write '2000'.

The 'write' (not writeMicroseconds) function is a higher level function which is supposed to handle the 'angle'. It allows you to put values like '90' or '180' etc units of degrees into the 'write' function. However, the control of these sorts of servos are really based on the duration (pulse width) of a square pulse waveform. So if the actual servo you have doesn't truly have physical movable limits of 0 degrees and 180 degrees, then putting in a value of 0 or 180 into the 'write' function might not actually give you physical 0 degrees or physical 180 degrees on the actual servo.

I think the same thing applies to the writeMicroseconds function. That is.... sure, we could put in a microseconds value of 2000 .... but the servo might not go to 180 degrees if the actual servo motor doesn't actually cover up to 180 degrees (physically).

In my code, I remember I got the code from somewhere, and just modified it a bit. The lines where it has writeMicroseconds should all be writeMicroseconds --- which I've now corrected. So the 'write' that was there is now changed to writeMicroseconds.

nerixs:
You have chosen 100 as the starting value.

The code came from the internet somewhere. You can choose any suitable starting value, and you can also choose any suitable incrementing value. If you wanted to start from 1000, then that's ok too. And you the increment could be '50' instead of '64'.