Position Control with Motor Library

The best way to control servos is with a handy Adafruit CircuitPython Motor module which simplifies setting the duty cycle to control servos (and even allows controlling servos from different PWM hardware like the PCA9685 board).

CircuitPython Library Install

To follow this approach you'll need to install the Adafruit CircuitPython Motor library on your CircuitPython board.  

First make sure you are running the latest version of Adafruit CircuitPython for your board.

Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle.  Our introduction guide has a great page on how to install the library bundle for both express and non-express boards.

Remember for non-Express boards, you'll need to manually install the necessary libraries from the bundle:

  • adafruit_motor

You can also download the adafruit_motor folder from its releases page on Github.

Before continuing make sure your board's lib folder has the adafruit_motor folder copied over.

Now connect to the board's serial REPL so you are at the CircuitPython >>> prompt. 

Python Library Install

On Linux, you'll need to install the Adafruit_Blinka library that provides the CircuitPython support in Python. Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready!

Once that's done, from your command line run the following command:

  • pip3 install adafruit-circuitpython-motor

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

Controlling a Servo

Then import the board and pulseio modules as before.  We'll create a PWM output just like as shown in the first section--the motor library will take this PWM output and add an extra level of simple control on top of it:

import board
import pulseio
pwm = pulseio.PWMOut(board.D5, frequency=50)

Now let's import the servo submodule from the adafruit_motor module and create an instance of the Servo class from it:

from adafruit_motor import servo
servo = servo.Servo(pwm, min_pulse=750, max_pulse=2250)

Notice the servo class needs to be told what PWM output the servo is connected to for your board.  If you're following the wiring and this guide it will be a PWM output on board pin 5 (be sure to create this with a 50 hz frequency as shown!).

There are a few optional keyword parameters that you might specify in the initializer too.  These aren't shown and are useful for using very specialized or custom servos with different ranges or pulse width values--for simple servos you don't typically need to set these values:

  • actuation_range - The range in degrees of the servo movement.  The default is 180 degrees.
  • min_pulse - The minimum position pulse length in microseconds (default 1000 us).
  • max_pulse - The maximum position pulse length in microseconds (default 2000 us).

Here we've change the minimum pulse from the default 1000 microseconds to 750, and the default maximum pulse from 2000 microseconds to 2250 to ensure we get the full sweep as some servos differ. Some experimentation may be required!

Controlling the servo is simple once you have the class created, just set the angle property to a value from 0 to 180 degrees!

servo.angle = 0
servo.angle = 90
servo.angle = 180

Notice each time you set angle the servo springs to life and moves!

If you don't see the servo moving be sure you have it wired and powered exactly as shown. Also make sure you've created the PWM output exactly as shown above too (note the 50 hz frequency!).

There's another type of servo class in the module that you might find useful too, the ContinuousServo class.  This is for controlling continuous rotation servos that move completely around like a small motor instead of point at specific angles. For these servos you control their speed (or throttle). Create an instance just like with the Servo class above:

continuous = adafruit_motor.servo.ContinuousServo(pwm, min_pulse=750, max_pulse=2250)

With these servos you set the throttle property to a value from -1 to 1 (or anything in between, including fractional values). Where -1 is fully speed 'backwards' and 1 is full speed 'forwards'. A value of 0 should stop the motor (but your servo might need to be trimmed a bit and have a small value set that stops its movement instead of zero, experiment with values yourself to see).

continuous.throttle = -1   # Full backwards
continuous.throttle = 0    # Stop
continuous.throttle = 1    # Full forwards
continuous.throttle = 0.5  # Half speed forwards

Examples

Note that the pin numbers are different in the examples below! You'll need to update them to match your wiring.

Standard Servo

Here's a complete standard servo sweep example written for the adafruit_motor library. Remember save this as code.py on your board to have it run:

# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""CircuitPython Essentials Servo standard servo example"""
import time
import board
import pwmio
from adafruit_motor import servo

# create a PWMOut object on Pin A2.
pwm = pwmio.PWMOut(board.A2, duty_cycle=2 ** 15, frequency=50)

# Create a servo object, my_servo.
my_servo = servo.Servo(pwm)

while True:
    for angle in range(0, 180, 5):  # 0 - 180 degrees, 5 degrees at a time.
        my_servo.angle = angle
        time.sleep(0.05)
    for angle in range(180, 0, -5): # 180 - 0 degrees, 5 degrees at a time.
        my_servo.angle = angle
        time.sleep(0.05)

Continuous Servo

Here is an example for a continuous servo:

# SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""CircuitPython Essentials Servo continuous rotation servo example"""
import time
import board
import pwmio
from adafruit_motor import servo

# create a PWMOut object on Pin A2.
pwm = pwmio.PWMOut(board.A2, frequency=50)

# Create a servo object, my_servo.
my_servo = servo.ContinuousServo(pwm)

while True:
    print("forward")
    my_servo.throttle = 1.0
    time.sleep(2.0)
    print("stop")
    my_servo.throttle = 0.0
    time.sleep(2.0)
    print("reverse")
    my_servo.throttle = -1.0
    time.sleep(2.0)
    print("stop")
    my_servo.throttle = 0.0
    time.sleep(4.0)

This guide was first published on Jan 15, 2018. It was last updated on Oct 12, 2022.

This page (High Level Servo Control) was last updated on Mar 27, 2023.

Text editor powered by tinymce.