LeRobot documentation

Развёртывание политики (lerobot-rollout)

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Развёртывание политики (lerobot-rollout)

lerobot-rollout — это единый CLI для развёртывания обученных политик на реальных роботах. Он поддерживает несколько стратегий выполнения и бэкендов инференса, от быстрой оценки до непрерывной записи и сбора данных с участием человека.

Быстрый старт

Помимо дополнительных компонентов для вашего робота и политики, дополнительные зависимости не требуются.

lerobot-rollout \
    --strategy.type=base \
    --policy.path=lerobot/act_koch_real \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --task="pick up cube" \
    --duration=30

Это запускает политику на 30 секунд без записи.

Выбор устройства

Передайте --device=cpu или --device=cuda, чтобы переопределить устройство чекпоинта на хосте, где это устройство доступно. Определённое устройство применяется к конфигурации политики до загрузки политики и построения её процессоров. Например, добавьте --device=cpu к команде выше, чтобы запустить чекпоинт, обученный на CUDA, на хосте только с CPU, если политика поддерживает выполнение на CPU. Проверьте, что инференс на CPU может обеспечить требуемую частоту управления, прежде чем развёртывать систему на роботе.

Если параметр --device не указан, rollout использует устройство из конфигурации policy, если оно задано, иначе автоматически выбирает доступное устройство. Аналогичное поведение наблюдается для RolloutConfig(device=...) вместе с build_rollout_context.


Стратегии

Выберите стратегию с помощью --strategy.type=<name>. Каждая стратегия определяет собственный цикл управления со своими семантиками записи и взаимодействия.

Базовая ( --strategy.type=base )

Автономное выполнение политики без записи данных. Используйте этот режим для быстрой оценки, демонстраций или когда вам нужно только наблюдать за роботом.

lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Put lego brick into the box" \
    --duration=60
ФлагОписаниеПо умолчанию
--durationВремя выполнения в секундах (0 = бесконечно)0
--taskОписание задачи, передаваемое в политику—
--display_dataПередача наблюдений/действий в Rerun для визуализацииfalse

Sentry ( --strategy.type=sentry )

Непрерывная автономная запись с периодической загрузкой в Hugging Face Hub. Границы эпизодов вычисляются автоматически на основе разрешения камеры и FPS, поэтому каждый сохранённый эпизод формирует полный видефайл, что обеспечивает эффективную загрузку.

Состояние политики (скрытое состояние, очередь RTC) сохраняется на границах эпизодов: робот не сбрасывается между эпизодами.

lerobot-rollout \
    --strategy.type=sentry \
    --strategy.upload_every_n_episodes=5 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --dataset.repo_id=${HF_USER}/rollout_eval_data \
    --dataset.single_task="Put lego brick into the box" \
    --duration=3600
ФлагОписаниеПо умолчанию
--strategy.upload_every_n_episodesЗагрузка в Hub каждые N эпизодов5
--strategy.target_video_file_size_mbЦелевой размер видеофайла для ротации эпизодовauto
--dataset.repo_idОбязательно. Репозиторий на Hugging Face для записанного набора данных—
--dataset.push_to_hubОтправлять ли на Hub при завершении работыtrue

Выделение ( --strategy.type=highlight )

Автономный прогон с записью по требованию через кольцевой буфер с ограничением по памяти. Буфер хранит последние N секунд телеметрии. Нажмите клавишу сохранения, чтобы сбросить буфер и начать живую запись; нажмите её снова, чтобы сохранить эпизод. При использовании асинхронного бэкенда каждый переключатель приостанавливает инференс, инвалидирует поставленные в очередь/интерполированные движения и запрашивает поддерживаемый локальный холд перед блокирующим сливом или сохранением. После этого корректный прогон возобновляется с нового захвата.

lerobot-rollout \
    --strategy.type=highlight \
    --strategy.ring_buffer_seconds=30 \
    --strategy.save_key=s \
    --strategy.push_key=h \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_highlight_data \
    --dataset.single_task="Pick up the red cube"

Управление с клавиатуры:

КлючДействие
s (настраиваемый)Начать запись (очистить буфер) / остановить и сохранить эпизод
h (настраиваемый)Загрузка набора данных в Hub
ESCОстановить сессию
ФлагОписание
--strategy.ring_buffer_secondsДлительность буферизации телеметрии (по умолчанию: 10)
--strategy.ring_buffer_max_memory_mbОграничение по памяти для кольцевого буфера (по умолчанию: 1024)
--strategy.save_keyКлюч для переключения записи (по умолчанию: s)
--strategy.push_keyКлюч для отправки на Hub (по умолчанию: h)

DAgger ( --strategy.type=dagger )

Сбор данных с участием человека. Чередует автономное выполнение политики и вмешательство человека через телеоператора. Кадры вмешательства помечаются как intervention=True. Требуется телеоператор (--teleop.type).

Подробное описание приведено в руководстве Сбор данных с участием человека в цикле.

Режим только с исправлениями (по умолчанию): Записываются только окна с исправлениями человека. Каждое исправление становится одним эпизодом.

lerobot-rollout \
    --strategy.type=dagger \
    --strategy.num_episodes=20 \
    --policy.path=outputs/pretrain/checkpoints/last/pretrained_model \
    --robot.type=bi_openarm_follower \
    --teleop.type=bi_openarm_mini \
    --dataset.repo_id=${HF_USER}/rollout_hil_data \
    --dataset.single_task="Fold the T-shirt"

Режим непрерывной записи (--strategy.record_autonomous=true): Записываются как автономные, так и корректирующие кадры с ротацией эпизодов по времени (как в Sentry).

lerobot-rollout \
    --strategy.type=dagger \
    --strategy.record_autonomous=true \
    --strategy.num_episodes=50 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/rollout_dagger_data \
    --dataset.single_task="Grasp the block"

Управление с клавиатуры (устройство ввода по умолчанию):

КлючДействие
SpaceПриостановка / возобновление выполнения политики
TabНачать / остановить корректировку человеком
EnterОтправить датасет на Hub (режим только с исправлениями)
ESCОстановить сессию

Ввод с помощью ножной педали также поддерживается через --strategy.input_device=pedal. Настройте коды педали с помощью флагов --strategy.pedal.*.

Если робот поддерживает удержание позиции при откате, пауза обновляет последнюю целевую позицию, фактически применённую драйвером, включая её обрезание и целевое положение захвата. До первой команды целевое значение задаётся валидированной измеренной позой. Это сохраняет заданную ошибку позиции, а не изменяет целевое значение на измеренную позу; робот может завершить стабилизацию к этой цели, пока продвижение по траектории политики остановлено. Проверьте поведение руки с грузом и захвата на реальном роботе; программное удержание не гарантирует сохранение захвата или физической неподвижности.

ФлагОписание
--strategy.num_episodesКоличество эпизодов коррекции для записи (по умолчанию: --dataset.num_episodes)
--strategy.record_autonomousТакже записывать автономные кадры (по умолчанию: false)
--strategy.upload_every_n_episodesОтправлять на Hub каждые N эпизодов (по умолчанию: 5)
--strategy.input_deviceУстройство ввода: keyboard или pedal (по умолчанию: keyboard)
--strategy.smooth_handoverПлавная передача управления при паузе / начале коррекции (по умолчанию: true). Отключите для телеуправления в стиле «сцепление», которое перенастраивает систему отсчёта от текущей позы робота при включении
--teleop.typeОбязательный. Тип телеоператора

Эпизодическая ( --strategy.type=episodic )

Запись, ориентированная на эпизоды, которая повторяет поведение lerobot-record. Политика управляет роботом в каждом эпизоде; необязательный телеоператор может управлять роботом во время фазы сброса между эпизодами.

lerobot-rollout \
    --strategy.type=episodic \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so100_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/rollout_eval_data \
    --dataset.num_episodes=20 \
    --dataset.episode_time_s=30 \
    --dataset.reset_time_s=10 \
    --dataset.single_task="Pick up the red cube"

Teleop является необязательным — если он опущен, робот удерживает своё положение во время фазы сброса.

Управление с клавиатуры:

КлючДействие
→ (вправо)Завершить текущий эпизод досрочно
← (влево)Отбросить эпизод и записать его заново
ESCОстановить сеанс записи
ФлагОписание
--dataset.num_episodesКоличество эпизодов для записи
--dataset.episode_time_sДлительность каждого эпизода записи в секундах. По умолчанию используется значение --duration, если оно задано, а данное значение не указано
--dataset.reset_time_sДлительность фазы сброса между эпизодами в секундах
--teleop.typeНеобязательно. Телеоператор для управления роботом во время сбросов
--strategy.reset_to_initial_positionСбрасывать ли робота в начальное положение между эпизодами
--strategy.smooth_leader_to_follower_handoverВключать или отключать плавную передачу управления от лидера к последователю.
--strategy.smooth_handoverПлавная передача управления телеоперации при начале сброса (по умолчанию: true). Отключите для телеопераций с режимом «сцепление», которые перенастраивают систему отсчёта от текущей позы робота при активации

Принесите свою стратегию

--strategy.type принимает любую стратегию, зарегистрированную в окружении, а не только встроенные, перечисленные выше. Стратегия — это два класса в пакете, устанавливаемом через pip: конфигурация, зарегистрированная на RolloutStrategyConfig, и подкласс RolloutStrategy, названный по ней без суффикса Config — та же конвенция SomethingConfig/Something, что и для кастомного оборудования, разрешаемая из модуля или пакета конфигурации.

from dataclasses import dataclass
from typing import ClassVar

from lerobot.rollout import RolloutContext, RolloutStrategy, RolloutStrategyConfig


@RolloutStrategyConfig.register_subclass("patrol")
@dataclass
class PatrolStrategyConfig(RolloutStrategyConfig):
    dataset_mode: ClassVar[str] = "required"  # the engine creates the dataset for you
    legs: int = 2  # becomes --strategy.legs


class PatrolStrategy(RolloutStrategy):
    def run(self, ctx: RolloutContext) -> None:
        ...  # the paced control loop: see the contract on RolloutStrategy.run

    def teardown(self, ctx: RolloutContext) -> None:
        ctx.data.dataset.finalize()
        self._teardown_hardware(ctx.hardware, ctx.runtime.cfg.return_to_initial_position)

