Controlling Servos with Arduino Uno R3

Hi everyone,

This is my first time posting here. I'm working on a project where I have to build a pan/tilt mechanism for a camera. I decided to use a couple of servos and a pan-tilt bracket to get it done, so I purchased two standard Hitec Servos (continuous rotation), and an Arduino Uno R3. Whenever I try to test the servo according to the example code supplied by Arduino, that is supposed to cause the servo to sweep back and forth, the response is always a continuous 360 degree rotation by the servos. I cannot get it to behave as the code seems to indicate it should. The code is shown below:

// 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);  // 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 
  } 
}

Any help would be most appreciated. I'm worried I may have the wrong type of servos or controller - I'm a relative amateur when it comes to controlling servos, though I do have some experience with C and C++, mostly for academic purposes. Thanks in advance!

Kareem

A normal servo only goes 0..180 degrees. You said you purchased a servo that has been modified for continuous rotation and that has different programming characteristics:

Quoting from the ServoWrite documentation:
Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with 0 being full-speed in one direction, 180 being full speed in the other, and a value near 90 being no movement).

What Mr.Meissner said. Continuous servos are cool if you want to build a differential drive or something like that, but for your purpose you really need regular servos.

Thank you both for your replies and your help.

The reason I ordered continuous rotation servos was because the requirements of my pan-tilt stipulate it must be able to pan 360 degrees. The servos I found, if not continuous, would only go to a max of 180 degrees. I was not aware that this would sacrifice my ability to control position.

I'm still fiddling with the code to try and familiarize myself with controlling the speed and so forth. Is there anything I can do along the lines of maybe adding a potentiometer to regain that ability to control position? Obviously I'm stuck with these servos now, I'd like to find a way to make them work.

Thanks again for the help.

Think out loud, if you had used a 1:2 gear ratio, I think you would have been able to do 360 degrees at a cost of only being able to specify position to 2 degrees instead of 1. However, that would be an extra complication, and you would have to make sure the pulley and gears could handle the weight.

On a continuous rotation servo, this will set the speed of the servo (with 0 being full-speed in one direction, 180 being full speed in the other, and a value near 90 being no movement).

Four push buttons to move the servo back and forth with a predefined speed for pan and tilt
Four switches (sensors) to indicate the end of the pan or tilt you maximum need.
If the camera is true wireless you do not need to use end switches on the panning.

So with continous servo it is still possible.

Paco

You could do something with encoders to get control of the position of your servos, but I'd be more inclined to save the stuff you have for another project and get something more appropriate for the task at hand. Take a look at sail winch servos - there are examples that will do 360 degrees, or substantially more.

Hello everyone i would like to ask that can i write codes for a modified hitec servo.?

tibayo1:
Hello everyone i would like to ask that can i write codes for a modified hitec servo.?

Pretty sure the answer to that would be "yes", but what do you mean? Codes to do what? What does modified mean?

Also, you should start a new thread for this question, rather than hi-jacking an existing discussion.

I made one of these a few years ago and finally abandoned the servo idea, it works OK(ish) for tilt (the camera has to be balanced or the servo needs to be drawing power to keep position which eats batteries), but for 360° panning a geared stepper motor was the answer then all the Arduino has to do is count pulses for any repeatable position in the 360°. Eventually both pan and tilt were powered by steppers which gave me precise positional control. If you include a worm gear in the gear train any off balance camera doesn't try to turn the motor(s), but any imbalance increases the load on the motor.

Chris

If you get sail winch servos they can do about 2.5 revolutions (~900 deg) with full position control.

...R

I need to know whether the Arduino can control servos more accurately than by one degree? If so, can someone point me to example code? The only examples I have found, use 1 degree steps, apparently.

There is a project I'd like to use the Arduino for, but the servos must be able to be controlled much finer than 1 degree.

For example, the servos to move a total of 20 degrees, 10 left, and 10 right. If the sensors I am using could be converted to produce 1024 steps, I'd like to have say 1000 steps for that 20 degree range of travel, or 0.02 degrees per step.

Is that possible, or is the Arduino limited to 1 degree? Or is it possible to use a range of 180 "steps" for the servo signal, confined within a 20 degree total range, which would be 0.11 degrees per step. That might be workable for this project, but not as ideal as finer steps.

Reason is for a homemade Chart Recorder, with servos driving pens. Therefore the limited range of motion and need for finer steps than 1 degree.

Here is the project, which unfortunately has gotten no replies. I'm concerned it never will since it has already slid to page 3 of the list in less than 12 hours.

http://forum.arduino.cc/index.php?topic=209702.msg1540306#msg1540306

  • George Gassaway

Take a look at servo.writemicroseconds. It's more granular than servo.write which takes degrees as a parameter.

Here is the project, which unfortunately has gotten no replies. I'm concerned it never will since it has already slid to page 3 of the list in less than 12 hours.

I looked at the post and could not find a real question in the material.

but the servos must be able to be controlled much finer than 1 degree

You probably won't get any finer resolution than ~.5 deg with a typical hobby servo.

