This is a fork of google-deepmind/mujoco_mpc. Everything below the divider is DeepMind's original README, unchanged. This section describes what I added on the
mjx_hexapodbranch.
A physically faithful simulation of a HiWonder miniHexa hexapod — a small 18-DOF six-legged robot — built inside MuJoCo MPC, walking to an interactively-placed goal under real-time model-predictive control, then ported to MuJoCo's JAX backend (MJX) to train a reinforcement-learning policy small enough to eventually run on the robot's 240 MHz ESP32.
26 commits of first-party work, May–July 2026, solo. The full write-up is
mjpc/tasks/hexapod/PROJECT_PROGRESS.md —
seven phases, the problem each was solving, and what came out of it.

Faceplant — The failure only appeared once the controller stopped receiving perfect state, which is exactly the class of bug that otherwise waits until the code is on hardware.

Working — rotates to face the goal, walks to it in a tripod gait, stands on arrival.
The training run that lied. A 1000-iteration overnight PPO run finished with mean reward trending up in the console tail. The full TensorBoard history showed mean episode length collapsing from ~280 steps to ~36 — the policy was getting better at walking and better at ending the episode as fast as possible. The five tracking terms had been ported straight out of the C++ MPC residual as unbounded quadratic costs, which is correct for MPC (fixed horizon, never terminates) and inverts the objective under RL: at a measured per-step reward of −1.3 to −2.1 against an alive bonus of 0.1, surviving one more step is strictly worse than dying. Nothing was syntactically wrong — the JAX gait template had already been unit-tested against a standalone C++ extraction of the same maths and agreed to 2.8 × 10⁻¹⁵. The port was correct and the semantics were not. Phase 7 →
The symptom rarely names the layer. Getting it to walk at all was four distinct failure
classes, and only one was the cost function: a chirality bug in the hip-yaw targets, a
genuinely mis-specified objective, a yaw gain fighting another controller, and — the reason
none of the earlier fixes quite worked — MuJoCo's xmat storing body axes as columns, not
rows, so the body-forward direction the whole steering stack was built on was wrong except
by coincidence. Every one of these would have got worse by reaching for the nearest knob.
Phase 2 →
Measure, don't assume. The yaw-tracking reward looked like a weight worth retuning. An
open-loop sweep with the learned residual disabled — measuring what the hand-designed gait
can physically do — found instead a sign inversion at the MPC↔RL seam (invisible to every
test on either side of it) and a command range uncalibrated by 25–40×: ±1.5 rad/s commanded
produced ±0.06 rad/s sustained. The policy had spent 1000 iterations being graded against a
target it could not reach. Same pattern as the actuator-gain sweep in
validation.md, where the obvious
conclusion — weak actuators — was wrong, and the ~8 mm standing sag turned out to be
foot-contact softness.
| MPC task (C++) | mjpc/tasks/hexapod/ — hexapod.cc/.h, hexapod.xml, task_flat.xml, task_obstacles.xml |
| MJX/RL environment | python/mujoco_mpc/mjx/tasks/hexapod/ — env.py, trajectory_generator.py, train_rsl_rl.py |
| Validation | validation.md — an 11-step ladder, each step gating the next |
| Sensor modelling | IMU_SIMULATION.md, LIDAR_SIMULATION.md |
| RL design docs | rl_*.md — written before implementation, ~1,590 lines |
| Build & run | mjpc/tasks/hexapod/readme.md |
./build/bin/mjpc --task="Hexapod Flat"Status. The MPC task works. The RL policy does not yet — the first training run was
reward-hacked, the cause is fixed and verified, and a re-train against the retained baseline
is the next step. Reward weights and PPO hyperparameters are first-pass values inherited from
mujoco_playground's Go1 configuration and are labelled as such in the code; domain
randomisation is designed but deliberately deferred pending real servo and IMU noise specs.
Third-party credit. The manufacturer's firmware and documentation are HiWonder's copyright
and are not redistributed here; mjpc/tasks/hexapod/scripts/pdf_to_md.py is the converter used
to make them searchable locally. The attitude filter in hexapod.cc is not mine — it is
Sebastian O. H. Madgwick's (paper,
2010), transliterated from the Arduino port
the firmware vendors, and it carries GPL/LGPL-2.1 terms rather than this repo's Apache-2.0.
Provenance, the reproduced extent, and where my version deviates are documented in
IMU_SIMULATION.md and in the
attribution block above the function.
MuJoCo MPC (MJPC) is an interactive application and software framework for real-time predictive control with MuJoCo, developed by Google DeepMind.
MJPC allows the user to easily author and solve complex robotics tasks, and currently supports multiple shooting-based planners. Derivative-based methods include iLQG and Gradient Descent, while derivative-free methods include a simple yet very competitive planner called Predictive Sampling.
- Overview
- Graphical User Interface
- Installation
- Predictive Control
- Contributing
- Known Issues
- Citation
- Acknowledgments
- License and Disclaimer
To read the paper describing this software package, please see our preprint.
For a quick video overview of MJPC, click below.
For a longer talk at the MIT Robotics Seminar in December 2022 describing our results, click below.
A more recent, December 2023 talk at the IEEE Technical Committee on Model-Based Optimization is available here:
Quadruped task:
Bimanual manipulation:
Rubik's cube 10-move unscramble:
Humanoid motion-capture tracking:
For a detailed dive of the graphical user interface, see the MJPC GUI documentation.
MJPC is tested with Ubuntu 20.04 and macOS-12. In principle, other versions and Windows operating system should work with MJPC, but these are not tested.
Operating system specific dependencies:
Install Xcode.
Install ninja and zlib:
brew install ninja zlibsudo apt-get update && sudo apt-get install cmake libgl1-mesa-dev libxinerama-dev libxcursor-dev libxrandr-dev libxi-dev ninja-build zlib1g-dev clang-12git clone https://github.com/google-deepmind/mujoco_mpc- Change directory:
cd mujoco_mpc- Create and change to build directory:
mkdir build
cd build- Configure:
cmake .. -DCMAKE_BUILD_TYPE:STRING=Release -G Ninja -DMJPC_BUILD_GRPC_SERVICE:BOOL=ONcmake .. -DCMAKE_BUILD_TYPE:STRING=Release -G Ninja -DCMAKE_C_COMPILER:STRING=clang-12 -DCMAKE_CXX_COMPILER:STRING=clang++-12 -DMJPC_BUILD_GRPC_SERVICE:BOOL=ONNote: gRPC is a large dependency and can take 10-20 minutes to initially download.
- Build
cmake --build . --config=Release- Run GUI application
cd bin
./mjpcWe recommend using VSCode and 2 of its extensions (CMake Tools and C/C++) to simplify the build process.
- Open the cloned directory
mujoco_mpc. - Configure the project with CMake (a pop-up should appear in VSCode)
- Set compiler to
clang-12. - Build and run the
mjpctarget in "release" mode (VSCode defaults to "debug"). This will open and run the graphical user interface.
If you encounter build issues, please see the Github Actions configuration. This provides the exact setup we use for building MJPC for testing with Ubuntu 20.04 and macOS-12.
We provide a simple Python API for MJPC. This API is still experimental and expects some more experience from its users. For example, the correct usage requires that the model (defined in Python) and the MJPC task (i.e., the residual and transition functions defined in C++) are compatible with each other. Currently, the Python API does not provide any particular error handling for verifying this compatibility and may be difficult to debug without more in-depth knowledge about MuJoCo and MJPC.
-
Build MJPC (see instructions above).
-
Python 3.10
-
(Optionally) Create a conda environment with Python 3.10:
conda create -n mjpc python=3.10
conda activate mjpc- Install MuJoCo
pip install mujocoNext, change to the python directory:
cd pythonInstall the Python module:
python setup.py installTest that installation was successful:
python "mujoco_mpc/agent_test.py"Example scripts are found in python/mujoco_mpc/demos. For example from python/:
python mujoco_mpc/demos/agent/cartpole_gui.pywill run the MJPC GUI application using MuJoCo's passive viewer via Python.
If your installation fails or is terminated prematurely, we recommend deleting the MJPC build directory and starting from scratch as the build will likely be corrupted. Additionally, delete the files generated during the installation process from the python/ directory.
See the Predictive Control documentation for more information.
See the Contributing documentation for more information.
MJPC is not production-quality software, it is a research prototype. There are likely to be missing features and outright bugs. If you find any, please report them in the issue tracker. Below we list some known issues, including items that we are actively working on.
- We have not tested MJPC on Windows, but there should be no issues in principle.
- Task specification, in particular the setting of norms and their parameters in XML, is a bit clunky. We are still iterating on the design.
- The Gradient Descent search step is proportional to the scale of the cost function and requires per-task tuning in order to work well. This is not a bug but a property of vanilla gradient descent. It might be possible to ameliorate this with some sort of gradient normalisation, but we have not investigated this thoroughly.
If you use MJPC in your work, please cite our accompanying preprint:
@article{howell2022,
title={{Predictive Sampling: Real-time Behaviour Synthesis with MuJoCo}},
author={Howell, Taylor and Gileadi, Nimrod and Tunyasuvunakool, Saran and Zakka, Kevin and Erez, Tom and Tassa, Yuval},
archivePrefix={arXiv},
eprint={2212.00541},
primaryClass={cs.RO},
url={https://arxiv.org/abs/2212.00541},
doi={10.48550/arXiv.2212.00541},
year={2022},
month={dec}
}The main effort required to make this repository publicly available was undertaken by Taylor Howell and the Google DeepMind Robotics Simulation team.
All other content is Copyright 2022 DeepMind Technologies Limited and licensed under the Apache License, Version 2.0. A copy of this license is provided in the top-level LICENSE file in this repository. You can also obtain it from https://www.apache.org/licenses/LICENSE-2.0.
This is not an officially supported Google product.