Конфигурация определяет, что движок организует от имени стратегии, поэтому в LeRobot не нужно знать её тип:

ДекларацияЭффект
dataset_mode"none" (по умолчанию) отклоняет флаги --dataset.*, "optional" фиксирует их, если они переданы, "required" делает --dataset.repo_id обязательным
requires_teleopДелает --teleop.type обязательным
supports_interactiveПозволяет использовать --interactive=true; в этом случае run() должен соблюдать контракт перезапускаемости, описанный в RolloutStrategy
supports_sim_robotРазрешает --robot.type=sim; в этом случае run() должен запускать новый эпизод каждый раз, когда текущий завершается (см. lerobot.robots.sim_robot)
requires_streaming_encoding()Возвращает True, если кадры записываются изнутри цикла управления: --dataset.streaming_encoding принудительно включен
extra_dataset_features()Столбцы датасета, принадлежащие стратегии (например, intervention в DAgger); каждая записанная кадра должна содержать их

Назовите дистрибутив lerobot_strategy_<name>, и lerobot-rollout импортирует пакет до разбора CLI — выполняется только его __init__.py, поэтому импортируйте конфигурацию именно там. Пакет с любым другим именем загружается вместе с подмодулями с помощью --strategy.discover_packages_path=<package>. Поля dataclass стратегии становятся флагами --strategy.*:

lerobot-rollout \
    --strategy.type=patrol \
    --strategy.legs=3 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_patrol \
    --dataset.single_task="patrol the aisle"

SentryStrategy (запись, безопасный интерактивный режим) и BaseStrategy (без записи) — это эталонные реализации, от которых следует отталкиваться; send_next_action, safe_push_to_hub и estimate_max_episode_seconds из lerobot.rollout.strategies — это вспомогательные функции, на которых они построены.

Для асинхронных бэкендов контракт диспетчеризации является обязательным. Публикуйте каждое захваченное наблюдение с помощью engine.notify_observation(obs_processed), вызывайте send_next_action(...) на каждом автономном такте мотора, включая такты интерполяции и удержания, а затем вызывайте engine.pump_query(obs_processed). Если вызывать только engine.get_action(), то будет обойден рукопожатный процесс разрешения и удержания: запланированный текстовый запрос может ждать бесконечно, а терминальная ошибка может никогда не сигнализировать об остановке.

Сторонние стратегии могут вызывать self._tick(timer, new_cycle=interpolator.needs_new_action()) вместо timer.tick(...), чтобы включить периодическую отчетность о состоянии после _init_engine(ctx).

send_next_action построена на lerobot.inference.dispatch_tick и его компонентах (next_interpolated_action, commit_action, dispatch_permitted), которые единожды кодируют этот порядок: dispatch_allowed() до и после получения действия, а также перед отправкой; недействительность интерполяции, поддерживаемая локальная удерживающая пауза и acknowledge_hold() в случае отказа; и record_dispatch() после отправки. Удерживающая пауза, которая не удалась, никогда не подтверждается. Используйте эти вспомогательные функции, а не переосуществляйте последовательность; send_next_action лишь добавляет кадр набора данных, обработчик действий на стороне робота и учёт ритма. В удалённых контекстах ctx.policy.policy, preprocessor и postprocessor установлены в None; используйте ctx.policy.inference и конвейеры на стороне робота в ctx.processors.

Оберните известную блокирующую работу по записи в середине выполнения в self._pause_for_recording(ctx), включая очистку кольцевого буфера и завершение эпизода. Это отменяет асинхронное движение перед остановкой записи и возобновляет работу только в том случае, если выполнение всё ещё здорово и активно. Стратегии с фазами, управляемыми оператором, должны передавать своё текущее разрешение на движение как resume_allowed. Следующее действие должно поступать из свежего наблюдения; сохранённая работа не должна оживлять приостановленное, остановленное или аварийное выполнение.


Визуализация предсказаний политики

С флагом --display_data просмотрщик также отображает то, что предсказывает политика, помимо действий: воображаемые кадры камеры от модели мира, предсказанное подзадание, ограничивающие рамки, нарисованные поверх изображения с камеры. Каждая политика сама решает, что именно она предсказывает, и включает это в своём собственном конфиге, например --policy.return_predicted_video=true для LingBot-VA. Предсказание получает имя по тому, что оно предсказывает: Rerun показывает предсказанное observation.images.top как prediction.images.top, предсказанное подзадание как prediction.subtask, а рамки — под их камерой (<camera>/prediction); Foxglove публикует их на темах /prediction/... и аннотациях изображений <camera topic>/prediction. При использовании RTC предсказание обновляется один раз за чанк. См. Принесите свою политику, чтобы возвращать предсказание из политики.

Бэкенды инференса

Выберите бэкенд с помощью --inference.type=<name>. Локальная синхронная и RTC-инференс используют политику, настроенную ниже. Удалённый бэкенд получает контракт политики с сервера и не загружает веса на компьютер робота.

Синхронизация (по умолчанию)

Один вызов политики на каждый такт управления. Основной цикл блокируется до вычисления действия.

