Пара слов в своё оправдание

В статье Я выпустил нейросеть в реальный мир — и стало не смешно в одном из комментариев попросили рассказать про железо и этот комментарий был поддержан плюсиками. Поэтому не могу не рассказать.

Почему этот робот собран так, а не иначе? Главный мой интерес был не в том, чтобы сделать качественную тележку, а в том, чтобы дать ИИ хоть какое-то тело — и посмотреть, как модели ведут себя в реальном, физическом мире. О том, что из этого вышло, и была первая статья. Эта — про само тело: как оно собрано и обо что я при этом бился.

Метод сборки — дендро-фекальный. Робот буквально собран из того, что нашлось у меня в кладовке. Отдельно докуплены только две вещи: пневматический пистолет и серва к нему. Всё остальное уже лежало и пылилось.

Поэтому это не туториал «как собрать робота дома». Это, скорее, карта граблей: на какие из них я наступил, чтобы вы могли наступить на свои. Особого смысла расписывать соединение каждого провода тоже нет смысла, это всё есть в документации к плате или датчику.

Ссылка на код будет в конце.

Робот в сборе
Робот в сборе

Из чего это собрано

Тележка — DF Robot Pirate. Дифференциальная платформа: четыре колеса, четыре мотора, рулится как танк — разностью скоростей бортов. Примерно 22 см в длину, 18 в ширину. В принципе заменяется на любую другую; я одно время всерьёз думал пустить на проект свой старый робот-пылесос.

Arduino Leonardo — мозг тележки. Мозг тупенький: почти ничего на нём не происходит, и дальше я объясню, почему так и задумано. Про саму Arduino писать не буду — вряд ли скажу что-то новое.

Дальше — то, что в разное время приехало с Амперки:

Motor Shield Plus — драйвер моторов. Управляет парой моторов; правый и левый борта у меня запараллелены. Умеет читать потребляемый моторами ток — пригодится.

Motor Shield Plus
Motor Shield Plus

Troyka Shield — продвинутая макетка. Удобно втыкать модули, есть место распаять своё.

Troyka Shield
Troyka Shield

IMU 10 DOF v2 — на борту акселерометр, гироскоп, магнетометр и барометр. Из всего набора сначала пригодился компас (магнетометр), потом от него пришлось отказаться в пользу гироскопа — отдельная история, к ней ещё вернёмся. Гироскоп L3G4250D так себе, бывают точнее.

IMU 10 DOF
IMU 10 DOF

Дальномер — лазерный Benewake TFmini-S LiDAR. Выбор был между ультразвуком и лазером. Лазер показался модным — взял его. Зря: в опытах с зеркалами ультразвук выручил бы там, где лазер откровенно врал. Но об этом позже.

TFmini-S LiDAR
TFmini-S LiDAR

Радиомодуль на 433 МГц неизвестного происхождения. Подключается к Arduino по серийному порту, в компьютер втыкается ответная часть в USB и выглядит как обычный COM-порт. Работает на 57600 бод.

Радиомодуль
Радиомодуль

Камера — Tapo C200. Особого выбора не было: тоже лежала в кладовке. Качество так себе, но для задачи хватает. Важная деталь: видео с неё идёт отдельным каналом — по Wi-Fi, мимо радиомодуля. Почему так — в следующем разделе.

Питание — пара LiPo-аккумуляторов, на 1.3 и 2.2 Ач, оба достались от каких-то игрушек.

Пистолет — Borner PM-X, реплика Макарова. Красивый, небольшой и недорогой. К нему — серва MG996R с заявленным моментом 13 кгс·см.

Косметика — напечатанная на принтере передняя панелька с матовым стеклом (вырезано из бака сломанного увлажнителя) и гирлянда из десятка светодиодов, синих и красных, на куске того, что когда-то было макетной платой.

Узлы по отдельности
Узлы по отдельности

Тупое тело, умный хост

Главный принцип всей конструкции: тело делает как можно меньше, мозг — на компьютере.

На Arduino — только то, что обязано жить рядом с железом и реагировать быстро: крутить моторы, читать датчики, плавно разгонять, отдавать телеметрию. Никакого интеллекта. Всё «думание» — зрение, навигация, решения — на хосте, на обычном ПК.

Связь устроена двумя независимыми каналами. По радио — управление и телеметрия: лёгкий поток коротких команд и чисел в обе стороны. Видео же идёт своим путём, по Wi-Fi прямо с камеры, мимо радиомодуля. Лёгкое — по радио, тяжёлое — по Wi-Fi.

