Servos range smaller than expected

Hello,

First of all, I'm sorry if I post this message in the category or if I do anything wrong... It's my first time posting on the forum :blush:.

The thing is I'm trying to do a robot with a pan-tilt to put a camera on it. So I'm using servos (MG995) and the arduino library "Servo". The thing is that with my code, I am unable to make the motor rotate the 180° that it should be able to rotate. The motor turn only something like 100° when I ask for 180°.

Or I got another code on an another platform (energia and the texas instrument stuff) that is able to make it turn 180°. Meaning it's the code fault.

I'm alimenting this servos with the 5V delivered by the arduino.
Here is my code :

//Servo switch

#include <Servo.h>

Servo myservo;
int pushButton = 2;
int buttonAnte=-1;
int pos = 0;    
int car = 70;
int oldCar = 25;
int time=0;
int var=0;

int motor1Pin = 4;    // H-bridge leg 1 (pin 2, 1A)
const int motor2Pin = 3;    // H-bridge leg 2 (pin 7, 2A)
const int enablePin = 5; 

void setup() {
  Serial.begin(9600);
  pinMode(pushButton, INPUT);
  myservo.attach(9,600,2400); //600 - 2400
  
  pinMode(motor1Pin, OUTPUT); 
  pinMode(motor2Pin, OUTPUT); 
  pinMode(enablePin, OUTPUT);
  digitalWrite(motor1Pin, HIGH);   // set leg 1 of the H-bridge low
  digitalWrite(motor2Pin, LOW);
  
  myservo.write(car);
}

void loop() 
{
 
  int var = 1;
  int buttonState = digitalRead(pushButton);
  Serial.print(buttonState);
 /************PRemier********/

  if (buttonState==0){
    if(car>0){
      digitalWrite(enablePin, HIGH);
      myservo.write(car);
      car=car-1;
      //Serial.println(car);
      delay(5);
    }
    else{
      digitalWrite(enablePin, LOW);
      Serial.println("Standby");
    }
  }
  else{
    digitalWrite(enablePin, HIGH);
        if(car<180){
      myservo.write(car);
      car=car+1;
      
      delay(5);
    }
    Serial.println(car);
    myservo.write(car);
  }
  
}

Thank you very much, any help will be really appreciated :). And tell me if you want some more info.

Try increasing 2400 to 2600 and higher

myservo.attach(9,600,2400); //600 - 2400

I tried that and that didn't work =(.

In fact, nothing changed in the servos response. So, for "fun" I tried to initialized the servos like this (by the way, I tool an simpler code, the one named "sweep" in the example to study that problem) :

// Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.


#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int pos = 0;    // variable to store the servo position 
 
void setup() 
{ 
  myservo.attach(9,600,600);  // 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>=1; 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 
  } 
}

It shouldn't be able to move right ?

And ... Suspense... Nothing changed. The servos still move from 0 to 100° (more or less). So I guess there is a problem in the servos library but I'm a little bit bugged by this conclusion.

Try controlling your servo with Servo.writeMicroseconds() which gives you a lot more control than using degrees. All servos are different and it may be that yours works from the equivalent of -20 degrees or something like that. Nominally the range is from 1000 microseconds to 2000 microseconds corresponding to 0 deg and 180 deg. But it may work down to 500 microseconds or even less. You will need to experiment.

With all of the servos I have it is possible to slowly turn the arm manually to see where the physical end-stops are. Only try this when the servo is disconnected from power.

The number of microseconds is the width of the electrical pulse sent to the servo which interprets the width to determine the angle for the servo arm.

...R

Powering the servo from the arduino may be a problem - the servo will likely draw more current than the arduino can provide, particularly under load. Are you running your tests with the pan/tilt mechanism attached? Also, the range that servos can move through varies. However, it sounds as though you tested this exact servo in another rig and got the 180 you're looking for - is that the case?

Thanks for all the answers !

So, I tried to use the function writeMicroseconds() and I got a couple of weird bug.
First of all, the servo still stop at the same position (between 0 and 120°) but with new start point and end point. I tried to go further than those position with no luck... :frowning:

Here is my new code

// Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.


#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 

 
void setup() 
{ 
  Serial.begin(9600);
  Serial.println("Start \n");
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  myservo.write(0);
  Serial.println("Begin");
} 
 
 
void loop() 
{ 
  for(int pos = 200; pos < 2501; pos =pos+ 5)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.writeMicroseconds(pos);              // tell servo to go to position in variable 'pos' 
    Serial.println(pos);
    delay(5);                       // waits 15ms for the servo to reach the position 
  } 
  for(int pos = 2500; pos>=200; pos=pos-5)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.writeMicroseconds(pos);              // tell servo to go to position in variable 'pos' 
    Serial.println(pos);
    delay(5);                       // waits 15ms for the servo to reach the position 
  } 
  myservo.writeMicroseconds(1500);
  delay(1000);
}

If I don't print pos, the program just crash and I don't know why. Here, for example, the last line of the code just made the whole program crash... The arduino board (Nano) just reset and start all over again.
Plus, if the servos is not at 200 at the start of the for statement, the program crash as well :/...
I really have no idea of what... I put the red wireof the servos on the 5V supply ad the bromn on the gnd. The orange one is on the 9th pin of the arduino.

And if I'm movind the servo "by hands" I can see that the end point is far from were the servos is going using the servos library... It actually is 180°...

