Процесс разработки проекта и описание архитектуры системы
Этот документ предназначен для сопровождающих проекта и тех, кто расширяет его. Он системно описывает текущую архитектуру VLM_Grasp_Interactive, цепочку вызовов «фронтенд — бэкенд», механизм исполнения в MuJoCo, механизм непрерывных задач и распределение обязанностей между ключевыми файлами проекта.
После прочтения вы должны уметь:
- понимать полный путь проекта от «ввода естественного языка на веб-странице» до «захвата и размещения в MuJoCo»;
- понимать, как связаны фронтенд, FastAPI, сегментация VLM/SAM, GraspNet, исполнение движений и уведомления о запасах;
- понимать, почему проект поддерживает «непрерывные задачи», а не сбрасывает среду при каждой команде;
- продолжать расширять проект новыми объектами, новой логикой размещения и новыми бизнес-интерфейсами, не ломая уже работающие задачи захвата.
1. Цели проекта
Цель проекта — не просто интерфейс управления роботом, а «наглядная, интерактивная и непрерывно выполняемая» демонстрационная система в симуляции. Система получает задачу на естественном языке, показывает ход выполнения в веб-интерфейсе, а на бэкенде вызывает модули визуальной сегментации, вывода кандидатов захвата и исполнения в MuJoCo; в итоге выполняются захват, размещение, бросок и другие действия.
Сейчас в проекте уже в первую очередь реализованы следующие возможности:
- ввод команд на китайском языке в естественной форме и быстрые предустановки;
- связка веб-фронтенда и бэкенда FastAPI;
- показ симуляции MuJoCo в реальном времени в веб-интерфейсе;
- определение и сегментация целей VLM + SAM;
- вывод кандидатов захвата GraspNet;
- адаптация специальной логики для целевых объектов: шоколад, яблоко, губка, тарелка, фруктовая корзина и др.;
- непрерывное выполнение задач: вторая команда выполняется на состоянии сцены после первой.
2. Способы запуска и точки входа
Сейчас используется единое окружение vlm_grasp311.
2.1 Единая точка входа: веб-фронтенд и бэкенд
micromamba run -n vlm_grasp311 python main.py
После выполнения запускается сервис FastAPI, и браузер открывается автоматически. Адрес по умолчанию:
http://127.0.0.1:8000/
2.2 Прочие исторические точки входа
- main_openclaw.py: ранняя главная программа.
- main_vlm.py: экспериментальная точка вызова VLM.
Актуальная демонстрационная цепочка описана в main.py.
3. Общая архитектура
Систему можно разделить на пять слоёв:
- слой взаимодействия с фронтендом;
- слой веб-сервиса и управления сессиями;
- слой восприятия и понимания задач;
- слой вывода захвата и исполнения движений;
- слой бизнес-расширений.
Ниже показана основная схема вызовов проекта.
flowchart TD
A["Страница интерфейса<br/>frontend/index.html + frontend/app.js"] --> B["Точка входа FastAPI<br/>main.py"]
B --> C["Управление сессиями и состоянием<br/>SessionRecord + SSE"]
C --> D["Диспетчер исполнения MuJoCo<br/>MuJoCoCommandRunner"]
D --> E["Среда и рендеринг<br/>UR5GraspEnv"]
D --> F["Сегментация<br/>vlm_process.py"]
D --> G["Вывод захвата и размещения<br/>grasp_process.py"]
G --> H["GraspNet / облако точек / IK / исполнение действий"]
C --> I["Запасы и уведомления<br/>workflow_hooks.py + inventory.py + integrations.py"]
4. Описание основных каталогов
4.1 Веб-слой
-
frontend/index.html Структура страницы, статические кнопки, резервные скрипты событий, шаблоны кнопок предустановок.
-
frontend/app.js Конечный автомат фронтенда, отправка сессий, подписка на SSE, обновление предпросмотра, запись предустановок в текстовое поле, вывод отладочной информации.
-
frontend/styles.css Стили страницы, эффект свечения панелей при наведении, раскладка области предпросмотра и общая визуальная тема.
4.2 Веб-бэкенд и главный управляющий слой
- main.py
Главная точка входа системы. Отвечает за:
- запуск FastAPI;
- подключение статических файлов фронтенда;
- приём команд
/api/command; - создание и ведение сессий;
- передачу задач исполнителю MuJoCo;
- передачу состояния фронтенду через
/api/session/{id}и/api/session/{id}/events; - вывод кадров предпросмотра в реальном времени через
/api/session/{id}/frame.
4.3 Слой восприятия и исполнения
-
vlm_process.py Модуль VLM и сегментации изображений. Отвечает за:
- вызов мультимодальной модели для понимания команды и изображения;
- вывод текстового описания цели и рамок на изображении;
- вызов локального или удалённого SAM для сегментации;
- формирование
mask_source,mask_destinationи отладочных наложений.
-
grasp_process.py Основной модуль вывода захвата и размещения. Отвечает за:
- построение облака точек по карте глубины и маске;
- вызов GraspNet для генерации кандидатов захвата;
- оценку точек захвата и размещения по геометрии целевого объекта;
- решение обратной кинематики (IK);
- управление манипулятором в MuJoCo: захват, подъём, перемещение, размещение, возврат;
- специальную логику для отдельных объектов, например сопоставление для шоколада, яблока, губки и яблочной корзины.
-
[manipulator_grasp/env/ur5_grasp_env.py
(manipulator_grasp/env/ur5_grasp_env.py)Обёртка среды MuJoCo. Отвечает за:- загрузку XML-сцены;
- инициализацию манипулятора и захвата;
- управление офлайн-рендерингом и пассивным окном просмотра (viewer);
- унификацию ракурса между веб-интерфейсом и симулятором;
- при сбое рендеринга пересоздаёт только бэкенд рендеринга, не сбрасывая состояние мира.
4.4 Сцены и конфигурация ракурса
-
scene_robocasa_layout51_style34.xml Основная сцена, которая используется сейчас.
-
scene_robocasa_layout51_style34.view.jsonФайл настройки ракурса по умолчанию для основной сцены. Веб-интерфейс и окно MuJoCo читают один и тот же ракурс. Этот файл может создаваться локальным процессом отладки и не обязан входить в публичный учебный код.
4.5 Бизнес-расширения
-
workflow_hooks.py Побочные эффекты после успешной задачи: изменение запасов, уведомление о низком остатке, синхронизация с внешними системами.
-
inventory.py Система запасов с хранением в файлах: фиксирует изменения количества после выполнения некоторых задач.
-
integrations.py Внешние webhook и интерфейсы уведомлений Feishu.
5. Порядок работы фронтенда
Основная задача фронтенда — не управлять роботом, а организовать ввод команды, состояние сессии на бэкенде и изображение симуляции в интерфейс, который можно демонстрировать и отлаживать.
5.1 Состав страницы
Веб-интерфейс состоит из трёх панелей:
- слева: поле ввода команд;
- в центре: предпросмотр сцены;
- справа: временная шкала выполнения и отладочный вывод.
Левая панель служит для ввода команд на естественном языке и быстрого заполнения текстового поля кнопками предустановок. Центральная область показывает текущий кадр MuJoCo в реальном времени или заглушку. Правая панель показывает, как продвигается сессия: разбор языка, сегментация целей, вывод захвата, решение IK, исполнение движений и итоговый результат.
5.2 Отправка команды
Сейчас фронтенд поддерживает два способа отправки:
- нажать кнопку «Выполнить команду»;
- нажать
Enterв поле ввода.
Логика находится в frontend/app.js. Фронтенд отправляет команду на адрес:
POST /api/command
После отправки фронтенд переходит в состояние «running» и начинает подписку на SSE-поток этой сессии.
5.3 Обновление состояния сессии
Фронтенд получает ход выполнения через такие интерфейсы:
GET /api/session/{session_id}GET /api/session/{session_id}/eventsGET /api/session/{session_id}/frame
Здесь:
eventsпередаёт структурированное состояние: trace, журналы, названия стадий, результаты;frameотдаёт текущий последний кадр предпросмотра в PNG.
Это означает, что фронтенд не обращается к MuJoCo напрямую и не участвует в планировании исполнения: вся работа идёт через состояние сессии FastAPI.
6. Сессии и планирование на бэкенде
6.1 Объект сессии
В main.py каждая команда соответствует одному объекту SessionRecord. Он хранит:
session_id;- строку команды;
- разобранную структуру задачи;
- список trace;
- текущее состояние:
running,success,failure; - текст результата;
- адрес URL предпросмотра;
- отладочные журналы;
- снимок запасов.
При каждой отправке команды фронтенд бэкенд создаёт новую сессию или продолжает указанную, затем запускает фоновый поток, который выполняет настоящую задачу MuJoCo.
6.2 Разбор команды
Разбор команды выполняется в main.py и в основном обеспечивается функциями:
_normalize_text_extract_objects_infer_relation_parse_task
Результат разбора приводится к структурированной задаче:
{
"type": "pick_place",
"source": "apple",
"destination": "apple_rack",
"relation": "in",
"all_items": False,
}
Этот шаг — вход всей системы и основа для дальнейшего распределения по специальной логике.
6.3 Общие и специальные задачи
Бэкенд сейчас не полностью полагается на унифицированную общую логику, а использует схему «общий каркас + адаптация под конкретный объект».
Например:
- задача шоколада в первую очередь закрепляет за собой сущность сцены, соответствующую
SNICKERS; - задача яблока различает яблоко на разделочной доске и яблоко в фруктовой корзине;
- задача губки различает губку на столе и губку в подставке;
- места размещения для фруктовой корзины и подставки для губки — не просто «центр полки», а специально вычисляемые эффективные слоты.
Причина простая: одного только общего понимания текста и одной только сегментации недостаточно для сложной сцены — часто система путает одинаковые предметы или выбирает неподходящее место размещения. В проекте такие частые ошибки устраняются правилами для конкретных объектов.
7. Основной путь исполнения в MuJoCo
Фактическое исполнение происходит в MuJoCoCommandRunner.
Основной путь одной операции захвата и размещения можно описать так:
- убедиться, что среда инициализирована;
- получить RGB и глубину;
- выполнить сегментацию исходного объекта;
- оценить мировые координаты точки захвата;
- выполнить сегментацию целевой зоны размещения или сразу использовать специальный слот размещения;
- построить облако точек и запустить GraspNet;
- решить IK для захвата, подъёма, перемещения, размещения и возврата;
- пошагово исполнить движения в MuJoCo;
- непрерывно передавать кадры и состояние стадий на фронтенд.
7.1 Получение RGB-D
Логика получения находится в:
- main.py: функция
_capture_rgbd; - [ur5_grasp_env.py
(manipulator_grasp/env/ur5_grasp_env.py): функцияrender.
Бэкенд получает:
img: RGB-изображение текущей камеры;depth: карту глубины для того же ракурса.
Все последующие сегментация, облако точек и вывод захвата строятся на этой паре синхронизированных данных RGB-D.
7.2 Сегментация исходного объекта
Сегментация исходного объекта выполняется функцией segment_image в vlm_process.py и связанной с ней логикой.
Поддерживаются три варианта входа:
- только текст команды;
- текст + подсказка в виде рамки (bbox) сцены;
- текст + явное переопределение метки.
В проекте многие исправления стабильности относятся именно к этому слою. Например:
- для шоколада добавляется подсказка «на упаковке написано SNICKERS»;
- для губки добавляется подсказка «предпочтительно губка, обведённая красным кругом»;
- для яблочной подставки используется специальная цель, а не только общее слово «полка».
7.3 Облако точек и GraspNet
Вывод кандидатов захвата находится в grasp_process.py.
Основная цепочка обработки:
- по RGB, глубине и маске построить организованное облако точек;
- отфильтровать недействительные точки по порогу глубины;
- вызвать GraspNet для генерации кандидатов захвата;
- выполнить фильтрацию по коллизиям;
- отсортировать по центру цели, направлению захвата и расстоянию;
- выбрать итоговую позу захвата.
Если при этом появляется ошибка:
No valid masked point cloud points after depth filtering
обычно проблема не в IK, а во входе на более раннем этапе. Типичные причины:
- маска попала не на тот объект;
- карта глубины неисправна;
- произошёл сбой офлайн-рендеринга.
7.4 IK и исполнение движений
Исполнение движений также реализовано в grasp_process.py.
Порядок стадий сейчас такой:
homehubhover_pickpregraspgraspgrasp_closelifthover_placepreplaceplacereleaseretreathub_returnreset
Каждая стадия через callback передаётся на фронтенд, который показывает название текущей стадии и последний кадр.
8. Механизм непрерывных задач
Это одна из ключевых инженерных особенностей проекта.
8.1 Цель проекта
Проект требует, чтобы вторая задача выполнялась на состоянии мира после завершения первой, а не заново возвращала MuJoCo-сцену в начальное состояние.
Например:
- сначала выполняется «Положи шоколад на тарелку» (请把巧克力放到盘里);
- шоколад оказывается на тарелке;
- затем выполняется «Переложи яблоко с доски на полку с яблоками и сохрани его» (将菜板上的苹果放置有苹果的架子上保存);
- в этот момент в симуляции шоколад всё ещё должен оставаться на тарелке.
8.2 Текущая реализация
Управление средой находится в MuJoCoCommandRunner в main.py.
Принцип такой:
UR5GraspEnvвызываетreset()только при первом использовании;- последующие задачи переиспользуют тот же
self._env; - поэтому
mj_modelиmj_dataсохраняют состояние после предыдущей задачи.
8.3 Стратегия восстановления при сбое рендеринга
В ходе непрерывных задач однажды сломался бэкенд офлайн-рендеринга, и веб-интерфейс показывал:
- чёрный предпросмотр;
- глубину с постоянным большим значением;
- сбой последующего построения облака точек.
Чтобы решить эту проблему, в [ur5_grasp_env.py (manipulator_grasp/env/ur5_grasp_env.py) добавлены следующие механизмы:
- при обнаружении некорректного вывода рендеринга не сбрасывается вся сцена MuJoCo;
- пересоздаются только ресурсы офлайн-рендеринга: renderer, окно GLFW, офлайн-контекст;
mj_modelиmj_dataсохраняются.
Поэтому система сейчас одновременно обеспечивает два свойства:
- непрерывность состояния мира;
- восстановление после сбоя рендеринга.
9. Ракурс камеры и редактор сцены
9.1 Единый источник ракурса
Ракурс по умолчанию в веб-интерфейсе и в окне MuJoCo берётся из одного файла настроек сцены:
scene_robocasa_layout51_style34.view.json
Логика чтения находится в:
- [ur5_grasp_env.py
(manipulator_grasp/env/ur5_grasp_env.py)
9.2 Как действует настройка ракурса
Если файл scene_robocasa_layout51_style34.view.json существует, симулятор читает эту настройку камеры. После этого:
- окно просмотра симулятора использует этот ракурс;
- офлайн-рендеринг веб-интерфейса тоже использует этот ракурс.
Так обеспечивается согласованность: камера, которую видит пользователь в веб-интерфейсе, совпадает с камерой локального отладчика MuJoCo. Публичный репозиторий сохраняет нужную для работы сцену и логику чтения, но не содержит локальный инструмент редактирования сцены.
10. Отладочные артефакты и промежуточные файлы
Проект записывает много промежуточных результатов в каталог temp/, чтобы упростить поиск неисправностей.
10.1 Изображения и результаты сегментации
Типичный каталог вывода:
temp/images/
Там находятся:
*_mask_source.png*_mask_destination.png*_mask_source_overlay.png*_mask_destination_overlay.png
По этим файлам легко проверить:
- правильно ли VLM/SAM нашли целевой объект;
- попадает ли рамка на нужный предмет;
- совпадает ли наложение с реальным изображением.
10.2 Состояние запасов
Состояние запасов сохраняется в:
temp/inventory/
Это основа для демонстрации бизнес-логики.
11. Расширение: запасы, заказы и уведомления Feishu
Помимо демонстрации захвата, в проект подключён небольшой бизнес-контур.
11.1 Списание запасов
После некоторых успешных задач вызывается функция из workflow_hooks.py:
record_task_success_effects(...)
Она:
- обновляет локальные запасы;
- определяет, не наступил ли низкий остаток;
- отправляет уведомление во внешний webhook;
- при необходимости отправляет напоминание в Feishu.
11.2 Внешние интеграции
integrations.py отвечает за:
- внешние webhook робота;
- уведомления Feishu;
- чтение локального конфигурационного файла.
Этот слой не участвует в управлении захватом; он лишь передаёт события успешного выполнения в другие системы.
12. Специальная логика для отдельных объектов
В проекте уже сделаны специальные адаптации для отдельных объектов, и это одна из главных причин устойчивой работы системы.
12.1 Шоколад
- Использует подсказку с семантикой
SNICKERSдля точного выбора нужного шоколада. - Не даёт перепутать шоколад с другими мелкими предметами сцены.
12.2 Яблоко
appleпо умолчанию сопоставляется с яблоком на разделочной доске.apple_rackсопоставляется с фруктовой корзиной.- Точка размещения яблока — не центр всей полки, а специальная позиция внутри фруктовой корзины.
12.3 Губка
- Поддерживается раздельное моделирование губки и её подставки.
- Поддерживается логика пакетной уборки.
- Точка размещения — специальный слот внутри подставки для губки, а не абстрактный «центр полки».
13. Рекомендуемый порядок разработки
Если вы продолжаете разработку, рекомендуем следующий порядок.
13.1 Порядок подключения нового объекта
- Определить имя body целевого объекта в XML сцены.
- В main.py добавить псевдонимы команд на китайском языке.
- В grasp_process.py добавить сопоставление
SCENE_BODY_NAMES. - При необходимости написать функцию мировых координат для специальной зоны размещения.
- Выполнить в веб-интерфейсе две задачи подряд и проверить, сохраняется ли состояние.
13.2 Порядок отладки
При сбое проверяйте в таком порядке:
- показывает ли журнал веб-интерфейса переход к реальному исполнению в MuJoCo;
- правильны ли маски исходного и целевого объектов в
temp/images; - не чёрный ли предпросмотр в веб-интерфейсе и не сбит ли цвет;
- нет ли сбоев в карте глубины;
- правильно ли сопоставлены исходный и целевой объекты в
grasp_process.py; - используется ли для точки размещения общая логика вместо специальной.
14. Типичные сбои и способы восстановления
14.1 Чёрный экран в веб-интерфейсе
В первую очередь подозревайте сбой бэкенда офлайн-рендеринга, а не код фронтенда. Система уже умеет автоматически пересоздавать ресурсы рендеринга, но если старый процесс уже сломался, самый прямой способ восстановления — перезапустить main.py.
14.2 После фильтрации по глубине не осталось точек облака
Типичный текст ошибки:
No valid masked point cloud points after depth filtering
Сначала проверьте:
- правильна ли сегментация цели;
- нормальна ли глубина;
- попадает ли цель в зону видимости камеры при текущем ракурсе.
14.3 Объект захвачен или размещён неправильно
Сначала проверьте:
- есть ли для этого объекта специальное сопоставление;
- не используется ли ещё общая цель
shelf; - не является ли точка размещения центром всего большого контейнера вместо допустимой точки внутри контейнера.
15. Направления дальнейшего развития
Исходя из текущего состояния кода, в первую очередь стоит заняться тремя направлениями.
15.1 Стабильность
- подключить специальные сопоставления для большего числа частых объектов;
- для контейнеров создать логику «допустимых слотов внутри контейнера»;
- стандартизировать обнаружение сбоев рендеринга.
15.2 Поддерживаемость
- вынести псевдонимы объектов, имена сущностей сцены и стратегии размещения в единый конфигурационный файл;
- выделить правила для объектов, которые сейчас разбросаны по
main.pyиgrasp_process.py, в отдельный модуль.
15.3 Демонстрационные возможности
- добавить больше скриптов непрерывных задач;
- добавить кнопку сброса среды, чтобы в одном проекте уживались режим «непрерывного выполнения» и режим «ручного возврата в исходное состояние»;
- показывать на фронтенде больше промежуточных состояний: наложения сегментации, количество кандидатов захвата, текущее имя целевой сущности.
16. Ключевые файлы, упомянутые в этом документе
- main.py
- grasp_process.py
- vlm_process.py
- [manipulator_grasp/env/ur5_grasp_env.py
(manipulator_grasp/env/ur5_grasp_env.py) - workflow_hooks.py
- inventory.py
- integrations.py
- frontend/index.html
- frontend/app.js
- frontend/styles.css
В зависимости от задачи этот документ можно читать по трём путям:
- как руководство по запуску для тех, кто демонстрирует систему;
- как описание архитектуры для разработчиков;
- как справочник по поиску неисправностей для тех, кто отлаживает систему.