Работает со всеми политиками. Дополнительные флаги не требуются.

Поточная обработка по фрагментам ( --inference.type=rtc )

Фоновый поток асинхронно формирует блоки действий. Основной цикл управления опрашивает наличие следующего готового действия, пока политика параллельно вычисляет следующий блок.

Используйте RTC с совместимыми моделями VLA (Pi0, Pi0.5, SmolVLA), чтобы перекрывать инференс и движение. Для непрерывного выполнения по-прежнему необходимо достаточно воспроизводимых действий, чтобы покрыть задержку инференса и её вариативность.

lerobot-rollout \
    --strategy.type=base \
    --inference.type=rtc \
    --inference.rtc.execution_horizon=10 \
    --inference.rtc.max_guidance_weight=10.0 \
    --policy.path=${HF_USER}/pi0_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Pick up the cube" \
    --duration=60 \
    --device=cuda
ФлагОписание
--inference.rtc.execution_horizonШаги для смешивания с предыдущим фрагментом (по умолчанию: зависит от политики)
--inference.rtc.modeguided (по умолчанию) или обученный префикс trained для совместимых контрольных точек Pi05
--inference.rtc.max_guidance_weightСила принуждения к согласованности (по умолчанию: зависит от политики)
--inference.rtc.prefix_attention_scheduleГрафик смешивания: LINEAR, EXP, ONES, ZEROS
--inference.queue_thresholdПорог обратного давления; обученный RTC требует как минимум своей максимальной задержки
--inference.action_starvation_grace_sОжидание нового движения после голодания на поддерживаемом роботе (по умолчанию 1.0; 0 приводит к немедленной ошибке)

См. руководство Real-Time Chunking для подробностей о настройке параметров RTC.

Локальный RTC выполняется в фоновом потоке процесса rollout без транспорта. Сервер и клиент на одном и том же компьютере используют вместо этого --inference.type=remote. См. руководство по удалённому режиму для выравнивания/смешивания чанков и поведения при ожидании, общего для асинхронных бэкендов.

Ожидание требует поддерживаемого робота. Обычный локальный RTC остаётся доступным без этой возможности, но запланированные паузы при смене текста/инструкции и восстанавливаемое голодание требуют её. Позиционно управляемые последователи SO, OMX, Koch, HopeJr и Rebot поддерживают эту функцию; у OpenArm, Reachy2 и бимануальных обёрток есть ограничения конфигурации, перечисленные в таблице поддержки роботов. При наличии поддержки пустой буфер может удерживать последнее применённое целевое значение в течение action_starvation_grace_s (по умолчанию 1 секунда), включая время, необходимое для обработки старых результатов инференса и предсказания на основе нового захвата. После начала движения нулевое время ожидания или неподдерживаемый робот приводят к немедленной ошибке при исчерпании; для запуска действует собственный дедлайн. В отличие от прежнего локального пути RTC, исчерпание больше не является бесконечно пропускаемым тиком. Время ожидания никогда не продлевает истёкшие лимиты запроса или свежести.

Локальный RTC предоставляет эти дополнительные бюджеты через --inference.:

ПараметрПо умолчаниюЗначение
max_observation_age_s5 sМаксимальный возраст источника при выполнении действия
action_timeout_s10 sОткрытый запрос на действие
startup_timeout_s120 sНачальная подготовка и запуск в режиме свежих действий
language_timeout_s120 sПланируемая языковая операция

Это начальные значения, а не измеренные аппаратные гарантии. RTC должен сохранять достаточно воспроизведения после подстройки для следующего вывода и временного запаса. Повышение queue_threshold не поможет, если вывод регулярно потребляет доступный горизонт предсказания; снизьте задержку или проверьте более длинный горизонт/другую частоту действий.

Сбой терминала никогда не приводит к автоматическому возобновлению движения политики. При наличии работоспособного получения наблюдений и управления актуаторами остановка системы учитывает параметр --return_to_initial_position (по умолчанию true) и размыкает соединение. Возврат требует чтения полного наблюдения, поэтому постоянный сбой камеры может помешать этому процессу. Невыполнение команды подавляет дальнейшее движение при остановке для всех бэкендов, включая синхронный. Это не изменяет синхронное предсказание и не вводит восстановление, специфичное для камеры.

Compilation and instruction changes

Компиляция RTC прогревает как начальные, так и префиксные вызовы, включая репрезентативную ненулевую задержку, до начала движения. Хотя значение по умолчанию для --compile_warmup_inferences равно 2, для включения RTC требуется минимум 3; в журналах запуска указывается фактическое количество. Время прогрева должно укладываться в startup_timeout_s. Последующие инструкции, изменяющие формы тензоров, могут вызывать повторную компиляцию и приводить к превышению дедлайна воспроизведения или операции.

Смена задачи во время инференса приводит к отбрасыванию устаревшего результата. Поддерживаемые роботы останавливаются и запрашивают новые действия; если такая возможность ожидания отсутствует, оставшиеся действия могут исчерпаться. На таких роботах рекомендуется менять задачи между запусками.


Интерактивные сессии

