Accepted to the 2026 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS 2026).
Zeyu Lou1,†, Tianran Zhang2,†, Xinquan Yue1, Ya Jing3, and Chenyang Si1,*
1Nanjing University ·
2The Hong Kong University of Science and Technology (Guangzhou)
· 3Beijing University of Technology
†Equal contribution. *Corresponding author.
Pretrained weights · Quickstart · Demo
TL;DR: SafeLoop adds proactive hazard prediction, safe-anchor recording, and motion-planned rollback to a frozen VLA without modifying its parameters.
SafeLoop is an outer-loop safety controller for frozen manipulation policies. It predicts near-future body/stuck and object hazards, records safe trajectory anchors, executes motion-planned rollback, and resumes the base policy from the recovered state.
The released implementation uses a Pi0 LIBERO policy, a frozen
Qwen2.5-VL-3B backbone with a compact multitask prediction head, and a
three-action decision head over noop, record, and rollback.
- Weights: Jaqen0-0/SafeLoop
- Pinned artifact manifest:
configs/release/artifacts_pi0_v1.json
The left rollout uses the frozen Pi0 policy. The right rollout uses the same policy with SafeLoop; the controller records a safe anchor, rolls back, and resumes policy execution.
safety_guard/
controller.py SafeLoop controller and rollback interface
memory.py safe-anchor memory
libero_motion.py LIBERO rollback motion planning
qwen_multitask.py predictor dataset, head, loss, and inference
rl_policy_decider.py noop/record/rollback decision policy
online_rl.py online decision-head optimization
scripts/
quickstart_pi0_safeloop.sh one-task Pi0 + SafeLoop rollout
serve_pi0_policy.py inference-only OpenPI server bootstrap
download_release_weights.py pinned weight download and SHA256 check
check_release_environment.py dependency, submodule, and asset checks
evaluate_pi0_safeguard_closed_loop.py rollout and data collection
run_release_predictor_training.py predictor training recipes
run_release_decider_training.py decision-head training recipe
run_release_24task_eval.py configurable LIBERO evaluation runner
third_party/
LIBERO/ pinned simulator submodule
openpi/ pinned Pi0 policy/client submodule
The release has been validated on Linux with Python 3.10, CUDA 12.4, and an
NVIDIA H20 GPU. Python package versions are pinned in
pyproject.toml and
requirements/libero-eval.txt.
Install the system packages required by Python virtual environments, video export, and headless MuJoCo rendering:
sudo apt-get update
sudo apt-get install -y python3.10 python3.10-venv git ffmpeg libegl1 libgl1 libglfw3 libosmesa6Clone the Pi0-only release and create its environment:
git clone --branch release/safeloop --recurse-submodules https://github.com/Loule0-0/SafeLoop.git
cd SafeLoop
bash scripts/setup_release_env.sh
source .venv/bin/activateDownload the pinned Qwen model:
export QWEN_MODEL="$PWD/.artifacts/Qwen2.5-VL-3B-Instruct"
hf download Qwen/Qwen2.5-VL-3B-Instruct \
--revision 66285546d2b821cf421d4f5eb2576359d3770cd3 \
--local-dir "$QWEN_MODEL"Download the Pi0 LIBERO checkpoint through the pinned OpenPI code:
export OPENPI_ROOT="$PWD/third_party/openpi"
(
cd "$OPENPI_ROOT"
env -u VIRTUAL_ENV uv sync --frozen \
--no-install-package lerobot \
--no-install-package rerun-sdk \
--no-install-package evdev \
--no-install-package av
)
export PI0_CHECKPOINT_DIR="$(
cd "$OPENPI_ROOT"
env -u VIRTUAL_ENV uv run --no-sync python -c \
'from openpi.shared import download; print(download.maybe_download("gs://openpi-assets/checkpoints/pi0_libero"))'
)"The SafeLoop predictor and decision weights are downloaded automatically by the Quickstart. To download or validate them separately:
export SAFELOOP_WEIGHTS="$PWD/.artifacts/safeloop_weights"
python scripts/download_release_weights.py --output-dir "$SAFELOOP_WEIGHTS"
python scripts/download_release_weights.py --output-dir "$SAFELOOP_WEIGHTS" --check-onlyRun the Pi0 + SafeLoop example for LIBERO-10 task 6, seed 389:
export QWEN_MODEL="$PWD/.artifacts/Qwen2.5-VL-3B-Instruct"
export PI0_CHECKPOINT_DIR=/path/to/cached/pi0_libero
bash scripts/quickstart_pi0_safeloop.shThe script verifies all eight released SafeLoop checkpoints, starts the Pi0
websocket policy server, checks the environment and endpoint, and writes the
rollout summary and video under outputs/quickstart/.
Useful overrides:
SAFELOOP_TASK=libero_10:9 SAFELOOP_SEED=214 \
POLICY_CUDA_VISIBLE_DEVICES=0 SAFELOOP_CUDA_VISIBLE_DEVICES=0 \
bash scripts/quickstart_pi0_safeloop.shSet SAFELOOP_START_POLICY_SERVER=0 to use an existing policy server at
POLICY_HOST:POLICY_PORT. Set SAFELOOP_SYNC_OPENPI=0 when the pinned OpenPI
environment is already installed.
export SAFELOOP_ROOT="$PWD"
cd "$OPENPI_ROOT"
env -u VIRTUAL_ENV uv sync --frozen \
--no-install-package lerobot \
--no-install-package rerun-sdk \
--no-install-package evdev \
--no-install-package av
env -u VIRTUAL_ENV CUDA_VISIBLE_DEVICES=0 \
uv run --no-sync python "$SAFELOOP_ROOT/scripts/serve_pi0_policy.py" policy:checkpoint \
--policy.config=pi0_libero \
--policy.dir="$PI0_CHECKPOINT_DIR"Validate the endpoint from the SafeLoop environment:
python scripts/check_release_environment.py \
--scope eval \
--check-policy-server \
--policy-host 127.0.0.1 \
--policy-port 8000The default profile contains 24 configured LIBERO tasks and 16 seeds per task. Each suite uses the rollout horizon from the pinned OpenPI LIBERO evaluator.
python scripts/run_release_24task_eval.py \
--model-dir "$QWEN_MODEL" \
--weights-dir "$SAFELOOP_WEIGHTS" \
--output-root "$SAFELOOP_OUTPUT/eval_24task" \
--libero-root "$PWD/third_party/LIBERO" \
--openpi-root "$OPENPI_ROOT" \
--checkpoint-dir "$PI0_CHECKPOINT_DIR"Run a single task or a single seed without editing the config:
python scripts/run_release_24task_eval.py \
--model-dir "$QWEN_MODEL" \
--weights-dir "$SAFELOOP_WEIGHTS" \
--output-root "$SAFELOOP_OUTPUT/smoke" \
--task libero_10:9 \
--seeds 214 \
--dry-runUse --profile base_policy_reference to disable SafeLoop with the same task and
seed selection.
The predictor training implementation and recipe configuration are included for
reference. The dataset used to train the released weights is not part of the
public release. To train on a compatible local dataset, point SAFELOOP_DATA at
its root and materialize it before running the recipes:
export SAFELOOP_DATA=/path/to/compatible/local_dataset
python scripts/materialize_hf_training_data.py \
--dataset-dir "$SAFELOOP_DATA" \
--out "$SAFELOOP_DATA/materialized"Run all pinned predictor stages:
python scripts/run_release_predictor_training.py \
--dataset-dir "$SAFELOOP_DATA" \
--data-root "$SAFELOOP_DATA/materialized" \
--model-dir "$QWEN_MODEL" \
--weights-dir "$SAFELOOP_WEIGHTS" \
--output-root "$SAFELOOP_OUTPUT"The staged recipe definitions and initialization checkpoints are in
configs/release/v56_predictor_training.json.
With the Pi0 policy server active:
python scripts/run_release_decider_training.py \
--model-dir "$QWEN_MODEL" \
--weights-dir "$SAFELOOP_WEIGHTS" \
--output-root "$SAFELOOP_OUTPUT" \
--libero-root "$PWD/third_party/LIBERO" \
--openpi-root "$OPENPI_ROOT" \
--checkpoint-dir "$PI0_CHECKPOINT_DIR" \
--policy-host 127.0.0.1 \
--policy-port 8000The reward terms, initialization checkpoint, task sequence, and optimizer
settings are stored in
configs/release/v56_decider_training.json.
python -m pytest -qIf you find SafeLoop useful, please cite:
@inproceedings{lou2026safeloop,
title = {SafeLoop: Risk-Aware Rollback for Vision-Language-Action Manipulation},
author = {Lou, Zeyu and Zhang, Tianran and Yue, Xinquan and Jing, Ya and Si, Chenyang},
booktitle = {2026 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
year = {2026}
}SafeLoop is released under the Apache License 2.0. The pinned LIBERO and OpenPI submodules retain their own licenses.
