Let's look at the most basic example from the Servo guide:

import time
import board
import pulseio
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)

This works fine for us if we only have one servo, and we don't have anything else that we want to happen at the same time. But once we add in another thing, we'd have the same trouble as before — time.sleep() delaying our other actions unintentionally.

In the next version we adopt the "is it time yet" approach in order to avoid the use of time.sleep():

# SPDX-FileCopyrightText: 2020 FoamyGuy for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
This example script shows how to sweep servo(s) without using
time.sleep().
"""

import time
import board
import pwmio
from adafruit_motor import servo

SERVO_LIST = [
    {
        "MAX_ANGLE": 180,
        "MIN_ANGLE": 0,
        "PREV_TIME": -1,
        "PIN": board.A1,
        "DELAY_BETWEEN": 0.05,
        "SERVO": None,
        "MOVE_BY": 5
    }
]

for cur_servo in SERVO_LIST:
    pwm = pwmio.PWMOut(cur_servo["PIN"], duty_cycle=2 ** 15, frequency=50)
    # Create a servo object.
    cur_servo["SERVO"] = servo.Servo(pwm)


while True:
    # Store the current time to refer to later.
    now = time.monotonic()
    for servo in SERVO_LIST:
        if now >= servo["PREV_TIME"] + servo["DELAY_BETWEEN"]:
            try:
                servo["SERVO"].angle += servo["MOVE_BY"]
            except ValueError as e:

                if servo["MOVE_BY"] > 0:
                    servo["SERVO"].angle = servo["MAX_ANGLE"]
                else:
                    servo["SERVO"].angle = servo["MIN_ANGLE"]

            if servo["SERVO"].angle >= servo["MAX_ANGLE"] or \
                servo["SERVO"].angle <= servo["MIN_ANGLE"]:

                servo["MOVE_BY"] = -servo["MOVE_BY"]

            servo["PREV_TIME"] = now

This version also moves the configuration for the servo sweeping into a list of dictionaries so that additional servos with different sweeping effects can be added easily.

To add an additional servo, you would make a copy of the dictionary that is in SERVO_LIST and change any of the fields that we want to the new desired parameters:

{
    "MAX_ANGLE": 90,
    "MIN_ANGLE": 45,
    "PREV_TIME": -1,
    "PIN": board.A2,
    "DELAY_BETWEEN": 0.03,
    "SERVO": None,
    "MOVE_BY": 5
}

SERVO and PREV_TIME should be left as their default values. The rest of the code will fill them in when needed. 

MAX_ANGLE and MIN_ANGLE are the degrees at which the servo will turn around to move the opposite direction.

PIN is the IO pin that the servo is connected to.

DELAY_BETWEEN is how long it will wait between each servo step. This is in seconds, and you likely want to keep it pretty small in most situations. 

MOVE_BY is how many steps the servo will take each time it moves. 

Here is an example of a list with two servos in it. You could continue adding more if you wanted.

SERVO_LIST = [
    {
        "MAX_ANGLE": 180,
        "MIN_ANGLE": 0,
        "PREV_TIME": -1,
        "PIN": board.A1,
        "DELAY_BETWEEN": 0.05,
        "SERVO": None,
        "MOVE_BY": 5
    },
    {
        "MAX_ANGLE": 90,
        "MIN_ANGLE": 45,
        "PREV_TIME": -1,
        "PIN": board.A2,
        "DELAY_BETWEEN": 0.03,
        "SERVO": None,
        "MOVE_BY": 5
    }
]

This guide was first published on Oct 08, 2020. It was last updated on Sep 07, 2020.

This page (Servos) was last updated on Jun 07, 2023.

Text editor powered by tinymce.