WildBill, thanks for the tip on servo.writemicroseconds. That seems like it'll do what I need for the servo resolution.

zoomkat:

Here is the project, which unfortunately has gotten no replies. I'm concerned it never will since it has already slid to page 3 of the list in less than 12 hours.

I looked at the post and could not find a real question in the material

I guess I should have made a more obvious stand-out question or summary set of questions in my Chart Recorder thead.

http://forum.arduino.cc/index.php?topic=209702.msg1540306#msg1540306

I did say and ask this:

"From what I have been reading, I can input to the Arduino a reference voltage for it to compare to. So let's say for example I could produce a reference voltage of exactly 1.023 volts for it. Does that mean that the Arduino would convert the sensor voltages to 1 millivolt steps? If I used a reference voltage of 0.255 volts, would the Arduino be able to convert the sensor voltages to .25 milivolt steps sensitivity?"

That was asking for confirmation that I understood correctly what the Arduino could do. If I used a reference voltage of 1.023, would it indeed be able to convert to steps as fine as . 1 mV?

And if I used a reference voltage of 0.255, could it convert to steps in .25 mV increments?

Then I mentioned the servos, saying I'd like to be able to drive them as fine as .005 ms if it was possible. But I was not sure, so I asked:

"Does it seem like the Arduino can do this? I'm trying to get a handle on that before I buy one and start tinkering."

Maybe what I should have done was posted two separate topics, one about converting VERY small voltage changes into very fine steps. And a separate one about fine control of servos. And not bothered to explain why any of it needed to work that way or what it was for.

I guess what you are saying is you read it and figured, yep, this guy has found out how it works, without posting a message to say: "Yes, all that you wrote is what it'll do." I really need to hear that my understandings are correct, I'm not going to pull the trigger to get into this until I know that I'm on the right track for converting very small voltage changes, and that the servos can be driven very finely by those small voltage changes.

Now, it does sound like the Servos can be driven that accurately, which leaves the converision of low voltage changes into very fine steps unverified.

As for real-world resolution accuracy of the servos, I do not know the exact resolution. What I do know is that the original analog circuit I used to drive the servo pens, produced a very smooth output. No visible jagged steps, as the plots of a slow increase or decrease in temperature, were viewed by eye. I know that .5 degree would be visibly jagged in the plot, because the pen arms move only a range of about 20 degrees. So if the resolution was only 0.5 degree, there would have been 40 steps, very jagged for the pen plots.

The best way to get things as smooth as possible is to drive the servos with as fine resolution of a signal as possible (within reason), then the real-world resolution depends on the servo itself. Not to use far cruder signal resolution that gives up on however finely the servo might have been able to resolve it. I know what I've seen in the plots is way better than .5 degree resolution.

This thread in RC Groups , in the last message (#6), puts the resolution capability of JR and Spektrum servos at 2048 steps for 90 degrees, which would be a resolution of 0.044 degrees.

  • George Gassaway

then the real-world resolution depends on the servo itsel

That is where you need to do a reality check. Hobby servos probably have a built in ~5us dead band to limit hunting, which could eventually damage the servo pot. The RC posting has an erroneous assumption that typical hobby servos will actually respond to very small us pulse changes, which in the real world may not be fact. Final accuracy can be gained by gearing down the servo rotation output to a lower value (180 deg rotation to 20 deg rotation). In the past I made the below setup with a bamboo skewer attached to a servo so I could observe the skewer tip for incremental movement. Incremental 1us commands were sent to the servo and the movement was observed. Repeatable movement accuracy was limited to about a 5us band. Best you should get a servo like you plan to use and see how it actually performs for your situation.

I imagine that the Arduino should be able to work as you say with a reference voltage of 1.023v as it has an internal reference of 1.1v (why not use that). You would need to read the Atmega328 datasheet to find out if it would work with a reference of 0.255 volts. But bear in mind you can use maths to convert the adc vales to whatever range you want. The only limitation is that the ADC can only distinguish 1024 different levels. In any case you will need to do some experiments to see exactly how your device works and, perhaps, make some adjustments in your software.

You should also be aware of the difference between the instructions you give the servo and how it responds. @Zoomkat's comments about actual performance need to be taken into account.

I have never owned a sail winch servo so I don't know how precisely they can be positioned - it could be (to use @Zoomkat's estimate) 0.5 deg within 900 deg or it could be 1.25 deg within 900. If the former you could gear it down by 2.5:1 for an accuracy of 0.5/2.5 or 0.2 deg.

You should also keep in mind that servos are/were designed for systems with immediate feedback (such as flying model aircraft) in which small absolute errors don't matter.

...R

zoomkat and Robin2, thanks very much for the replies.

When I said the real world servo resolution would depend on the servo itself, I was referring to sending it high resolution signals, so it would indeed be the servo itself that reached it's own limit of resolution, whatever that limit was. As opposed to giving it far cruder signals nowhere near as fine as the servo would be able to do.

And I think we are now on the same page there. Your resolution tests were impressive. 5 microseconds is the lowest resolution I'm looking at giving it anyway. Now I have your info to thank for knowing it can do that.