Добавьте --interactive=true, чтобы управлять rollout из терминала, а не запускать его сразу. Аппаратное обеспечение подключается, а политика загружается как обычно, но робот остаётся неподвижным, пока вы не введёте /start — это удобно, если нужно сначала расставить сцену, дать новые инструкции политике между попытками или выполнить несколько дублей, не тратя время на повторную загрузку.

lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_smolvla_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="pick up the cube" \
    --interactive=true
КомандаДействие
/startЗапуск (или перезапуск) цикла управления политикой
/subtask <text>Измените инструкцию в рамках текущего запуска; асинхронный инференс может перейти в запланированную паузу. Без аргумента выводится текущая задача. Влияет только на политики, использующие язык как условие (SmolVLA, π0/π0.5 и аналогичные). При использовании внешнего планировщика /subtask также возвращает управление из autosteer
/vqa <text>Задайте вопрос о том, что робот видит в данный момент. Только во время выполнения и только с текстовой головой политики или внешним планировщиком
/autosteer <goal>Передайте высокоуровневую цель и позвольте текстовой голове политики или внешнему планировщику выбрать подзадачи. /autosteer off возвращает управление; без аргумента выводится текущая цель
/resetОстановите движение, верните робота в исходное положение и восстановите инструкцию --task
/stopЗавершите сеанс и выполните стандартные процедуры завершения работы
/helpСписок команд
> /start
Rollout running — task 'pick up the cube'. /subtask <text> to change it, ...
> /subtask put the cube in the box
Task: 'pick up the cube' → 'put the cube in the box' (applies from the next policy inference)
> /vqa is the cube inside the box?
Asked: 'is the cube inside the box?' — answering from the next observation...
Q: is the cube inside the box?
A: No — the cube is on the table to the left of the box.
> /reset
Task restored to 'pick up the cube'
Resetting — returning the robot to its initial position...
Robot reset — holding at initial position. /start to run.
> /stop

Строки, начинающиеся с >, — это то, что вы вводите; сессия не выводит собственный приглашающий символ.

Ctrl-C по-прежнему завершает работу в обычном режиме, а закрытие stdin (Ctrl-D или конец скрипта, переданного через конвейер) завершает сессию — поэтому скрипт, переданный через конвейер, должен держать stdin открытым в течение всего предполагаемого времени работы:

(printf '/start\n'; sleep 60; printf '/stop\n') | lerobot-rollout ... --interactive=true

/subtask обновляет задачу для последующего вывода. При использовании --inference.type=sync предварительно вычисленные действия для чанков отбрасываются. При локальном RTC или удалённом выводе изменение задачи во время запроса действия приводит к отбрасыванию устаревшего результата. На роботе, поддерживающем локальный режим удержания, движок инвалидирует поставленные в очередь или интерполированные движения, ожидает подтверждения удержания со стороны цикла управления, а затем запрашивает новые движения в соответствии с новой задачей. Ожидайте остановку во время этого перехода; непрерывное плавное смешивание не гарантируется. Изменение задачи между запросами может сохранить уже принятые действия для обеспечения непрерывности. Локальный RTC на роботе без поддержки удержания также отбрасывает устаревший результат, но может исчерпать оставшиеся действия и завершиться. Если такой робот не может корректно удерживать позицию, меняйте инструкции между запусками.

При использовании локального --use_torch_compile=true инструкция, изменяющая формы обрабатываемых тензоров, может вызывать повторную компиляцию. Отступы (padding) могут сохранять некоторые изменения задач при той же форме, но последующая компиляция не гарантированно уложится в оставшееся время воспроизведения или дедлайн изменения инструкции: это может привести к фатальной ошибке. Оставьте компиляцию отключенной при исследовании инструкций, если эти переходы не были валидированы. Изменения во время начального прогрева компиляции не запрашивают удержание движения, поскольку движение политики еще не началось.

/vqa и /autosteer требуют политики, которая объявляет поддержку генерации текста и реализует PreTrainedPolicy.generate_text(), например, соответствующим образом обученный чекпоинт EO1 или внешний планировщик. Поддержка проверяется перед принятием запроса; поведение, специфичное для чекпоинта, всё ещё требует валидации.

/vqa отвечает на основе следующего наблюдения и выводит результат, когда он готов, поэтому вы можете продолжать вводить команды в это время; одновременно обрабатывается только один вопрос (собственные запросы autosteer используют тот же слот). При использовании внешнего планировщика вопрос обрабатывается на рабочем потоке, пока робот продолжает действовать, и ничего из описанного ниже не применяется. Асинхронные бэкенды сначала переходят в подтверждённое локальное удержание и отменяют поставленные в очередь/интерполированные движения, затем отправляют свежее наблюдение в текстовый путь. Активное исправное выполнение возобновляется с нового блока действий после получения ответа; приостановленные или остановленные выполнения остаются неактивными. Синхронная генерация текста выполняется инлайн на потоке управления и отбрасывает заранее вычисленные действия политики, поэтому следующий такт возобновляется с нового вывода. Время запроса учитывается в --duration. Вопросы принимаются только во время активного выполнения — у простаивающего движка нет текущего представления. Если инструкция или контекст выполнения делают асинхронный ответ недействительным, вместо устаревшего ответа на вопрос приходит одно уведомление об отмене. Конец сегмента также сообщает о неотвеченных вопросах, включая генерацию, которая всё ещё выполняется; сообщение об отмене не прерывает вызов работающей модели и не освобождает её слот запроса раньше времени.

