3.16. Управление сервоприводом

Любительский (RC) сервопривод – это небольшой двигатель с редуктором в герметичном корпусе со встроенным замкнутым управлением по положению. Внутри корпуса находятся двигатель постоянного тока, понижающий редуктор, потенциометр, подключённый к выходному валу, и небольшая плата драйвера, которая сравнивает показания потенциометра с уставкой, поступающей извне. Драйвер вращает двигатель в том направлении, которое уменьшает ошибку, и останавливается, когда положение совпадает. Со стороны камеры ничего из этого не видно – вы просто указываете сервоприводу, куда двигаться.

3.16.1. Сигнал ШИМ

Сервопривод принимает уставку в виде сигнала ШИМ с фиксированной частотой кадров 50 Гц, где ширина импульса выбирает положение:

  • Импульс 1,0 мс приводит вал к одному концу его хода.

  • Импульс 1,5 мс устанавливает вал в центре.

  • Импульс 2,0 мс приводит вал к другому концу.

Всё, что между ними, отображается на промежуточное положение.

Три ряда осциллограмм прямоугольной формы, расположенные вертикально. Каждый ряд показывает один период 20 мс ШИМ с частотой 50 Гц с узким высоким импульсом в начале: 1,0 мс в верхнем ряду, 1,5 мс в среднем, 2,0 мс в нижнем.

Кадр ШИМ сервопривода длится 20 мс; ширина импульса (1,0 – 2,0 мс) выбирает положение.

В отличие от светодиодов и двигателей, сервопривод не усредняет ШИМ. Команда – это сама ширина импульса: внутренняя логика сервопривода измеряет каждый импульс, соответственно устанавливает цель и вращает двигатель, пока выход не совпадёт. Коэффициент заполнения как доля (от 5 % до 10 % по всему диапазону) случаен – значение имеет абсолютная ширина импульса, и именно ею нужно управлять программе.

3.16.2. Подключение

Любительские сервоприводы используют трёхпроводной разъём:

  • Питание (обычно красный): собственное питание сервопривода, как правило от 4,8 В до 6 В. Не питайте сервопривод от шины 3,3 В камеры – она не сможет обеспечить ток при заклинивании, и напряжение на шине просядет.

  • Земля (обычно чёрный или коричневый): обратный путь для питания сервопривода, соединённый с землёй камеры, так что сигнал также имеет общую опорную точку.

  • Сигнал (обычно белый, жёлтый или оранжевый): линия ШИМ от GPIO камеры.

3.16.3. Код

duty_u16() сработал бы, но он задаёт коэффициент заполнения как долю периода – неудобно для сигнала, где важна абсолютная ширина импульса, а период фиксирован. duty_ns() задаёт ширину импульса напрямую в наносекундах:

from machine import PWM, Pin

servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000)  # centre

Несущая – 50 Гц (период 20 мс); время высокого уровня в каждом цикле составляет ровно 1500 мкс. Небольшая вспомогательная функция делает отображение положения в импульс явным:

def set_position(angle):
    # angle: 0..180 degrees mapped to 1.0..2.0 ms
    pulse_us = 1000 + (angle * 1000) // 180
    servo.duty_ns(pulse_us * 1000)

set_position(0)      # full one way
set_position(90)     # centre
set_position(180)    # full the other way

Медленная развёртка по диапазону:

import time

for angle in range(0, 181, 5):
    set_position(angle)
    time.sleep_ms(20)
for angle in range(180, -1, -5):
    set_position(angle)
    time.sleep_ms(20)

Диапазон 1,0 – 2,0 мс является стандартным, но многие сервоприводы принимают более широкий диапазон (часто от 500 мкс до 2500 мкс) для полного хода. Техническое описание сервопривода указывает точные пределы ширины импульса; значения вне этого диапазона могут с силой ударить двигатель в его механические упоры.

Для сервопривода с нестандартным диапазоном вынесите пределы в константы и параметризуйте отображение:

PULSE_MIN_US = 500     # full one way (from the data sheet)
PULSE_MAX_US = 2500    # full the other way

def set_position(angle):
    span_us = PULSE_MAX_US - PULSE_MIN_US
    pulse_us = PULSE_MIN_US + (angle * span_us) // 180
    servo.duty_ns(pulse_us * 1000)