- MuJoCo simulation (
mj_step()
) does not guarantee real-time execution. - Unreal Engine renders frames at real-time pace (e.g., 60fps).
- Without adjustment, the visualized motion in Unreal won't match real-world timing.
- If MuJoCo is faster or slower, we must scale Unreal’s time to match it.
Concept | Description |
---|---|
timestep (mjModel.opt.timestep ) |
Simulation step size in seconds (e.g., 0.002 = 500Hz). |
simulated_time |
MuJoCo internal clock (mjData.time ). |
real_time_passed |
Real-world clock elapsed time. |
simulation_speed |
Ratio of MuJoCo simulated time to real-world time.simulation_speed = simulated_time / real_time_passed |
Goal: Keep
simulation_speed ≈ 1.0
for realistic visualization.
- Choose
mjModel.opt.timestep
based on your robot’s control loop frequency. - Recommended:
0.001
(1kHz) or0.002
(500Hz).
Example:
model.opt.timestep = 0.002; // 500Hz
Track two times:
- MuJoCo Time:
mjData.time
- Real Clock Time: Use high-res system timer (e.g.,
std::chrono::steady_clock
).
Calculate each frame:
simulation_speed = (mjData.time - mjDataStart) / (realTimeNow - realTimeStart)
Interpretation:
simulation_speed > 1.0
→ MuJoCo is faster than real-time → Speed up Unreal.simulation_speed < 1.0
→ MuJoCo is slower than real-time → Slow down Unreal.
Use Unreal’s Global Time Dilation to sync:
UGameplayStatics::SetGlobalTimeDilation(GetWorld(), simulation_speed);
MuJoCo Speed | Unreal Time Dilation |
---|---|
2.0x faster | 2.0 |
0.5x slower | 0.5 |
- Unreal runs at ~60fps.
- MuJoCo might need multiple steps per Unreal frame.
- Example: if MuJoCo timestep = 0.002s (500Hz), and Unreal is 60fps:
0.002s * 8 steps = 0.016s
→ matches ~60Hz frame time.
Typical Unreal frame update:
for (int i = 0; i < numMuJoCoStepsPerFrame; ++i)
mj_step(model, data);
| Parameter