/autosteer передаёт политике цель и запрашивает у неё следующий подзадачу каждые --autosteer_interval_s секунд (по умолчанию 10), применяя каждый подзадачу через тот же путь, что и /subtask, и объявляя о нём в чате. Каждый запрос — это полная генерация текста, поэтому интервал является параметром стоимости: меньшие значения приводят к более раннему повторному планированию, но тратят больше времени цикла на генерацию текста вместо действий. Прогресс плана хранится в политике, а не в rollout, поэтому план исчезает вместе с сегментом; секвенсор также останавливается при /reset, /subtask, /autosteer off и при первом сбое планирования.

Логи ниже уровня ERROR приглушаются во время выполнения сессии, чтобы рутинный вывод не перемешивался с тем, что вы вводите; ошибки и критические сбои инференса по-прежнему отображаются, а обычное ведение логов возобновляется после завершения сессии. Сводки по частоте выводятся в чате, а запуск без --interactive возвращает живой лог.

Сессии работают по SSH и на машинах без графического интерфейса — сервер отображения не требуется.

Запись в интерактивном режиме. --strategy.type=sentry также принимает --interactive=true и непрерывно записывает данные, пока вы управляете: каждый сегмент /start…/reset сохраняет полные эпизоды, а также один финальный частичный эпизод, при этом датасет остаётся открытым до завершения работы. Кадры содержат информацию о происхождении задачи для действия, которое было фактически отправлено, поэтому действия, уже поставленные в очередь или интерполированные в рамках старой задачи, сохраняют старую метку.

Блокирующие сохранения эпизодов во время выполнения приостанавливают асинхронный вывод, отменяют поставленные в очередь и интерполированные действия и запрашивают поддерживаемый локальный режим ожидания. Возобновление происходит с нового захвата только в том случае, если выполнение остаётся активным и в нормальном состоянии. Аналогичная защита применяется к сохранениям DAgger и к сбросу/сохранению кольцевого буфера Highlight. Приостановка записи и обычное голодание разделяют физическое поведение ожидания, но их дедлайны и причины для возобновления остаются отдельными.

lerobot-rollout \
    --strategy.type=sentry \
    --policy.path=${HF_USER}/my_smolvla_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_cube_sessions \
    --task="pick up the cube" \
    --interactive=true

Остальные стратегии записи (episodic, DAgger, highlight) не поддерживаются: они привязывают собственные клавиатурные команды и завершают формирование набора данных при выходе из run(), поэтому их невозможно перезапускать сегмент за сегментом.

Внешний планировщик

--planner.model_id=<name> направляет запросы /vqa и /autosteer через VLM-клиент конвейера аннотаций (дополнение annotations), а не через текстовый слой политики. Вызовы выполняются в рабочем потоке, пока робот продолжает действовать, и для них не запрашивается блокировка языка, за одним намеренным исключением: при запуске /autosteer backend инференза приостанавливается до первого ответа планировщика, поскольку цель является контекстом для планировщика, а не инструкцией для политики. Асинхронные backends (rtc, remote) отбрасывают действия, уже поставленные в очередь или вычисляемые для предыдущей инструкции; синхронный backend удерживает робота. Как только первый подзадача применяется, backend возобновляет работу с нового наблюдения. /subtask по-прежнему применяет вашу инструкцию напрямую и отменяет автоматическое планирование; поздние ответы планировщика не могут её переопределить.

Планировщик работает с любым бэкендом инференса. При локальном инференсе он переиспользует рецепт подзадач загруженного процессора, если он есть, а в противном случае запрашивает короткую инструкцию; это не гарантирует, что чекпоинт сможет её выполнить. --planner.instructions='["pick up the cup","open the drawer"]' ограничивает вывод планировщика: VLM просят выбрать одну из этих строк, а ответ с подзадачей, отсутствующей в списке, считается ошибкой. Регистр букв, лишние пробелы и точка в конце игнорируются, а собственная формулировка списка передаётся в policy. Без этого флага список читается из меток задач обучающего датасета чекпоинта (через его train_config.json). Все метки попадают в промпт, поэтому для датасетов с большим количеством задач передавайте флаг со списком покороче. Если датасет не удаётся прочитать, в лог записывается предупреждение, а вывод планировщика остаётся свободным. При удалённом инференсе policy находится на стороне сервера, поэтому ни рецепт, ни обучающая лексика локально недоступны: явно передавайте --planner.instructions, иначе ответы останутся свободными. Планировщик протестирован только на оборудовании с локальным инференсом.