The idea of using gearing with the servos to get even finer resolution, since I only need them to rotate 20 degrees, that is a really good one. For some other project that would be quite useful. But for this, it seems like the Arduino can do what is needed, with unmodified servos.

And what Robin2 said in confirming that what I wanted to do in using very small voltage changes, by using a very small reference voltage to get the most out of 1024 steps, I was really glad to read that.

Servos, have used lots in many R/C models for a very long time. Overall servo quality has gotten so much better. And for the sake of most of the models I fly, a lot smaller and lighter and cheaper.

So, I went out and got a Uno at Radio Shack today (They were out, and none nearby had any either. I ended up getting an experimenter's kit by Maker Shed, I was going to buy a breadboard pack also so the kit price was only a bit more).

I'll be doing a little testing tonight. But will start with some existing code and get a bit used to using and tweaking code with the Uno before I try to get it to do exactly what I need for the project.

Thanks again.

  • George Gassaway

An update.

I did some simple experiments to get to learn using the Arduino. And got to testing servos. Modified some code (sweep) to make it work with the writeMicroseconds command, and confine the range between 1200 and 1800 microseconds, or 1300 and 1700. And tested with different microsecond values for the sweep, and different delays. Some of the delays were a lot more than should be used, but they did help in being able to count the step versus a ruler to see how many for 1/2" of motion when the servo pen would be. Ideally, I would have used a loop counter so that the delays would be faster but run a few loops before incrementing (or decrementing), but I have not learned that yet.

I sort of replicated zoomkat's test, with a small thin wood dowel taped to the servo arm, at the length of the arm used for the pens on the servo arms of the chart recorder. Even at 5 microsecs, it'll be decent resolution. It does work under 5 microseconds but not without a bit of jumpiness when as low as 1 microseconds. I did find that when I changed the delay from 500 (to be able to see individual step movement), to a much shorter delay, that the 1 microsecond motion looked to be smoother. But I won't know which ends up best for the project, till I have the sensor/voltage front end solved and let the actual sensor voltage command the servo.

So, now I'm trying to deal with the front end of the problem, to be able to use a very small change in sensor voltage (perhaps as little as 50 millivolts range, from say 100 mV to 150 mV).

At this point should I open a new thread specifically about that? I will say this much. I tried out an experiment (AnalogReadSerial) that reads voltages and display via the Serial Monitor. The voltage values were displayed to two decimal point accuracy. I hope I'm wrong but that looks like it's not displaying anything less than 100th of a volt, or 10 mV. For this project, that would be very crude. I know the info I've found says that even with 5V as the reference, the Arduino will break that down into .0049 volts, finer than Serial Monitor is displaying. So I am hoping that either the Serial Monitor does not display beyond 2 decimal points, or better yet the specific code I used did not call for more accuracy than that (So hopefully it is possible to get finer voltage display from the monitor).

Robin2:
I imagine that the Arduino should be able to work as you say with a reference voltage of 1.023v as it has an internal reference of 1.1v (why not use that). You would need to read the Atmega328 datasheet to find out if it would work with a reference of 0.255 volts. But bear in mind you can use maths to convert the adc vales to whatever range you want. The only limitation is that the ADC can only distinguish 1024 different levels. In any case you will need to do some experiments to see exactly how your device works and, perhaps, make some adjustments in your software.

I need to find out more about how to convert the adc values to a range. It sounds to me like you may be saying that I could for example define a range from 100 mV to 200 mV, and that the Arduino then could break that down to a hair less than 0.1 mV. Do I understand that correctly?

I did try one test along those lines, but due to the above issue with the Serial Monitor not displaying anywhere near that accuracy, I can't find out if it works.

FWIW - below is the modified "Sweep" code I tinkered around with.

  • George Gassaway

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

//Slight mods by George Gassaway to test for writeMicroseconds, and limited range of motion.

#include <Servo.h>

Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created

int pos = 1300; // 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 = 1200; pos < 1800; 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'
delay(100); // waits for the servo to reach the position
}
for(pos = 1800; pos>=1200; pos -= 1) // goes from 180 degrees to 0 degrees
{
myservo.writeMicroseconds(pos); // tell servo to go to position in variable 'pos'
delay(500); // waits for the servo to reach the position
}
}

George, good to see progress. Please put your code in code tags - use the # button above the edit window.

To start off don't bother converting voltages to floating point values - just study the numbers that the ADC returns and convert them with a calculator and pencil if need be. The ADC should be able to detect voltages of 1/1024 of the reference voltage. So with the 1.1v internal reference it should detect 1 millivolt. You may find that it has a small constant error which your code can allow for.

You also need to be aware that the Atmega328 expects a source impedance of 10k for inputs to the ADC. I discovered this when I was trying to control something with a 100k potentiometer which gave a lot of random error in the ADC readings. Changing to a 10k pot solved the problem. If your source impedance is too high you may get satisfactory results by averaging a few readings. A more complex solution would be to use an OpAmp to make the signal suitable for the ADC (I'm getting a bit out of my depth now).

A pot is a good device for learning about the ADC.

...R