Servomotors

  • While continuous servo motors that can rotate continuously can be found, most servo motors (also often referred to as servos or servo motors) can only rotate their output shaft within approximately 180°. They are commonly used in radio-controlled car models to steer the wheels or in radio-controlled aircraft models to control surfaces (ailerons). The figure below shows two servo motors of different sizes.

    Image

    The servo motor on the right is a so-called standard servo motor. This is the most common type of servo motor. Such servo motors often have identical sizes and mounting hole distances. The much smaller (and lighter) servo motor on the left is intended for aircraft. These servo motors are called 9g servos.

    Servos with higher build quality and higher torque have metal gear reducers instead of nylon. Most servo motors operate at a nominal voltage of about 5 V within an allowable voltage range of 4 to 7 V. Connecting hobbyist servo motors is usually done through wires ending in a 3-pin connector: power, ground, and control signal.

    Large and sometimes quite powerful servo motors are also available for use, but they are not as standardized as hobbyist low-power servos.

    Servo Motor Mechanism
    A servo motor consists of a direct current (DC) motor that drives a reducer, which reduces the motor's rotation speed while increasing the torque on the shaft. To control the position of the output shaft, it is connected to a position sensor (typically a variable resistor). To control the power and the direction in which the servo motor turns, the control circuitry uses an input signal from the position sensor in conjunction with a control signal specifying the desired position.


    Image

    The control unit, upon receiving the desired position value from the control signal, subtracts the actual position value, producing an "error signal" that can be positive or negative. This "error signal" is then fed into the motor's power supply, causing it to change the position of the shaft in the required direction. The greater the difference between the desired and actual positions of the output shaft, the faster the motor will rotate towards the desired position. As the error value (discrepancy) approaches zero, the motor's power supply decreases.
  • The control signal for a servo motor is not a voltage, as one might expect, but a pulse-width modulation (PWM) signal. This signal is standard for all hobbyist servo motors and looks as depicted in the figure.

    Image

    A servo motor expects a control pulse to arrive every 20 ms. A 1.5 ms pulse duration will set the servo motor to its central position, corresponding to a 90° rotation of the output shaft. Shorter pulses at 1.0 ms will set the output shaft to the initial position at 0°, while longer pulses at 2.0 ms will position it at the extreme 180° angle. In reality, this range may be slightly less than the full 180°, with no pulse shortening at one end and pulse lengthening at the other. It's not uncommon for a 0° position to require a 0.5 ms pulse, while 180° might need a 2.5 ms pulse.
  • In this experiment, we will learn how to rotate the output shaft of a servo motor to a specified angle using both Arduino and Raspberry Pi.

    For the Arduino board, there is a servo motor control library capable of generating pulses on any of its pins, so you don't have to use a special pin marked as PWM output. The servo motor is controlled through the serial interface monitor window, where you send the angle value to which you want to rotate the motor's shaft.

    Generating precise pulse durations on Raspberry Pi is more complex than on Arduino. The Arduino board is equipped with hardware timers that generate the required pulses, while on Raspberry Pi, you have to generate pulses through software. Since Raspberry Pi has an operating system that can run multiple processes competing for processor time, the PWM pulse duration can sometimes be longer than required, causing slight trembling of the servo motor's output shaft. Therefore, in cases where high precision is needed, external PWM devices should be used (see "Project: Dancing Pepe Doll on Raspberry Pi").

    Equipment

    A remarkable feature of servo motors is that their motor control electronics are enclosed inside the drive housing, eliminating the need for separate H-bridges or transistor motor control blocks. All you need to do is connect the 5 or 6V power supply to the motor power contacts and provide low-level control pulses from the digital output of your Raspberry Pi or Arduino.

    The diagram below shows the connection of the servo motor to Raspberry Pi. In this case, one of the servo motor horns is already attached (they come with the servo motor in a small package), allowing you to see the position of the servo motor shaft.

    Components

    For this experiment, you will need the following components to work with Arduino and Raspberry Pi:

    - 9g servo motor
    - Male-to-male jumper wires
    - Female-to-male jumper wires (only for Raspberry Pi)

    Image

    A small 9V servo motor should work just fine, powered by 5V directly from the Raspberry Pi or Arduino board. However, if you plan to control a more powerful servo motor, you will need an external power source, such as a 6V battery compartment used in previous experiments.

    Raspberry Pi Connection

    The connection of the servo motor pins to the GPIO pins of the Raspberry Pi is done using "male-to-female" jumper wires.

    Image

    Raspberry Pi Program

    The Python program uses the PWM (Pulse Width Modulation) functions of the RPi.GPIO library to generate control pulses for the servo motor.

    Generating pulses of the correct duration in the library involves a lot of calculations. If you don't want to delve into the details but need the program for your projects, simply copy its code and call set_angle to set the servo motor's position.

    Code: Select all

    import RPi.GPIO as GPIO
    import time
    
    servo_pin = 18
    
    # Tweak these values to get full range of servo movement
    deg_0_pulse = 0.5   # ms (1)
    deg_180_pulse = 2.5 # ms
    f = 50.0   # 50Hz = 20ms between pulses (2)
    
    # Do some calculations on the pulse width parameters
    period = 1000 / f # 20ms  (3)
    k = 100 / period         # duty 0..100 over 20ms (4)
    deg_0_duty = deg_0_pulse * k  # (5)
    pulse_range = deg_180_pulse - deg_0_pulse
    duty_range = pulse_range * k  # (6)
    
    # Initialize the GPIO pin
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(servo_pin, GPIO.OUT)  # (7)
    pwm = GPIO.PWM(servo_pin, f)      
    pwm.start(0)
    
    def set_angle(angle):   # (8)
        duty = deg_0_duty + (angle / 180.0) * duty_range
        pwm.ChangeDutyCycle(duty)
    
    try:
        while True:    # (9)
            angle = input("Enter angle (0 to 180): ")
            set_angle(angle)
    finally:
        print("Cleaning up")
        GPIO.cleanup()
    
    
    NOTE

    Each servo motor may require slightly different control pulse durations to ensure operation across the full range of angles. Two constants, deg_0_pulse and deg_180_pulse, are used to set the control pulses at 0° and 180° angles, respectively. To achieve the maximum range of motion, these constants should be adjusted as needed.


    Let's clarify some points in the program using the comments provided:

    1. This section of the program performs calculations related to pulse duration.

    2. Sending a pulse every 20 ms means that you need to set the PWM frequency (f) to 50 pulses per second.

    3. The period (20 ms) is calculated as 1000 divided by f. If you want to use a different pulse frequency, simply change the value, and the other calculations will adjust accordingly.

    4. When changing the PWM duty cycle, it should be set in the range of 0 to 100. The k constant is initially defined as 100 divided by the period and can be used to scale the angle value to the working range.

    5. To convert the pulse duration for the 0° angle to the working range of 0 to 100, multiply the pulse duration by k.

    6. Similarly, the working range is calculated by multiplying the pulse range (pulse_range) by k.

    7. GPIO pins are configured, and PWM starts to work.

    8. The set_angle function converts the angle value to a duty cycle value and then sets it using pwm.ChangeDutyCycle.

    9. The main loop is very similar to the Arduino program's version: it first requests an angle value and then recalculates and outputs it.

    Uploading and Running the Program

    Run the program with the following command:

    $ sudo python servo.py

    Use the serial port monitor window to control the servo motor just as you did with Arduino. Enter angles and observe how the servo motor confidently takes the specified position:

    Code: Select all

    $ sudo python servo.py 
    Enter angle (0 to 180): 90
    Enter angle (0 to 180): 0 
    Enter angle (0 to 180): 180
    Enter angle (0 to 180): 90 
    Enter angle (0 to 180): 0

    For the most part, the servo motor will respond to commands smoothly. However, if you closely monitor it for some time, you may notice slight jitter, especially if the Raspberry Pi is multitasking while generating the pulses. This should be expected because the longer the pulse generated by the Raspberry Pi, the more often the processor will be distracted by other tasks.

    If the servo motor's jitter is too significant, an alternative to software-based pulse generation on the Raspberry Pi could be using hardware modules, such as the Adafruit 16-Channel PWM/Servo Driver board (product code 815). This module requires only two signal pins on the Raspberry Pi for interaction and, when used with the Adafruit-supplied Python library, allows you to control 16 servo motors.
  • Servo motors respond very quickly to position change commands. In this project, this property is used to pull the puppet's strings and make it dance or move in any desired direction.
    Image
    The control of the servo drives is based on step-by-step playback of a list of positions of their working parts. In the section "Project: Pepe Doll finds his voice," the puppet will be able to speak, and in the future, thanks to the Internet connection, it will be able to perform a dance specified by a particular hashtag.

    Components

    For this project on a Raspberry Pi, you will need the following components:

    16-channel 12-bit PWM/Servo driver module
    4 x 9g servo motors
    Adapter with a round socket and screw clamps
    Female-to-female jumper wires
    Male-to-male jumper wires
    5V 2A power supply
    4 toothpicks (approximately 7-8 cm each)
    Small puppet (with strings for each limb)
    A sheet of mounting cardboard, A4 size
    Hot glue gun or epoxy glue and a drill

    Project scheme

    The Raspberry Pi is mainly used in the project so that it can be connected to the Internet, as will be shown later. However, Arduino can also be used. In this case, external Adafruit PWM/Servo modules will not be needed, and the servo motors will need to be connected to Arduino using a breadboard and male-to-male jumper wires. However, you will need a bunch of these jumper wires!

    The puppet's arms and legs are controlled by four 9g servo motors - one for each arm and leg. The servo motors are controlled using a 16-channel PWM/Servo controller board from Adafruit. An additional advantage of this design is that the connectors on the servo motor wires can be directly connected to the connectors on the controller board (in the diagram, only the middle wire from each servo motor to the board is shown to avoid confusion).
    Image
    The simultaneous operation of four servo motors requires the use of a separate battery pack for their power supply. This is necessary to reduce the interference from the motors on the operation of the Raspberry Pi.

    The length of the plastic swing arms supplied with the servo motors for our project is insufficient, so to ensure the full range of motion of the puppet's arms and legs, it is necessary to extend the servo motor arms using toothpicks.

    Assembly of the project

    In this project, creating a dancing puppet requires a lot of mechanics, electronics, and programming. Below are the steps necessary to implement the project.

    Step 1: Extending the servo motor arms
    The servo motors come with a small packet of various plastic swing arms that can be installed on the output shaft of the servo motor. Choose a straight swing arm and glue a toothpick to it as shown in the diagram below. A hot glue gun or epoxy glue works well for this purpose.
    Image
    Note that a drop of glue is left at the end of each toothpick. This is necessary to prevent the puppet strings from slipping when they are attached to the end of the toothpick.

    Step 2: Making the chassis
    To control the movement of the puppet's limbs, the swing arms of the four servo motors must be able to move freely up and down. To place everything in the right positions, make cuts on a suitable mounting panel (photo sticker cardboard works well).

    To accurately determine the locations of the cuts, use a template. Place the printed template from the file on the mounting panel and attach it lightly with glue so that it can be removed before attaching the servo motors to this panel.
    Image
    Image
    After making two large cuts in the panel with a utility knife according to the template, also drill two small holes that are needed for the strings going to the puppet's head and bearing its weight.
    Image

    Step 3: Attaching the servo motors
    Remove the paper template from the mounting panel and attach the extended swing arms to the output shafts of the servo motors. Attach the swing arms not too tightly so that they can be removed if needed to adjust the servo motor's position.
    Image
    Align the servo motors so that all swing arms can move freely and do not interfere with each other. Before gluing the servo motors, remove the labels from them, as the servo motors will adhere better.

    Step 4: Puppet Preparation
    The diagram shows the puppet that we will control in this project. One string is attached to the top of the puppet's head, bearing the weight of the puppet. This string should be passed through the two holes drilled in the mounting panel (chassis) and tied underneath it.

    Each leg of the puppet is attached to a separate string, and the arms are connected together by a string that is attached to one of the shoulders of the wooden crossbar. Preliminary, oyu need to cut the strings going from the hands to the shoulders of the crossbar, and pass them through a hole in one of the shoulders, then tie them together. To prevent the cut ends of the nylon strings from fraying, they should be melted using a match or a hot hairdryer. It is better, if possible, not to cut the strings, but to untie their ends that are attached to the wooden crossbar.

    Before attaching the puppet to the new structure, it is necessary to connect all the servo motors and run the programs to set the swing arms of all the servo motors in the correct position.
    Image

    Step 5: Connecting the wires
    It is best to orient the Raspberry Pi board so that the (I^2)C interface connector is on the opposite side from the servo controller module. This will be more convenient when using equipment when Pepe gains a voice.

    If you want to reduce the amount of soldering, you can limit yourself to soldering only the four connectors for the servo motors, as in this project only four are involved. After connecting the wires according to the diagram shown above, everything should look as shown in the diagram below.
    Image
    Make sure to correctly connect the connectors of all the servo motors: the orange control wire should be at the top, and the brown or black ground wire (GND) should be at the bottom.

    Now you can connect the 5V power supply for the servo motors and a separate power supply for the Raspberry Pi through the USB connector.

    Step 6: Running the test program
    To set the servo motors in the correct position, you need to use a separate program that allows you to set the swing arms of all servo motors at a specific angle.

    Code: Select all

    #!/usr/bin/python
    
    from Adafruit_PWM_Servo_Driver import PWM
    import time
    
    # ===========================================================================
    # Example Code
    # ===========================================================================
    
    # Initialise the PWM device using the default address
    pwm = PWM(0x40)
    # Note if you'd like more debug output you can instead run:
    #pwm = PWM(0x40, debug=True)
    
    servoMin = 150  # Min pulse length out of 4096
    servoMax = 600  # Max pulse length out of 4096
      
    def map(value, from_low, from_high, to_low, to_high):
      from_range = from_high - from_low
      to_range = to_high - to_low
      scale_factor = float(from_range) / float(to_range)
      return to_low + (value / scale_factor)
      
      
    def set_angle(channel, angle):
      pulse = int(map(angle, 0, 180, servoMin, servoMax))
      pwm.setPWM(channel, 0, pulse)
    
    pwm.setPWMFreq(60)                        # Set frequency to 60 Hz
    while (True):
      angle = input("Angle:")
      set_angle(0, angle)
      set_angle(1, angle)
      set_angle(2, angle)
      set_angle(3, angle)
    The Adafruit servo motor module uses the (I^2)C interface, which is disabled by default on the Raspberry Pi.

    SETTING UP (I^2)C ON RASPBERRY PI

    First, make sure your package manager is up to date by running the following command:

    $ sudo apt-get update

    Next, launch the raspi-config configurator:

    $ sudo raspi-config

    In the menu that appears, select Advanced, then (I^2)C. You will be asked, Would you like the ARM I2C interface to be enabled? Choose Yes. You will then be asked, Would you like the I2C kernel module to be loaded by default? In this case, the appropriate choice is Yes. Select Finish to exit the raspi-config configurator.

    Run the following command from your home directory to install some useful tools for (I^2)C:
    sudo apt-get install python-smbus i2c-tools

    To verify that the Raspberry Pi is connected to the Adafruit servo motor board and ready to work, you can run the following command:
    $ sudo i2cdetect -y 1

    You should see the following result (the numbers 40 and 70 in the table indicate that the board is connected):
    Image
    After setting up the (I^2)C interface, remove the swing arms from the servo motor shafts and run the program provided above. When prompted, enter the angle value of 90

    $ sudo python set_servos.py
    Angle: 90
    Angle:


    The servo motors should buzz and rotate to the 90° angle. Now you can attach the swing arms as close to horizontal as possible, as allowed by the teeth on the servo motor shafts.

    Step 7: Connecting the puppet
    Now that all the servo motors are set at 90°, tie the string coming from the puppet's head to the holes in the center of the chassis. Then tie the strings coming from the puppet's limbs to the extended swing arms of the servo motors. Attach the strings in a way that the arms and legs are in a halfway raised position.

    You can now run the program again and, by entering different angles, check if the puppet's limbs cover the maximum range of movements.

    Raspberry Pi program

    The program for this project can be considered just a starting point. It uses an array of servo motor position values, where you can input your own values to control the puppet's movements. The main "dance" is somewhat rudimentary, but it can hardly be called elegant.

    You can run the program even before looking at the code.

    Code: Select all

    from Adafruit_PWM_Servo_Driver import PWM   # 1
    import time
    
    pwm = PWM(0x40)
    
    servoMin = 150  # Min pulse length out of 4095     # 2
    servoMax = 600  # Max pulse length out of 4095
    
    dance = [      # 3
      #lh  lf  rf  rh
      [90, 90, 90, 90],
      [130, 30, 30, 130],
      [30, 130, 130, 30]    
    ]
    
    delay = 0.2   # 4
      
    def map(value, from_low, from_high, to_low, to_high):  # 5
      from_range = from_high - from_low
      to_range = to_high - to_low
      scale_factor = float(from_range) / float(to_range)
      return to_low + (value / scale_factor)
      
      
    def set_angle(channel, angle):  # 6
      pulse = int(map(angle, 0, 180, servoMin, servoMax))
      pwm.setPWM(channel, 0, pulse)
      
    def dance_step(step):  # 7
      set_angle(0, step[0])
      set_angle(1, step[1])
      set_angle(2, step[2])
      set_angle(3, step[3])
      
    
    pwm.setPWMFreq(60)   # 8
    
    
    while (True):   # 9
      for step in dance:
          dance_step(step)
          time.sleep(delay)
    Let's clarify some points of the program step by step, using the line annotations made in the comments:

    1. The Adafruit board can be used not only to control servo motors, but also other devices that accept PWM signals, such as LEDs. That's why the code imports a class called PWM.

    2. Two constants, servoMin and servoMax, set the pulse duration between 0 and 4095, where 4095 corresponds to 100% duty cycle.

    3. The dance array contains three sets of data for a specific dance. You can add as many lines as you want. Each line consists of an array of four values. This is the angle of rotation for the left hand, left leg, right leg, and right hand respectively. Since the servo motors for the arms and legs are mounted mirror-wise to each other, an angle greater than 90° means raising the arm but lowering the leg (this should be considered when creating your own original dance).

    4. The delay variable sets the pause between each dance step. The smaller its value, the faster the puppet will move.

    5. The map function is used to scale the angle value to the right (maximum) pulse duration value when used in the set_angle function.

    6. The set_angle function has two parameters: the first one sets the servo motor channel number (from 0 to 3), and the second one sets the angle of rotation.

    7. The dance_step function sets the angles for the four limb servo motors and moves each servo motor to the specified angle.

    8. Setting the PWM frequency to 60 times per second provides a series of pulses every 17 microseconds, which is approximately what the servo motor needs.

    9. In each iteration of the main program loop, one step in the dance is performed - the servo motors are set to the specified angles, followed by a pause before the next step. When all the steps specified in the program are completed, it starts over.

    Let Pepe not only dance...

    Try changing the contents of the dance data array to create your own puppet movements. You can try to make the puppet walk, perform wave-like motions, or stand on one leg. Setting a slightly longer delay between steps provides more opportunities to observe the puppet's movements and make adjustments to the dance data array.