This week I worked on learning servo control with the extender module using a cheap Hitec HS-55 servo from Amazon.
This solution can be found on my Gadgeteer GitHub repository.
Servo control requires PWM output. This requires the extnder module be attached to a socket containing PWM pins. I used sockect #11 which has PWM outputs for pins 7, 8, and 9.
The board has enough power to drive the servo using the 5V pin off the extender module.
After the setup, basic programming examples are easy to find on-line. The problem with most of the examples are they don’t take the time to move the servo into account. Moving the servo 1 degree doesn’t take as long as 180. I wanted a more accurate method.
First, I setup at button to start the servo moving on a separate thread.
void button_ButtonPressed(Button sender, Button.ButtonState state)
{
isActive = !isActive;
if (isActive)
{
servoThread = new Thread(RunServo);
servoThread.Start();
}
else
{
servoThread.Join();
}
}
My RunServo method calls a MoveServo method. In this example, I move the servo through a few position then through a range by 10 degrees.
static void RunServo()
{
int currentPosition = 0;
pwmOutput.Active = true;
while (true)
{
if (!isActive)
{
pwmOutput.Active = false;
return;
}
// we're not sure where the servo might be
// ... assume it's at the max position
currentPosition = MoveServo(pwmOutput,2400, 1500);
currentPosition = MoveServo(pwmOutput, currentPosition, 650);
currentPosition = MoveServo(pwmOutput, currentPosition, 2350);
for (UInt32 hightime = 650; hightime <= 2350; hightime += 100)
{
currentPosition = MoveServo(pwmOutput, currentPosition, hightime);
}
}
}
The MoveServo method uses the current position and target position to calculate the range moved. Looking up the specs of the HS-55 shows that for 4.8V the servo will move 60 degrees in 0.18 seconds. This is about 3.333 miliseconds per degree (or a ns 100 pulse). I round up to 4.
static int MoveServo(PWMOutput server, int currentPosition, uint targetPosition)
{
int milliSecondsPerDegreeWait = 4; // 3.333 really...
pwmOutput.SetPulse(20 * 1000000, targetPosition * 1000);
Thread.Sleep((System.Math.Abs((currentPosition - (int)targetPosition))/10) * milliSecondsPerDegreeWait);
return (int)targetPosition;
}