Raspberry Pi Pico: управление сервоприводом (MicroPython)
В этом руководстве вы узнаете, как управлять хобби-сервоприводами с помощью Raspberry Pi Pico, запрограммированного на MicroPython. Сервоприводы можно контролировать с помощью ШИМ-сигналов для точного перемещения на определённый угол. Наиболее распространённые модели — SG90 и S0009.
Впервые работаете с Raspberry Pi Pico? Прочитайте следующее руководство: Начало работы с Raspberry Pi Pico (и Pico W).
В этом руководстве мы рассмотрим следующие темы:
Предварительные требования
Прежде чем продолжить, убедитесь, что выполнены следующие предварительные требования.
Прошивка MicroPython
Для выполнения этого руководства вам необходима прошивка MicroPython, установленная на плату Raspberry Pi Pico. Также вам потребуется IDE для написания и загрузки кода на плату.
Рекомендуемая IDE для MicroPython на Raspberry Pi Pico — Thonny IDE. Следуйте следующему руководству, чтобы узнать, как установить Thonny IDE, прошить прошивку MicroPython и загрузить код на плату.
Также, если вы предпочитаете программировать в VS Code, можете начать со следующего руководства:
Необходимые компоненты
Вам также понадобятся следующие компоненты:
Raspberry Pi Pico
Сервопривод (SG90 или S0009)
Соединительные провода
Макетная плата
Знакомство с сервоприводами
Вы можете устанавливать вал сервопривода в различные углы от 0 до 180 градусов (в зависимости от модели). Сервоприводы управляются с помощью сигнала широтно-импульсной модуляции (ШИМ/PWM). ШИМ-сигнал, отправляемый на двигатель, определяет положение вала.
Для управления двигателем можно просто использовать возможности ШИМ Raspberry Pi Pico, отправляя сигнал частотой 50 Гц с соответствующей длительностью импульса.
Обычно сервоприводы S0009 или SG90 (способные поворачиваться на 180 градусов), которые мы используем в этом руководстве и которые применяются в большинстве проектов с микроконтроллерами, имеют диапазон длительности импульса приблизительно от 550 до 2400 микросекунд:
Минимальная длительность импульса (0 градусов): около 550 микросекунд
Максимальная длительность импульса (180 градусов): около 2400 микросекунд
Для сервоприводов, которые перемещаются только в диапазоне 90 градусов, обычно используются следующие значения длительности импульса:
Минимальная длительность импульса (0 градусов): около 1000 микросекунд
Максимальная длительность импульса (90 градусов): около 2000 микросекунд
Эти значения могут незначительно отличаться у разных моделей сервоприводов. Попробуйте найти даташит для вашего сервопривода или протестируйте эти значения и затем скорректируйте их соответствующим образом.
В моём случае я не нашёл даташит для своего конкретного сервопривода, но использование значений длительности импульса по умолчанию, применяемых в большинстве библиотек Arduino (от 550 до 2400 микросекунд), хорошо работает для того, который мы используем.
Расчёт скважности
На основе этих значений длительности импульса мы можем рассчитать скважность (duty cycle) для установки вала двигателя в определённый угол. Скважность — это отношение длительности импульса к общему периоду сигнала. Мы можем использовать следующую формулу:
Скважность (%) = (длительность_импульса / период) x 100
Период — это величина, обратная частоте. Наша частота составляет 50 Гц, что соответствует 1/50 = 0,02 секунды (20000 микросекунд).
Итак, чтобы установить двигатель в положение 0 градусов, нам нужна скважность 2,75%:
Скважность = (550 / 20000) x 100 = 2,75%
В Raspberry Pi Pico значение скважности 100% представлено цифровым значением 65535, а 0% — значением 0 (подробнее о ШИМ с Raspberry Pi Pico здесь). Таким образом, мы можем отобразить значения скважности в диапазон 0–65535 Raspberry Pi Pico следующим образом:
Отображённое значение = Скважность x (максимальное_значение / 100)
Итак, позиция 0 градусов будет соответствовать:
Отображённое значение = 2,75 x (65535 / 100) = 1802
Выполнив аналогичную процедуру для остальных значений, мы получим:
Минимальная длительность импульса (0 градусов) соответствует 1802
Максимальная длительность импульса (180 градусов) соответствует 7864
Подключение сервопривода к Raspberry Pi Pico
Сервоприводы имеют три провода: питание, земля и сигнал. Провод питания обычно красный, GND — чёрный или коричневый, а сигнальный провод обычно жёлтый, оранжевый или белый.
При использовании небольшого сервопривода, такого как S0009 (или SG90), вы можете питать его непосредственно от вывода питания Raspberry Pi Pico. Однако для других моделей может потребоваться внешний источник питания (проверьте даташит вашего сервопривода).
Провод |
Цвет |
Raspberry Pi Pico |
|---|---|---|
Питание/VCC |
Красный |
5V (VBUS) |
GND |
Чёрный или коричневый |
GND |
Сигнал |
Жёлтый, оранжевый или белый |
GPIO 0 (или любой другой ШИМ-пин) |
Для управления сервоприводом вы можете подключить сигнальный (data) вывод к любому GPIO, способному генерировать ШИМ-сигналы. Все выводы, отмеченные на схеме распиновки светло-зелёным цветом, могут генерировать ШИМ-сигналы (по сути, это все GPIO). Мы подключим его к GPIO 0, но вы можете использовать любой другой GPIO, при условии что укажете правильный пин в коде.
Управление сервоприводом с помощью ШИМ
Положение вала сервопривода можно контролировать, отправляя ШИМ-сигнал с определённой длительностью импульса. Ранее мы выяснили, что:
Минимальная длительность импульса (0 градусов): около 550 микросекунд
Максимальная длительность импульса (180 градусов): около 2400 микросекунд
Следующий код перемещает сервопривод в позицию 0 градусов, затем на 90 градусов и, наконец, на 180 градусов. Затем цикл повторяется, и сервопривод снова перемещается на 0, 90 градусов и так далее. Это простой пример, чтобы вы поняли, как устанавливать сервопривод в определённые углы.
from machine import Pin, PWM
from time import sleep
# Настройка ШИМ-пина для управления сервоприводом
servo_pin = machine.Pin(0)
servo = PWM(servo_pin)
# Установка скважности для различных углов
max_duty = 7864
min_duty = 1802
half_duty = int(max_duty/2)
# Установка частоты ШИМ
frequency = 50
servo.freq (frequency)
try:
while True:
# Сервопривод на 0 градусов
servo.duty_u16(min_duty)
sleep(2)
# Сервопривод на 90 градусов
servo.duty_u16(half_duty)
sleep(2)
# Сервопривод на 180 градусов
servo.duty_u16(max_duty)
sleep(2)
except KeyboardInterrupt:
print("Keyboard interrupt")
# Отключение ШИМ
servo.deinit()
Как работает код
Мы начинаем с подключения необходимых библиотек, включая класс PWM из модуля machine для управления сервоприводом с помощью ШИМ.
from machine import Pin, PWM
from time import sleep
Мы инициализируем ШИМ на GPIO 0 для управления нашим сервоприводом. Мы называем его servo.
# Настройка ШИМ-пина для управления сервоприводом
servo_pin = machine.Pin(0)
servo = PWM(servo_pin)
Мы определяем минимальную, максимальную и половинную скважности для управления сервоприводом. Мы рассчитали эти значения в предыдущем разделе.
# Установка скважности для различных углов
max_duty = 7864
min_duty = 1802
half_duty = int(max_duty/2)
Затем мы устанавливаем частоту ШИМ для управления сервоприводом. Как мы видели ранее, нам нужна частота 50 Гц. Мы используем метод freq() объекта servo для установки частоты.
# Установка частоты ШИМ
frequency = 50
servo.freq (frequency)
В цикле while мы используем метод duty_u16() для установки скважности ШИМ. Сначала мы устанавливаем сервопривод в угол 0 градусов:
# Сервопривод на 0 градусов
servo.duty_u16(min_duty)
sleep(2)
Затем на 90 градусов и, наконец, на 180 градусов.
# Сервопривод на 90 градусов
servo.duty_u16(half_duty)
sleep(2)
# Сервопривод на 180 градусов
servo.duty_u16(max_duty)
sleep(2)
Когда программа останавливается пользователем, мы отключаем ШИМ с помощью метода deinit().
# Отключение ШИМ
servo.deinit()
Тестирование кода
Запустите предыдущий код на вашем Raspberry Pi Pico. Если вы используете Thonny IDE, нажмите на зелёную кнопку Run (Запуск).
Двигатель должен перейти в позицию 0 градусов и оставаться там две секунды. Затем он перейдёт на 90 градусов ещё на две секунды и, наконец, на 180 градусов ещё на две секунды. Это будет повторяться бесконечно, пока вы не остановите программу.
Если вы слышите странный жужжащий звук при углах 0 или 180 градусов, это означает, что вы пытаетесь управлять сервоприводом за пределами его допустимого диапазона длительности импульсов. В этом случае вам следует попробовать скорректировать минимальное и/или максимальное значения, пока шум не прекратится. Эти значения хорошо работают для моего конкретного сервопривода, но для других моделей может потребоваться некоторая настройка.
Управление сервоприводом с помощью библиотеки
Необходимость рассчитывать конкретные значения скважности для определённого угла может быть утомительной задачей и может привести к ошибкам и опечаткам при написании кода. Чтобы упростить задачу, мы можем создать функцию или, что ещё лучше, использовать библиотеку.
Библиотека servo.py для MicroPython
Мы используем библиотеку, найденную по следующей ссылке:
from machine import Pin, PWM
class Servo:
__servo_pwm_freq = 50
__min_u16_duty = 1802
__max_u16_duty = 7864
min_angle = 0
max_angle = 180
current_angle = 0.001
def __init__(self, pin):
self.__initialise(pin)
def update_settings(self, servo_pwm_freq, min_u16_duty, max_u16_duty, min_angle, max_angle, pin):
self.__servo_pwm_freq = servo_pwm_freq
self.__min_u16_duty = min_u16_duty
self.__max_u16_duty = max_u16_duty
self.min_angle = min_angle
self.max_angle = max_angle
self.__initialise(pin)
def move(self, angle):
# round to 2 decimal places, so we have a chance of reducing unwanted servo adjustments
angle = round(angle, 2)
# do we need to move?
if angle == self.current_angle:
return
self.current_angle = angle
# calculate the new duty cycle and move the motor
duty_u16 = self.__angle_to_u16_duty(angle)
self.__motor.duty_u16(duty_u16)
def stop(self):
self.__motor.deinit()
def get_current_angle(self):
return self.current_angle
def __angle_to_u16_duty(self, angle):
return int((angle - self.min_angle) * self.__angle_conversion_factor) + self.__min_u16_duty
def __initialise(self, pin):
self.current_angle = -0.001
self.__angle_conversion_factor = (self.__max_u16_duty - self.__min_u16_duty) / (self.max_angle - self.min_angle)
self.__motor = PWM(Pin(pin))
self.__motor.freq(self.__servo_pwm_freq)
Эта библиотека предполагает, что ваш сервопривод вращается в диапазоне от 0 до 180 градусов и что минимальное и максимальное значения скважности — это те, которые мы рассчитали ранее (максимум: 7864, минимум: 1802). Если у вас другие значения, вам следует скорректировать их в файле библиотеки прямо в следующих строках.
from machine import Pin, PWM
class Servo:
__servo_pwm_freq = 50
__min_u16_duty = 1802
__max_u16_duty = 7864
min_angle = 0
max_angle = 180
current_angle = 0.001
Сохраните файл библиотеки на вашем Raspberry Pi Pico с именем servo.py. Вы можете выполнить следующие шаги:
Скачайте код библиотеки. Вы можете найти файл servo.py здесь.
Скопируйте код в файл в Thonny IDE;
Перейдите в File > Save as… и выберите Raspberry Pi Pico;
Сохраните файл с именем servo.py (не меняйте имя)
Теперь, когда вы загрузили библиотеку на Raspberry Pi Pico, мы можем использовать функциональность библиотеки в нашем коде.
Управление сервоприводом — MicroPython
Следующий код делает то же самое, что и предыдущий пример, но использует методы библиотеки, которые более интуитивно понятны в использовании. Кроме того, вы можете указать конкретное значение угла, в которое хотите переместить двигатель.
from servo import Servo
from time import sleep
# Создание объекта Servo на пине 0
servo=Servo(pin=0)
try:
while True:
# Сервопривод на 0 градусов
servo.move(0)
sleep(2)
# Сервопривод на 90 градусов
servo.move(90)
sleep(2)
# Сервопривод на 180 градусов
servo.move(180)
sleep(2)
except KeyboardInterrupt:
print("Keyboard interrupt")
# Отключение ШИМ
servo.stop()
Как работает код
Вы начинаете с импорта класса Servo из библиотеки servo.
from servo import Servo
Затем вы создаёте объект Servo на GPIO 0. Если вы используете другой GPIO, вам нужно только изменить следующую строку.
# Создание объекта Servo на пине 0
servo=Servo(pin=0)
Затем в цикле мы просто используем метод move() объекта servo и передаём в качестве аргумента позицию, в которую хотим переместить двигатель, в градусах. Например:
# Сервопривод на 0 градусов
servo.move(0)
sleep(2)
# Сервопривод на 90 градусов
servo.move(90)
sleep(2)
# Сервопривод на 180 градусов
servo.move(180)
sleep(2)
Измените код и попробуйте с различными значениями углов.
Наконец, когда пользователь прерывает выполнение кода, мы останавливаем двигатель с помощью метода stop(). Это отключит ШИМ на пине, подключённом к двигателю.
except KeyboardInterrupt:
print("Keyboard interrupt")
# Отключение ШИМ
servo.stop()
Тестирование кода
Загрузите или запустите предыдущий код на Raspberry Pi Pico. Сервопривод должен вести себя точно так же, как в предыдущем примере. Но на этот раз в коде более интуитивно понятно перемещать сервопривод в определённую позицию.
Если вы хотите запускать этот код на Raspberry Pi Pico, когда он не подключён к компьютеру, вы должны сохранить код в файл с именем main.py и загрузить его на плату (File > Save as… > Raspberry Pi Pico).
Заключение
В этом руководстве вы узнали, как управлять хобби-сервоприводом с помощью Raspberry Pi Pico, запрограммированного на MicroPython. Мы показали вам, как управлять им, просто используя ШИМ-сигналы с правильной длительностью импульса, а также с помощью библиотеки.
Если вы хотите подключить другие моторы к Raspberry Pi Pico, ознакомьтесь с руководствами ниже: