Sim2Real Quick Start Guide¶
Train a navigation policy in simulation. Deploy on real hardware. Zero code changes.
Prerequisites¶
| Requirement | For Simulation | For Real Hardware |
|---|---|---|
| Python 3.10+ | Required | Required |
threewe[sim] |
Required | Required |
stable-baselines3 |
Required | Required |
| ROS2 Jazzy | Not needed | Required |
| Physical robot | Not needed | Required |
Installation¶
Step 1: Train in Simulation¶
from threewe import Robot
import threewe.gym # registers 3we/* Gymnasium environments
import gymnasium
from stable_baselines3 import PPO
# Create environment — runs entirely in simulation
env = gymnasium.make("3we/Navigation-v1", max_steps=500)
# Train PPO for 50k steps (~2 minutes)
model = PPO("MultiInputPolicy", env, verbose=1)
model.learn(total_timesteps=50_000)
model.save("nav_ppo")
Step 2: Evaluate in Simulation¶
import asyncio
from threewe import Robot
async def evaluate(backend="gazebo"):
async with Robot(backend=backend) as robot:
pose = robot.get_pose()
print(f"Start: ({pose.x:.2f}, {pose.y:.2f})")
result = await robot.move_to(x=2.0, y=1.5)
print(f"Reached: ({result.final_pose.x:.2f}, {result.final_pose.y:.2f})")
print(f"Success: {result.success}")
asyncio.run(evaluate("gazebo"))
Step 3: Deploy on Real Hardware¶
That's it. No retraining. No fine-tuning. No code modification.
One-Click Script¶
For the complete experience (train + evaluate + compare):
# Simulation only
./examples/sim2real_demo/reproduce.sh
# Simulation + real hardware comparison
./examples/sim2real_demo/reproduce.sh --real
Understanding the Results¶
The script outputs a comparison table:
Sim path length: 2.634m (52 steps)
Real path length: 2.891m (58 steps)
Endpoint error: 0.043m
Transfer ratio: 1.10
| Metric | Good | Acceptable | Investigate |
|---|---|---|---|
| Endpoint error | < 0.1m | < 0.3m | > 0.3m |
| Transfer ratio | 0.8–1.2 | 0.6–1.5 | < 0.6 or > 1.5 |
| Path length ratio | ~1.0 | 0.7–1.3 | varies widely |
A transfer ratio of 1.0 means simulation and real-world behavior are identical. Values near 1.0 indicate strong Sim2Real transfer.
Advanced: Domain Randomization¶
To improve transfer robustness, enable domain randomization during training:
from threewe.sim.domain_randomization import DomainRandomization
dr = DomainRandomization()
# Each episode samples different physics/sensor parameters
params = dr.sample()
# params includes: mass_scale, friction_scale, lidar_noise_scale, etc.
Advanced: Quantitative Validation¶
Use the built-in Sim2Real benchmark for rigorous transfer testing:
from threewe.benchmark.sim2real import STANDARD_TRANSFER_TESTS, evaluate_transfer
# 5 standard transfer tests with pass/fail criteria
for test in STANDARD_TRANSFER_TESTS:
print(f"{test.name}: {test.metric.value} (multiplier: {test.pass_multiplier})")
Run the full validation suite:
Troubleshooting¶
| Issue | Cause | Fix |
|---|---|---|
| Robot doesn't move | robot_bringup not running |
ros2 launch robot_bringup robot.launch.py |
| Large endpoint error | Wheel slip on surface | Enable domain randomization during training |
| Timeout on real hardware | Nav2 not configured | Check ros2 topic list for /cmd_vel |
| Import error | Missing dependencies | pip install threewe[sim] stable-baselines3 |
Video Recording Tips¶
For creating a side-by-side demonstration video:
- Run simulation in one terminal, record Gazebo window
- Run real hardware, record robot with fixed camera
- Overlay terminal output showing the code (highlight
backend=parameter) - Use OBS Studio with side-by-side scene layout
- Add LiDAR point cloud visualization via RViz2 as picture-in-picture