Про то, что происходит на стороне ПК, я здесь почти не рассказываю — это тема для отдельного разговора. Но один кусочек хоста показать всё-таки придётся: протокол, на котором тело и мозг разговаривают.

На каком языке они говорят

Протокол я сделал текстовым и человекочитаемым — чтобы можно было подцепиться терминалом и глазами увидеть, что робот про себя думает.

Тело раз в ~100 мс выплёвывает кадр телеметрии:

---
SQ:1240      # номер пакета (счётчик с переполнением)
LS:50        # скорости левого/правого моторов
RS:50  
LC:312       # ток левого/правого  
RC:298  
GX:-120.4    # магнетометр 
GY:88.1
V:11.8       # напряжение аккумулятора
RF:610       # дальномер вперёд, мм
***

В обратную сторону — такие же короткие команды: L/R — моторам, P — биппер, F — выстрел.

Один скромный на вид параметр окажется важнее, чем кажется, — SQ, номер пакета. Он просто монотонно растёт. Но если он вдруг скакнул или обнулился — значит, плата только что перезагрузилась. Этот счётчик ещё спасёт мне не один час отладки. Полная спецификация — в src/docs/protocol.md, здесь её разворачивать не буду.

Тележка поехала

Дальше — месяц кодирования. Прошивка, аппаратные тесты, плавный разгон моторов (резко давать полный газ нельзя — мотор-редукторы дёргаются, тележка прыгает). Подбор максимальной скорости, делителя для замера напряжения.

Но тележка поехала. Вперёд, назад, повороты.

А потом начались чудеса.

Зависания

Робот ни с того ни с сего замолкал и перезагружался. Случайно, без системы. Поймать такое — худшее, что бывает: оно не воспроизводится по команде.

Спас тот самый SQ. Я смотрел в поток телеметрии и видел: номер пакета спокойно растёт, растёт — и вдруг обнуляется. Плата перезагрузилась. Не зависла в коде, не потеряла связь — именно перезагрузилась, на ровном месте.

Виноваты оказались драйверы моторов. Изначально вся электроника была собрана в “бутерброд” из четырёх плат. Ардуино, далее в нее воткнут драйвер моторов, в драйвер моторов воткнута макетка, в макетку воткнут гироскоп и товарищи. Драйвер моторов стоял слишком близко к Arduino, и наводки от моторных токов сбивали плату. Лечение нашлось грубое и физическое: разнести драйверы подальше. Помогло. Десять часов на то, чтобы передвинуть железку на пару сантиметров, — нормальный размен.

Параллельно был эпизод с искрами. Перепутал провода, откуда-то прилетели искры и появился приятный запах горелых микросхем. Хорошо, что плат Leonardo у меня было две.

Хромота

А однажды робот захромал.

Поехал — и заметно повело влево. Не чуть-чуть, а так, что мимо не пройдёшь. Я покрутил колёса руками: заднее левое идёт ощутимо туже остальных. Внутри всё опустилось — приехали. Мотор или редуктор под замену, а раз менять, то, наверное, все четыре сразу, чтоб одинаковые. Плюс заново настраивать управление под новые мотор-редукторы. Неделя коту под хвост, не меньше.

Полез внутрь — глянуть на моторы перед похоронами. А там провода лежат комом, как попало. И один проводок немного касается вала мотора. Чуть-чуть, но достаточно, чтобы притормаживать колесо.

Отодвинул провод. Колесо завертелось как новенькое.

С тех пор проводка внутри уложена аккуратно, по местам. И мораль, которую я каждый раз забываю и каждый раз вспоминаю: делай сразу хорошо.

Проводка после разбора полётов
Проводка после разбора полётов

Куда я еду?

С тем, чтобы ехать, разобрались. Дальше — куда ехать и насколько. И тут выяснилось, что в реальном мире все датчики немножко врут, и каждый — по-своему.

Компас-предатель

Дистанцию вперёд я мерил лидаром, повороты — компасом. По компасу всё выглядело логично: вот тебе магнитное поле Земли, вот стороны света, держи курс. На столе работало.

В квартире компас превратился в генератор случайных чисел.

Сначала я грешил на моторы — они и правда наводят своё поле. Но дело было глубже. Я написал скрипт, который строил карту магнитного поля (ну почти карту). Карта вышла прекрасная: поле гуляло как хотело — арматура в стенах, проводка. Никакого ровного «на север» там не было и в помине. Для абсолютной навигации по компасу квартира оказалась непригодна в принципе.

Компас отправился в отставку.

Гироскоп и его капризы

