Эмулятор сервопривода онлайн: проверка Servo.h-скетча без платы
Серво-скетч готов, а запускать страшно: плата, питание, провод сигнала — и с порога непонятно, почему рог дёргается, то ли код не тот, то ли питание проседает. Урок про подключение SG90 разбирает провода и питание по шагам — здесь же порядок обратный: сначала скетч в браузере, где ток не течёт и рог не заедает, железо — потом.
Сервопривод добавляется на стенд симулятора из каталога: жёлтый провод с меткой SRV, у детали — круговая шкала с рисками 0, 45, 90, 135, 180 и янтарной иглой вместо рога. Ниже — тест крайних положений, потенциометр как ручка управления, качание без delay и честная граница, где модель кончается.
Что видно на стенде
Сервопривод в каталоге компонентов — деталь «Сервопривод»: один сигнальный вывод на любой ШИМ-пин (3, 5, 6, 9, 10, 11), провод жёлтый, на плашке у колодки — «СИГНАЛ». Рог нарисован честно: круговая шкала с рисками на 0, 45, 90, 135 и 180 градусах, янтарная игла показывает текущий угол, цифра под шкалой дублирует его числом. Скетч ведёт рог теми же вызовами, что и на плате: attach(), write(), writeMicroseconds() и read() движок исполняет построчно.
- Игла вместо рога: угол виден в градусах, риски на 0, 45, 90, 135 и 180 — крайние точки и середина читаются взглядом.
- Старт с 90°: сразу после attach() движок ставит середину шкалы — как библиотека Servo.h на плате; ноль сам по себе не поставится.
- write() обрезается в 0-180: угол 250 или минус 30 движок зажмёт на краю — скетч узнает об этом по read().
- writeMicroseconds() живой: вилка 544-2400 мкс, 1500 мкс — те самые 90°; импульсную арифметику можно проверить прямо здесь.
- Фолбэк от ШИМ: без объекта Servo угол считается из analogWrite — 255 даёт 180°, 127 около 90°, 0 даёт 0°.
Тест крайних положений без питания
#include <Servo.h> Servo sv; // сигнальный провод — пин 9 void setup() { sv.attach(9); Serial.begin(9600); Serial.println(sv.read()); // 90 — старт с середины шкалы} void loop() { sv.write(0); // левый край Serial.println(sv.read()); // 0 delay(1000); sv.write(180); // правый край Serial.println(sv.read()); // 180 delay(1000);}Монитор печатает тройку «90 — 0 — 180», игла ходит от риска до риска, и обе крайние точки достигаются без единого провода: в браузере нет ни питания, ни упоров, ни заеданий — рог послушен всегда. На плате всё иначе: 0° и 180° упираются в механический ограничитель, серво жужжит и тянет ток в никуда. Поэтому после браузерного теста крайностей калибруют рабочую вилку конкретного экземпляра — приём разобран в уроке про калибровку min-max.
Потенциометр как ручка управления
#include <Servo.h> Servo sv; void setup() { sv.attach(9); Serial.begin(9600);} void loop() { int x = analogRead(A0); // ручка: 0..1023 int ugol = map(x, 0, 1023, 0, 180); // → 0..180 sv.write(ugol); Serial.print("x="); Serial.print(x); Serial.print(" ugol="); Serial.println(ugol); delay(15);}В симуляторе пару к серво составляет ручной потенциометр: ползунок на A0 крутится мышкой, число едет 0-1023, map() переводит его в градусы, игла следует следом. Перепутанные края map(x, 0, 1023, 180, 0) видны сразу — ручка крутится «наоборот», рог зеркалит. Разбор схемы «потенциометр плюс серво» по строкам ведёт урок про ручное управление серво; сама ручка со шкалой 0-1023 — тема лендинга из блока ссылок.
Плавное качание без delay
#include <Servo.h> Servo sv;unsigned long moment = 0;int ugol = 90;int napravl = 1; // +1 — к 180, −1 — к 0 void setup() { sv.attach(9); Serial.begin(9600);} void loop() { if (millis() - moment >= 20) { // шаг каждые 20 мс moment += 20; ugol += napravl; if (ugol >= 180 || ugol <= 0) napravl = -napravl; sv.write(ugol); } // паузы на весь цикл нет: кнопки и датчики опрашиваются без остановки}Блокирующая пауза против неблокирующего таймера: нажмите кнопку и сравните.
Подгружаем интерактив…
Лаборатория выше — про неблокирующий таймер, и для серво это не абстракция: классическое качание на delay(20) глушит весь остальной скетч, кнопка мертва, датчик молчит. Шаг по градусу на millis() держит loop живым — тот же ход иглы, но без заморозки. Плавность наращивается дальше: интерполяция и eased-движение разобраны в уроке про плавный ход без delay().
Честная граница: модель против живого привода
| Проверка | Симулятор | Только железо |
|---|---|---|
| Угол 0-180: attach, write, read | да, построчно как в скетче | то же |
| writeMicroseconds(): 544-2400 мкс | да: 1500 мкс ≈ 90° | то же |
| Качание и потенциометр-ручка | да: игла следует за кодом | то же, плюс инерция рога |
| Ток хода и стопора | нет: движок не знает SG90 и MG996R | да: стартовый пик роняет USB-питание |
| Гудение, нагрев, дрожание на месте | нет: модель идеальная | да — гудит, греется, дрожит |
| Люфт, упоры, заедания | нет: заеданий в браузере не бывает | да — края бьются об ограничитель |
Движок знает угол, а не привод: ни SG90, ни MG996R в модели нет, поэтому ток, момент и джиттер серво не моделируются — в симуляторе привод идеальный, а реальный гудит в покое, греется при удержании и на старте просаживает питание так, что плата перезагружается. Сигнальную часть браузер заменяет полностью, силовую — никогда: пики тока и лечение питания разбирает урок про пик тока и сброс платы, а гудение и подрагивание лечат detach() и фильтры — их место уже на макетке.
Грабли серво-скетча
- Забытый attach(): без него объект Servo не привязан к пину, игла стоит на месте — движок ждёт, серво на плате молчит.
- analogWrite() на плату с надеждой на сим: в браузере 127 даёт около 90° по фолбэку, а живая плата быстрый ШИМ от серво не ждёт — управляйте импульсами через Servo.h.
- Крайние 0 и 180 в постоянном удержании: в симе рог молчит, на плате — жужжание и нагрев; рабочая вилка 5-175° и detach() в простое лечат.
- map() с перепутанными краями: ручка и рог едут в противофазе; в браузере это видно за секунду — рог зеркалит движение ползунка.
- Углы за пределами 0-180: write(250) движок зажмёт на 180 и не пожалуется; сверяйте границы своего кода по read(), иначе на плате упрётесь в упор.