Driving a Servo with the Pyboard

Contents

What is a Servo?

A servomotor  is a motor with a positional sensor (e.g. an encoder or potentiometer) combined for positional feedback so that there is precise control over exactly how much it moves. The motion can be rotary or linear depending upon the type of servo.

The servomotor is usually referred to simply as a servo.  Unlike standard motors that spin continuously when powered, a servo only moves to a specific position at a speed commanded by a control signal. The input to its control is a signal (either analog or digital) representing the desired position of the output shaft.

The type of motor is not critical to a servo, and different types may be used. At the simplest, brushed permanent magnet DC motors are used, owing to their simplicity and low cost. Small industrial servomotors are typically electronically commutated brushless motors.

MicroPython pyb.Servo Class

This class is exclusive to the Pyboard and is simple to use.


Syntax:
pyb.Servo(id)
Creates and returns a Servo object.

Where:
  id : Values are 1 to 4 corresponding to
       pins X1 through X4. The servo control
       wire is connected to this Pyboard pin.

 Syntax:            
Servo.angle(angle)
If no arguments are given, this
function returns the current angle.
If arguments are given, this function
sets the angle of the servo.

Where:
  angle : The angle to move to in degrees.

Syntax:
Servo.calibration(pulse_min,
                  pulse_max,
                  pulse_centre,
                  pulse_angle_90,
                  pulse_speed_100)

This method allows each servo to be
individually 'tuned'.

If no arguments are given, this function
returns the current calibration data, as
a 5-tuple.

If arguments are given, this function
sets the timing calibration.

Where:
  pulse_min : The minimum allowed pulse width.
  pulse_max : The maximum allowed pulse width.
  pulse_centre : Pulse width for the zero position.
  pulse_angle_90 : Pulse width for 90 degrees.
  pulse_speed_100 : Pulse width for a speed of 100.
          

Pyboard Driving an MG-90S Servo

This example use of the pyb.Servo class will use an inexpensive but popular MG-90S hobby class servo. They have metal gears and a small size but generate surprising torque during motion.

The MG-90S is a micro-sized digital servo that uses a closed-loop feedback system to achieve precise angular positioning. The servo used in this project supposedly rotates from -90° to 90° (i.e. a total of 180°).

The MG-90S servo is controlled with PWM. It expects a signal pulse every 20 milliseconds (a 50Hz frequency) on the signal line. The duration of this High pulse determines the target angle:

  • 1.0ms pulse: Typically moves to -90°
  • 1.5ms pulse: Typically moves to 0°
  • 2.0ms pulse: Typically moves to 90°

Any other position between these limits is a proportionally timed pulse. An internal potentiometer is used to determine position, probably not quite as accurately as more expensive servos with position encoders.

The comments in the code are self explanatory.


Code:
# An MG-90S servo is connected to the Pyboard.
# Red wire (Vcc) to Pyboard V+ (5V)
# Brown wire (GND) to Pyboard GND
# Orange wire (Control signal) to Pyboard X1 ie Servo(1)

# This program initialise the MG-90S then inside an
# endless loop the servo is firstly moved in one degree
# steps from -90 degrees to 90 degrees.
# Then the sequence is reversed i.e. from -90 degrees
# to 90 degrees. Each one degree step is allowed 5 ms
# to complete.

from pyb import Servo, delay
mg90s = Servo(1)


# Position the MG-90S
mg90s.angle(0)
delay(10)
mg90s.angle(-90)
delay(1000)

# Continue till user interrupted
while True:
    # Move -90 to 90 in 1 degree steps
    for i in range(-90, 91):
        mg90s.angle(i)
        delay(5)
    delay(50)
    # Move 90 to -90 in 1 degree steps  
    for i in range(90, -91, -1):
        mg90s.angle(i)
        delay(5)
    delay(50)
          

The above code worked as expected except for one (minor?) issue. The output shaft was able to rotate precisely to its -90° position. However in the opposite direction it was only able to reach 85°.

This issue might be sorted by using the calibration() method to 'play' around with the pulse_max  parameter value. Then again, maybe this is the limit of movement for this particular servo.