Что такое PinPort и почему это не обычная симуляция
В онлайн-лаборатории PinPort скетч для Arduino Uno управляет 3D-симуляцией города с машинами, пешеходами и светофорами. По улицам ездит шестиколёсный робот-доставщик R-D6, и его движением рулит обычный скетч для Arduino Uno, а не скрипт на JavaScript. Схему собирают в браузере, скетч пишут там же, а исполняет его эмулятор микроконтроллера. Заявленная цель проекта — обучение детей и взрослых в кружках робототехники (описание проекта).
Под капотом работают три компонента в одной петле: компилятор, эмулятор инструкций и физический движок. Компилятор живёт на сервере и собирает скетч через arduino-cli. Эмулятор ATmega328P исполняет полученную прошивку покомандно. Rapier считает физику: корпус робота, шесть колёс и моторы — твёрдые тела, светофоры, машины и пешеходы — кинематические тела с собственной логикой. Шаг мира равен 2 мс, и плата с физикой идут поочерёдно: две миллисекунды процессора, затем один шаг мира.
Связка получается тяжёлой, но она объясняет, зачем вообще эмулировать микроконтроллер. Пользователь пишет код в стиле Arduino, а не подгоняет логику робота под API конкретного симулятора.
Робот R-D6: шесть колёс и разворот на месте
R-D6 — шестиколёсный робот-доставщик, который умеет разворачиваться на месте. В симуляции это твёрдое тело с корпусом, шестью колёсами и моторами в Rapier. Разворот на месте снимает часть головной боли с навигации: не нужно выписывать дугу там, где места мало, а из тупика робот выбирается без сложной последовательности манёвров. Для учебной задачи это удобно, потому что большая часть ошибок новичков связана с точностью поворота, а не со скоростью.
Чем это отличается от симуляций на JavaScript
В типичной браузерной симуляции робота логика написана на JavaScript и живёт в том же процессе, что и физика. Здесь код пользователя — это скетч для Arduino Uno. Разница практическая: набор команд, работа с регистрами и периферией остаются «ардуиновскими», поэтому навыки ближе к реальной плате, чем к игровому движку. Про ограничения стоит сказать сразу: эмулятор покрывает только реализованные модули, и о полной замене живого железа речи нет. Утверждать, что PinPort — единственный проект такого рода, оснований тоже нет: сравнимых инициатив может быть больше, просто здесь детали раскрыты публично.
Как скетч Arduino попадает в браузер: компиляция и эмуляция
Цепочка сборки и запуска предсказуема для тех, кто работал с Arduino: код на C++ в привычной среде, сборка на стороне сервера, исполнение в виртуальном микроконтроллере.
arduino-cli на сервере: как собирается прошивка
Скетч уходит на сервер, где arduino-cli превращает его в прошивку для ATmega328P. Это стандартный инструмент командной строки из экосистемы Arduino, и выбор его логичен: синтаксис и библиотеки для пользователя остаются привычными, а установка тулчейна на своём компьютере не нужна. Что именно происходит с ошибками компиляции и как они показываются в интерфейсе, в доступном описании не раскрыто.
Эмулятор ATmega328P: 16 МГц, таймеры, ШИМ, I2C, UART
Прошивка исполняется покомандно в эмуляторе ATmega328P с частотой 16 МГц. Эмулятор поддерживает таймеры, ШИМ, I2C и UART, то есть тот набор периферии, которого хватает для управления моторами и чтения датчиков. Это принципиальный момент: скетч не интерпретируется как скрипт высокого уровня, а именно исполняется, поэтому состояния регистров, прерывания и тайминги ведут себя похоже на реальную плату. Про остальные модули микроконтроллера данных нет: список поддержки ограничен перечисленным.
Связка эмулятора и физики: как робот едет
Мост между цифровыми сигналами и движением собран вручную, и это самая интересная часть проекта. Плата и физика идут поочерёдно: две миллисекунды процессора, затем один шаг мира длиной 2 мс.
Драйвер L298N и моторы: от ШИМ до напряжения
За эти две миллисекунды отдельный класс собирает с выводов платы скважность ШИМ на ENA/ENB и уровни на IN1–IN4 драйвера L298N, а затем превращает их в напряжение на моторах. Схема знакомая: L298N — распространённый драйвер коллекторных моторов, и логика «два пина направления плюс ШИМ на скорость» встречается почти в каждом учебном проекте на Arduino. Номиналы напряжения в источнике не приводятся, поэтому конкретные значения имеет смысл сверять с документацией к драйверу.
Обратная связь: цифровые пины, лидар и навигатор на I2C
В обратную сторону идут показания датчиков. Цифровые пины попадают на выводы D2 и D3, а лидар и навигатор реализованы как регистры устройств на шине I2C. Механика такая же, как у MPU6050 или DS3231: первый байт записи задаёт номер регистра, дальше чтение идёт подряд.
Лидар сидит на адресе 0x52 и отдаёт 36 секторов по 10°, расстояние в сантиметрах как uint16 и номер оборота, обновление 10 раз в секунду. Навигатор с камерой светофоров висит на 0x53 и передаёт флаги, сигнал перехода, номер точки, курс, угол на цель, расстояния, скорость и координаты, обновляясь 50 раз в секунду (карта регистров).
Отдельная деталь, которая многое говорит о разнице между теорией и практикой: скан лидара занимает 72 байта, а буфер библиотеки Wire на Uno — всего 32 байта. Поэтому встроенная библиотека RD6.h читает скан тремя кусками по 24 байта, и только тогда, когда счётчик оборотов изменился. Без этой проверки скетч читал бы одни и те же данные повторно и управлял роботом по устаревшей картинке.
Детерминизм: почему результат одинаков на любом компьютере
Если связать эмулятор и физику через реальное время, один и тот же скетч на слабом ноутбуке и на сильном десктопе поедет по-разному. Один успеет прогнать больше шагов физики между тактами платы, второй меньше, и робот окажется в другой точке города. Для уроков с автопроверкой и арены, где заезды считает сервер, такой разброс недопустим: результат обязан совпадать везде.
Зерно случайности и фиксированная сетка решений
Проблему снимают три решения. Случайность задаётся зерном. Время измеряется шагами физики, а не миллисекундами системных часов. Решения принимаются на фиксированной сетке. В сумме это убирает зависимость от производительности машины.
Оговорка: в доступном описании не раскрыто, как именно инициализируется зерно и какова величина сетки решений. Поэтому повторить детерминизм «по мотивам обзора» не получится, нужен доступ к исходному коду проекта.
Хеши состояний мира: как проверяют идентичность
Проверка строится на хеше состояния мира: два запуска на разных машинах сравниваются по нему. Совпали хеши, значит поведение идентично. Формат хеша, момент его снятия и частота сравнения в источнике не раскрыты. Практический вывод осторожный: хеш — удобный инструмент контроля воспроизводимости, но абсолютной гарантии идентичности при любых условиях он не даёт, особенно если позже в проект добавят источники вроде реального времени или сетевых данных.
Навигация: Дейкстра, pure pursuit и камера светофоров
Маршрут строится алгоритмом Дейкстры, а движение по нему идёт с использованием pure pursuit. Оба алгоритма классические и давно описаны в литературе по мобильной робототехнике, экзотики тут нет. Оговорка по фактам: деталей реализации ни Дейкстры, ни pure pursuit в доступном описании проекта нет, поэтому дальше общий принцип, а не пересказ кода PinPort.
Как работает pure pursuit в этом проекте
Pure pursuit выбирает точку на маршруте впереди робота и ведёт его к ней, пересчитывая цель по мере движения. Дальняя точка даёт плавную траекторию и срезанные углы, ближняя — точное удержание линии и дёрганое управление. Конкретный вынос точки в PinPort не указан, так что подбирать его придётся по поведению робота на тестовом маршруте. Pure pursuit работает в связке с навигатором: тот отдаёт курс и угол на цель, и именно эти данные определяют, куда робот поворачивает.
Лидар: 36 секторов и три луча на сектор
В симуляции лидар — это набор лучей в мире Rapier. В каждом секторе их три: отклонение −3°, 0° и +3°, из попаданий берётся ближайшее. Итого 108 лучей на скан, скан обновляется 10 раз в секунду.
Почему три, а не один: с одиночным лучом на сектор столб светофора толщиной 14 см с пяти метров проскакивал между лучами, и робот в него врезался. Дальность лидара — 20 м, всё, что дальше, приходит как 2000 см, то есть «ничего нет».
Кому и зачем это нужно: обучение, кружки, арена
Проект адресован детям и взрослым в кружках робототехники. Смысл в том, что лаборатория работает в браузере: для старта не нужны плата, драйвер, моторы и лидар. Схему собирают на экране, скетч пишут в редакторе, результат видно сразу в 3D-городе (обучение и арена).
Уроки с автопроверкой и арена: как это работает
Уроки с автопроверкой проверяют результат скетча автоматически, без преподавателя. Арена даёт режим заездов, где счёт ведёт сервер. Обе механики опираются на детерминизм: если бы один и тот же скетч давал разный результат на разных машинах, автопроверка превратилась бы в лотерею, а соревнования — в тест производительности компьютера.
Ограничения подхода: что не заменит эмуляция
Эмуляция не воспроизводит физические нюансы реальной платформы: трение и износ механики, шум и дрейф датчиков, задержки шины, просадки питания. Это общее свойство любой модели, а не претензия к конкретному проекту. Есть и приземлённое ограничение: набор поддерживаемой периферии ограничен тем, что реализовано в эмуляторе. В источнике перечислены таймеры, ШИМ, I2C и UART; про другие модули данных нет, так что скетч с нестандартной периферией может не собраться или не заработать. Для кружка этого достаточно, для отладки реального продукта — нет.
Как попробовать и что проверить
- Открыть онлайн-лабораторию PinPort, собрать схему с платой, драйвером L298N и моторами, затем написать скетч для Arduino Uno.
- Убедиться, что робот R-D6 едет и разворачивается на месте: это проверка связки ШИМ, L298N и Rapier.
- Вывести в монитор значения с лидара 0x52 и проверить, что скан читается тремя кусками по 24 байта и обновляется раз в 100 мс.
- Проверить навигатор 0x53: курс, угол на цель, номер точки и сигнал перехода должны приходить 50 раз в секунду.
- Прогнать один и тот же скетч на двух машинах разной мощности и сравнить хеш состояния мира. Расхождение означает, что в логику просочилось реальное время.
- Изучить библиотеку RD6.h и примеры скетчей: чтение регистров и работа с буфером Wire там разобраны на конкретном коде.
Если хочется глубже разобраться в механике, начните с класса, который переводит скважность ШИМ и уровни IN1–IN4 в напряжение на моторах: именно он определяет, насколько правдоподобно робот ведёт себя в городе.
Источник
Все факты и технические детали в статье приведены по публикации «Город для робота-курьера в браузере: Arduino Uno, физика и пешеходы, которые уступают дорогу» (Habr, 12 октября 2026).