Вы потратили недели, накручивая эпизоды в Isaac Sim. Политика Diffusion Policy сходится, робот в симуляции хватает кубик с точностью 99%. Вы чувствуете себя богом робототехники. А потом вы загружаете ту же нейросеть на реальный SO-101 — и он делает что-то невнятное, похожее на пьяный вальс. Знакомо?
Разрыв между симуляцией и реальностью — главная головная боль любого, кто пишет политики для роботов. Но к 2026 году боль можно притупить. Связка Hugging Face Hub как реестра политик, LeRobot v0.5.0 как бэкенда для обучения, Strands Agents на AWS как рантайма для деплоя и MolmoAct2 как VLA-мозга превращает перенос из симуляции на железо в процедуру, а не в шаманство.
В этой статье я покажу, как собрать пайплайн sim-to-real, который реально работает на манипуляторе SO-101 (да, том самом, который мы собирали в гайде за 30 тысяч рублей). Без магии. Только код, осознанные костыли и немного мата.
Что вы получите на выходе: Рабочую политику, обученную в симуляции (Nvidia Isaac Lab или MuJoCo), которая после калибровки через Strands Agents запускается на реальном железе с минимальным даунтаймом. Весь процесс занимает около 2 часов, если данные уже собраны.
Почему симуляция врёт (и как это исправить)
В симуляции идеальные моторы, нулевой бэклэш и контакт физики, который никогда не зависает. Реальный SO-101 — это китайские сервоприводы с люфтом, трение в редукторах и задержка управления через USB-сериал. Стандартный трюк — рандомизация физических параметров (domain randomization) — работает, но только если вы позаботились об адаптации на уровне исполнения политики.
Вместо того чтобы делать рандомизацию вслепую, мы используем GR00T (General Robot 00 Technology — да, Nvidia назвала это именно так) — фреймворк, который в 2026 году добавил поддержку автоматического профилирования реальных моторов. GR00T собирает данные о динамике SO-101 в реальном времени и подгоняет симулятор под железо. Но это тема отдельной статьи. Сейчас мы пойдем другим путём — через Strands Agents.
Архитектура: от пикселей к сервоприводам
Вот как выглядит наш пайплайн:
Симуляция (Isaac Lab / MuJoCo) → LeRobot (обучение Diffusion Policy или ACT) → Hugging Face Hub (версионирование и реестр) → Strands Agents (деплой на AWS) → MolmoAct2 (VLA-модель для визуального восприятия) → SO-101 (реальное железо).
Ключевой момент: Strands Agents — это не просто оркестратор. Он умеет запускать политику на Edge-устройстве (Nvidia Jetson Orin или обычный x86-промышленный ПК) и динамически подгружать с Hugging Face Hub новые веса без перезапуска контейнера. Именно это позволяет обновить политику, не останавливая производство.
Пошаговый план: как НЕ надо делать
Звучит логично: натренировал в симуляции → загрузил на Hub → запустил агента → робот работает. На практике же вы споткнетесь на трёх местах: несовместимость формата данных, отсутствие калибровки наблюдений и игнорирование задержек управления. Я покажу, как обойти каждый.
1 Подготовка датасета в LeRobot (симуляция или реальность?)
Для обучения в симуляции мы используем LeRobot v0.5.0 с поддержкой Unity ML-Agents и Isaac Lab. Собираем данные, эпизод за эпизодом. Выходной формат — HDF5 + JSON. Важно: в симуляции вы получаете ground-truth состояние (положение сочленений без шума), а на реальном роботе — только показания энкодеров. Разница может быть 2-5 градусов на суставе.
Как компенсируем: Во время сбора датасета в симуляции добавляем гауссов шум к наблюдениям (среднее 0, std 0.02 рад). Это грубо, но достаточно для старта. Лучше, конечно, использовать Domain Randomization внутри симулятора — но мы упрощаем.
from lerobot.common.datasets import LeRobotDataset
import numpy as np
dataset = LeRobotDataset(
repo_id="my-org/so101-sim-pick-v1",
robot="so101",
fps=30,
features=["observation.state", "action"]
)
# Добавляем шум при сохранении (симуляция несовершенства энкодеров)
for episode in episodes:
for frame in episode:
noisy_state = frame["observation.state"] + np.random.normal(0, 0.02, size=6)
dataset.add_frame({
"observation.state": noisy_state,
"action": frame["action"]
})
dataset.save()
2 Обучение политики: почему ACT, а не Diffusion Policy
\nДиффузионные политики (Diffusion Policy) отлично работают в симуляции — они сглаживают шум и дают плавные траектории. Но на реальном SO-101 без точной обратной связи по моменту диффузия начинает дрожать из-за инерции. ACT (Action Chunking with Transformers) с chunk size 16 даёт более стабильное поведение, потому что предсказывает сразу блок действий, а не одно действие за раз.
Мой выбор: обучаем ACT, а Diffusion Policy оставляем как fallback. Код обучения — стандартный из LeRobot, но с увеличенным до 1000 шагов warmup.
python lerobot/scripts/train.py \
--policy.type=act \
--dataset.repo_id=my-org/so101-sim-pick-v1 \
--output_dir=./outputs/act_so101 \
--training.num_epochs=100 \
--training.batch_size=64 \
--training.lr=1e-4
3 Публикация на Hugging Face Hub: не просто push
ЛеРобот умеет пушить датасеты и политики на HF Hub. Но если вы просто запустите dataset.push_to_hub(), Strands Agents не сможет подхватить веса, потому что не знает, какая модель где лежит. Нужно создать карточку модели с аннотациями.
from huggingface_hub import HfApi
api = HfApi()
api.create_repo("my-org/so101-pick-act", repo_type="model")
api.upload_folder(
repo_id="my-org/so101-pick-act",
folder_path="./outputs/act_so101",
commit_message="ACT policy for SO-101 sim-to-real v1"
)
Добавьте в README.md поле robot: "so101" и sim_to_real: true. Это нужно для автоматического обнаружения агентом.
4 Настройка Strands Agents на AWS
Strands Agents — это managed-сервис AWS (GA с 2025 года), который умеет запускать контейнеры с политиками на любом edge-устройстве, подключенном к облаку. Для SO-101 мы используем агента типа AWS robot agent.
# deploy.yaml
agent:
name: so101-prod
robot_type: "so101"
policy:
source: "hf://my-org/so101-pick-act"
runtime: "lerobot:0.5.0"
hardware:
device: "jetson-orin-nx"
camera_ids: ["c920", "d435"]
При запуске агент скачивает модель с Hub, включает VLA-модуль MolmoAct2 (от Hugging Face, специально дообученный для SO-101) для обработки изображений, и запускает политику в реальном времени. MolmoAct2 отвечает за визуальное восприятие: находит объект, выдает bounding box, а ACT предсказывает действия.
Осторожно: MolmoAct2 требует около 8 GB VRAM для inference. На Jetson Orin NX это приемлемо, но не забудьте отключить все визуальные эффекты в ОС. И да, используйте TensorRT для ускорения — иначе частота кадров упадёт ниже 10 FPS.
5 Первый запуск на реальном железе
Соединяем SO-101 с Jetson через USB-C, запускаем агента. Если всё настроено правильно, политика из симуляции начнёт управлять реальным роботом. Первое, что вы заметите — тряска. Это нормально. Причина: разница в частоте управления (в симуляции 100 Hz, в реальности — 30-50 Hz).
Решение: В конфиге агента добавьте задержку между шагами политики (sleep_ms=20) и включите low-pass фильтр на выходе action. В LeRobot для этого есть класс SmoothActionFilter.
from lerobot.agents.filters import SmoothActionFilter
filter = SmoothActionFilter(alpha=0.3) # экспоненциальное сглаживание
for obs in stream:
action = policy.select_action(obs)
smoothed_action = filter(action)
robot.send_action(smoothed_action)
Грабли на которые я наступил (и вы наступите)
- Разная базовая система координат. В симуляции zero position — это вертикально вверх, на SO-101 zero — это любое положение при включении. Калибруйте через homing sequence перед каждым запуском.
- Задержка камеры. MolmoAct2 обрабатывает изображение 100-200 мс. За это время робот может уехать. Решение: добавить предсказание следующего состояния (state estimation) прямо в политику.
- Перегрев Jetson. При долгом инференсе MolmoAct2 + ACT SoC нагревается до 80°C. Ставьте радиатор или вентилятор. Иначе троттлинг убьёт точность.
Когда симуляция не нужна: PhysicalAgent и сбор данных на реальном роботе
Иногда проще не заморачиваться с sim-to-real, а сразу учиться на реальных данных. PhysicalAgent позволяет адаптировать VLA-модель (вроде MolmoAct2) без дорогого обучения — через in-context learning. Он смотрит несколько демонстраций и повторяет. Но это работает только для простых задач типа pick-and-place. Для сложных манипуляций sim-to-real остаётся королём.
Кстати, если у вас нет SO-101, можно собрать мобильного манипулятора за 20 000 рублей по этому гайду и адаптировать пайплайн под него. Но придётся переписать калибровку.
Вопросы, которые вы постесняетесь задать
Что делать, если политика в симуляции работает идеально, а на реальном роботе — дёргается?
Скорее всего, проблема в частоте управления. Убедитесь, что вы используете ту же частоту, что и при обучении. В LeRobot есть параметр delta_t в датасете. Если в симуляции было 0.01 с, а на железе 0.03 с — политика сойдёт с ума. Решение: переобучить с учётом реальной частоты или добавить адаптивный шаг.
MolmoAct2 — это бесплатно?
Модель открыта под лицензией Apache 2.0, но для коммерческого использования на AWS нужно купить лицензию через Hugging Face Enterprise Hub. Для хобби-проектов — бесплатно.
Нужен ли ROS2?
Строго говоря, нет. Strands Agents общается с роботом через WebSerial или MQTT. Но если у вас уже есть ROS2-стек, агент умеет подключаться к топикам через rosbridge.
Неочевидный совет на закуску
Не пытайтесь сразу перенести политику из симуляции на железо. Сначала запустите на реальном роботе случайные или записанные траектории, снимите логи и сравните их с симуляцией. Используйте GR00T для обратной калибровки. Если разница в положении суставов больше 3 градусов — рандомизация не спасёт, нужно править модель робота в симуляторе.
И ещё: Hugging Face Hub в 2026 году поддерживает автоматическую конвертацию политик между форматами LeRobot, PyTorch и TensorRT. Загрузите свою ACT-модель, и Hub сам соберёт оптимизированный бинарник для Jetson. Это сэкономит часы ручного тюнинга.
А если вам кажется, что sim-to-real — это слишком сложно, вспомните: ещё пять лет назад такое было доступно только лабораториям с бюджетом в $1M. Сейчас у вас есть LeRobot, Strands Agents и открытый SO-101 за 30 тысяч рублей. Действуйте.