Шесть версий, шесть неудач: почему программа не понимает, что пульт отключён?
Вот этот рычажок софт видит идеально: каждое положение, каждый переход. А вот включён ли сам пульт — не видит вообще, и эта история о том, почему.
В лаборатории 361.Robotics мы обучаем китайского гуманоида Walker Tienkung TK2301 управляться голосом на русском языке. В предыдущих публикациях мы рассказывали про сам голосовой стек, внешний микрофон и программное вставание по голосовой команде. В комплекте с роботом идёт штатный пульт дистанционного управления: классическая радиосистема с тумблерами, джойстиками и кнопками, а приёмник спрятан внутри корпуса. Один из тумблеров мы приспособили под голосовой режим: поднят — робот слушает и отвечает, опущен — не слышит и молчит. Чтобы довести голосовой пайплайн до рабочего состояния, нам пришлось заняться отдельным расследованием. Задача казалась обычной, а итог получился вполне закономерным: программа не способна узнать то, что не передаёт ей железо. Это рассказ о том, как методичный перебор гипотез приводит в тупик и как из этого тупика выбраться.
Пульт выключен или рычажок опущен?
Чтобы с роботом было удобнее работать, мы решили разделить два разных состояния: пульт выключен полностью и пульт включён, но голосовой режим отключён тумблером. Внешне разница невелика, однако для оператора она принципиальна. Если он сам перевёл рычажок, это осознанный шаг, и никаких подсказок не требуется. Если же пульт выключен или у него разрядился аккумулятор, роботу следовало бы сообщить об этом голосом.
Задача выглядела вполне выполнимой. Приёмник публикует положение рычажков в поток сообщений каждые 23 миллисекунды, то есть чуть более сорока раз в секунду. Логично было ожидать, что ситуации «рычажок физически стоит в среднем положении» и «приёмник вообще ничего не принимает» чем-то отличаются в этом потоке.
Что мы только не проверяли
Начали с самого очевидного: потеряв сигнал пульта, приёмник должен как-то известить об этом остальную систему. Проверка показала, что это не так. Он продолжает публиковать данные с прежней частотой, просто подставляя значения безопасного состояния. Так работает любая радиосистема: при потере связи она переходит в заранее заданное безопасное положение, чтобы, скажем, дрон не улетел в неизвестном направлении, а плавно завис или приземлился. Беда в том, что в формате сообщений эти безопасные значения ничем не отличаются от реального положения рычажка.

Затем мы попытались найти зацепку в событиях переключения: в потоке есть специальные метки переходов между положениями рычажка. И здесь неудача. При потере сигнала приёмник сам формирует точно такие же метки, словно рычажок кто-то действительно сдвинул рукой.
Следующим шагом стали тайм-ауты между сообщениями. Вдруг при обрыве связи паузы удлиняются или меняются иным образом? Мы провели замеры на длинной дистанции: интервал неизменно составляет те же 23 миллисекунды, публикация не прекращается ни разу.
Была у нас и более изящная гипотеза, связанная с траекторией. Когда рычажок двигает человек, он проходит через промежуточные положения, тогда как подстановка безопасного значения при потере связи должна давать мгновенный скачок сразу к конечной величине. Значит, разницу можно было бы уловить по форме перехода в данных. Но и это не сработало. Рычажок трёхпозиционный, он переключается между фиксированными положениями, и промежуточных значений в потоке не возникало ни при ручном движении, ни при потере связи. В обоих случаях переход выглядит как мгновенный скачок.
Пробовали подойти и со стороны логов самого приёмника. Его программный модуль распространяется в виде закрытого бинарника, однако текстовый поиск по нему выдал упоминание функции с подходящим названием. Мы проверили, пишет ли она что-нибудь в системный журнал при срабатывании. Файл журнала оказался пустым: либо функция на деле не вызывается, либо мы не нашли тот журнал, куда записи попадают на самом деле.
Последняя идея была самой прямолинейной: подключиться к тому же физическому порту параллельно и прочитать сырые байты самостоятельно, минуя всю остальную систему. Выяснилось, что порт монопольно занят процессом-приёмником, и второму читателю подключиться просто невозможно.
Шесть разных гипотез, и все они упёрлись в один и тот же факт: рабочая система приёмника передаёт наверх только итоговое положение рычажка, без какого-либо признака того, реальное оно или подставлено на случай потери связи.

