A complete ROS2 workspace for the Unitree G1 humanoid robot, featuring teleoperation, SLAM/navigation with MOLA-LO.
This repository provides a comprehensive ROS2 software stack for the Unitree G1 humanoid robot, including hardware abstraction, teleoperation, and system bringup. It is designed to facilitate development and experimentation with the G1 robot in ROS2 environments.
unitree_ws/
├── docker/
│ ├── compose.yaml # Docker Compose (humble + ros2router)
│ ├── foxy/ # ROS2 Foxy container
│ ├── humble/ # ROS2 Humble container (x86_64)
│ ├── humble_arm64/ # ROS2 Humble container (arm64, onboard)
│ └── ros2router/ # Husarnet DDS bridge for remote access
├── src/
│ ├── unitree_g1_stack/
│ │ ├── unitree_g1_bringup/ # Launch files and configs
│ │ ├── unitree_g1_description/ # URDF and meshes
│ │ ├── unitree_g1_driver/ # SDK interface node
│ │ ├── unitree_g1_navigation/ # Navigation configs
│ │ └── unitree_g1_teleop/ # Joystick teleoperation
│ ├── livox_ros_driver2/ # Livox LiDAR driver
│ └── unitree_ros2/ # Unitree SDK ROS2 wrapper
├── data/
│ ├── bag_files/ # Recorded rosbags
│ └── maps/ # Saved MOLA maps (.mm, .simplemap)
└── scripts/ # Utility scripts
G1 Specifications and Software Requirements
JetPack Version: Unitree G1 robots typically run on NVIDIA Jetson Orin NX with JetPack 5.1 or later. Please ensure the versions of L4T and JetPack on your robot match the requirements for the ROS2 packages and SDK versions used in this codebase. (About G1)
- NVIDIA L4T version on a Jetson Orin NX: 35.3.1
- NVIDIA JetPack version on a Jetson Orin NX: 5.1.1
git clone --recursive https://github.com/YoheiHayamizu/unitree_g1_codebase.git unitree_ws
cd unitree_wsIf you already cloned without --recursive, initialize submodules manually:
git submodule update --init --recursiveThis repository includes Dockerfiles for ROS2 Foxy, Humble (remote development), and Humble arm64 (onboard). The Humble image is recommended for the latest features and better support.
| Image | Directory | Use Case |
|---|---|---|
docker/humble/ |
x86_64 | Remote development on a host machine |
docker/humble_arm64/ |
arm64 | Onboard development on Jetson Orin NX (G1) |
docker/foxy/ |
x86_64 | Legacy ROS2 Foxy (may need tweaks) |
Docker Compose runs the ROS2 development container alongside ros2router for Husarnet-based remote topic forwarding. See docker/README.md for full details.
cd docker
# Configure environment
cp .env.template .env
# Edit .env: set CYCLONEDDS_IFACE to your host's network interface
# Find it with: ip -br addr show | grep UP
# Build and extract (first time only)
docker compose build humble
bash humble/setup_and_run.sh
# Start both humble and ros2router
docker compose up -d
# Open a shell in the humble container
docker compose exec humble bashFor onboard (arm64) or standalone use without ros2router:
cd docker/humble_arm64 # or docker/humble
./docker_build.sh # Build the image (first time only)
./setup_and_run.sh # Extract artifactsIf you prefer to set up the environment without Docker, follow these steps:
You will need to install ROS2 (Foxy or Humble) and the necessary dependencies for the packages in this workspace. Dependencies include but are not limited to:
- Unitree SDK (for the driver package)
- Unitree Python SDK
- Unitree ROS2 (for the ROS2 wrapper around the SDK)
- Livox SDK (for the LiDAR)
- Livox ROS Driver 2 (for the LiDAR)
- RealSense ROS (if using RealSense cameras)
- MOLA-LO dependencies (for navigation)
Unitree provides Unitree SDK and Unitree ROS2 packages that are required for the driver and ROS2 wrapper. You can find them on their GitHub repositories:
- Unitree SDK: GitHub Repo
- Unitree ROS2: GitHub Repo
If you are using a Livox LiDAR, you will also need to install the Livox SDK and the Livox ROS Driver 2 package:
- Livox SDK: GitHub Repo
- Livox ROS Driver 2: GitHub Repo
For RealSense cameras, you will need to install the RealSense ROS package:
- RealSense ROS: GitHub Repo
After installing the dependencies, you can build the ROS2 workspace using colcon:
source /opt/ros/humble/setup.bash # Source your ROS2 environment
colcon build --symlink-install --packages-select unitree_g1_stackNote: Make sure you have
livox_ros_driver2andunitree_ros2packages properly built and sourced before building theunitree_g1_stack, as they are dependencies for the driver and navigation packages.
After building, source the workspace to overlay it on your ROS2 environment:
source install/setup.bashros2 launch unitree_g1_bringup bringup.launch.pyros2 launch unitree_g1_bringup teleop.launch.pyController Reference:
| Button | Function |
|---|---|
| L1 (hold) | Deadman switch (required for walking) |
| L2 + R2 | Emergency stop (DAMP mode) |
| Triangle/Y | Stand up |
| Cross/A | Sit down |
| Left Stick | Forward/backward, strafe |
| Right Stick | Rotation |
ros2 launch unitree_g1_bringup mola_lidar_odometry.launch.py \
lidar_topic_name:=/livox/lidar \
generate_simplemap:=TrueMove the robot around, then save the map:
ros2 service call /map_save mola_msgs/srv/MapSave "map_path: '/unitree_ws/data/maps/my_map'"ros2 launch unitree_g1_bringup mola_lidar_odometry.launch.py \
start_active:=False \
start_mapping_enabled:=False \
lidar_topic_name:=/livox/lidar \
mola_initial_map_mm_file:=/unitree_ws/data/maps/my_map.mm \
mola_initial_map_sm_file:=/unitree_ws/data/maps/my_map.simplemapmm-viewer -l libmola_metric_maps.so /path/to/your/map.mmros2 bag record -a --exclude "/config_change_status|/frontvideostream|/lf/odommodestate|/odommodestate"The robot uses DDS (CycloneDDS) for communication. Key settings:
ROS_DOMAIN_ID=0(must match the robot)CYCLONEDDS_IFACEindocker/.envmust point to the host interface on the robot's network- Host must be connected to the robot's network (typically
192.168.123.x)
When using Docker Compose, the CycloneDDS interface is configured via the CYCLONEDDS_IFACE environment variable in docker/.env. See docker/README.md for details.
- Driver Package - SDK interface details
- Teleop Package - Joystick configuration
- MOLA-LO Docs - Navigation system
BSD 3-Clause License - See LICENSE for details.
This section describes how to set up and run MOLA-LO (LiDAR Odometry) with the Unitree G1 robot equipped with a Livox LiDAR sensor.
In a terminal, launch MOLA-LO, enabling saving the map in simple-map format:
ros2 launch unitree_g1_bringup mola_lidar_odometry.launch.py \
lidar_topic_name:=/livox/lidar \
generate_simplemap:=TrueNote: Remember replacing /livox/lidar with your actual PointCloud2 topic with raw LiDAR data.
Next, move the robot around.
Once you have completed the mapping session, save the map by calling the following service in another terminal:
ros2 service call /map_save mola_msgs/srv/MapSave "map_path: '/tmp/my_map'"Watch the response to check that success is true. Your map is now stored as file(s) named /tmp/my_map*.
You can check how the final metric map looks like using:
mm-viewer -l libmola_metric_maps.so /path/to/your/map.mmWhere the -l flag is used to load the additional metric map classes defined in mola_metric_maps, and used in the lidar3d-default pipeline.
Launch MOLA-LO in non-mapping mode, loading the prebuilt map you saved earlier:
ros2 launch unitree_g1_bringup mola_lidar_odometry.launch.py \
start_active:=False \
start_mapping_enabled:=False \
lidar_topic_name:=/livox/lidar \
mola_initial_map_mm_file:=/unitree_ws/data/maps/airlab.mm \
mola_initial_map_sm_file:=/unitree_ws/data/maps/airlab.simplemapor launch MOLA-LO in non-mapping mode in a terminal and load the prebuilt map by using service calls in another terminal:
ros2 launch unitree_g1_bringup mola_lidar_odometry.launch.py \
start_active:=False start_mapping_enabled:=False \
lidar_topic_name:=/livox/lidar \Then, load the map using the following service calls:
ros2 service call /map_load mola_msgs/srv/MapLoad "map_path: '/unitree_ws/data/maps/airlab'"Note: Remember replacing /lidar1_points with your actual PointCloud2 topic with raw LiDAR data.
start_mapping_enabled:=Falsedisables map updates, so the loaded map will remain static.start_active:=Falseis recommended so LO does not attempt to match incoming sensor data until a relocalization method or rough initial localization is set (see next section below).
If you want to interact with the Unitree G1 robot without using an Ethernet cable, you can use Husarnet, a secure and easy-to-use VPN service that allows you to connect to your robot over the internet.
- Create a Husarnet Account: Go to the Husarnet website and create an account.
- Install Husarnet on Your Robot (Jetson Orin): Follow the instructions on the Husarnet website to install the Husarnet client on your Unitree G1 robot. This typically involves running a few commands in the terminal of your robot.
- Install Husarnet on Your Local Machine: Install the Husarnet client on your local machine (laptop or desktop) that you will use to connect to the robot.
- Connect Your Robot to Husarnet: After installing Husarnet on both your robot and local machine, you will need to connect your robot to the Husarnet network. This usually involves running a command on your robot that generates a unique ID, which you can then use to connect from your local machine.
ping your-robot-husarnet-id.husarnet.com
- Access Your Robot: Once connected, you can access your robot using the Husarnet network. You can use SSH to connect to the robot’s terminal or set up ROS2 communication over Husarnet to interact with your ROS2 nodes and topics.
ssh unitree@your-robot-husarnet-id
To use ROS2 over Husarnet, you need ros2router running on both the robot and your local machine. The Docker Compose setup in docker/ starts ros2router automatically alongside the humble container:
cd docker
docker compose up -d # Starts both humble and ros2routerTopics forwarded over Husarnet are controlled by docker/ros2router/filter.yaml. Edit the allowlist and restart:
# After editing filter.yaml:
docker compose restart ros2routerYou also need to set up ros2router on the robot side. See the docker/ros2router/ directory for configuration details.