Home > .NET Framework, Embedded > Notes on Driving the Parallax Standard Servo

Notes on Driving the Parallax Standard Servo

I needed to learn how to interface my microcontroller with a Parallax Standard Servo, which I bought at Radio Shack. The process went fairly smoothly, overall, but I did have some notes to share that others may find helpful.

The Parallax Standard Servo documentation, version 2.1, lists the following values for driving the servo using pulse-width modulation:

    0 degrees: 1.3 milliseconds
   90 degrees: 1.5 milliseconds
  180 degrees: 1.7 milliseconds

Yeah, that gave me about +/- 30 degrees…at best. I eventually came across version 2.2 of the documentation which lists more realistic values:

    0 degrees: 0.75 milliseconds
   90 degrees: 1.5 milliseconds
  180 degrees: 2.25 milliseconds

While much better, that resulted in something closer to 80 degrees of travel. Here are the values that resulted for me in a full +/- 90 degrees for me, based on trial and error:

    0 degrees: 0.6 milliseconds
   90 degrees: 1.5 milliseconds
  180 degrees: 2.39 milliseconds (see following comment)

As an aside, this servo takes approximately 1 second to travel from 0 to 180 degrees.

Why not use 2.4 milliseconds for 180 degrees? Well, when I used that value the servo motor began to vibrate/oscillate as it held position (similar to how a stepper motor feels at low RPM). I felt like perhaps the servo controller was attempting to over-rotate the motor. The problem went away when I backed the value down to 2.39, and there seemed to be no loss of position accuracy.

Notes on the .NET Micro Framework

I’m using the .NET Micro Framework for this project. The way to signal the servo is to call SetPulse(square_wave_period_in_nanoseconds, pulse_duration_in_nanoseconds). The official Parallax documentation states the communication protocol consists of a carrier wave between 0.75 ms – 2.25 ms of high-time + 20 milliseconds of low time. This results in a varying period for the carrier wave (unless you are holding steady). The standard way of communicating with a servo like this is to use a total fixed period of 20 ms, where the low time equals 20 ms minus the high time, which is a different interpretation.

The standard way seemed to result in the same gross positioning accuracy. However, I did have an intermittent issue using this technique where signaling the 180 position would result in a noticeable servo motor vibration, the same effect observed when using 2.4ms to signal 180 degrees. This issue occurred approximately 50% of the time over roughly two dozen trials. This problem never occurred at 2.39ms when I implemented the official protocol. My hunch is that this technique resulted in signaling the servo controller to over-rotate the motor, but I’m just guessing. I’m going to use the official protocol, personally, even though all of the other documentation, and forum posts, that I’ve read use the unofficial approach. YMMV.

So, here’s all the code needed to drive a Parallax Standard/Futaba Servo using a PWM pin (on a Fez Panda II in this case):

        private const uint AS_NANO_SECONDS   = 1000;
        private const uint PULSE_WIDTH       = 20000 * AS_NANO_SECONDS;

        private const uint SERVO_0_DEGREES   = 600 * AS_NANO_SECONDS;
        private const uint SERVO_NEUTRAL     = 1500 * AS_NANO_SECONDS;
        private const uint SERVO_180_DEGREES = 2390 * AS_NANO_SECONDS;


        // Setup one of the PWM pins for modulating the servo signal.
        var servo = new PWM((PWM.Pin) FEZ_Pin.PWM.Di5);

        // Center and hold the neutral position (0 degrees) by
        // invoking SetPulse with the "official" protocol.
        // The "unofficial" but "standard" way would be:
        //     servo.SetPulse(PULSE_WIDTH, SERVO_NEUTRAL);

        // Full right and hold.

        // Center and hold.

        // Full left and hold.
        servo.SetPulse(PULSE_WIDTH + SERVO_180_DEGREES, SERVO_180_DEGREES);

        // Center and hold.

Notes on the Fez Panda II.

I do not yet own a scope, but I tried wiring a 10k resistor in series with the signal wire between the servo (white wire on the servo to pin Di5 on the Fez). This made no noticeable difference in the servo’s operation. I assume that the Fez’s internal resistor is handling impedance matching, or that the servo can tolerate a low impedance signal.

The regulated 5v power rail does not provide enough current to drive the servo. Instead, I created a battery consisting of 4 2600 mAh NiMH “AA” cells in a 2×2 plastic holder from Radio Shack. I used a homemade adapter that goes from a 9v battery connector to a male “M” sized power connector. This allowed me to plug the battery into the Fez’s external power port. This provided ample supply for the servo. However, after a little bit of rundown on the batteries, the current drain while the servo was repositioning would cause the Fez to brownout.

For testing purposes, I kept the Fez simultaneously supplied with 5v from via the USB port. The servo’s red pin was wired directly to the VIN pin, the black pin to GND, and as mentioned earlier, the white pin to Di5. I did not need a 5v voltage regulator since the custom battery’s voltage never exceeded the servo’s maximum input voltage of 6.0v. The documentation notes that this servo can tolerate up to 9v for a limited duration, but if I use the (nominal) 7.2v battery I have, I will use a regulator.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: