Getting Started

A research platform for training and deploying manipulation policies on the AR4 6-DOF robot arm.

Built on ROS 2 Jazzy, Gazebo Harmonic, MoveIt2, and LeRobot — the full pipeline runs in Docker so you don't need a local ROS install.

The general workflow is:

Record episodes → Train SmolVLA → Run inference → Repeat

Quick Start

New here? This is the full pipeline in five commands. All commands must be run from inside the ar4-physical-ai/ folder — open a terminal, cd ar4-physical-ai, and keep that terminal open.

StepCommandNotes
1. Build imagesdocker compose buildFirst time only — takes ~20–30 min
2. Start simulationdocker compose --profile sim upOpens Gazebo + RViz2. Wait for "MoveIt Servo ready" in logs
3. Collect episodesdocker compose run --rm recordNew terminal — arm moves to home, then you drive it
4. Train SmolVLASee Train SmolVLANeeds a GPU
5. Run policydocker compose run --rm smolvlaNew terminal — arm runs autonomously

The detailed steps for each stage are in the workflows below.


Table of Contents

  1. Prerequisites
  2. Installation
  3. Docker Services Overview
  4. Workflows
  5. Visualizing with Foxglove
  6. VS Code Dev Container
  7. Packages
  8. Updating the Driver Submodule
  9. Related Projects

Prerequisites

  • Docker with NVIDIA GPU support — install nvidia-container-toolkit
  • X11 display for the Gazebo GUI — if you get a permission error, run xhost +local:docker once in your terminal before starting
  • Xbox One (or compatible) controller — USB or Bluetooth; plug it into any USB port, it is detected automatically
  • ROS 2 Jazzy on your host machine — only needed if you want to use rqt_image_view to preview the wrist camera. If you don't have it, Foxglove works without any local ROS install

Installation

# Clone with submodules (the AR4 ROS driver lives under vendor/)
git clone --recurse-submodules https://github.com/aegean-ai/ar4-physical-ai.git
cd ar4-physical-ai
 
# Build all Docker images (base → overlay → dev)
# This takes a while the first time — grab a coffee
docker compose build

Forgot --recurse-submodules? Run git submodule update --init --recursive to fix it.

Important: Every docker compose command in this README must be run from inside the ar4-physical-ai/ folder. If you open a new terminal, cd back into the repo first:

cd ar4-physical-ai
docker compose --profile sim up

Docker Services Overview

Every runtime service belongs to a profile, so you always say which stack you want. A bare docker compose up starts nothing. That is deliberate: a --profile flag adds to the profile-less services rather than replacing them, so when the simulation had no profile, --profile hardware up booted Gazebo alongside the real arm and the two sets of /joint_states collided.

Three profiles match the three things this repo does.

CommandWhat it starts
docker compose --profile sim upGazebo GUI + MoveIt2 + RViz2 (simulation)
docker compose --profile dataset up -dThe above plus the Zenoh router and bridge, for episode recording
docker compose --profile infer-server up -dSmolVLA policy server (run this on the GPU box)

The rest are role profiles you combine with those, or one-shot services you launch by name.

CommandWhat it starts
docker compose --profile hardware up hardware moveit-hardwareReal AR4 driver + MoveIt2
docker compose --profile headless up sim-tabletop-headlessGazebo without a display (for servers / CI)
docker compose --profile obs up foxglove-bridgeFoxglove WebSocket bridge
docker compose run --rm recordXbox teleop + LeRobot recorder
docker compose run --rm smolvlaSmolVLA policy inference
docker compose run demoC++ pick-and-place demo

Naming a service explicitly activates its profile for you, so docker compose up sim-tabletop moveit still works without a --profile flag.

Model training is not a compose profile. It is a one-shot job with per-run names and hyperparameters, which compose's one-container-per-service model works against, so it stays in scripts/train_local.sh and scripts/train_remote.sh.

Services that run with docker compose run are one-shot interactive containers — they start, do their job, and exit cleanly on Ctrl-C. The simulation (up) stays running in the background while you use them.

Stopping everything

./scripts/down.sh

Use this rather than docker compose down, which only considers the profiles active for that one invocation and walks silently past the rest. It exits 0 while leaving containers running.


