Go Down

Topic: How to prevent stall on servo when returning to position 0 (Read 2730 times) previous topic - next topic

cubangt

So to begin I'm using the sweep sketch found here
https://www.arduino.cc/en/Tutorial/Sweep

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)

MarkT

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.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

cubangt

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..

TomGeorge

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... :)
Everything runs on smoke, let the smoke out, it stops running....

cubangt

this is the original code:

Code: [Select]
#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
   }
}

Southpark

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.

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?


jremington

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.

Southpark

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.

Code: [Select]

/*
 * 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.write(2400);
     delay(4000);
     myservo.write(1500);
     delay(4000);
   }
}


cubangt

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?
Code: [Select]
#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
   }
}

Southpark

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 we 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.

Go Up