I checked the need voltage of the servos and in the datasheet they say it's between 4C ~ 6V so it should be alright with 5V, shouldn't it ? I'm not doing the tests with the pan-tilt structure. Just a little horn on it =).
Yep you're right, I tested it on anther ship and I got the 180°. The thing is that I want to be able to use it with my arduino since I'm far more confident with it :|.

edit : the resetting thing came from the servos draining to much power, you were right ! So I just put a capacitor between the power supply and he ground and it stops resetting. I still have my no 180° problem tough.

You haven't said whether the servo can physically move farther than the positions it stops at with the Arduino.

If you are powering it with the Arduino 5v supply you may get problems with the Arduino if the servo reaches its end-stop and tries to go further drawing a much heavier current. Normally they make a noticeably different noise when they reach the end-stop. It's better to have a separate power supply for the servos.

Have you tried a different servo in case the servo is faulty?

...R

Hey !

The servos can physically move farther than the position it stops at with the arduino. However I've conduct a test with 5 of them using a power supply and oscilloscope and stuff and, when I move them by changing the frequency, they don't go farther than the position it stops at with arduino. So, it appears that it is not the arduino fault but more the servo fault. The other one that can go 180° seems to be a copy. I conduct the same test on it and, even tough it is able to go 180°, it is not accurate at all. =)

So thanks for the answers, but I think that the problem isn't in the arduino =)

basic servo code for testing servos

// zoomkat 10-22-11 serial servo test
// type servo position 0 to 180 in serial monitor
// or for writeMicroseconds, use a value like 1500
// for IDE 0022 and later
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7, 500, 2500);  //the pin for the servo control, and range if desired
  Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string 
    int n = readString.toInt();  //convert readString into a number

    // auto select appropriate value, copied from someone elses code.
    if(n >= 500)
    {
      Serial.print("writing Microseconds: ");
      Serial.println(n);
      myservo.writeMicroseconds(n);
    }
    else
    {   
      Serial.print("writing Angle: ");
      Serial.println(n);
      myservo.write(n);
    }

    readString=""; //empty for next input
  } 
}

It sounds like the potentiometers in the servos are not positioned correctly or their internal software is wrong. Could you get someone with real R/C equipment to test them?

If it's the potentiometers it may be possible to take them apart and correct the problem but it's probably not worth the trouble.

I suggest you buy another servo that you know works correctly - have them demonstrate it in the shop if possible and then keep that as your principal test device.

On the other hand I have never had a bad servo...

...R

Hey all !

I'll just use those ones with their 90° of rotation. I think I'll follow your suggestion Robin2 in the future. Seems like a good advice =).
I think it's not worth the trouble to test them with a real R/C equipment and it's not that easy to find one anyways. I tested them with an oscilloscope and stuff to see if I could find the problem like this but I'm not skillful enough in that kind of subject to conduct a real test :S.

Thanks for the help everyone. I'm glad that this community exist for it is very easy to find help and solution =D

when I move them by changing the frequency

Stop right there.
Explain, please.

Ok I'll try to explain but since I conduct the test with a friend of mine I'll try to be as precise as possible.

I had my arduino Nano plug into my computer and we were watching the output of the PWM that was sending the signal to the servos on the oscilloscope. We wanted to know how the function writeMicroseconds() and write() behaved. So we changed the values while watching the signal sent by the Arduino to be sure that nothing was out of range or, to know if when I was asking for 600 ms for example the Arduino was indeed sending a signal at 600 ms. We wanted to know if they were any problem in the servo library. :relaxed:
The results were exactly what they were supposed to be so we guessed the problem was coming from the servos itself since the electronics is working correctly with an other servos.

By that time, I tried the code on an other servos (MG90S) and everything work perfectly. So I think it come from the servos.

If you got any idea or I wasn't clear or need more information or think it is wrong, please tell me ! I want to understand what exactly isn't working =).

when I was asking for 600 ms for example the Arduino was indeed sending a signal at 600 ms.

1.6Hz when the servo expects a frame rate of 50Hz?
Why were you messing with the frequency?
The servo is a PWM device; it expects a 50Hz signal with around a 5 to 10% duty-cycle.

Ho ! I suddenly understand what you mean ! I'm sorry I've used the wrong formulation in my first message. I didn't change the frequency but the pulse width.

I'm sorry English is not my first language and sometimes I end saying dummy/unclear things :/.

The servo is still not expecting 600ms pulses.

I tried to see the full range of values to control the shaft. Starting at 1500ms I've decrease that value until the servo stop. And the limit was 600 ms. Above it, it moves, under it, nothing happen. So I guess 600ms was my zero.

I've been searching on this page Servo - Arduino Reference, to know how the function was working. As it is suggested, I tried to know the "real" maximum and minimum, in case it was the reason why the servo wasn't doing 180°. That is why I ended up with a 600ms as a minimum and 2400ms as a maximum.

Are you, perhaps, confusing microseconds (us) with milliseconds (ms) ?

Yes I totally am, you're right... Sorry for making you waste your time =(

If you look at this page Servo - Arduino Reference you will see that the default range for the servo library is 544 microseconds to 2400 microsecs. If you need to try a wider range you can change the limits using Servo.attach(pin, min, max). That would allow you to try much lower (or higher) values. (I've no idea why anyone wasted his time (and ours) putting in default limits in the first place)

If you try to drive a servo to a "too low" number it should behave with the same noise/vibration as when it is driven with a "too high" number - in both cases it is trying to go further than its own physical limit.

...R

Mariduino:
I tried to know the "real" maximum and minimum, in case it was the reason why the servo wasn't doing 180°. That is why I ended up with a 600ms as a minimum and 2400ms as a maximum.