На складе производителя стройматериалов под погрузку приходят десятки фур в день: габариты фиксированные, машины разные. Часть фур приезжает с кривым кузовом: занижена высота к кабине, неровные борта, наваренные крючки и кронштейны на стойках у дверей. Внутрь такой кузов выглядит нормально, пока в него не заедет погрузчик с паллетой шириной 2,40 м и не упрётся в выступ, которого там быть не должно.

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

Задача, которая стояла перед командой: автоматизировать этот осмотр. Убрать человека из точки принятия решения и выдавать вердикт «грузить / не грузить» по объективным числам, а не по взгляду грузчика.

Требования заказчика сразу задали высокую планку. Нужно мерить три габарита: ширину свободного прохода, высоту от пола до горизонтальной балки, длину — и находить посторонние предметы внутри кузова. Пороги жёсткие: ширина меньше 2,43 м — отказ, высота меньше 2,60 м — отказ, длина меньше 8 м — отказ. Зазор между «входит» и «не входит» — 2 см: паллета шириной 2,40 м идёт впритык, и выступающий на стойке крючок, съедающий эти 2 см, делает кузов непригодным. То есть мерить надо с точностью лучше сантиметра — и не у ворот, а на всей глубине кузова, до 15 м от точки установки.

Сложность в том, что выбор решения нельзя проверить в бою. Лидар едет из-за рубежа, поставка долгая, а ошибка в рабочей дистанции, угле обзора или плотности точек вскроется уже после закупки. Можно сказать, что лидар выбирали вслепую. Читайте, что из этого получилось.

Сначала геометрия

Досадная ошибка в таком проекте — выбрать сенсор по красивой строке “дальность до N метров”. Для промышленной задачи дальность сама по себе почти ничего не гарантирует. Важнее ответить на вопросы:

·        видит ли сенсор всю нужную зону контроля с выбранной точки монтажа?

·        хватает ли плотности точек на объекте, который нужно анализировать?

·        не попадает ли важная область в “мёртвую зону” или слишком косой угол?

·        будут ли точки на тех поверхностях, по которым потом строится решение?

·        можно ли отличить: объект уже на месте от объект ещё маневрирует?

Дальность — это предел, на котором сенсор вообще видит хоть что-то, а не дистанция, на которой он различает выступ в 2 см. Между этими двумя величинами лежит всё, что определяет, заработает система или нет. 

Собрали упрощённую геометрическую модель: положение сенсора относительно проёма ворот, рабочую зону, граничные дистанции, поле зрения и сценарии появления грузовика в кадре. Не цифровой двойник объекта — инженерная проверка «хватит или нет» до того, как отдавать деньги. Из этой модели отдельно считали плотность точек на разных дистанциях. На близком расстоянии облако может выглядеть плотным и убедительным, а на дальнем крае ROI точек уже не хватит для устойчивого вывода — тем более когда задача не просто «увидеть объект», а принять решение по его геометрии с точностью до сантиметра.

Вендорский драйвер из коробки отдавал поток в ROS 2, поэтому мы исключили разработку собственного парсера сырых данных. Связка ROS 2 Humble и Ubuntu 22.04 штатно встала на серверное железо.  Архитектурно мы ограничили зону ответственности ROS 2: фреймворк работает исключительно как слой получения сенсорных данных. Вендорский узел публикует облако в формате PointCloud2 — бинарном blob-массиве с координатами и интенсивностью точек. Наш адаптер подписывается на этот топик, читает кадр и сразу переводит его в массив NumPy для геометрического анализа.  Такое разделение позволило не втягивать прикладную логику внутрь графа ROS. Вся математика живет в отдельном сервисе и общается с аппаратным слоем через стандартную HTTP/API-архитектуру. 

От облака до решения

Лидар приехал, базовая цепочка была уже спроектирована. Архитектура разделена на две части: слева — сенсор и ROS 2, справа — прикладной сервис, который умеет взять один снимок сцены, обрезать нужную зону, проверить готовность и запустить более тяжелый анализ.

Пайплайн движения данных устроен следующим образом:

  1. Лидар сканирует пространство и генерирует сырое 3D-облако.

  2. Вендорский драйвер принимает этот поток и публикует его в ROS 2 в виде топика.

  3. Наш адаптер подписывается на топик и выдергивает из него один актуальный кадр облака.

  4. Полученный бинарный blob PointCloud2 переводится в стандартный numpy-массив координат.

  5. К массиву применяются пространственные фильтры: отсекается все, что находится за пределами дальности и заданной рабочей зоны.

  6. Легкий программный контур анализирует этот остаток и решает, готова ли сцена к финальному сканированию.

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

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

