# go2_ros2_sdk: bringing Unitree GO2 robots onto a ROS 2 graph

> This unofficial Python SDK exposes AIR, PRO and EDU variants of the Unitree GO2 to ROS 2 over WebRTC on Wi-Fi or CycloneDDS on Ethernet. It covers URDF, joint states, IMU, foot force sensors, point clouds and a Foxglove bridge, and it has a known 1 Hz joint state lag on newer firmware.

**abizovnuralem/go2_ros2_sdk** — Unofficial ROS2 SDK support for Unitree GO2 AIR/PRO/EDU

- Repository: https://github.com/abizovnuralem/go2_ros2_sdk
- Stars: 1,065 · Forks: 225
- Language: Python
- License: BSD-2-Clause
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/abizovnuralem-go2-ros2-sdk

## What problem go2_ros2_sdk actually solves

The Unitree GO2 quadruped ships with its own SDKs, but a ROS 2 user has no native topic graph for the robot's sensors. go2_ros2_sdk fills that gap. It is an unofficial integration written in Python that exposes the GO2 AIR, PRO and EDU variants as ROS 2 nodes over two transports: WebRTC over Wi-Fi and CycloneDDS over Ethernet. The WebRTC transport is the work of another developer, credited in the README to @tfoldi, whose own project go2-webrtc is the underlying streaming layer.

The scope is broad. The published roadmap marks as done: URDF, real-time joint state sync, real-time IMU sync, joystick control, topic information, foot force sensor feedback, a lidar stream with PointCloud2 output, camera stream, Foxglove bridge, laser scan, multi-robot support, both transport protocols, PointCloud map creation and storage, SLAM through slam_toolbox, navigation through nav2, and object detection with coco. The only roadmap entry left open is AutoPilot, and it carries no check mark.

Foot force feedback is worth flagging as a hardware caveat rather than a software one. The README says access to foot force sensors is available on some GO2 PRO models or EDU units, so a reader with an AIR should not assume the topic will exist. The project is also explicit that the WebRTC path requires you to close the mobile app connection before connecting to the robot over Wi-Fi.

## The refactor that took the lidar stream from 2 Hz to 7 Hz

The maintainer's note at the top of the README is the most informative paragraph in the whole document, and it is also an admission. He writes that he had not updated the repository in a long time, that changes accumulated until the project became messy, and that he has now refactored it using Clean Architecture principles.

The concrete payoff he cites is the lidar stream. It used to run at around 2 Hz, and after the refactor it updates at 7 Hz. That is a 3.5 times increase in point cloud delivery, which matters for anyone running slam_toolbox or building a PointCloud map against the robot's lidar.

The mechanism behind that number is not described in detail. There is no architecture diagram, no layer diagram and no explanation of which services the Clean Architecture split produced. The directory listing at the repository root is the only structural evidence available: it shows `go2_robot_sdk`, `go2_interfaces`, `lidar_processor`, `lidar_processor_cpp`, `coco_detector`, `speech_processor` and `docker`, plus a `3d_map.ply` file at the top level and a `requirements.txt`. A separate C++ lidar processor sitting beside a Python one suggests the hot path was moved out of Python, but the README does not say so, so treat that as an inference from the file layout rather than a documented design decision.

The published release list contains a single entry, v0.2.0, dated 2024-06-07, so the version number in your package manager will not tell you whether you have the refactored code.

## Joint states still arrive at 1 Hz and URDF lags behind

The same note explains why the refactor did not fix everything. Joint states still arrive at 1 Hz, so the README warns that you may notice URDF update lag and attributes it to the new firmware, version v1.1.7. The author says a workaround is still needed and that one has not been found yet.

This is the sharpest trade-off in the project. A quadruped that publishes joint angles at 1 Hz is enough for visualization, for recording, and for checking that a gait command took effect. It is not enough for closed-loop control built on joint state feedback, and it is the kind of limit that only becomes obvious once a graph is live.

Nothing in the repository claims a target rate, an option to raise it, or a configuration key that changes it. If your work depends on faster joint state feedback, the SDK as described does not provide a knob for it, and the firmware version is called out as the reason, which means an SDK-side workaround may not be the right layer to attack.

The board also mixes two cadences into one robot: 7 Hz lidar and 1 Hz joints. Any synchronizer you write downstream has to reconcile them, and the README does not mention a synchronizer, so that work is on you.

## Firmware 1.1.15 changed the WebRTC handshake key