Практика не дала решения, но что ещё можно сделать теоретически?
По итогам этой серии проверок вывод получился однозначным: на программном уровне при текущей конфигурации железа отличить «пульт выключен» от «оператор намеренно переключил рычажок» невозможно. Дело не в том, что мы не сумели найти способ. Нужная информация попросту не попадает в доступный нам поток данных, поэтому и способа не существует в принципе.
Оставалось три теоретических пути, причём все они лежат уже не в программной плоскости, а в аппаратной или организационной.
Первый. У приёмника есть собственное мобильное приложение для тонкой настройки. Теоретически в нём можно задать для состояния «потеря связи» нестандартное значение за пределами обычного рабочего диапазона, и тогда его удалось бы распознавать программно.
Второй. У приёмника имеется отдельный, пока не задействованный порт служебной телеметрии. Теоретически к нему можно припаять ещё один переходник и попытаться с нуля реверс-инжинирить закрытый протокол производителя пульта. Этот вариант таил реальный риск повредить рабочее оборудование ради, по сути, косметического улучшения UX. Мы решили, что игра не стоит свеч.
Третий. Обратиться к производителю робота с просьбой добавить в официальный формат сообщений явный флаг «связь потеряна». Это самый правильный путь, но всё зависит от того, насколько оперативно и охотно вендор откликается на подобные запросы. Гарантий нет, и быстрого результата ждать не стоит.
Итоговое решение — не чинить программно, а объяснить пользователю
Раз программно проблему решить не удалось, решение переместилось в плоскость UX. Мы ввели для оператора простое правило: после включения или выключения пульта один раз провести рычажком через среднее положение и только затем поднимать его для активации голоса. Так рычажок гарантированно совершает настоящий физический переход, который система обязательно зафиксирует, и неоднозначность исчезает. Решение не самое элегантное, зато работает, а оператору понятно, что делать.

Когда шесть неудач всё же приводят к результату
Расследование велось методично: мы составили перечень конкретных проверяемых гипотез, испытывали каждую на живом оборудовании и лишь после того, как все разумные и осуществимые варианты были исчерпаны, признали, что программными средствами задачу дальше не решить. Помогла не очередная попытка двигаться в прежнем направлении, а готовность сделать шаг назад и сменить уровень, на котором принимается решение. Вместо стремления «починить программно то, что должно быть видно в потоке» мы признали, что источника данных нет, и решили задачу иначе: простой договорённостью с оператором вместо технического обходного манёвра.
Не всякая инженерная проблема поддаётся лобовой атаке, особенно когда приходится иметь дело с закрытым сторонним оборудованием. Шести гипотез хватило, чтобы честно убедиться: на программном пути идти действительно некуда.
Это четвёртая история из нашей работы с этим роботом: голосовой стек, внешний микрофон, вставание по голосовой команде — а теперь ещё и пульт в роли чёрного ящика. Впереди будут новые — если тема вам интересна, подписывайтесь, мы обязательно расскажем.
С радостью отвечу на вопросы в комментариях. Особенно любопытно мнение тех, кто работал с RC-радиосистемами в продакшене: удавалось ли вам извлечь признак потери связи из закрытого приёмника, или все в итоге приходят к такому же организационному обходному решению?
Сейчас в нашей лаборатории трудятся четыре платформы: гуманоиды Unitree G1 EDU+, Leju Kuavo 4Pro и UBTech Walker Tienkung — Embodied Intelligence, а также промышленный квадрупед Unitree B2. Мы активно с ними экспериментируем, обучая роботов сценариям реального применения и решению бизнес-задач. О других кейсах расскажем в следующих статьях на SE7ENе. А пока мы их готовим, приглашаем в наш Telegram-канал 361.Robotics — о робототехнике, воплощённом ИИ и новой экономике, которая формируется вокруг них.
Если вы хотите приобрести робота для компании или личного использования, мы поможем с поставкой гуманоидов, квадрупедов и другой робототехники из Китая, а также адаптируем оборудование под задачи заказчика.
Мы открыты к обмену опытом, сотрудничеству, совместной работе над интересными проектами и просто знакомству с увлечёнными людьми. Хотите увидеть современных роботов вживую — напишите нам и приезжайте на экскурсию в лабораторию 361.Robotics в Москве (м. Павелецкая).
Как человечество изобретало красоту: атлас из 195 визуальных стилей, от пещеры Ласко до уирдкора
Многогранник смыслов
Карта риска фондовых рынков: как Швейцария обошла Турцию по рискованности
Тайна римских додекаэдров: найдено 134 предмета, но их назначение по-прежнему неизвестно
Пиранези и ИИ: что перед нами — фотография или гравюра?
Чем жили советские люди без интернета?
Как зародилась жизнь?
Позвольте машине ошибаться