Part III · The Robotics Side
15.Simulation & the Sim-to-Real Bridge
“More mature solutions have often followed the zero-shot sim-to-real transfer scheme, which works particularly well for locomotion and navigation — the dynamics involved are relatively stable and easy to simulate.”
Chapter 14 named two curses that pull against each other: real samples are expensive, and simulation is wrong. This chapter is about the resolution that produced nearly every L4 result in the field — train in a simulator you know to be wrong, but train across a distribution of wrong simulators wide enough that reality is one of them. We derive why that works, build the system identification that narrows the distribution, and construct the teacher–student scheme that lets a policy use information at training time it will never have at deployment. Ferris arrives.
Foundation
Integrator stability bounds, the contact LCP with friction cones, domain randomization as distributional robustness, CMA-ES system identification, asymmetric actor–critic unbiasedness, and the teacher–student KL objective.
Conceptual
The randomization wall: watch a narrow policy's perfect peak collapse into a broad, lower, shippable competence curve.
Practical
rl-sim's parameterized rapier environments with randomization hooks, a rayon rollout farm, and CMA-ES parameter fitting.
After this chapter you can
- Explain why explicit integrators go unstable and how the step size bound relates to system stiffness
- Describe what a contact solver actually computes and why contact is where simulators diverge from reality
- Formulate domain randomization as a distributionally-robust objective and explain the peak/robustness trade
- Use system identification to fit simulator parameters to logged real data
- Explain the asymmetric actor–critic and why privileged information is safe for the critic but not the actor
- Construct a teacher–student pipeline and say why distillation beats training the student directly
15.1 What a physics engine actually does
A simulator advances rigid-body state by integrating Newton–Euler dynamics subject to constraints. Three components decide its fidelity, and each is a place where reality departs.
The integrator. Chapter 2 showed explicit Euler manufacturing energy on Pendle. The stability condition for an explicit scheme is roughly , where is the fastest eigenvalue of the linearized dynamics. Stiff systems — high-gain contacts, rigid transmissions — have enormous , forcing tiny steps. Simulators therefore use semi-implicit or fully implicit schemes, which add artificial damping: stable, and systematically wrong in a direction that makes simulated robots feel more sluggish than real ones.
The constraint solver. Joints and contacts are constraints, resolved by solving a system each step. Most engines use iterative solvers with a fixed iteration budget, so constraints are satisfied approximately. Insufficient iterations produce visible artifacts: joints that stretch, stacked objects that sink.
Contact. This is the hard one. Non-penetration and Coulomb friction together form a complementarity problem: either the bodies are separated and the normal force is zero, or they touch and the force is non-negative — and the friction force lies inside a cone whose size depends on the normal force. Written as an LCP,
where are normal and tangential impulses. Exact solutions are expensive, so engines approximate — linearizing the friction cone into a pyramid, softening the complementarity with regularization parameters (erp, cfm and their relatives).
15.2 Meet Ferris
Ferris is a quadruped: four legs, three actuated joints each, twelve degrees of freedom. His state includes base position and orientation, base linear and angular velocity, joint positions and velocities — 36 numbers before any terrain sensing.
Ferris is the right robot for this chapter because he is the archetype of the field's clearest success. Quadruped locomotion reached commercial deployment through exactly the pipeline built here, and the reasons are worth naming: his dynamics are dominated by rigid-body motion, his contacts are intermittent and roughly point-like (much easier than the sustained sliding contact of manipulation), and a fall is recoverable rather than catastrophic.
His low-level control is a PD controller at each joint, following position targets:
The policy outputs at 50 Hz; the PD loop runs at 1 kHz. That choice is itself a piece of design — Chapter 17 examines why almost everyone makes it — and it means the policy commands positions, not torques, with the PD gains absorbing a great deal of high-frequency dynamics the policy would otherwise have to learn.
15.3 Domain randomization
Here is the central idea, and it is counterintuitive at first: do not try to build one accurate simulator. Build a distribution of inaccurate ones, and train a policy that works across all of them.
Formally, let parameterize the simulator — masses, friction coefficients, motor gains, latencies, sensor noise — with . Train
If the real robot's parameters lie within the support of , a policy that performs well in expectation over should perform acceptably at — without ever having seen it. That is zero-shot transfer.
Domain randomization: buying the worst case
ch15-randomization-wallTwo computed-torque policies found by policy search — one trained at the nominal mass only, one across a randomized range — then evaluated on masses neither has seen.
Randomized, on the real robot
0
at m = 1.35 kg
Nominal-only, on the real robot
0
trained at m = 1.00 exactly
Worst case — randomized
0
min over the whole grid
Worst case — nominal
0
the number that would ship
Assumed mass — nominal-only
0kg
what that policy thinks it is holding
Assumed mass — randomized
0kg
hedged upward as insurance
The trade is visible in the widget and worth stating plainly: you buy robustness by giving up peak performance. A policy trained at one friction value is superb at exactly that value and useless a little away from it. A broadly randomized policy is merely good everywhere. Since you cannot measure the real value precisely, merely-good-everywhere is what ships.
What to randomize on Ferris: link masses and inertias (±20%), friction coefficients (0.4–1.2), motor gains and strength (±30%), actuation latency (0–30 ms), sensor noise and bias, external pushes, and terrain geometry. What not to randomize: things you can measure precisely, like link lengths from CAD. Randomizing those wastes capacity on uncertainty you do not have.
15.4 System identification: narrow the distribution
Randomization is expensive in policy capacity — the wider , the more conservative the policy. So narrow it where you can, by fitting simulator parameters to real data.
Collect trajectories from the real robot, then solve
over the parameters you care about. The objective is non-convex, non-differentiable through the simulator, and low-dimensional — which makes it ideal for CMA-ES, an evolutionary strategy that maintains a Gaussian over parameters and adapts its covariance to the local landscape.
The practical pipeline is: identify what you can, randomize around the residual uncertainty, and use the identification's own uncertainty to set the randomization width. That is more principled than choosing ±20% because it sounds reasonable.
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use rayon::prelude::*;
/// Everything the simulator lets us vary — one draw per episode.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct DomainParams {
pub mass_scale: [f64; 13], // base + 12 links
pub friction: f64,
pub motor_kp: f64,
pub motor_kd: f64,
pub latency_steps: usize,
pub terrain_roughness: f64,
}
#[derive(Clone)]
pub struct RandomizationRanges {
pub mass_scale: (f64, f64),
pub friction: (f64, f64),
pub motor_kp: (f64, f64),
pub latency_steps: (usize, usize),
pub terrain_roughness: (f64, f64),
}
impl RandomizationRanges {
pub fn sample<R: Rng>(&self, rng: &mut R) -> DomainParams {
DomainParams {
mass_scale: std::array::from_fn(|_| {
rng.gen_range(self.mass_scale.0..=self.mass_scale.1)
}),
friction: rng.gen_range(self.friction.0..=self.friction.1),
motor_kp: rng.gen_range(self.motor_kp.0..=self.motor_kp.1),
motor_kd: rng.gen_range(0.5..=2.0),
latency_steps: rng.gen_range(self.latency_steps.0..=self.latency_steps.1),
terrain_roughness: rng.gen_range(
self.terrain_roughness.0..=self.terrain_roughness.1
),
}
}
}
/// Collect rollouts across many randomized worlds in parallel.
/// Each worker derives its stream from the run seed, so results reproduce
/// exactly regardless of how many cores are available.
pub fn parallel_rollouts(
policy: &Policy,
ranges: &RandomizationRanges,
n_envs: usize,
horizon: usize,
seed: u64,
) -> Vec<Episode> {
(0..n_envs)
.into_par_iter()
.map(|i| {
let mut rng = ChaCha8Rng::seed_from_u64(seed.wrapping_add(i as u64));
let params = ranges.sample(&mut rng);
let mut env = FerrisEnv::with_params(params);
env.rollout(policy, horizon, &mut rng)
})
.collect()
}15.5 Privileged information: asymmetric actors and teacher–student
Here is the observation that unlocked rough-terrain locomotion.
In simulation you know everything: exact contact forces, the true friction coefficient, terrain height beneath every foot, the robot's precise velocity. On hardware you know almost none of it. The naive response is to train only on what the robot will have, which throws away information that would make training far easier.
Asymmetric actor–critic exploits the asymmetry. The critic sees privileged state ; the actor sees only deployable observations . This is legitimate: the critic is a training-time device that is discarded at deployment, and giving it privileged information reduces its variance without biasing the policy gradient — the gradient's correctness depends on the actor's conditioning, not the critic's.
Teacher–student distillation goes further, and is the ANYmal recipe:
- Train a teacher with full privileged access — terrain map, friction, contact states. This policy learns quickly because the problem is nearly fully observed.
- Train a student that sees only real sensors (joint encoders, IMU, and a short history), by supervised imitation of the teacher's actions:
- Deploy the student.
15.6 Zero-shot or few-shot? A decision procedure
Tang's survey gives an empirical answer, and it is worth stating as a procedure.
Zero-shot transfer — train entirely in simulation, deploy without adaptation — works when the dominant dynamics simulate faithfully. That means locomotion, navigation, and flight. These are the L4 results.
Few-shot adaptation — fine-tune with a small amount of real data — is needed when simulation captures the structure but not the details: contact-rich assembly, deformable objects, anything where friction and compliance decide the outcome.
Real-world learning without simulation is necessary when there is no usable simulator at all: physical human–robot interaction, where the human is the unmodelable part. These results sit at L1–L2, and Chapter 16's offline methods are the main tool.
The decision rule: ask what fraction of your task's difficulty lies in phenomena your simulator represents faithfully. Locomotion is mostly rigid-body dynamics — simulate it. Cloth manipulation is mostly deformation — do not expect zero-shot to work.
15.7 Chapter bridge
The sim-to-real bridge is built. Randomize what you cannot measure, identify what you can, use privileged information at training time and distill it away for deployment, and choose zero-shot or few-shot by asking what your simulator actually gets right.
But some tasks have no usable simulator, and some have no writable reward. When the human is part of the environment, or when the task is easier to show than to specify, a different source of information is needed.
Chapter 16 turns to demonstrations. We prove why naive imitation fails in a way supervised learning does not — errors compound quadratically in the horizon — build the correction, and then develop offline RL: learning good policies from a fixed dataset without any environment interaction at all. It is the closest thing robot learning has to the pretraining paradigm that transformed the rest of machine learning.
- 01Foundation●●●Integrator stability
Derive the stability bound Δt ≤ 2/|λ| for explicit Euler on the linear system ẋ = λx. Then estimate λ_max for a joint with PD gains Kp = 100, Kd = 5 and inertia 0.1, and state the maximum stable step size.
- 02Foundation●●●The friction cone
Write the contact complementarity conditions for a single point contact with Coulomb friction. Explain what is lost when the friction cone is linearized into a pyramid, and in which direction the approximation errs.
- 03Foundation●●●Randomization as robust optimization
Show that maximizing E_ξ[J_ξ] under an exponentially tilted distribution corresponds to a soft-min over ξ with a KL penalty. What does the tilting temperature correspond to in the robust-optimization picture?
- 04Foundation●●●Why the critic may cheat
Prove that the policy gradient remains unbiased when the critic is conditioned on privileged state unavailable to the actor. Then explain precisely why the same is not true if the ACTOR is conditioned on it.
- 05Conceptual●●●The randomization frontier
In the randomization widget, find the range that maximizes worst-case performance over friction ∈ [0.7, 1.6]. Compare against the range that maximizes performance at the nominal value. They will differ — explain which one you would deploy.
- 06Conceptual●●●Crank the step size
Return to Chapter 2’s integrator playground and find the Δt at which each integrator destabilizes. Then argue what the equivalent failure looks like for a quadruped’s contact solver.
- 07Practical●●●System identification with CMA-ES
Generate "real" trajectories from a Ferris simulation with hidden parameters, then recover them with CMA-ES from logged data. Investigate which parameters are identifiable from a standing trajectory versus a trotting one, and explain the difference in terms of excitation.
- 08Practical●●●Measure the transfer gap
Train two Reacher policies — one at nominal parameters, one with ±25% randomization — then evaluate both across a grid of held-out "real" parameter values. Plot both surfaces and report the worst case for each. The narrow policy should win at nominal and lose everywhere else.
References
Baseline references
- Kober, J., Bagnell, J. A. & Peters, J. (2013). Reinforcement Learning in Robotics: A Survey. International Journal of Robotics Research 32(11)§6.1 core issues in mental rehearsal, and §7.5 on the use of simulation in robot RL — the pre-deep-learning statement of this chapter’s problem.
- Tang, C. et al. (2024). Deep Reinforcement Learning for Robotics: A Survey of Real-World Successes. Annual Review of Control, Robotics, and Autonomous Systems link§3.3 simulator-usage axis, and §5 — the empirical basis for the zero-shot/few-shot decision procedure in §15.6.
Further reading & modern sources
- Tobin, J., Fong, R., Ray, A., Schneider, J., Zaremba, W. & Abbeel, P. (2017). Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World. IROS 2017The visual randomization result that named the technique.
- Peng, X. B., Andrychowicz, M., Zaremba, W. & Abbeel, P. (2018). Sim-to-Real Transfer of Robotic Control with Dynamics Randomization. ICRA 2018Dynamics randomization with recurrent policies — the implicit system identification of §15.3.
- Hwangbo, J. et al. (2019). Learning agile and dynamic motor skills for legged robots. Science Robotics 4(26)Learned actuator models — identifying the part of the robot the rigid-body simulator gets most wrong.
- Lee, J., Hwangbo, J., Wellhausen, L., Koltun, V. & Hutter, M. (2020). Learning quadrupedal locomotion over challenging terrain. Science Robotics 5(47)The teacher–student pipeline of §15.5, in the form this chapter reconstructs.
- Kumar, A., Fu, Z., Pathak, D. & Malik, J. (2021). RMA: Rapid Motor Adaptation for Legged Robots. RSS 2021Explicit latent estimation of the dynamics parameters — making implicit system identification a designed component.
- Pinto, L., Andrychowicz, M., Welinder, P., Zaremba, W. & Abbeel, P. (2018). Asymmetric Actor Critic for Image-Based Robot Learning. RSS 2018The privileged-critic construction and its unbiasedness argument.
- Hansen, N. (2016). The CMA Evolution Strategy: A Tutorial. arXiv:1604.00772 linkCMA-ES, used here for system identification and in Chapter 17 for policy search over movement-primitive weights.