Workflows

Visualizing with Foxglove

Foxglove Studio lets you visualize all ROS 2 topics (camera feed, joint states, TF tree, etc.) in a browser — no ROS install needed on your machine.

# Start the WebSocket bridge alongside the sim
docker compose --profile sim up -d
docker compose --profile obs up foxglove-bridge

Then open app.foxglove.dev, click Open connection, choose WebSocket, and enter:

ws://localhost:8765

VS Code Dev Container

The dev service mounts the source code and colcon build artifacts so you can edit and rebuild without rebuilding the Docker image.

Open this folder in VS Code and choose "Reopen in Container" — it uses .devcontainer/devcontainer.json which points at the dev service.

You can also start it manually:

docker compose --profile dev up dev
docker exec -it ar4-physical-ai-dev-1 bash

Packages

This project

PackageDescription
ar4_msgsCustom ROS 2 interfaces (PolicyAction, EpisodeStep, SetTask, ExecuteSkill)
ar4_teleopXbox gamepad teleop + LeRobot episode recorder node
ar4_policy_serverSmolVLA inference backend (local + remote HTTP)
ar4_moveit_cpp_demoSimple C++ pick-and-place demo using MoveIt

LeRobot ecosystem (pip-installed)

PackageDescription
lerobotRecording, training, and inference framework
lerobot-rosROS 2 bridge — makes AR4 appear as a native LeRobot robot

AR4 ROS Driver (git submodule under vendor/ar4_ros_driver/)

PackageDescription
annin_ar4_descriptionURDF/Xacro robot model and meshes
annin_ar4_driverHardware interface for Teensy, ros2_control integration
annin_ar4_firmwareTeensy and Arduino Nano firmware sketches
annin_ar4_gazeboGazebo Harmonic simulation
annin_ar4_moveit_configMoveIt2 motion planning configuration

Repository layout

ar4_msgs/              Custom ROS 2 interfaces
ar4_teleop/            Gamepad teleop + scripted MoveIt recorder (moveit_record_node)
ar4_lerobot/           Decoupled numpy-2 LeRobot recorder (camera/joints over Zenoh)
ar4_policy_server/     SmolVLA inference backend + ROS bridge (inference_node)
ar4_episodes/          Episode config, recording, export, replay helpers
ar4_skills/            Behavior-tree skills and tuning
ar4_rerun/             Decoupled Zenoh → Rerun visualisation recorder
ar4_moveit_cpp_demo/   C++ pick-and-place demo using MoveIt
gs/                    Language-grounded 3D Gaussian-splatting pipeline
gpu-server/            Remote train/infer server assets (ar4-train, ar4-infer)
configs/               Training configs (e.g. smolvla_ar4.yaml)
scripts/               Dataset push, local/remote train, mesh generation
docker/                Dockerfile.gpu (multi-stage), entrypoint.sh, cyclonedds.xml
zenoh/                 Zenoh router config, CycloneDDS bridge config
data/                  Local data store (gitignored)
docs/                  Documentation content (MDX)
docs-site/             Fumadocs / Next.js documentation site
vendor/ar4_ros_driver/ Git submodule — upstream AR4 ROS driver

Datasets are recorded in LeRobot v3.0 format (Parquet + MP4) and pushed to Hugging Face Hub or Cloudflare R2; both the human teleop and scripted-expert recorders write the same image/state/action schema (realised joint positions as action).


Updating the Driver Submodule

To pull in upstream AR4 driver fixes:

git submodule update --remote vendor/ar4_ros_driver
git add vendor/ar4_ros_driver
git commit -m "chore: update ar4_ros_driver submodule"
docker compose build  # rebuild images to include the new driver

Documentation

This documentation site is built with Fumadocs (Next.js); the content lives in docs/ and this page is its homepage. To run it locally:

cd docs-site
npm install
npm run dev            # serves at http://localhost:3000

Other commands (from docs-site/):

npm run build          # static export to docs-site/out/
npm start              # serve the production build


License

MIT License — see LICENSE.

The AR4 ROS Driver submodule is also MIT licensed (Copyright © 2021 Dexter Ong).