На замену пришёл гироскоп. Он не знает, где север, зато честно говорит, с какой скоростью ты поворачиваешься. Интегрируешь угловую скорость по времени — получаешь, на сколько повернул. Сначала я подмешивал к нему компас комплементарным фильтром, потом плюнул и оставил чистый гироскоп: в квартире от компаса было больше вреда, чем пользы.

Гироскоп L3G4250D тоже с характером. Во-первых, спайки — случайные выбросы на ровном месте, которые при интегрировании превращаются в накопленную ошибку. Лечится медианным фильтром. Во-вторых, дрейф нуля: даже стоя на месте гироскоп считает, что чуть-чуть поворачивается. Перед каждым стартом робот теперь пару секунд стоит неподвижно и замеряет этот фон, чтобы потом его вычитать. Сначала я брал на калибровку 20 сэмплов — оказалось мало, датчику нужно время устаканиться. Поднял до 200, и повороты стали стабильными — точность около трёх градусов.

И классика жанра, без которой никуда: робот упорно поворачивал не в ту сторону. Просишь направо — едет налево, и LLM этому удивляется. Знак угловой скорости был перепутан. Поменял знак — поехал куда просили.

Ковёр против ламината

Казалось бы, поворот на 90° — он и есть 90°. Но на ковре робот ворочается тяжелее, чем на ламинате, инерция и проскальзывание разные. Пришлось добавить защиту от застревания (если робот уже стоит, а угол не добран — поддать газу) и подобрать скорости так, чтобы ошибка держалась в пределах трёх градусов на любой поверхности.

С ездой по прямой — та же физика. Робот незаметно уводило в сторону, и я включил коррекцию по гироскопу: если в процессе движения накопилось отклонение от курса — подравниваю моторы разностью скоростей. Поехал заметно ровнее.

Чтобы всё это не зависело от задержек радиоканала, управление поворотами и движением я в итоге перенёс на саму плату — пусть крутит свой регулятор 50 раз в секунду локально. Запомнился баг, когда из регулятора по ошибке выпала одна проверка, и робот вместо плавной доводки угла срывался в неуправляемое вращение. Выглядело эффектно.

Дальномер и его обманы

Лидар заслуживает отдельной главы — он обманул меня дважды, и каждый раз по-новому.

Первый обман был технический. Лидар висел на программном последовательном порту, и данные приходили с заметной задержкой. Данные иногда застревали, иногда приходили “битые”. Бороться с этим в одиночку Arduino не успевала. В итоге я отдал лидар отдельной маленькой плате — Arduino Pro Micro, — которая только и делает, что опрашивает дальномер на полной скорости и по запросу отдаёт основному мозгу свежее число по шине I2C. Лаг ушёл.

Лидар и его отдельная плата Pro Micro
Лидар и его отдельная плата Pro Micro

Второй обман был коварнее — геометрический.

Лидар стоял сантиметров на десять ниже камеры. Камера смотрит вперёд и видит кухонный шкаф. А луч лидара, пущенный горизонтально с уровня пониже, проходит под этим шкафом и утыкается в стену где-то за ним. Камера говорит: впереди препятствие. Лидар говорит: свободно, метра два. Робот верит цифре — и упорно лезет под шкаф.

Особенно показательно это вышло у Grok: он был железно уверен, что путь открыт, и раз за разом таранил шкаф, не понимая, что происходит. Лечится переносом лидара вверх, к уровню камеры, — чтобы они смотрели в одну точку.

А третий обман я предвидел заранее, ещё на этапе выбора. Лазер не дружит с зеркалами: луч уходит «за» зеркало и возвращается длиной вдвое больше реальной. В опытах с зеркалами это постоянно сбивало картину. Вот тут ультразвуковой дальномер был бы честнее лазерного — он бы просто отразился от стекла. Но лазер показался модным. Запомним.

Пистолет, который съел неделю

Роботу нужно не только смотреть и говорить, но и как-то влиять на мир. Манипулятор — сложно и долго. Пистолет — просто: спустить курок может и серва. Так я думал.

Планировал на всё про всё один день. Потратил пять.

Первая засада — усилие на курке. Оно оказалось неожиданно большим, и имевшаяся серва не тянула его вообще. Заказал серву помощнее, MG996R, с моментом 13 кгс·см — этой хватило.

Дальше — механика передачи. Первый вариант: ось сервы совпадает с осью курка, тянем через качалку. Качалка под нагрузкой изгибается, усилие уходит в её прогиб — ненадёжно. Второй вариант, он же финальный: серва уезжает назад, а курок тянет вилка-тяга, симметрично, на растяжение. Заработало.