The most technically specific part of the documentation concerns a breaking change in the robot's own firmware. Starting with GO2 firmware 1.1.15, the robot wraps its RSA public key in the LAN handshake, the `con_notify` message, with a per-device AES-128 key, identified as `data2 == 3`, rather than the older static key, `data2 == 2`. The SDK reads that key from a parameter named `aes_key`, or from the `ROBOT_AES_KEY` and `GO2_AES_KEY` environment variables.

The failure signature is an explicit error string:

```
Failed to complete encrypted handshake: Failed to load RSA public key: RSA key format is not supported
```

If your robot is still on the older firmware, `data2 == 2` or unencrypted, the README says the key can be left unset. The key is 32 hex characters, and it can be obtained with the account credentials registered to the robot. The README points at the `unitree_webrtc_connect` project, which ships a `fetch_aes_key.py` example and a `unitree-fetch-aes-key` command line tool, installed with pip and run against an email, password and device type of Go2. The output lists the key for each robot on the account, keyed by serial number, so a multi-robot deployment needs one key per machine rather than one shared secret.

## Building the workspace with rosdep and colcon

Installation is a standard ROS 2 workspace build, and every command is given verbatim in the README. The clone uses the `--recurse-submodules` flag, which is worth noting because the repository has a `.gitmodules` file and the submodules are not optional extras.

```shell
mkdir -p ros2_ws
cd ros2_ws
git clone --recurse-submodules https://github.com/abizovnuralem/go2_ros2_sdk.git src
sudo apt install ros-$ROS_DISTRO-image-tools
sudo apt install ros-$ROS_DISTRO-vision-msgs

sudo apt install python3-pip clang portaudio19-dev
cd src
pip install -r requirements.txt
cd ..
```

The build stage assumes `ros2` and `rosdep` are already present, and the README links to the Humble installation instructions if they are not:

```shell
source /opt/ros/$ROS_DISTRO/setup.bash
rosdep install --from-paths src --ignore-src -r -y
colcon build
```

The README is blunt about pip: if `pip install` does not complete cleanly, various features will not work. Its worked example is `open3d`, which does not yet support `python3.12`, so you need a 3.11 `venv` set up first. The pinned requirements file backs that up, listing `aiortc==1.9.0` and `numpy==1.26.4` exactly, alongside `aiohttp`, `paho-mqtt`, `python-dotenv`, `wasmtime`, `open3d`, `torch`, `torchvision`, `pycryptodome`, `opencv-python` and `pydub`.

The tested matrix is narrow: Ubuntu 22.04 on the iron, humble and rolling distributions, with a continuous integration badge. The Python 3.10 badge and the IsaacSim 4.0 badge appear in the header, and the project also claims Linux 64-bit and Windows 64-bit support.

## Launching the robot with ROBOT_IP and CONN_TYPE

Running requires the robot to be in Wi-Fi mode with a known IP address. The README describes finding it through the mobile app, going to Device, then Data, then Automatic Machine Inspection, and reading the STA Network entry for `wlan0`.

The launch sequence is three environment variables and one launch file:

```shell
source install/setup.bash
export ROBOT_IP="robot_ip" #for muliple robots, just split by ,
export CONN_TYPE="webrtc"
ros2 launch go2_robot_sdk robot.launch.py
```

The comment on `ROBOT_IP` is the whole multi-robot story: comma separated addresses, matching the roadmap entry for multi robot support. `CONN_TYPE` accepts `webrtc` or `cyclonedds`, which is the same pair of values the Docker section uses. Set `CONN_TYPE` to `cyclonedds` when you are on Ethernet.

`robot.launch.py` starts many services and nodes at once. The README names two of them, `robot_state_publisher` and `ros2_go2_vid`, and says the file starts many. Only the first is unsurprising, since publishing a URDF that matches the robot is the whole reason for `robot_state_publisher` to be in a robot SDK, and the Foxglove bridge entry in the roadmap explains why a video node would be in the same graph.

What the launch file does not reveal is its parameter surface. The `aes_key` parameter is mentioned in the firmware section, but the README does not show it being passed on a command line, so the practical route is the `ROBOT_AES_KEY` or `GO2_AES_KEY` environment variable.

## Docker compose as a separate entry point

A Docker path exists, and the README describes environment variables being set beforehand, hardcoded in `docker/docker-compose.yaml`, or supplied on the command line. The documented run is:

```shell
cd docker
ROBOT_IP=<ROBOT_IP> CONN_TYPE=<webrtc/cyclonedds> docker-compose up --build
```

