Как управлять сервоприводами с помощью ESP32
Хобби-сервоприводы — это удобные и полезные устройства для самых разных проектов. Хотя изначально они использовались в радиоуправляемых автомобилях и самолётах, теперь они встречаются во всевозможных других приложениях благодаря своим возможностям точного позиционирования. Просто укажите им, куда повернуть, и они сделают это за вас.
В этом руководстве вы узнаете, как управлять сервоприводом с помощью ESP32. Мы начнём с того, что заставим серво автоматически поворачиваться вперёд и назад. Затем мы добавим потенциометр для ручного управления положением серво. Наконец, мы расширим проект для одновременного управления несколькими сервоприводами. Для начала мы рассмотрим основы сервоприводов. Однако, если вы уже знакомы с этими основами, можете сразу перейти к разделу подключение оборудования.
Давайте начнём!
Основы сервоприводов
Внутри типичного хобби-сервопривода вы найдёте пять основных компонентов, работающих вместе: двигатель постоянного тока, редуктор, качалку серво, потенциометр и блок управления.
Двигатель постоянного тока: Это основной компонент, обеспечивающий вращающую силу. Он похож на хобби-моторчики из игрушек, но именно способ управления имеет решающее значение. Двигатель постоянного тока соединён с выходным валом через систему шестерён.
Редуктор: Редуктор (система шестерён) играет ключевую роль в увеличении крутящего момента двигателя и повышении точности его движений. Он снижает скорость двигателя, но увеличивает его силу.
Качалка серво: Это пластиковый рычаг (или колесо), прикреплённый к выходному валу (части, которая фактически вращается). Качалка серво даёт вам место для крепления того, что вы хотите, чтобы серво двигало — например, руку робота или руль направления на модели самолёта.
Потенциометр: Это переменный резистор, который действует как датчик положения. Он подключён непосредственно к выходному валу. Когда выходной вал вращается, сопротивление потенциометра изменяется. Это сообщает блоку управления точное положение двигателя.
Блок управления: Это «мозг» сервопривода. Он принимает сигналы от внешнего контроллера (например, ESP32), проверяет положение потенциометра и управляет двигателем постоянного тока.
Как эти части работают вместе
Сервопривод работает с использованием так называемой «замкнутой системы обратной связи».
Когда вы отправляете сигнал серво с командой переместиться в определённое положение, блок управления принимает эту команду.
Потенциометр физически соединён с выходным валом, поэтому он всегда знает текущее положение серво. Когда двигатель вращается, выходной вал поворачивается, и вместе с ним поворачивается потенциометр. Это вращение изменяет сопротивление потенциометра, создавая напряжение, которое непосредственно соответствует текущему положению выходного вала (и, следовательно, двигателя). Это напряжение служит обратной связью для блока управления.
Блок управления постоянно сравнивает это напряжение обратной связи (представляющее текущее положение двигателя) с сигналом желаемого положения от микроконтроллера.
Если есть разница (сигнал «ошибки») между желаемым и текущим положением, блок управления регулирует мощность и направление двигателя постоянного тока, чтобы устранить эту разницу.
По мере движения двигателя напряжение обратной связи потенциометра изменяется, непрерывно обновляя информацию блока управления о текущем положении двигателя.
Как только двигатель достигает желаемого положения, сигнал ошибки становится нулевым, и блок управления останавливает двигатель.
Весь этот процесс происходит очень быстро и многократно. Серво постоянно проверяет своё положение и вносит мельчайшие корректировки, чтобы оставаться именно там, где должно быть. Вот почему сервоприводы так хорошо удерживают своё положение, даже когда внешние силы пытаются их сдвинуть.
Вся эта система называется «сервомеханизм» или просто «серво». Она работает как замкнутая система управления, использующая отрицательную обратную связь для точного управления скоростью и направлением двигателя, позволяя ему достигать и поддерживать определённое положение.
Как работают сервоприводы?
Хобби-сервоприводы управляются с помощью хитрой техники, называемой широтно-импульсной модуляцией (ШИМ).
ШИМ работает путём отправки серии электрических импульсов на серво через регулярные интервалы. Для большинства хобби-сервоприводов эти импульсы отправляются примерно 50 раз в секунду (50 Гц). Это означает, что новый импульс приходит каждые 20 мс (1/50 секунды).
Для управления положением серво важна не частота отправки импульсов, а длительность каждого импульса. Эта длительность называется «шириной импульса» (или «скважностью» сигнала ШИМ, если вы предпочитаете технический термин).
Короткий импульс около 1 мс или менее указывает серво переместиться на 0 градусов (до упора в одну сторону)
Средний импульс около 1,5 мс устанавливает серво на 90 градусов (точно посередине)
Более длинный импульс около 2 мс перемещает серво на 180 градусов (до упора в другую сторону)
Для промежуточных положений используются ширины импульсов между этими значениями. Например, если мы хотим установить серво в положение 45 градусов (на полпути между 0 и 90 градусами), мы бы использовали импульс длительностью около 1,25 мс.
Это означает, что мы можем точно контролировать, куда именно указывает серво, тщательно управляя длительностью каждого импульса. Блок управления серво принимает эти импульсы, измеряет их ширину и перемещает двигатель в соответствующее положение.
Анимация ниже поможет вам визуализировать, как изменения ширины импульса соответствуют различным положениям серво.
Не все сервоприводы одинаковы
Важно отметить, что точный диапазон ширины импульса может немного различаться у разных моделей сервоприводов. Некоторые сервоприводы могут использовать диапазон, например, 0,5 мс для 0 градусов и 2,5 мс для 180 градусов.
Вот почему всегда полезно заглянуть в даташит, который идёт с вашим конкретным сервоприводом. Даташит расскажет вам, какие именно ширины импульсов использовать для различных положений с вашим конкретным серво.
Подключение сервопривода
Практически все хобби-сервоприводы поставляются со стандартным трёхконтактным разъёмом с шагом 0,1″ (2,54 мм). Хотя цветовая маркировка проводов может различаться у разных производителей, контакты обычно расположены в одном и том же порядке.
Вот описание распиновки:
GND — контакт заземления.
5V — контакт питания сервопривода. Большинству хобби-сервоприводов для правильной работы требуется напряжение от 4,8 В до 6 В. Обеспечение правильного напряжения важно — слишком мало, и серво не будет иметь достаточной силы, слишком много — и вы можете повредить его.
Control — принимает сигнал ШИМ (широтно-импульсная модуляция) от микроконтроллера, который определяет положение серво.
Примечание
Цветовая маркировка проводов может различаться у разных производителей, но провод питания почти всегда красный, что позволяет легко его идентифицировать. Провод заземления обычно чёрный или коричневый, а провод управления — оранжевый, жёлтый или белый.
Подключение сервопривода к ESP32
Отлично! Давайте подключим сервопривод к ESP32.
Для этого эксперимента мы будем использовать микросервопривод SG90. Этот маленький, но мощный мотор работает от 5 В (может работать в диапазоне от 4,8 В до 6 В постоянного тока) и может поворачиваться до 180 градусов — 90 градусов в каждом направлении.
Важно отметить, что когда серво находится в покое, оно потребляет всего около 10 мА тока. Но когда оно движется, потребление значительно возрастает — от 100 мА до 250 мА. Это означает, что для большинства простых проектов мы можем питать серво напрямую от вывода VIN на ESP32. Но если ваш сервопривод потребляет более 250 мА, следует использовать отдельный источник питания, чтобы не повредить ESP32.
Для подключения микросервопривода SG90 к ESP32:
Подключите красный провод к выводу VIN на ESP32.
Подключите чёрный или коричневый провод к выводу GND (земля).
Подключите оранжевый или жёлтый провод к GPIO13 на ESP32. На самом деле можно использовать любой GPIO ESP32, так как каждый из них способен генерировать сигнал ШИМ. Однако рекомендуется избегать использования GPIO 9, 10 и 11, поскольку они подключены к встроенной SPI-флеш-памяти и не рекомендуются для других целей. Для получения дополнительной информации обратитесь к справочнику по распиновке ESP32.
Вот краткая справочная таблица подключений:
Сервопривод |
ESP32 |
|---|---|
5V |
VIN |
GND |
GND |
Control |
GPIO13 |
Пожалуйста, обратитесь к изображению ниже, чтобы увидеть правильную схему подключения.
Настройка Arduino IDE
Мы будем использовать Arduino IDE для программирования ESP32, поэтому, пожалуйста, убедитесь, что у вас установлено дополнение ESP32, прежде чем продолжить:
Микроконтроллер ESP32 быстро стал одной из самых популярных плат среди любителей, инженеров и людей, интересующихся Интернетом вещей (IoT)…
Установка библиотеки
Arduino IDE поставляется со встроенной библиотекой Servo для управления сервоприводами, но, к сожалению, она несовместима с ESP32. Тем не менее, существует несколько библиотек, созданных специально для ESP32, многие из которых эмулируют библиотеку Arduino Servo, добавляя при этом дополнительную функциональность.
Для этого руководства мы решили использовать библиотеку ESP32Servo от Kevin Harrington. Эта библиотека не только воспроизводит возможности оригинальной библиотеки Arduino Servo, но и добавляет некоторые дополнительные функции.
Для установки библиотеки:
Сначала откройте Arduino IDE. Затем нажмите на значок Library Manager на левой боковой панели.
Введите «ESP32Servo» в поле поиска, чтобы отфильтровать результаты.
Найдите библиотеку «ESP32Servo», созданную Kevin Harrington.
Нажмите кнопку Install, чтобы добавить её в Arduino IDE.
Пример 1: Развёртка сервопривода
Первый пример выполняет развёртку вала сервопривода вперёд и назад на 180 градусов. Загрузите скетч.
#include <ESP32Servo.h>
// create servo object to control a servo
Servo myservo;
// variable to store the servo position
int pos = 0;
// GPIO pin used to connect the servo
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
int servoPin = 13;
void setup() {
// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
// Standard 50hz servo
myservo.setPeriodHertz(50);
// attach the servoPin to the servo object and set the sweep range
// For SG90, 500 and 2400 might be more suitable
// different servos may require different min/max settings
myservo.attach(servoPin, 500, 2400);
}
void loop() {
// goes from 0 degrees to 180 degrees
for (pos = 0; pos <= 180; pos += 1) {
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
// goes from 180 degrees to 0 degrees
for (pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
Примечание
После загрузки скетча на ESP32 и подключения оборудования вы должны наблюдать, как серво совершает развёрточное движение. Однако вы можете заметить, что серво не достигает полного разворота на 180 градусов. Это связано с тем, что каждый сервопривод может немного отличаться. Чтобы настроить диапазон развёртки, измените минимальное и максимальное значения времени в скетче. Путём экспериментов вы можете определить оптимальные значения для вашего конкретного мотора. Например, для серво SG90 значения 500 и 2400 могут быть более подходящими.
Объяснение кода
Сначала подключается библиотека ESP32Servo.h. Эта библиотека предоставляет функции для управления сервоприводами на ESP32.
#include <ESP32Servo.h>
Затем создаётся объект myservo класса Servo. Этот объект представляет сервопривод, которым вы будете управлять. На ESP32 можно создать до 16 таких объектов.
Servo myservo;
В той же глобальной области определяются две переменные: одна для хранения текущего положения серво в градусах (pos) и другая для указания GPIO-вывода, к которому подключён сигнальный провод вашего сервопривода (servoPin).
int pos = 0;
int servoPin = 13;
В функции setup вы заметите несколько строк, связанных с выделением таймеров. Это необходимый шаг при использовании библиотеки ESP32Servo, поскольку микроконтроллер ESP32 использует таймеры для генерации сигналов ШИМ, управляющих сервоприводами.
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
Затем частота сигнала ШИМ устанавливается на 50 Гц (Герц), что является стандартной частотой для большинства хобби-сервоприводов. Однако вы можете поэкспериментировать с этим значением для улучшения производительности вашего конкретного сервопривода.
myservo.setPeriodHertz(50);
Далее метод myservo.attach() используется для привязки объекта серво к фактическому GPIO-выводу (servoPin) на ESP32. Этот метод также устанавливает минимальную и максимальную ширину импульса (в микросекундах), определяющие диапазон движения серво. В этом примере минимальная ширина импульса установлена на 500 микросекунд, что соответствует положению 0 градусов, а максимальная — на 2400 микросекунд, что соответствует положению 180 градусов. Эти значения могут потребовать корректировки в зависимости от конкретного сервопривода, который вы используете.
myservo.attach(servoPin, 500, 2400);
Функция loop() содержит два цикла for. Первый цикл выполняет развёртку серво от 0 до 180 градусов. Внутри этого цикла метод myservo.write(pos) обновляет положение серво до текущего значения переменной pos, которая увеличивается на один градус в каждой итерации. После каждого обновления функция delay(15) приостанавливает программу на 15 миллисекунд, чтобы дать серво достаточно времени для достижения указанного положения.
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
Второй цикл выполняет развёртку серво обратно от 180 градусов до 0 градусов, также обновляя положение серво и ожидая 15 миллисекунд для каждого градуса.
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
Пример 2: Управление серво с помощью потенциометра
Следующий пример включает потенциометр, чтобы мы могли вручную регулировать положение серво. Этот проект может быть чрезвычайно полезен при управлении панорамированием и наклоном датчика, подключённого к сервоприводу.
Схема подключения
Мы повторно используем подключение из предыдущего примера, но на этот раз добавим потенциометр на 10 кОм. Подключите один конец потенциометра к земле, другой к VIN, а средний вывод к GPIO34.
Код Arduino
Код для того, чтобы серво следовало за положением ручки, проще, чем код для развёртки.
#include <ESP32Servo.h>
// create servo object to control a servo
Servo myservo;
// GPIO pin used to connect the servo
// Recommended PWM pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
int servoPin = 13;
// GPIO pin used to connect the potentiometer
// Recommended ADC pins on the ESP32 include 0,2,4,12-15,32-39; 34-39 are recommended for analog input
int potPin = 34;
// Variable to store the value from the analog pin
int val;
void setup() {
// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
// Standard 50hz servo
myservo.setPeriodHertz(50);
// attach the servoPin to the servo object and set the sweep range
// For SG90, 500 and 2400 might be more suitable
// different servos may require different min/max settings
myservo.attach(servoPin, 500, 2400);
}
void loop() {
val = analogRead(potPin); // read the value of the potentiometer (0 to 4096 for 12-bit ADC)
val = map(val, 0, 4096, 0, 180); // scale it to use it with the servo (0 to 180)
myservo.write(val); // set the servo position according to the scaled value
delay(200); // wait for the servo to reach the position
}
Объяснение кода
Обратите внимание, что введены две новые переменные: одна для указания GPIO-вывода, к которому подключён потенциометр (potPin), и другая для хранения значения с аналогового входа (val).
int potPin = 34;
int val;
Мы начинаем функцию loop с чтения значения с potPin.
val = analogRead(potPin);
Функция analogRead() возвращает значение от 0 до 4096. Однако нам необходимо масштабировать его, поскольку серво может поворачиваться только на 180 градусов.
Один из способов — использовать функцию Arduino map(), которая пересчитывает число из одного диапазона в другой. Строка ниже преобразует показание в градусы от 0 до 180.
val = map(val, 0, 4096, 0, 180);
Наконец, мы используем команду write() для обновления положения серво до угла, выбранного потенциометром.
myservo.write(val);
Пример 3: Управление несколькими сервоприводами
ESP32 имеет 16 каналов ШИМ, что означает, что вы можете напрямую управлять до 16 сервоприводами. Библиотека ESP32Servo, которую мы используем, также поддерживает все 16 каналов ШИМ, что упрощает добавление дополнительных сервоприводов в ваш проект.
Схема подключения
Давайте добавим ещё один сервопривод в вашу схему. Однако вместо питания через вывод VIN на ESP32 мы будем использовать отдельный источник питания. Это гарантирует, что сервоприводы получат достаточный ток. Подключите сигнальный вывод нового сервопривода к GPIO14 на ESP32.
На изображении ниже показано, как всё подключить.
Код Arduino
Теперь давайте модифицируем предыдущий пример кода, чтобы оба сервопривода выполняли развёртку вперёд и назад от 0 до 180 градусов независимо друг от друга.
#include <ESP32Servo.h>
// create two servo objects
Servo servo1;
Servo servo2;
int servo1Pin = 13;
int servo2Pin = 14;
int pos = 0; // position in degrees
ESP32PWM pwm;
void setup() {
// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
servo1.setPeriodHertz(50); // Standard 50hz servo
servo2.setPeriodHertz(50); // Standard 50hz servo
servo1.attach(servo1Pin, 500, 2400);
servo2.attach(servo2Pin, 500, 2400);
}
void loop() {
// sweep 1st servo from 0 degrees to 180 degrees
for (pos = 0; pos <= 180; pos += 1) {
servo1.write(pos);
delay(15);
}
// sweep 2nd servo from 0 degrees to 180 degrees
for (pos = 0; pos <= 180; pos += 1) {
servo2.write(pos);
delay(15);
}
// sweep 1st servo from 180 degrees to 0 degrees
for (pos = 180; pos >= 0; pos -= 1) {
servo1.write(pos);
delay(15);
}
// sweep 2nd servo from 180 degrees to 0 degrees
for (pos = 180; pos >= 0; pos -= 1) {
servo2.write(pos);
delay(15);
}
}
Объяснение кода
Давайте рассмотрим изменения и дополнения в этом коде по сравнению с первым:
Вместо одного объекта серво теперь создаются два объекта серво, servo1 и servo2.
Servo servo1;
Servo servo2;
Определены две константы, servo1Pin и servo2Pin, со значениями 13 и 14 соответственно. Они представляют GPIO-выводы на ESP32, к которым подключены два сервопривода.
int servo1Pin = 13;
int servo2Pin = 14;
Для обоих servo1 и servo2 устанавливается стандартная частота серво 50 Гц с помощью метода setPeriodHertz(). Метод attach() привязывает оба объекта servo1 и servo2 к соответствующим GPIO-выводам на ESP32. Значения 500 и 2400 передаются в качестве аргументов для указания минимальной и максимальной ширины импульса для обоих сервоприводов, которые определяют диапазон движения от 0 до 180 градусов.
servo1.setPeriodHertz(50);
servo2.setPeriodHertz(50);
servo1.attach(servo1Pin, 500, 2400);
servo2.attach(servo2Pin, 500, 2400);
Функция loop() состоит из четырёх циклов for. Первый цикл выполняет развёртку servo1 от 0 до 180 градусов. Второй цикл выполняет развёртку servo2 от 0 до 180 градусов. Третий цикл выполняет развёртку servo1 обратно от 180 до 0 градусов. Четвёртый цикл выполняет развёртку servo2 обратно от 180 до 0 градусов.
Как и ранее, для каждого градуса движения положение серво обновляется с помощью метода write(), и 15-миллисекундная задержка позволяет серво достичь заданного положения.
// sweep 1st servo from 0 degrees to 180 degrees
for (pos = 0; pos <= 180; pos += 1) {
servo1.write(pos);
delay(15);
}
// sweep 2nd servo from 0 degrees to 180 degrees
for (pos = 0; pos <= 180; pos += 1) {
servo2.write(pos);
delay(15);
}
// sweep 1st servo from 180 degrees to 0 degrees
for (pos = 180; pos >= 0; pos -= 1) {
servo1.write(pos);
delay(15);
}
// sweep 2nd servo from 180 degrees to 0 degrees
for (pos = 180; pos >= 0; pos -= 1) {
servo2.write(pos);
delay(15);
}
Что дальше?
Хотите вывести управление сервоприводом на новый уровень? Вы можете использовать встроенные возможности Wi-Fi ESP32 для создания веб-интерфейса. Это позволяет удалённо регулировать положение серво с любого устройства с веб-браузером. Это открывает массу интересных идей для проектов, таких как создание роботизированных рук с дистанционным управлением, умных домашних устройств, открывающих жалюзи или кормящих домашних животных, или даже реалистичных аниматронных фигур с движениями, которыми можно управлять на расстоянии.
Сервоприводы — это универсальные моторы, которые можно точно позиционировать на определённый угол, что делает их идеальными для самых разных проектов…