Курс Arduino с нуля · Движение
Урок 22. Сервопривод: плата двигает предметы
Первая деталь, которая двигается по-настоящему: сервопривод поворачивается на заданный угол и удерживает его. Разбираем, как он устроен, чем управляется и почему ему нужно много тока.
Что понадобится
- Плата Uno из набора
- Кабель USB
- Сервопривод SG90
- Макетная плата
- Потенциометр 10 кОм
- Тактовая кнопка
- 8 проводов «папа-папа»
Все детали есть в обучающем наборе, по которому идёт курс.
До сих пор плата умела показывать: светить, мигать, пищать. Сегодня она научится двигать — по-настоящему, с усилием. Это тот самый момент, ради которого многие и берутся за Arduino: устройство перестаёт быть картинкой на столе и начинает что-то делать руками.
Деталь называется сервопривод. Она умеет то, чего не умеет обычный мотор: повернуться ровно на заданный угол и удерживать его.
Что такое сервопривод
Сервопривод — это маленькая коробочка, из которой торчит пластиковая качалка. Скажешь ему «30 градусов» — качалка повернётся на 30 градусов и останется там. Скажешь «120» — доедет до 120 и снова замрёт. Диапазон у нашего сервопривода — от 0 до 180 градусов, то есть полукруг.
В пакетике вместе с сервоприводом лежат несколько насадок разной формы — крестовина, одиночная качалка, диск — и мелкие винты. Насадка просто надевается на вал сверху.
Почему он держит угол
Обычный мотор умеет только крутиться: подал ток — вертится, снял — остановился где попало. Сервопривод устроен хитрее. Внутри у него всё тот же мотор, но к нему добавлены шестерёнки, датчик угла и маленькая плата.
Отсюда и главное ощущение от сервопривода: если попробовать провернуть качалку пальцем, она упирается и возвращается назад. Это не «заклинило» — это работает та самая проверка внутри.
Не крутите качалку рукой с силой. Шестерёнки внутри пластиковые, и сорвать зубья проще, чем кажется. Если качалку нужно переставить — снимите её с вала, а не проворачивайте.
Как плата передаёт угол
Тут есть небольшой сюрприз. Плата не отправляет сервоприводу число «сорок пять градусов». Она отправляет короткий импульс — и вся команда прячется в его длине.
Считать эти микросекунды самому не придётся: за нас всё сделает готовая библиотека Servo. Она уже встроена в программу — устанавливать ничего не нужно, достаточно одной строчки в начале скетча.
Собираем схему
Схема на этот раз совсем короткая: у сервопривода всего три провода, и все три идут прямо в плату.
Отключите USB перед сборкой. И запомните цвета: коричневый (у некоторых сервоприводов чёрный) — всегда земля, красный — питание, оранжевый (бывает жёлтый или белый) — сигнал. Если перепутать красный и коричневый, сервопривод может выйти из строя.
Шаг 1. Проверка: встань посередине
Самая первая программа ничего не двигает — она просто задаёт угол один раз. Но именно она показывает, что всё собрано верно: при включении качалка дёрнется и встанет в среднее положение.
#include <Servo.h> // библиотека сервоприводов, она уже есть в программе
Servo arm; // так мы назвали свой сервопривод
void setup() {
arm.attach(9); // оранжевый провод сервопривода идёт в вывод 9
arm.write(90); // встань ровно посередине
}
void loop() {
// Здесь пусто: сервопривод сам держит заданный угол.
}
Разберём три новые строки. #include <Servo.h> подключает библиотеку — это как сказать программе «мне понадобятся команды для сервоприводов». Servo arm; создаёт сервопривод и даёт ему имя arm (можно любое другое). А arm.attach(9) сообщает, к какому выводу он подключён.
Дальше всё просто: arm.write(90) — «повернись на 90 градусов». Обратите внимание, что loop пустой, и это не ошибка: сервопривод сам держит угол, ему не нужно напоминать об этом каждую секунду.
Шаг 2. Три положения
Теперь заставим качалку ходить по трём точкам: край, середина, другой край.
#include <Servo.h>
Servo arm;
void setup() {
arm.attach(9);
}
void loop() {
arm.write(0); // до упора влево
delay(1000); // даём время доехать
arm.write(90); // середина
delay(1000);
arm.write(180); // до упора вправо
delay(1000);
arm.write(90); // и обратно в середину
delay(1000);
}
delay(1000) здесь обязателен. Команда write выполняется мгновенно, а вот качалке нужно время, чтобы доехать: примерно 0,1–0,2 секунды на каждые 60 градусов. Если убрать паузы, программа будет отдавать команды быстрее, чем сервопривод успевает поворачиваться, и он просто задрожит на месте.
Шаг 3. Плавный ход
Резкие броски от края до края смотрятся некрасиво. Чтобы движение стало плавным, будем поворачивать качалку по одному градусу — знакомым циклом for из шестого урока.
#include <Servo.h>
Servo arm;
void setup() {
arm.attach(9);
}
void loop() {
// Едем вперёд: угол растёт от 0 до 180.
for (int angle = 0; angle <= 180; angle++) {
arm.write(angle);
delay(15); // пауза даёт качалке успеть за командой
}
// И назад: угол убывает от 180 до 0.
for (int angle = 180; angle >= 0; angle--) {
arm.write(angle);
delay(15);
}
}
Меняя delay(15), вы меняете скорость: 5 — быстро, 30 — медленно и торжественно. Это и есть весь секрет плавных движений у роботов из видео.
Шаг 4. Углом управляет крутилка
Соединим сервопривод с потенциометром из четырнадцатого урока — и получится ручка, за которой качалка следует, как привязанная. Сюда же сразу поставим кнопку, она понадобится на пятом шаге.
#include <Servo.h>
Servo arm;
const int POT = A0; // средняя ножка крутилки
int lastAngle = -1; // какой угол отправили в прошлый раз
void setup() {
arm.attach(9);
Serial.begin(9600);
}
void loop() {
int value = analogRead(POT); // 0...1023
int angle = map(value, 0, 1023, 0, 180); // переводим в градусы
// Отправляем команду, только если угол реально изменился:
// иначе сервопривод будет мелко дрожать на месте.
if (angle != lastAngle) {
arm.write(angle);
lastAngle = angle;
Serial.print("угол: ");
Serial.println(angle);
}
delay(20);
}
Знакомая связка: analogRead даёт число от 0 до 1023, map переводит его в градусы от 0 до 180.
Новое здесь — проверка if (angle != lastAngle). Без неё программа отправляла бы команду по пятьдесят раз в секунду, даже когда крутилку никто не трогает, и сервопривод мелко дрожал бы от каждого случайного колебания. Приём простой и полезный: не повторяй команду, если ничего не изменилось.
Шаг 5. Кнопка: открыть и закрыть
Чаще всего от сервопривода нужны не все 180 градусов, а всего два положения — «закрыто» и «открыто». Заслонка, дверца, шлагбаум, кормушка для кота.
#include <Servo.h>
Servo arm;
const int BUTTON = 2;
bool opened = false; // сейчас открыто?
bool wasPressed = false; // была ли кнопка нажата в прошлый раз
void setup() {
arm.attach(9);
pinMode(BUTTON, INPUT_PULLUP);
arm.write(10); // стартуем в положении «закрыто»
}
void loop() {
bool pressed = digitalRead(BUTTON) == LOW;
// Ловим МОМЕНТ нажатия: раньше кнопка была отпущена, а теперь нажата.
if (pressed && !wasPressed) {
opened = !opened; // меняем состояние на противоположное
if (opened) {
arm.write(100); // подняли
} else {
arm.write(10); // опустили
}
delay(50); // короткая пауза от дребезга контактов
}
wasPressed = pressed;
}
Ловля момента нажатия — тот же приём, что и в одиннадцатом уроке: сравниваем, что было раньше и что стало сейчас. Без него сервопривод метался бы туда-обратно всё время, пока палец лежит на кнопке.
Осторожно с питанием
Сервопривод — первая деталь в курсе, которой нужен заметный ток. Светодиод берёт 10–20 миллиампер, а сервопривод в момент поворота — сотни. Плата, запитанная от USB, такое выдерживает, но на пределе.
Признаки, что питания не хватает: плата перезагружается в момент поворота, светодиод «L» моргает, монитор порта отваливается, сервопривод дёргается сам по себе. Один сервопривод без нагрузки обычно работает нормально; если нужно два и больше или качалка что-то толкает — питайте сервоприводы от отдельного источника на 5 вольт, соединив с платой только землю.
И ещё одно важное следствие: пока подключена библиотека Servo, на выводах 9 и 10 перестаёт работать плавная яркость (analogWrite). Библиотека забирает себе внутренний счётчик, который отвечал за эти два вывода. Светодиод, которому нужна плавность, вешайте на 3, 5, 6 или 11.
Не работает? Разбираемся
- Сервопривод молчит, качалка не шевелится. Проверьте оранжевый провод: он должен идти в вывод 9, тот же номер стоит в
attach(9). Затем питание — красный в 5V, коричневый в GND. - Дёргается и гудит, но не поворачивается. Это почти всегда питание: плате не хватает тока. Отключите остальные детали и попробуйте только сервопривод.
- Едет до упора и упирается с треском. Угол вышел за пределы. Убедитесь, что в
writeпопадают только числа от 0 до 180, а насадка при повороте ни во что не упирается. - Мелко дрожит на месте. На шаге 4 — нет проверки
if (angle != lastAngle). На остальных шагах — слабое питание или плохой контакт в разъёме. - Плата перезагружается при каждом повороте. Просадка питания. Уберите нагрузку с качалки, а лучше дайте сервоприводу отдельный источник.
- Ошибка «Servo does not name a type». Забыта первая строка
#include <Servo.h>— без неё программа не знает, что такоеServo.
Задания для тренировки
- РазминкаСделайте «метроном»: качалка ходит между 60 и 120 градусами с постоянным ритмом, а зуммер щёлкает в каждой крайней точке.
- ПосложнееСоедините сервопривод с датчиком света из пятнадцатого урока: чем темнее в комнате, тем сильнее поворачивается качалка. Получится стрелка-указатель освещённости.
- Со звёздочкой ⭐Сделайте так, чтобы по нажатию кнопки качалка ехала в другое положение плавно — и при этом программа продолжала слушать кнопку во время движения. Разбор ниже.
Показать разбор «плавно и не подвешивая программу»
Приём тот же, что в одиннадцатом и девятнадцатом уроках. Заводим две переменные: angle — где качалка сейчас, и target — куда она должна приехать. Кнопка меняет только target и тут же отпускает программу дальше. А отдельный кусочек кода раз в несколько миллисекунд подвигает angle на один градус в сторону цели.
#include <Servo.h>
Servo arm;
const int BUTTON = 2;
const int CLOSED = 10; // угол «закрыто»
const int OPENED = 100; // угол «открыто»
const int STEP_MS = 12; // пауза между градусами: больше — медленнее
int angle = CLOSED; // где качалка сейчас
int target = CLOSED; // куда она едет
unsigned long lastStep = 0;
bool wasPressed = false;
void setup() {
arm.attach(9);
pinMode(BUTTON, INPUT_PULLUP);
arm.write(angle);
}
void loop() {
// 1. Кнопка задаёт цель — и не ждёт, пока качалка доедет.
bool pressed = digitalRead(BUTTON) == LOW;
if (pressed && !wasPressed) {
if (target == CLOSED) {
target = OPENED;
} else {
target = CLOSED;
}
}
wasPressed = pressed;
// 2. Раз в STEP_MS миллисекунд двигаемся на один градус к цели.
if (angle != target && millis() - lastStep >= STEP_MS) {
lastStep = millis();
if (angle < target) {
angle++;
} else {
angle--;
}
arm.write(angle);
}
}
Обратите внимание: в этой программе нет ни одного delay. Поэтому нажатие кнопки замечается мгновенно — даже если качалка ещё в пути и поедет обратно с полдороги.
Что мы узнали
- Сервопривод поворачивается на заданный угол и удерживает его: внутри мотор, шестерёнки, датчик угла и плата, которая всё время сверяет одно с другим.
- Угол передаётся длиной импульса, но считать её самому не нужно — этим занимается библиотека Servo.
- Три команды покрывают почти всё:
#include <Servo.h>,attach(вывод)иwrite(градусы)от 0 до 180. - После команды нужна пауза: качалке требуется время, чтобы доехать. Ход по одному градусу с маленькой паузой даёт плавное движение.
- Не повторяйте команду, если значение не изменилось, — иначе сервопривод дрожит.
- Сервопривод потребляет много тока, а библиотека Servo отбирает плавную яркость у выводов 9 и 10.
В следующем уроке возьмёмся за обычный мотор. Он проще сервопривода, но подключить его напрямую к выводу платы нельзя — понадобится транзистор.
Частые вопросы
Как подключить сервопривод к Arduino?
У сервопривода три провода: коричневый или чёрный — на GND, красный — на 5V, оранжевый или жёлтый — на любой цифровой вывод, в уроке это вывод 9. Больше ничего не требуется: ни резисторов, ни макетной платы.
Какой командой задать угол сервопривода?
Сначала подключается библиотека Servo и создаётся сервопривод, например Servo arm. В setup вызывается arm.attach(9), а поворот задаётся командой arm.write(градусы) — числом от 0 до 180.
Почему сервопривод дрожит и гудит?
Две частые причины. Первая — не хватает тока: плата, питаемая от USB, проседает, и сервопривод дёргается. Вторая — программа повторяет команду write слишком часто; отправляйте её только когда угол реально изменился.
Можно ли питать сервопривод от платы Arduino?
Один маленький сервопривод без нагрузки обычно работает от 5V платы. Если сервоприводов несколько или качалка что-то двигает, нужен отдельный источник 5 вольт, а его земля соединяется с землёй платы.
Почему после подключения Servo перестала работать плавная яркость?
Библиотека Servo забирает себе внутренний счётчик платы, который отвечает за выводы 9 и 10. Команда analogWrite на этих двух выводах работать перестаёт — светодиод с плавной яркостью подключайте к выводам 3, 5, 6 или 11.