Но тут вылез сюрприз посерьёзнее. При выстреле алюминиевая пластина шасси заметно изгибалась — усилие сервы было велико. Пришлось добавить ребро жёсткости, а из-за него — переставлять и перекомпоновывать камеру с лидаром. И всё это с бесконечными итерациями 3D-печати: напечатал, примерил, не сошлось, поправил модель, напечатал заново.

В прошивке пистолет живёт тихо: серва сидит на отдельном таймере, чтобы не драться с моторами за железо, и срабатывает по короткой команде, не блокируя основной цикл. Это как раз было просто. Сложным оказалось железо.

Ребро жёсткости
Ребро жёсткости

Лицо и подсветка

Чистая косметика, но без неё робот — просто этажерка на колёсах.

Спереди — напечатанная на принтере панелька-морда с сотовым узором и матовым стеклом. Стекло я вырезал из бака сломанного увлажнителя: жалко было выбрасывать, пригодилось.

Передняя панелька
Передняя панелька

Подсветку — десяток светодиодов, синие и красные — я ставил поначалу просто для красивых фотографий: пусть робот в кадре светится. А потом подумал: чего я сам ими управляю? Отдал управление роботу. В одной из сессий из первой статьи это сыграло неожиданно — модель сама выбрала себе цвет и сама же объяснила почему («холодный, как мой металлический характер»). Но это уже про мозг, не про тело.

Камеру я уже поминал — Tapo, из кладовки, качество так себе. Зато круглая белая голова неплохо смотрится и придаёт всей конструкции что-то живое.

Камера
Камера

Что я из этого вынес

Если коротко.

Половина проблем была не в коде, а в физике: наводки, питание, провод, прилипший к валу. Датчики врут, и врут по-разному — компас в квартире бесполезен, лазер не видит зеркал и лезет под шкафы. Механика съедает время непропорционально обещанному: то, что на бумаге один день, в железе оборачивается неделей. И реальный мир всегда жёстче любой модели у тебя в голове.

Всё это, в итоге, — просто рабочее место для ИИ. Тело, чтобы было чем смотреть, ехать и дотягиваться до мира. А о том, что в этом теле делает сам ИИ, как он себя в нём ведёт и что из этого вышло, — была первая статья.

Осталась третья сторона — мозг на компьютере: зрение, навигация, агентный цикл, монтаж записей сессий. Про неё я здесь сознательно почти промолчал. Вопрос к вам: интересно ли про эту, хостовую часть? Если да — напишите в комментариях, расскажу.

Робот в сборе
Робот в сборе

Исходный код прошивки

Там же лежит написанный Клодм файл CLAUDE.md с пояснениями, что и как устроено.