Внешний планировщик получает последние --planner.history пар наблюдений/команд (по умолчанию 4), за которыми следуют текущие изображения. Каждая пара содержит наблюдение, использованное для запроса инструкции, и инструкцию, впоследствии принятую движком; принятие не означает успешного выполнения. Повторяющиеся инструкции остаются в истории, чтобы VLM мог оценить отсутствие прогресса. История очищается при ручном перехвате, сбросе, остановке, завершении сегмента или установке новой цели autosteer. Установите --planner.history=0, чтобы отключить её. /vqa может просмотреть эту историю, но не добавляет в неё записи. Для запроса следующего подзадания VLM должен сначала описать сцену и указать, выполнено ли предыдущее задание, находится ли оно в процессе или завершилось с ошибкой, и только затем назвать следующую инструкцию. Ответ done означает, что цель достигнута: autosteer останавливается, выполнение завершается, а робот удерживает свою позу до /reset или /start. Поздний done из периода до /subtask, /reset или новой цели отбрасывается. Каждое применённое подзадание выводится вместе с оценкой сцены моделью и задержкой запроса.

Запустите сервер VLM, совместимый с OpenAI, отдельно, а затем подключите его:

transformers serve Qwen/Qwen3-VL-8B-Instruct --port 8000
# Alternatively: vllm serve Qwen/Qwen3-VL-8B-Instruct --port 8000
lerobot-rollout ... --task="pick up the cup" --interactive=true \
    --planner.model_id=Qwen/Qwen3-VL-8B-Instruct \
    --planner.api_base=http://localhost:8000/v1
> /start
> /vqa What is the next short instruction to clear the table?
> /subtask put the cup in the sink
> /autosteer clear the table

Хостинговая модель работает аналогичным образом. В этом примере используются Hugging Face Inference Providers с токеном, имеющим разрешение «Make calls to Inference Providers»:

export HF_TOKEN=hf_...
lerobot-rollout ... --task="put all colored cubes in the green bin" --interactive=true \
    --planner.model_id=Qwen/Qwen3.8-27B:novita \
    --planner.api_base=https://huggingface.co/proxy/router.huggingface.co/v1 \
    --planner.api_key_env=HF_TOKEN

/vqa возвращает только ответ; /autosteer применяет инструкции. Настройте конечную точку с помощью --planner.api_base, а ключ — с помощью --planner.api_key_env=<variable> (предпочтительно, ключ не попадает в команды и логи) или --planner.api_key. --planner.request_timeout_s (по умолчанию 600) и --planner.request_max_retries (по умолчанию 2) ограничивают каждый запрос; --planner.camera_key выбирает одну камеру; --planner.log_path добавляет каждый обмен в виде одной строки JSON. Зависимости для обслуживания моделей должны находиться в окружении сервера. --autosteer_interval_s измеряет время движения робота после применения ответа, в дополнение к задержке запроса. Многоуровневое управление и автоматический инвентаризация сцен выходят за рамки этого адаптера.

Программное управление

RolloutController предоставляет те же операции, что и API библиотеки — потокобезопасные start() / reset() / stop() / set_task(), а также колбэк RolloutEvent, без привязки к stdin, вывода в консоль или подавления логов:

from threading import Event, Thread

from lerobot.rollout import (
    LinkedEvent,
    RolloutController,
    RolloutEvent,
    build_rollout_context,
    create_strategy,
)

parent = Event()  # your application's shutdown signal
ctx = build_rollout_context(cfg, LinkedEvent(parent))  # loads policy, connects robot
strategy = create_strategy(cfg.strategy)
strategy.setup(ctx)

controller = RolloutController(strategy, ctx, on_event=print)  # or your own observer
serve_thread = Thread(target=controller.serve)  # serve() blocks; run it where you like
serve_thread.start()

controller.start()                        # robot starts executing the policy
controller.set_task("grab the red cube")  # re-instruct mid-run
controller.reset()                        # stop movement, return home, stay warm
controller.stop()                         # end serve()

serve_thread.join()
strategy.teardown(ctx)  # teardown stays with the caller

RolloutController требует, чтобы событие завершения контекста было LinkedEvent, созданным, как описано выше: контроллер завершает сегменты выполнения через свой локальный флаг, тогда как ваше событие parent по-прежнему принудительно вызывает полное завершение. Установите play_sounds=False, если вы не хотите получать голосовые объявления.


Общие флаги

ФлагОписаниеПо умолчанию
--policy.pathОбязательный. Идентификатор модели HF Hub или путь к локальному чекпоинту—
--robot.typeОбязательный. Тип робота (например, so100_follower, koch_follower)—
--robot.portПоследовательный порт для робота—
--robot.camerasКонфигурация камеры (словарь JSON)—
--fpsЧастота вывода политики и записи данных30
--status_interval_sИнтервал между журналами состояния (0 отключает; только для неинтерактивного режима)5
--durationВремя выполнения в секундах (0 = бесконечно; для каждого сегмента, если интерактивный режим)0
--deviceУстройство Torch (cpu, cuda, mps)auto
--taskОписание задачи (используется, если набор данных не предоставлен)—
--display_dataПотоковая передача телеметрии в визуализацию Rerunfalse
--display_ip / --display_portАдрес удалённого сервера Rerun—
--interpolation_multiplierКоманды робота на действие политики (управление с частотой fps × N Гц)1
--interactiveЧат-сессия на stdin; робот простаивает до /start (base, sentry)false
--use_torch_compileВключите torch.compile для инференсаfalse
--resumeВозобновление предыдущей сессии записиfalse
--play_soundsСинтез голоса для мероприятийtrue