The `docker` directory in the repository root confirms the compose file is part of the tree. What the README does not state is the base image, the ROS distribution inside it, or how the container reaches the robot's network, and it does not mention Docker as a tested system in the compatibility table, which lists only Ubuntu 22.04 with three ROS 2 distributions. Treat Docker here as a convenience wrapper for people who cannot install the full ROS 2 toolchain locally, and verify network reachability to the robot yourself, because the documentation does not describe it.

The `3d_map.ply` file sitting in the repository root is a saved artifact of the roadmap item about creating and storing a PointCloud map. It is the only static data file visible in the top level listing, alongside `setup.cfg`, `.gitmodules`, `LICENSE` and `README.md`.

## Licence, release history and what is still unbuilt

The project carries a BSD-2-Clause licence, and the README links to the Open Source Initiative text for it. BSD-2-Clause is a permissive licence with a short grant and no patent grant, which in practical terms means redistribution conditions are light. Anyone integrating this SDK into a product should still read the LICENSE file at the repository root rather than relying on the summary, and should note that the code sits on top of work contributed by other developers, including the WebRTC transport credited to @tfoldi and the `unitree_webrtc_connect` project used to fetch the AES key.

Maintenance is mixed. The repository is not archived, and the last push was on 2026-07-13. The release list, however, holds exactly one published release, v0.2.0 from 2024-06-07, so the tag set is far older than the source tree. If you pin to a release tag you get pre-refactor code with the 2 Hz lidar stream; if you build from the default branch, which is master, you get the refactor and the firmware v1.1.7 joint state behaviour. There is no changelog file at the top level to arbitrate between those two states.

AutoPilot is the single roadmap item without a check mark, and the README gives no design, no partial state and no timeline for it. Treat it as unbuilt rather than in progress.

## Conclusion

go2_ros2_sdk suits ROS 2 developers who own an AIR, PRO or EDU GO2 and want the robot's sensors and joints on a standard graph without writing their own vendor bridge. It does not suit teams that need a vendor-supported stack, a release train with predictable version pinning, or joint state rates above 1 Hz, since the maintainer states the joint state lag on firmware v1.1.7 still needs a workaround. Before adopting it, confirm your robot's firmware version, fetch the per-device AES-128 key if it runs 1.1.15 or newer, and check that the `open3d` dependency installs cleanly on your Python version, since the README warns it does not support python3.12.

## FAQ

### How do I connect go2_ros2_sdk to my Unitree GO2 robot?

Set the robot to Wi-Fi mode, obtain its IP through the mobile app, then export `ROBOT_IP` and `CONN_TYPE` before running `ros2 launch go2_robot_sdk robot.launch.py`. For multiple robots, pass comma separated addresses in `ROBOT_IP`.

### What does the error 'RSA key format is not supported' mean when connecting over WebRTC?

It means the robot runs firmware 1.1.15 or newer, where the LAN handshake wraps the RSA public key with a per-device AES-128 key. Supply the 32 hex character key through the `aes_key` parameter or the `ROBOT_AES_KEY` environment variable.

### How fast are the lidar and joint state updates in go2_ros2_sdk?

After the refactor the lidar stream updates at 7 Hz, up from about 2 Hz before. Joint states still arrive at 1 Hz, which the README says causes URDF update lag on firmware v1.1.7 and still needs a workaround.

### Can I run go2_ros2_sdk with CycloneDDS instead of WebRTC?

Yes. The `CONN_TYPE` variable accepts `webrtc` or `cyclonedds`, with WebRTC used over Wi-Fi and CycloneDDS over Ethernet. The same pair of values is used in the Docker compose command.

### Which Unitree GO2 models does go2_ros2_sdk support?

The README lists AIR, PRO and EDU variants as compatible. Foot force sensor feedback is described as available on some GO2 PRO models or EDU units, so that particular topic may not be present on every AIR.

## Sources

- [abizovnuralem/go2_ros2_sdk on GitHub](https://github.com/abizovnuralem/go2_ros2_sdk)
- [Issues](https://github.com/abizovnuralem/go2_ros2_sdk/issues)
- [License: BSD-2-Clause](https://github.com/abizovnuralem/go2_ros2_sdk/blob/master/LICENSE)
- [README](https://github.com/abizovnuralem/go2_ros2_sdk/blob/master/README.md)
- [Releases](https://github.com/abizovnuralem/go2_ros2_sdk/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/abizovnuralem-go2-ros2-sdk