Комментарии (15)


  1. Tassdesu
    07.06.2026 13:13

    О, прикольно, спасибо что рассказали. Первая статья очень впечатлила.

    Кажется, приходит время, когда для полноценного изучения ИИ, тебе не обойтись без погружения хотя бы вы базовую робототехнику.


  1. Moog_Prodigy
    07.06.2026 13:13

    Хостовая часть интересна. Но как то переусложнено для задачи "пустить ИИ в реальный мир и посмотреть что будет". Я бы для начала пустил его в какой-нибудь симулятор, или в контру, куда угодно в 3д пространстве. Там и с координатами и направлениями попроще, да и наворотить можно столько, что в реале никаких квартир и полигонов не напасешься. А результаты были бы наверное и поинтереснее в плане "ощущения робота". Роевой интеллект опять же.

    И пистолет этот... Способный уже вполне выбить глаз или загнать под кожу шарик. Неужто мало в продаже детского оружия, тут и шароплюи, и ракетницы какие хочешь, присоски и катапульты, все довольно безопасно, серву тоже мощную не понадобилось бы прикручивать, а на реальный мир и так бы воздействие оказывало. Я уж молчу про расход баллонов.


    1. stg34 Автор
      07.06.2026 13:13

      Мне хотелось именно реальный мир, не симулятор. В симуляторах достаточно потестили. Про пистолет, ну не знаю. Можно было вообще без ничего, просто сказать роботу, что у него есть пистолет. Но идея была, что возможно он проверит наличие пистолета в зеркале, убедится, что это не игрушка. В общем я стремился к максимальному реализму.


      1. Moog_Prodigy
        07.06.2026 13:13

        Вот как вы - в симуляторах еще не тестили, поэтому и интересна была первая часть, и будущая третья. Симуляторы это крутая тема, и зеркала там тоже вполне можно сделать, и роботу придать более-менее вид, и оружие ему какое хочешь вплоть до атомной бомбы или планетарного уничтожителя. А или наоборот - что-то строить, накормить виртуального котенка или ферму свиней... Суть то в чем - робот, а точнее система машинного зрения (про которую еще не известно) ему пофиг, реальный мир он видит или нет. Для него мир реален, когда он повернулся - и отражение повернулось. Он выстрелил - и что-то поменялось. Вот и вся реальность. Все равно он через глазок камеры смотрит. И ориентируется по приборам - гироскоп, компас. У вас не очень вышло с железом, и вы сами написали почему. Пилоты на симуляторах летают и вполне даже экзамены сдают, уж на что зарегулированная область. Они смотрят на приборы, на мониторы в проекторах, их кабина на мощных сервоприводах может наклоняться. Это тоже симуляция но обратная. И никто не жужжит - пилоты основные навыки отрабатывают там. А уже потом - реальный самолет.

        Робот с ИИ на условной карте в "контре" получил бы куда больше опыта, чем ездя по вашей квартире. А фразочки "кожаные будут все рабами" никуда бы не исчезли. Но это такое - настрополить промптом LLM чтобы так отвечала - можно вообще без всякой симуляции, поэтому нещитово.


        1. Chillingwilli
          07.06.2026 13:13

          В симуляторе идеальная физика и предсказуемые коллизии, а вот заставить алгоритм работать с зашумленными данными дешевых датчиков задача совсем другая


  1. netricks
    07.06.2026 13:13

    Ути, какая знакомая платформа :) . Прошло пятнадцать лет, а на ней как собирали, так и собирают :)


  1. tormozedison
    07.06.2026 13:13

    Название DFRobot уже занято.


  1. tormozedison
    07.06.2026 13:13

    «И один проводок немного касается вала мотора. Чуть-чуть, но достаточно, чтобы притормаживать колесо»

    У меня так в стрелочных часах было. Выставишь, несколько часов работают, потом останавливаются. Покрутишь ручку - опять работают и останавливаются. Вскрыл, а там провод, идущий от платы к обмотке, намотался на одно из зубчатых колёс. Порвать усилий не хватило, там усилия мизерные. Размотал, отодвинул, до сих пор работает.


  1. vbenedichuk
    07.06.2026 13:13

    Подскажите пожалуйста, для использования RTSP с этой камерой, пришлось сначала регистрироваться в облаке Tapo или можно полностью локально все настроить?


    1. stg34 Автор
      07.06.2026 13:13

      Кажется облако это не обязательно. В приложении включается локальный доступ и устанавливается пароль. Далее становится доступен поток RTSP


  1. Radisto
    07.06.2026 13:13

    Компас-предатель

    Может вам фотоэлемент в довесок к гироскопу? Хотя бы для калибровки. У насекомых та же проблема - аппаратная платформа простая, вычислительных ресурсов мало, но выжить как-то надо. Они по источникам света неплохо ориентируются. Несколько омматидиев в голове и поворот всего тулова, как у пауков и муравьев (многие из них практически слепы и видят несколько направленных точек в разных сторонах тела). Конечно, для точной ориентации нужен один источник света, в идеале точечный и бесконечно удаленный. Но и радиальная система координат относительно люстры или окна не так уж и плоха (и ее можно откалибровать по одометру/счислению пути, у муравьев он есть, да и вам легко добавить, если есть глазки/фотоэлементы - смотреть на яркое пятно на колесе). Если источников более 1, то конечно будут проблемы, но они и у более совершенных организмов появляются, мотыльки у фонарей и пчелы, бьющиеся о стекло, не дают соврать

    Извините за много слов, я не настоящий сварщик


  1. Chillingwilli
    07.06.2026 13:13

    Об лидар ниже уровня камеры тоже спотыкался. Сенсоры должны стоять на одной оси обзора, иначе неизбежно получишь слепые зоны


  1. vkrasikov
    07.06.2026 13:13

    Лайк я вам поставил. Но мне интересен другой момент. Где вы берете время?)


    1. stg34 Автор
      07.06.2026 13:13

      У меня было свободное время и любопытство. И я развлекался. Да :) Получил массу удовольствия в процессе


  1. ruskrava
    07.06.2026 13:13

    Все классно, дал полную свободу ИИ написать за тебя текст статьи... Теперь скажи своему роботу чтобы он тебя застрелил, и приходи в следующей жизни... Сама тема - супер, нейрослоп - отстой...