Отчётность по частоте

Неинтерактивный rollout выводит статус каждые пять секунд. Измените интервал с помощью --status_interval_s=10 или отключите вывод с помощью --status_interval_s=0.

Rollout: loop 29.7/30 Hz · over budget 2/149 · starved 0 · infer 18.7 ms (worst 40.1) · process 2.41 GiB · GPU 5.12/79.6 GiB

Задержка — медианное/худшее значение за интервал (turnaround для RTC/удалённых). Недоступные поля опускаются; память GPU указана для всего устройства, а удалённая память — локальная. Отчёт приостанавливается, когда цикл блокируется.

Каждая стратегия сообщает о том, что её цикл управления фактически достиг, как и lerobot-record, lerobot-teleoperate и lerobot-replay — все они синхронизируются с одним и тем же таймером. Для каждого сохранённого эпизода формируется однострочная сводка, а по завершении цикла — в том числе при нажатии Ctrl-C — выводится блок, охватывающий весь прогон:

Cadence (episode 1): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/598 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence (episode 2): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/599 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence summary — whole run, 2 episodes · target 30 Hz × 2 (16.7 ms tick slot, 33.3 ms cycle budget): 2400 ticks, 1197 cycles judged
  effective cadence: 29.84 Hz policy / 59.67 Hz commands over 40.2 s measured
  cycles over the 33.3 ms work budget: 12/1197 (1.0%) — work mean 18.7 ms, worst 48.1 ms
  ticks over their 16.7 ms slot: 40/2400 (costs interpolation smoothness only)
  loop-body steps (share of measured work):
    observe      mean   3.13 ms · worst   9.00 ms ·  31.7% of work · 2400 calls
    process_obs  mean   0.50 ms · worst   1.00 ms ·   5.1% of work · 2400 calls
    infer        mean   5.18 ms · worst  40.00 ms ·  52.4% of work · 2400 calls
    send         mean   0.40 ms · worst   0.40 ms ·   4.1% of work · 2400 calls
    record       mean   0.67 ms · worst 620.00 ms ·   6.8% of work · 2402 calls
  pacing headroom: 7.4 ms slept per tick on average (max 13.0 ms) — near zero means the loop is saturated

Читайте сверху вниз: эффективная частота — это то, что вы получили по сравнению с --fps, циклы сверх бюджета — как часто цикл не мог удерживать эту частоту, разбивка по шагам показывает, куда ушло время, а запас по темпу около нуля означает, что не осталось ничего, чтобы поглотить медленный тик. Высокая доля infer указывает на политику или устройство; высокая доля observe указывает на камеры. Если worst шага значительно выше его mean, это разовое событие — выше record составляет 0,67 мс на кадр, а выброс в 620 мс — это блокирующий save_episode, завершивший эпизод.

Цикл здесь — это количество тиков, соответствующее одному действию политики (их --interpolation_multiplier). Потерять кадры можно только из-за целых циклов, превышающих бюджет 1/fps; если же один тик превышает выделенное ему время, это лишь делает интерполированное движение менее плавным, поэтому эти два показателя учитываются отдельно. Без интерполяции цикл состоит из одного тика, поэтому в отчёте различие между ними не проводится, и везде учитываются тики.

В интерактивных сессиях каждый сегмент /start имеет собственный таймер, поэтому отчёт отправляется в чат один раз за сегмент (/reset, /stop или --duration), а не один раз за процесс.


Программное использование

Для расширений lerobot.inference — это публичный пакет для конфигураций бэкендов, локальных движков и общих контрактов планирования. lerobot.remote_inference содержит реализацию удалённого движка, протокола, развёртывания и сессий; lerobot.rollout содержит цикл робота, стратегии, интерполяцию и запись. Импортируйте публичные символы из их пакетов, а не из файлов реализации. Необязательные зависимости для удалённого доступа нужны только при использовании удалённого бэкенда или сервера.

Для пользовательских развёртываний (например, с процессорами кинематики) используйте API модуля rollout напрямую:

from lerobot.rollout import BaseStrategyConfig, RolloutConfig, build_rollout_context
from lerobot.inference import SyncInferenceConfig
from lerobot.rollout.strategies import BaseStrategy
from lerobot.utils.process import ProcessSignalHandler

cfg = RolloutConfig(
    robot=my_robot_config,
    policy=my_policy_config,
    strategy=BaseStrategyConfig(),
    inference=SyncInferenceConfig(),
    fps=30,
    duration=60,
    task="my task",
)

signal_handler = ProcessSignalHandler(use_threads=True)
ctx = build_rollout_context(
    cfg,
    signal_handler.shutdown_event,
    robot_action_processor=my_custom_action_processor,       # optional
    robot_observation_processor=my_custom_obs_processor,     # optional
)

strategy = BaseStrategy(cfg.strategy)
try:
    strategy.setup(ctx)
    strategy.run(ctx)
finally:
    strategy.teardown(ctx)

См. examples/so100_to_so100_EE/rollout.py и examples/phone_to_so100/rollout.py для полных примеров с кинематическими процессорами.

Update on GitHub