Как сделать робота из того, что нашлось в кладовке. arduino.. arduino. DIY.. arduino. DIY. DIY или Сделай сам.. arduino. DIY. DIY или Сделай сам. Будущее здесь.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп. искусственный интеллект.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп. искусственный интеллект. лидар.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп. искусственный интеллект. лидар. Программирование микроконтроллеров.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп. искусственный интеллект. лидар. Программирование микроконтроллеров. робототехника.. arduino. DIY. DIY или Сделай сам. Будущее здесь. гироскоп. искусственный интеллект. лидар. Программирование микроконтроллеров. робототехника. самодельный робот.

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

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

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

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

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

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

Робот в сборе

Робот в сборе

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

Тележка — 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 с пояснениями, что и как устроено.

Автор: stg34

Источник