Best practice to reduce real-time latency when syncing control loop with MuJoCo simulation #2578
-
IntroI am a graduate student at NTU working on low-latency control systems for legged robots. I use MuJoCo to simulate different control strategies in tight real-time loops. My setupMuJoCo 2.3.7 My questionMy question: I’m currently calling Questions:
Really appreciate any advice ! thankyou Minimal model and/or code that explain my questionWe are using a simplified quadruped model with 12 motors and IMU. Here is the control loop logic (simplified): while True:
mujoco.mj_step(model, data)
send_control(data.ctrl)
read_sensors(data.sensordata)
time.sleep(0.001) # simulate 1ms loop
The delay increases over time once contact dynamics become heavier.
### Confirmations
- [X] I searched the [latest documentation](https://mujoco.readthedocs.io/en/latest/overview.html) thoroughly before posting.
- [X] I searched previous [Issues](https://github.com/google-deepmind/mujoco/issues) and [Discussions](https://github.com/google-deepmind/mujoco/discussions), I am certain this has not been raised before. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Can you post the output of the included testspeed binary for your model? |
Beta Was this translation helpful? Give feedback.
-
I ran into a similar issue while simulating a custom bipedal robot with a 1kHz control loop. Here are a few things that helped me reduce latency significantly: I switched from # Thread 1: Physics
while running:
with lock:
mj_step1(model, data)
do_other_stuff()
with lock:
mj_step2(model, data)
# Thread 2: Control
while running:
with lock:
update_ctrl(data)
read_sensors(data)
time.sleep(0.001)
This way, physics and control run in parallel but synced safely via locking. Huge difference in responsiveness.
I also trimmed down the sensor list in the XML — MuJoCo was computing some we didn’t need (like full contact forces). Removing those saved me a few ms per step.
Another trick: try switching to sparse solvers (mj_option.impratio = 1 + reduced solver iterations). Not always stable, but worth trying for speed.
Lastly, monitor your mjData.timer values — they give a good breakdown of where time is being spent during mj_step.
Hope some of this can help |
Beta Was this translation helpful? Give feedback.
I ran into a similar issue while simulating a custom bipedal robot with a 1kHz control loop. Here are a few things that helped me reduce latency significantly:
I switched from
mj_step()
to usingmj_step1()
andmj_step2()
in a split-thread setup. That allowed us to send controls and read sensors with finer control over the timing. Basically: