Как работают сервоприводы: импульсы, питание и ловушка Timer1
Как модельный сервопривод, например SG90, превращает импульс в угол, как пользоваться библиотекой Servo, как питать сервоприводы и почему библиотека отключает analogWrite() на D9 и D10.

Фото: Lukas Ruge · CC0
Модельный сервопривод, или просто серво, поворачивает свой вал на тот угол, который вы задали, и удерживает его в этом положении. Он может направлять датчик, двигать руку робота или поворачивать колесо, как руль. SG90 — популярный маленький сервопривод, и он же — одна из деталей симулятора CoreEngine.
Что внутри
Сервопривод — это четыре детали в одном маленьком корпусе:
- маленький мотор постоянного тока;
- редуктор, который делает вращение мотора медленнее и сильнее;
- потенциометр на выходном валу, который измеряет угол поворота вала;
- маленькая плата управления.
Плата сравнивает угол, который задаёт сигнал, с углом, который измеряет потенциометр. Если они различаются, плата крутит мотор в сторону нужного угла, и тем сильнее, чем больше разница. Когда углы совпадают, плата останавливает мотор. Это замкнутый контур управления, то есть управление с обратной связью. Похожим образом работает П-регулятор в проекте Робот, который держит дистанцию.
У SG90 три провода: коричневый — GND, красный — питание (4,8–6 В), оранжевый — сигнал.
Сигнал: один импульс каждые 20 мс
Сервопривод ждёт 50 импульсов в секунду — по одному каждые 20 мс. Угол задаёт ширина каждого импульса, то есть его длительность, а не количество импульсов. Вот значения по умолчанию в библиотеке Servo для Arduino:
| Длительность импульса | Угол |
|---|---|
| 544 мкс | 0 градусов |
| около 1472 мкс | 90 градусов |
| 2400 мкс | 180 градусов |
Получается примерно 10 мкс на градус. Эти значения по умолчанию точны не для каждого сервопривода. Многие SG90 поворачиваются не ровно на 180 градусов, а некоторые доходят до упора раньше, чем до 0 или 180 градусов.
Сервопривод держит угол, только пока продолжают приходить импульсы. Без импульсов большинство маленьких сервоприводов отключают свой мотор, и качалку на валу можно повернуть рукой.
Библиотека Servo
Библиотека сама формирует импульсы — в фоновом режиме и на любом цифровом пине:
#include <Servo.h>
Servo arm; // one Servo object for each servo
void setup() {
arm.attach(11); // signal wire (orange) on D11, a free pin on the robot car
arm.write(90); // turn to the middle
}Самые полезные вызовы:
| Вызов | Что делает |
|---|---|
arm.attach(11) |
запускает импульсы на D11 с длительностями по умолчанию, 544–2400 мкс |
arm.attach(11, 600, 2300) |
то же самое, но со своими длительностями импульсов для 0 и 180 градусов (значения для примера) |
arm.write(45) |
поворачивает вал на 45 градусов |
arm.writeMicroseconds(1500) |
задаёт длительность импульса напрямую, в мкс |
arm.read() |
возвращает последний угол, который вы задали; сам ничего не измеряет |
arm.detach() |
останавливает импульсы |
write() сразу возвращает управление программе, но сервоприводу нужно время, чтобы повернуться. Дайте ему это время, прежде чем рассчитывать на новый угол.
Поворот на угол или постоянное вращение
Обычный позиционный сервопривод вроде SG90 поворачивается в пределах примерно 180 градусов, а импульс задаёт его угол.
Сервопривод постоянного вращения выглядит так же, но может вращаться полными оборотами. Внутри потенциометр больше не следит за валом, а упор убран. Теперь импульс задаёт скорость и направление:
- импульс около середины (
write(90), примерно 1,5 мс): остановка; - импульсы короче: вращение в одну сторону;
- импульсы длиннее: вращение в другую сторону, тем быстрее, чем дальше они от середины.
Повернуться на заданный угол такой сервопривод не может, потому что больше не знает, где находится его вал. Точное значение для остановки у каждого сервопривода своё. Найдите его с помощью writeMicroseconds() или покрутите подстроечный винт, если он есть.
SG90 в симуляторе CoreEngine — позиционный сервопривод.
Питание: рассчитывайте по 1 А на сервопривод
SG90 работает от 4,8–6 В. В покое и без нагрузки он потребляет мало тока. Когда он начинает двигаться, то может на мгновение потребовать примерно до 0,7–1 А. Если несколько сервоприводов трогаются одновременно, эти броски тока складываются.
- USB. Вся плата Uno получает от USB не больше 500 мА. На столе один маленький сервопривод без нагрузки часто работает. Несколько сервоприводов или один, но сильно нагруженный, просаживают 5 В, и тогда Uno перезагружается или сервоприводы дёргаются.
- Робот-машина CoreEngine. Здесь пин 5V платы Uno получает питание от маленького стабилизатора L298N: около 4,4 В от четырёх батареек AA. Это меньше 4,8 В, нужных SG90, а ток 1 А этот стабилизатор дать не может.
- Источник получше. Возьмите источник, который даёт 4,8–6 В и около 1 А на каждый сервопривод, который может двигаться одновременно с другими. На робот-машине сам батарейный отсек даёт около 6 В — это верхняя граница диапазона SG90. Подойдёт и отдельный блок батареек.
- Общая земля (GND). Соедините минус источника питания сервопривода с GND платы Uno, иначе у сигнала не будет точки отсчёта.
Если ваш робот перезагружается, когда двигается сервопривод, прочитайте статью Почему робот перезагружается.
Ловушка Timer1
У ATmega328P на плате Uno три таймера. Каждый из них формирует широтно-импульсную модуляцию (ШИМ) для двух пинов:
| Таймер | Пины ШИМ | Что ещё его использует |
|---|---|---|
| Timer0 | D5, D6 (около 980 Гц) | millis() и delay() |
| Timer1 | D9, D10 (около 490 Гц) | библиотека Servo |
| Timer2 | D3, D11 (около 490 Гц) | tone() |
Как только в скетче подключён сервопривод, библиотека Servo отсчитывает время его импульсов по Timer1. С этого момента analogWrite() на D9 и D10 больше не выдаёт ШИМ, даже если к этим пинам не подключено ни одного сервопривода. Компилятор об этом не предупреждает. Типичный признак: мотор, у которого пин скорости подключён к D9 или D10, не слушается заданной скорости. Работают только 0 и 255, потому что для них analogWrite() выдаёт обычные LOW и HIGH.
Вот почему в робот-машине CoreEngine ШИМ для моторов (ENA и ENB) идёт с D5 и D6. Сервопривод можно добавить к роботу позже, и управление скоростью моторов сохранится. На D9 и D10 подключены TRIG и ECHO датчика HC-SR04, но это обычные цифровые сигналы: digitalWrite() и pulseIn() продолжают работать на этих пинах, даже когда действует библиотека Servo.
tone() делает то же самое с Timer2: мешает ШИМ на D3 и D11. Прежде чем использовать две библиотеки вместе, проверьте, какой таймер занимает каждая из них.
Дрожание: когда сервопривод дёргается
Если сервопривод трясётся или дёргается, когда должен стоять на месте, причина обычно одна из этих:
| Причина | Что помогает |
|---|---|
| Слабое или зашумлённое питание | источник, который может дать нужный ток; конденсатор 100–470 мкФ между плюсом и минусом питания сервопривода, рядом с ним; короткие провода питания |
| Нет общей земли | соедините минус источника питания сервопривода с GND платы Uno |
| Сервопривод давит на свой упор | найдите его настоящие пределы с помощью writeMicroseconds(), затем используйте attach(pin, min, max) |
| Тяжёлая нагрузка, которую нужно удерживать | нагрузка полегче или detach(), когда удерживать не нужно (тогда сервопривод перестаёт держать вал) |
| Скачущее входное значение | отфильтруйте значение, прежде чем передать его сервоприводу, например медианой трёх значений |
| Длинный сигнальный провод рядом с проводами моторов | короткий сигнальный провод подальше от проводов моторов |
В симуляторе
SG90 — одна из деталей симулятора CoreEngine. Его можно поставить на робота и подключить три его провода, а проверка подключения подскажет, если у него нет питания или не подключён сигнальный провод. Настоящий сервопривод есть в Маркете.