Первая версия логики работала прямолинейно: если в границах рабочей зоны появлялось критическое количество точек, система считала, что объект прибыл и можно запускать сканирование. На реальном КПП такой подход “разбился” о реалии, так как в процессе парковки сцена постоянно менялась: фура двигалась, сдавала назад неравномерно, могла заехать в зону контроля только задней частью или остановиться со смещением. Если кто-то маневрировал рядом, система пыталась обсчитать промежуточные кадры, что перегружало процессор.

Чтобы зафиксировать момент остановки, мы разделили алгоритм на два независимых контура.

  • Контур 1. Непрерывно анализирует поток данных на предмет стабильности. Он проверяет дисперсию координат и плотность точек в зоне интереса. Его цель — подтвердить, что объект заехал в рабочую зону, перестал двигаться и сцена замерла.

  • Контур 2. Находится в режиме ожидания и запускается один раз по триггеру от Контура 1, когда тот подтвердил стабильность сцены. Здесь выполняются основные операции: финальная фильтрация взвеси и пыли, выравнивание облаков после сдвига актуатора, сегментация плоскостей и расчет геометрических параметров кузова с формированием отчета.

В такой связке Контур 1 берет на себя валидацию прибытия машины, а Контур 2 включается один раз для точного обсчета геометрии. Это решило проблему ложных запусков, но на этапе тестирования облака точек возникли физические ограничения сенсора, которые нельзя было предусмотреть в симуляторе.

Конфликт жизненных циклов ROS 2 и веб-сервиса

Стык ROS 2 (с его подсистемой DDS, контекстами и жизненным циклом нод) и стандартного веб-сервиса потребовал пересмотра архитектуры. Попытка держать ROS-подписчика постоянно запущенным внутри долгоживущего веб-процесса приводила к системным сбоям. При частых запросах на сканирование возникали ошибки повторной инициализации контекста, зависания потоков и непредсказуемое поведение сервиса.

Для сценария дискретного сканирования кузова мы перешли на короткие ROS-сессии. Алгоритм поднимает контекст исключительно на время захвата одного кадра облака точек, после чего сессия принудительно завершается. В сценариях высокочастотного трекинга в реальном времени постоянный перевызов контекста дал бы недопустимый overhead, но для задачи «один снимок по запросу» такой подход стабилизировал пайплайн и исключил утечки памяти.

Второе техническое ограничение возникло на этапе визуализации. Промышленные серверы на КПП работают без графического окружения, что исключает использование интерактивных 3D-вьюверов для просмотра сырых облаков точек. Оператору склада требуются статические, легковесные артефакты для фиксации инцидентов. В качестве рабочего решения тяжелое 3D-облако программно конвертируется в плоские 2D-проекции и тепловые карты (хитмапы). Этот формат сохраняется в логах, передается по сети с минимальными задержками и прикладывается к отчету о непригодности кузова.

Локальная отладка через дампы PCD

Зависимость разработки от единственного аппаратного стенда блокировала процесс тестирования. Любое изменение в геометрических фильтрах, границах ROI или API требовало физического прогона фуры через рампу для получения актуального кадра с лидара.

Чтобы снять эту зависимость, мы внедрили пайплайн тестирования на основе сохраненных дампов облаков в формате PCD (Point Cloud Data). Эталонные сцены (пустой кузов, кузов с дефектами, маневрирование) снимались на объекте единожды. Дальше расчет плоскостей, фильтрация шума и генерация 2D-ответов прогонялись командой локально на этих дампах. Дополнительно был написан эмулятор внешнего контракта для проверки интеграции без доступа к физическому сенсору. Это исключило простой разработки и позволило отлаживать fallback-сценарии без постоянного доступа к железу.

Границы применимости и практический итог

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

В промышленном 3D-зрении железо — это только начало. Физику не обманешь: если на дальнем краю зоны в 15 метрах лучи расходятся так, что дефект в 2 сантиметра просто проваливается между ними, никакой софт эти точки из пустоты не восстановит. Пригодность конкретной модели нужно жестко вычислять по геометрии до закупки сенсора. Если плотность на границе зоны контроля математически не сходится — проект надо браковать еще на этапе черновиков.

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

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