Minimal robot-side ROS 2 container for validating Unitree GO2-W Sport API control through abstract motion commands (vx, vy, wz).
This repository is intentionally narrower than go2w_teleop_gamepad: instead of converting joystick input to Sport API commands, it keeps a robot-side service running in Docker and lets the operator trigger timed motion commands from a terminal.
The goal is to verify that the robot can be controlled through high-level body motion commands while relying on Unitree's onboard Sport API controller to interpret and execute them.
The v1 feature set is:
- Start a robot-side Docker container manually from a terminal.
- Send a timed motion command
(vx, vy, wz)from another terminal command. - Stop motion automatically after a bounded execution time.
- Trigger an emergency stop command that cancels the active motion and publishes
StopMove.
The container runs a ROS 2 node that:
- exposes
/motion_command/execute - exposes
/motion_command/stop - publishes
unitree_api/Requestto/api/sport/request - optionally monitors
/api/sport/response
Motion is executed by repeatedly publishing Move (api_id=1008) at a fixed rate for a bounded duration. When the duration expires, the node publishes StopMove (api_id=1003).
- This is experimental software and not a certified safety system.
- The robot must already be in a standing Sport-mode state that accepts
MoveandStopMove. - This repository does not issue
StandUp,RecoveryStand, orDamp. - The emergency stop in this repo uses
StopMove, notDamp, to avoid intentionally collapsing the robot. - Start with conservative command values and ample open space.
go2w_motion_command/
├── docker/
├── go2w_motion_command/
└── go2w_motion_command_interfaces/
Build on the robot:
./docker/run.sh buildStart the container manually:
./docker/run.sh up -dWatch logs:
./docker/run.sh logs -fStop the container:
./docker/run.sh downThe container does not auto-start. It runs only when started from the terminal.
Example forward motion for the default 2.0 seconds:
./docker/run.sh motion --vx 0.10 --vy 0.0 --wz 0.0Example yaw motion for 1.5 seconds:
./docker/run.sh motion --vx 0.0 --vy 0.0 --wz 0.20 --duration 1.5Emergency stop:
./docker/run.sh stopIf a motion is already active, the server rejects a new motion command until the current motion finishes or stop is called.
Defaults are stored in go2w_motion_command/config/motion_command_params.yaml.
default_duration_s = 2.0max_duration_s = 10.0allow_unrestricted_speeds = false— set totrueto enable higher speed limits belowmax_vx = 0.20(safe default) /max_vx_unrestricted = 0.60max_vy = 0.15(safe default) /max_vy_unrestricted = 0.45max_wz = 0.30(safe default) /max_wz_unrestricted = 0.90publish_rate_hz = 50.0
Requests outside these limits are rejected.
This repository follows the same basic robot-side pattern as go2w_teleop_gamepad:
- ROS 2 Humble
- CycloneDDS
network_mode: hosteth0pinned inCYCLONEDDS_URIunitree_apisourced fromunitree_ros2
This repository is a robot-side ROS 2 validation step for higher-level controllers. It proved that the Unitree GO2-W can be driven through the Sport API using abstract body-motion commands (vx, vy, wz) rather than joystick input. The container runs on the robot, exposes a timed motion-command service, and translates each command into repeated unitree_api/Request Move messages on /api/sport/request, followed by StopMove when the command ends or is cancelled.
This confirms that Unitree's onboard Sport-mode controller can digest high-level velocity commands and handle the underlying low-level balance and motion execution. For future controllers such as MPPI, the intended final integration is to replace the timed test-command source with an MPPI controller that publishes the same (vx, vy, wz) abstraction, while keeping the robot output path through the Sport API the same.