Tutorials 3 min read
Getting Started with ROS 2 for Humanoid Robotics
A practical guide to setting up ROS 2 Jazzy for humanoid robot simulation — from installation to your first walking controller in MuJoCo.
M
med Developer and robotics enthusiast tracking the open source humanoid robot ecosystem.
ROS 2 has become the de facto middleware for humanoid robotics research. This guide gets you from zero to a simulated biped in MuJoCo as efficiently as possible.
Prerequisites
- Ubuntu 24.04 LTS (ROS 2 Jazzy target)
- Python 3.12+
- 8GB RAM minimum (16GB recommended for MuJoCo)
Step 1: Install ROS 2 Jazzy
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
-o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \
http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | \
sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
sudo apt update
sudo apt install ros-jazzy-desktop ros-dev-tools
Add to your .bashrc:
source /opt/ros/jazzy/setup.bash
Step 2: Install MuJoCo
MuJoCo is now free (thanks DeepMind) and the best physics simulator for humanoid robotics:
pip install mujoco
Verify:
import mujoco
print(mujoco.__version__) # should print 3.x.x
Step 3: Create a workspace
mkdir -p ~/humanoid_ws/src
cd ~/humanoid_ws
colcon build
source install/setup.bash
Step 4: Your first URDF model
Create a minimal biped model. For a real project, you’d load a proper URDF from the robot manufacturer, but here’s a minimal structure:
<!-- robot.urdf -->
<robot name="biped">
<link name="base_link">
<visual>
<geometry><box size="0.3 0.2 0.5"/></geometry>
</visual>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" iyy="0.1" izz="0.05" ixy="0" ixz="0" iyz="0"/>
</inertial>
</link>
<link name="left_thigh"><!-- ... --></link>
<joint name="left_hip" type="revolute">
<parent link="base_link"/>
<child link="left_thigh"/>
<axis xyz="0 1 0"/>
<limit lower="-1.5" upper="1.5" effort="50" velocity="5"/>
</joint>
</robot>
Step 5: Publish joint states
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import JointState
import math, time
class SimpleController(Node):
def __init__(self):
super().__init__('simple_controller')
self.pub = self.create_publisher(JointState, 'joint_states', 10)
self.timer = self.create_timer(0.02, self.step) # 50 Hz
self.t = 0.0
def step(self):
msg = JointState()
msg.header.stamp = self.get_clock().now().to_msg()
msg.name = ['left_hip', 'right_hip', 'left_knee', 'right_knee']
# Simple sinusoidal gait
msg.position = [
0.3 * math.sin(self.t),
0.3 * math.sin(self.t + math.pi),
-0.6 * abs(math.sin(self.t)),
-0.6 * abs(math.sin(self.t + math.pi)),
]
self.pub.publish(msg)
self.t += 0.02 * 2 * math.pi * 0.5 # 0.5 Hz gait cycle
def main():
rclpy.init()
rclpy.spin(SimpleController())
Next Steps
This barely scratches the surface. The real work is in:
- Whole-body control — using libraries like
pink(Pink Is Not Kinematics) for real-time IK - State estimation — fusing IMU + leg odometry for robust pose estimation
- RL policies — training in Isaac Gym and transferring to MuJoCo/real hardware
The Open Duck Mini repository has a well-documented example of the full sim-to-real pipeline. Start there.