Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .dockerignore +30 -0
- .gitattributes +3 -0
- .gitignore +32 -0
- .gitmodules +4 -0
- .vscode/browse.vc.db +3 -0
- .vscode/c_cpp_properties.json +22 -0
- .vscode/settings.json +35 -0
- LICENSE +24 -0
- README.md +243 -3
- docker/Dockerfile +63 -0
- docker/docker-compose.yml +37 -0
- docker/entrypoint.sh +9 -0
- go2_control/go2_control/__init__.py +0 -0
- go2_control/go2_control/keyboard_teleop.py +150 -0
- go2_control/package.xml +21 -0
- go2_control/resource/go2_control +0 -0
- go2_control/setup.cfg +4 -0
- go2_control/setup.py +25 -0
- go2_interfaces/CMakeLists.txt +61 -0
- go2_interfaces/msg/AudioData.msg +2 -0
- go2_interfaces/msg/BmsCmd.msg +2 -0
- go2_interfaces/msg/BmsState.msg +9 -0
- go2_interfaces/msg/Error.msg +2 -0
- go2_interfaces/msg/Go2Cmd.msg +1 -0
- go2_interfaces/msg/Go2FrontVideoData.msg +8 -0
- go2_interfaces/msg/Go2Move.msg +3 -0
- go2_interfaces/msg/Go2RpyCmd.msg +3 -0
- go2_interfaces/msg/Go2State.msg +12 -0
- go2_interfaces/msg/HeightMap.msg +15 -0
- go2_interfaces/msg/IMU.msg +5 -0
- go2_interfaces/msg/InterfaceConfig.msg +3 -0
- go2_interfaces/msg/LidarState.msg +17 -0
- go2_interfaces/msg/LowCmd.msg +15 -0
- go2_interfaces/msg/LowState.msg +22 -0
- go2_interfaces/msg/MotorCmd.msg +7 -0
- go2_interfaces/msg/MotorCmds.msg +1 -0
- go2_interfaces/msg/MotorState.msg +11 -0
- go2_interfaces/msg/MotorStates.msg +1 -0
- go2_interfaces/msg/PathPoint.msg +7 -0
- go2_interfaces/msg/Req.msg +2 -0
- go2_interfaces/msg/Res.msg +3 -0
- go2_interfaces/msg/SportModeCmd.msg +13 -0
- go2_interfaces/msg/SportModeState.msg +17 -0
- go2_interfaces/msg/TimeSpec.msg +5 -0
- go2_interfaces/msg/UwbState.msg +19 -0
- go2_interfaces/msg/UwbSwitch.msg +1 -0
- go2_interfaces/msg/VoxelHeightMapState.msg +14 -0
- go2_interfaces/msg/VoxelMapCompressed.msg +21 -0
- go2_interfaces/msg/WebRtcReq.msg +10 -0
- go2_interfaces/msg/WirelessController.msg +5 -0
.dockerignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# colcon workspace artifacts (rebuilt inside the image)
|
| 2 |
+
build/
|
| 3 |
+
install/
|
| 4 |
+
log/
|
| 5 |
+
|
| 6 |
+
# git
|
| 7 |
+
.git/
|
| 8 |
+
.gitignore
|
| 9 |
+
|
| 10 |
+
# python
|
| 11 |
+
**/__pycache__/
|
| 12 |
+
*.py[cod]
|
| 13 |
+
*.egg-info/
|
| 14 |
+
.pytest_cache/
|
| 15 |
+
|
| 16 |
+
# runtime output, not source
|
| 17 |
+
vla_logs/
|
| 18 |
+
navila/result/
|
| 19 |
+
|
| 20 |
+
# heavy weights (fetched separately, not committed) — small in-repo YOLO
|
| 21 |
+
# weights under vlm/ are intentionally NOT excluded here, they ship with the image.
|
| 22 |
+
navila-ckpt/
|
| 23 |
+
*.safetensors
|
| 24 |
+
*.pth
|
| 25 |
+
|
| 26 |
+
# editor / misc
|
| 27 |
+
.vscode/
|
| 28 |
+
.DS_Store
|
| 29 |
+
.superpowers/
|
| 30 |
+
docs/
|
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
.vscode/browse.vc.db filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
go2_robot_sdk/dae/base.dae filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
go2_robot_sdk/meshes/base.STL filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*.egg-info/
|
| 5 |
+
.pytest_cache/
|
| 6 |
+
*.so
|
| 7 |
+
|
| 8 |
+
# ROS build/install artifacts
|
| 9 |
+
build
|
| 10 |
+
log
|
| 11 |
+
install
|
| 12 |
+
.vscode
|
| 13 |
+
.env
|
| 14 |
+
.DS_Store
|
| 15 |
+
go2_robot_sdk/.coverage
|
| 16 |
+
go2_robot_sdk/coverage.xml
|
| 17 |
+
|
| 18 |
+
# Runtime logs / dữ liệu sinh ra
|
| 19 |
+
vla_logs/
|
| 20 |
+
navila/result/
|
| 21 |
+
*.log
|
| 22 |
+
*.ply
|
| 23 |
+
*.pgm
|
| 24 |
+
*.pcd
|
| 25 |
+
|
| 26 |
+
# Checkpoint / trọng số lớn (tải lại bằng script; KHÔNG đẩy lên git)
|
| 27 |
+
navila-ckpt/
|
| 28 |
+
*.safetensors
|
| 29 |
+
*.pth
|
| 30 |
+
|
| 31 |
+
.superpowers/
|
| 32 |
+
docs/
|
.gitmodules
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[submodule "go2_robot_sdk/external_lib/aioice"]
|
| 2 |
+
path = go2_robot_sdk/external_lib/aioice
|
| 3 |
+
url = https://github.com/legion1581/aioice.git
|
| 4 |
+
branch = go2
|
.vscode/browse.vc.db
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:356be10c121d584a032686b7ddb2b0916ede175104aa86b128b274e4e089b032
|
| 3 |
+
size 1325277184
|
.vscode/c_cpp_properties.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"configurations": [
|
| 3 |
+
{
|
| 4 |
+
"browse": {
|
| 5 |
+
"databaseFilename": "${workspaceFolder}/.vscode/browse.vc.db",
|
| 6 |
+
"limitSymbolsToIncludedHeaders": false
|
| 7 |
+
},
|
| 8 |
+
"includePath": [
|
| 9 |
+
"/home/thanhnc/unige_ws/install/spot_sar_msgs/include/**",
|
| 10 |
+
"/opt/ros/jazzy/include/**",
|
| 11 |
+
"/home/thanhnc/Go2-Nav_System/go2_navigation/include/**",
|
| 12 |
+
"/usr/include/**"
|
| 13 |
+
],
|
| 14 |
+
"name": "ros2",
|
| 15 |
+
"intelliSenseMode": "gcc-x64",
|
| 16 |
+
"compilerPath": "/usr/bin/gcc",
|
| 17 |
+
"cStandard": "gnu11",
|
| 18 |
+
"cppStandard": "c++17"
|
| 19 |
+
}
|
| 20 |
+
],
|
| 21 |
+
"version": 4
|
| 22 |
+
}
|
.vscode/settings.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"ROS2.distro": "jazzy",
|
| 3 |
+
"python.autoComplete.extraPaths": [
|
| 4 |
+
"/home/thanhnc/unige_ws/build/spot_sar_sim",
|
| 5 |
+
"/home/thanhnc/unige_ws/install/spot_sar_sim/lib/python3.12/site-packages",
|
| 6 |
+
"/home/thanhnc/unige_ws/build/spot_sar_executive",
|
| 7 |
+
"/home/thanhnc/unige_ws/install/spot_sar_executive/lib/python3.12/site-packages",
|
| 8 |
+
"/home/thanhnc/unige_ws/build/spot_sar_planning",
|
| 9 |
+
"/home/thanhnc/unige_ws/install/spot_sar_planning/lib/python3.12/site-packages",
|
| 10 |
+
"/home/thanhnc/unige_ws/build/spot_sar_perception",
|
| 11 |
+
"/home/thanhnc/unige_ws/install/spot_sar_perception/lib/python3.12/site-packages",
|
| 12 |
+
"/home/thanhnc/unige_ws/build/spot_sar_nav",
|
| 13 |
+
"/home/thanhnc/unige_ws/install/spot_sar_nav/lib/python3.12/site-packages",
|
| 14 |
+
"/home/thanhnc/unige_ws/install/spot_sar_msgs/lib/python3.12/site-packages",
|
| 15 |
+
"/home/thanhnc/unige_ws/build/spot_sar_bringup",
|
| 16 |
+
"/home/thanhnc/unige_ws/install/spot_sar_bringup/lib/python3.12/site-packages",
|
| 17 |
+
"/opt/ros/jazzy/lib/python3.12/site-packages"
|
| 18 |
+
],
|
| 19 |
+
"python.analysis.extraPaths": [
|
| 20 |
+
"/home/thanhnc/unige_ws/build/spot_sar_sim",
|
| 21 |
+
"/home/thanhnc/unige_ws/install/spot_sar_sim/lib/python3.12/site-packages",
|
| 22 |
+
"/home/thanhnc/unige_ws/build/spot_sar_executive",
|
| 23 |
+
"/home/thanhnc/unige_ws/install/spot_sar_executive/lib/python3.12/site-packages",
|
| 24 |
+
"/home/thanhnc/unige_ws/build/spot_sar_planning",
|
| 25 |
+
"/home/thanhnc/unige_ws/install/spot_sar_planning/lib/python3.12/site-packages",
|
| 26 |
+
"/home/thanhnc/unige_ws/build/spot_sar_perception",
|
| 27 |
+
"/home/thanhnc/unige_ws/install/spot_sar_perception/lib/python3.12/site-packages",
|
| 28 |
+
"/home/thanhnc/unige_ws/build/spot_sar_nav",
|
| 29 |
+
"/home/thanhnc/unige_ws/install/spot_sar_nav/lib/python3.12/site-packages",
|
| 30 |
+
"/home/thanhnc/unige_ws/install/spot_sar_msgs/lib/python3.12/site-packages",
|
| 31 |
+
"/home/thanhnc/unige_ws/build/spot_sar_bringup",
|
| 32 |
+
"/home/thanhnc/unige_ws/install/spot_sar_bringup/lib/python3.12/site-packages",
|
| 33 |
+
"/opt/ros/jazzy/lib/python3.12/site-packages"
|
| 34 |
+
]
|
| 35 |
+
}
|
LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
BSD 2-Clause License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2024, RoboVerse community
|
| 4 |
+
|
| 5 |
+
Redistribution and use in source and binary forms, with or without
|
| 6 |
+
modification, are permitted provided that the following conditions are met:
|
| 7 |
+
|
| 8 |
+
1. Redistributions of source code must retain the above copyright notice, this
|
| 9 |
+
list of conditions and the following disclaimer.
|
| 10 |
+
|
| 11 |
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
| 12 |
+
this list of conditions and the following disclaimer in the documentation
|
| 13 |
+
and/or other materials provided with the distribution.
|
| 14 |
+
|
| 15 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 16 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 17 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 18 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 19 |
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 20 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 21 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 22 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 23 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 24 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
README.md
CHANGED
|
@@ -1,3 +1,243 @@
|
|
| 1 |
-
---
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Unitree Go2 — ROS 2 Navigation, Mapping and Low-level Control & Basic Vision-Language-Action
|
| 2 |
+
|
| 3 |
+
A ROS 2 workspace for the Unitree Go2 quadruped that pairs a classic navigation
|
| 4 |
+
stack (SLAM Toolbox mapping + Nav2) with a **Vision-Language-Action (VLA)** layer:
|
| 5 |
+
the robot can be driven by typing a natural-language instruction instead of a
|
| 6 |
+
joystick or a Nav2 goal. Two interchangeable VLA brains are included — a local
|
| 7 |
+
**Qwen2.5-VL** reasoning loop and **NaVILA** (VILA-8B), a model purpose-trained
|
| 8 |
+
for language-guided navigation.
|
| 9 |
+
|
| 10 |
+
|Systems|ROS2 distro|Build status|
|
| 11 |
+
|--|--|--|
|
| 12 |
+
|Ubuntu 24.04|jazzy||
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
## Repository map
|
| 16 |
+
|
| 17 |
+
| Path | Role |
|
| 18 |
+
|---|---|
|
| 19 |
+
| [`go2_robot_sdk/`](go2_robot_sdk) | WebRTC/LAN driver — camera, odom, lidar, URDF |
|
| 20 |
+
| [`go2_navigation/`](go2_navigation) | Bringup, mapping, Nav2, C++ lidar filtering pipeline |
|
| 21 |
+
| [`go2_control/`](go2_control) | Keyboard teleop node |
|
| 22 |
+
| [`go2_interfaces/`](go2_interfaces) | Shared ROS 2 message definitions |
|
| 23 |
+
| [`vlm/`](vlm) | Local VLA stack: Qwen2.5-VL engine, YOLO-assisted servoing, web console |
|
| 24 |
+
| [`navila/`](navila) | NaVILA (VILA-8B) inference server + setup/eval tooling (bare metal, not containerized) |
|
| 25 |
+
| [`docker/`](docker) | Containerized driver + navigation + local VLA bringup |
|
| 26 |
+
|
| 27 |
+
## Installation
|
| 28 |
+
|
| 29 |
+
```shell
|
| 30 |
+
mkdir -p ros2_ws
|
| 31 |
+
cd ros2_ws
|
| 32 |
+
git clone --recurse-submodules https://github.com/StrikeRobot/Go2-Nav_System src
|
| 33 |
+
sudo apt install ros-$ROS_DISTRO-image-tools ros-$ROS_DISTRO-vision-msgs
|
| 34 |
+
sudo apt install python3-pip clang portaudio19-dev
|
| 35 |
+
cd src
|
| 36 |
+
pip install -r requirements.txt
|
| 37 |
+
cd ..
|
| 38 |
+
source /opt/ros/$ROS_DISTRO/setup.bash
|
| 39 |
+
rosdep install --from-paths src --ignore-src -r -y
|
| 40 |
+
colcon build
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## Docker
|
| 44 |
+
|
| 45 |
+
```shell
|
| 46 |
+
cd docker
|
| 47 |
+
cp .env.example .env # if you keep one locally; otherwise export ROBOT_IP inline
|
| 48 |
+
ROBOT_IP=<go2-lan-ip> docker compose up go2 # driver + Nav2 stack
|
| 49 |
+
ROBOT_IP=<go2-lan-ip> docker compose --profile vla up vlm # + local VLA web console (GPU)
|
| 50 |
+
```
|
| 51 |
+
The image builds on `ros:jazzy-ros-base`, matching the distro this project is
|
| 52 |
+
developed against. `network_mode: host` is required for ROS 2 DDS discovery and
|
| 53 |
+
for the driver's WebRTC session with the robot on the LAN. The `vlm` service
|
| 54 |
+
requests a GPU via the [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) —
|
| 55 |
+
install that on the host first. **NaVILA is not containerized**: it needs its
|
| 56 |
+
own conda environment, a hand-patched `transformers` build for Blackwell GPUs,
|
| 57 |
+
and a ~16 GB checkpoint pulled at setup time, so it's run on bare metal via
|
| 58 |
+
[`navila/setup_navila_blackwell.sh`](navila/setup_navila_blackwell.sh) — see the
|
| 59 |
+
[NaVILA section](#brain-2--navila-vila-8b) below.
|
| 60 |
+
|
| 61 |
+
Never bake a real `ROBOT_IP`/`ROBOT_TOKEN` into the image or into
|
| 62 |
+
`go2_navigation/config/robot.yaml` — pass them as environment variables at run
|
| 63 |
+
time instead.
|
| 64 |
+
|
| 65 |
+
## Usage
|
| 66 |
+
|
| 67 |
+
Put the Go2 in Wi-Fi/STA mode and note its LAN IP (mobile app → Device → Data →
|
| 68 |
+
Automatic Machine Inspection → STA Network: `wlan0`). Set it once in
|
| 69 |
+
[`go2_navigation/config/robot.yaml`](go2_navigation/config/robot.yaml) or pass
|
| 70 |
+
`ROBOT_IP=<ip>` on any launch command (env always wins).
|
| 71 |
+
|
| 72 |
+
```shell
|
| 73 |
+
source install/setup.bash
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
### Mapping
|
| 77 |
+
|
| 78 |
+
```shell
|
| 79 |
+
ros2 launch go2_navigation mapping.launch.py
|
| 80 |
+
```
|
| 81 |
+
Mark a dock rectangle with tape as a fixed starting point. In the SlamToolbox
|
| 82 |
+
panel in `rviz`, select **Start At Dock**, drive the robot around with a
|
| 83 |
+
controller to build the map, then **Save Map** / **Serialize Map**.
|
| 84 |
+
|
| 85 |
+
### Autonomous navigation (Nav2)
|
| 86 |
+
|
| 87 |
+
```shell
|
| 88 |
+
ros2 launch go2_navigation navigation.launch.py
|
| 89 |
+
```
|
| 90 |
+
Loads a saved map and drives the robot with Nav2's standard global/local
|
| 91 |
+
planner stack + AMCL localization — set goals from `rviz` as usual.
|
| 92 |
+
|
| 93 |
+
### Manual teleop
|
| 94 |
+
|
| 95 |
+
```shell
|
| 96 |
+
ros2 run go2_control keyboard_teleop
|
| 97 |
+
```
|
| 98 |
+
Arrows = move, `q`/`e` = rotate, space = stop, `x` = quit. Releasing all keys
|
| 99 |
+
for >0.4 s triggers a dead-man stop.
|
| 100 |
+
|
| 101 |
+
## VLA navigation
|
| 102 |
+
|
| 103 |
+
Instead of a Nav2 goal, type an instruction and let a vision-language model
|
| 104 |
+
decide the motion step by step from the live camera feed. **No RL or learned
|
| 105 |
+
locomotion is involved anywhere in this stack** — every brain below only ever
|
| 106 |
+
emits a discrete motion command (`move forward 25 cm`, `turn left 30°`,
|
| 107 |
+
`stop`); the Go2's own built-in gait and this repo's closed-loop
|
| 108 |
+
`MotionController` (odom + lidar + E-Stop) execute it.
|
| 109 |
+
|
| 110 |
+
### Brain 1 — local Qwen2.5-VL (`vlm` package, "Demo1")
|
| 111 |
+
|
| 112 |
+
```shell
|
| 113 |
+
ros2 launch go2_navigation bringup.launch.py teleop:=true
|
| 114 |
+
```
|
| 115 |
+
```shell
|
| 116 |
+
cd ros2_ws/src
|
| 117 |
+
./vlm/scripts/run_demo1.sh
|
| 118 |
+
```
|
| 119 |
+
Open `http://localhost:8001`, type a goal in natural language (e.g. *"go to
|
| 120 |
+
the water bottle, turn right, stop at the chair"*) or a manual command (`move
|
| 121 |
+
forward 75 cm`, `turn left 90 deg`). Each step: camera frame → Qwen2.5-VL
|
| 122 |
+
prompt (with live odom/lidar/bbox metrics injected as state) → JSON
|
| 123 |
+
`{action, value, unit, is_finished, ...}` → `MotionController` executes →
|
| 124 |
+
repeat until `is_finished` or **Stop/E-Stop**.
|
| 125 |
+
|
| 126 |
+
Two control modes (`VLA_CONTROL`):
|
| 127 |
+
- `vlm` (default) — the model reasons over injected state and returns the next action.
|
| 128 |
+
- `servo` — continuous closed-loop visual servoing driven by YOLO detections,
|
| 129 |
+
bypassing the LLM once a target is locked on.
|
| 130 |
+
|
| 131 |
+
Swap in a stronger model instead of the local 3B:
|
| 132 |
+
```shell
|
| 133 |
+
VLA_BRAIN=api VLA_API_URL=<endpoint> VLA_API_KEY=<key> VLA_MODEL=qwen2.5-vl-7b-instruct \
|
| 134 |
+
./vlm/scripts/run_demo1.sh
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
<details>
|
| 138 |
+
<summary>Configuration reference — local VLM brain</summary>
|
| 139 |
+
|
| 140 |
+
| Env | Default | Meaning |
|
| 141 |
+
|---|---|---|
|
| 142 |
+
| `VLA_BRAIN` | `local` | `local` (Qwen2.5-VL-3B) \| `api` (OpenAI-compatible endpoint) \| `navila` |
|
| 143 |
+
| `VLA_CONTROL` | `servo` | `servo` (visual servo, YOLO-driven) \| `vlm` (JSON reasoning loop) |
|
| 144 |
+
| `USE_YOLO` | `1` | `0` disables the YOLO detector |
|
| 145 |
+
| `VLA_MAX_STEPS` | `20` | max steps per instruction |
|
| 146 |
+
| `VLA_MAX_TURN_DEG` | `10` | hard cap on turn angle per step (all brains) |
|
| 147 |
+
| `VLA_SEARCH_MAX_DEG` | `360` | give up searching after this much cumulative scan rotation |
|
| 148 |
+
| `VLA_HFOV_DEG` | `90` | camera horizontal FOV, used to convert pixel offset → angle |
|
| 149 |
+
| `VLA_CENTER_TOL_DEG` | `5` | (servo) angular tolerance considered "centered" |
|
| 150 |
+
| `VLA_SERVO_HZ` / `VLA_SERVO_VX` / `VLA_SERVO_WZ_MAX` / `VLA_SERVO_KP` | `20` / `0.25` / `0.175` / `1.5` | servo loop rate, forward speed, max turn rate, turn gain |
|
| 151 |
+
| `VLA_STOP_BOTTOM_PX` | `20` | stop once the target bbox bottom is within this many px of the frame edge |
|
| 152 |
+
| `MOTION_LIN_SPEED` / `MOTION_ANG_SPEED` / `MOTION_ANG_MAX_DEG` | `0.3` / `0.35` / `10` | discrete move/turn command speeds and turn-rate ceiling |
|
| 153 |
+
| `MOTION_FRONT_STOP` | `0.30` | lidar obstacle distance (m) that halts forward motion |
|
| 154 |
+
| `MOTION_TURN_SIGN` | `1` | set to `-1` if the robot turns opposite to the commanded direction |
|
| 155 |
+
| `VLA_YOLO_WEIGHTS` / `VLA_YOLO_MIN_CONF` / `VLA_YOLO_IMGSZ` | `yolo11n.pt` / `0.3` / `960` | detector weights, confidence threshold, inference resolution |
|
| 156 |
+
| `VLA_LOG_DIR` | `vla_logs` | per-step JSONL log directory |
|
| 157 |
+
| `DEMO_MOCK` / `VLM_SKIP_MODEL` | — | run the UI without a robot / without loading the model |
|
| 158 |
+
|
| 159 |
+
Full source of truth for these lives in [`vlm/webconsole/demo1/navloop.py`](vlm/webconsole/demo1/navloop.py)
|
| 160 |
+
and [`vlm/webconsole/demo1/motion.py`](vlm/webconsole/demo1/motion.py).
|
| 161 |
+
</details>
|
| 162 |
+
|
| 163 |
+
### Brain 2 — NaVILA (VILA-8B)
|
| 164 |
+
|
| 165 |
+
[NaVILA](https://github.com/AnjieCheng/NaVILA) is an 8B vision-language-action
|
| 166 |
+
model trained specifically for language-guided navigation. It's integrated as a
|
| 167 |
+
**System-2 / System-1 split brain**:
|
| 168 |
+
|
| 169 |
+
```
|
| 170 |
+
camera → 8-frame sliding buffer → HTTP → NaVILA (VILA-8B, System-2, GPU)
|
| 171 |
+
→ mid-level action text → parser → MotionCmd
|
| 172 |
+
→ MotionController → twist_mux → go2_driver → Go2 built-in gait (System-1)
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
- **System-2** (`navila_server.py`, its own conda env, port `8100`) loads the
|
| 176 |
+
8B checkpoint once and turns 8 camera frames + the instruction into an
|
| 177 |
+
action sentence (`"The next action is move forward 25 cm."`) — a pure
|
| 178 |
+
action policy, no chain-of-thought.
|
| 179 |
+
- **System-1** is the same odom/lidar-closed-loop `MotionController` used
|
| 180 |
+
above; NaVILA never touches locomotion or gait, only high-level intent.
|
| 181 |
+
|
| 182 |
+
First-time setup (downloads the code repo + checkpoint, patches `transformers`
|
| 183 |
+
for Blackwell GPUs):
|
| 184 |
+
```shell
|
| 185 |
+
bash navila/setup_navila_blackwell.sh
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
One-command run (driver + NaVILA server + web console):
|
| 189 |
+
```shell
|
| 190 |
+
cd ros2_ws/src/navila
|
| 191 |
+
./scripts/run.sh
|
| 192 |
+
```
|
| 193 |
+
Open `http://localhost:8001` and type an instruction **in English** (NaVILA is
|
| 194 |
+
trained on English R2R-style instructions), e.g. *"Walk forward down the
|
| 195 |
+
hallway and stop near the chair."* The reasoning panel shows the raw NaVILA
|
| 196 |
+
output, per-token confidence, and a link to the exact 8 frames the model
|
| 197 |
+
received.
|
| 198 |
+
|
| 199 |
+
<details>
|
| 200 |
+
<summary>Configuration reference — NaVILA brain</summary>
|
| 201 |
+
|
| 202 |
+
| Env / arg | Default | Meaning |
|
| 203 |
+
|---|---|---|
|
| 204 |
+
| `VLA_BRAIN=navila` | — | routes control to the NaVILA server |
|
| 205 |
+
| `VLA_NAVILA_URL` | `http://127.0.0.1:8100` | NaVILA server address |
|
| 206 |
+
| `VLA_NAVILA_FRAMES` | `8` | frames sent per request (must match server `--num-frames`) |
|
| 207 |
+
| `VLA_NAVILA_HISTORY_MAX` | `64` | raw history frames kept per instruction; uniformly resampled down to `VLA_NAVILA_FRAMES`, always including the first and current frame (matches the paper's sampling scheme) |
|
| 208 |
+
| `NAVILA_FALLBACK` | `stop` | behavior when the model output fails to parse: `stop` \| `scan` |
|
| 209 |
+
| `NAVILA_PREPROC` | `pad` | frame preprocessing: `fov` (undistort + forward crop, closest to training distribution) \| `pad` (full fisheye) \| `resize` \| `crop` |
|
| 210 |
+
| server `--model-path` | — | path to the downloaded checkpoint |
|
| 211 |
+
| server `--port` | `8100` | HTTP port |
|
| 212 |
+
| server `--num-frames` | `8` | frames processed per request |
|
| 213 |
+
|
| 214 |
+
Full parameter tables, the three Blackwell inference fixes (8-bit + eager
|
| 215 |
+
attention + 4D causal mask — see [`navila/setup_navila_blackwell.sh`](navila/setup_navila_blackwell.sh)),
|
| 216 |
+
and eval/debug tooling (`navila/tools/`) are documented inline in that script
|
| 217 |
+
and in [`navila/scripts/`](navila/scripts).
|
| 218 |
+
</details>
|
| 219 |
+
|
| 220 |
+
## Acknowledgements & citations
|
| 221 |
+
|
| 222 |
+
- Built on [abizovnuralem/go2_ros2_sdk](https://github.com/abizovnuralem/go2_ros2_sdk)
|
| 223 |
+
(RoboVerse community) — see [`LICENSE`](LICENSE).
|
| 224 |
+
- **NaVILA** — An-Chieh Cheng et al., *"NaVILA: Legged Robot Vision-Language-Action
|
| 225 |
+
Model for Navigation"*, 2024. Code: [AnjieCheng/NaVILA](https://github.com/AnjieCheng/NaVILA),
|
| 226 |
+
checkpoint: `a8cheng/navila-llama3-8b-8f` on Hugging Face. See the official
|
| 227 |
+
repository for the paper and up-to-date citation.
|
| 228 |
+
- **Qwen2.5-VL** — Alibaba Qwen team, model `Qwen/Qwen2.5-VL-3B-Instruct`.
|
| 229 |
+
- **Ultralytics YOLO11** — [ultralytics/ultralytics](https://github.com/ultralytics/ultralytics).
|
| 230 |
+
- **Nav2** and **slam_toolbox** — the ROS 2 Navigation Working Group /
|
| 231 |
+
[ros-navigation](https://github.com/ros-navigation) and
|
| 232 |
+
[SteveMacenski/slam_toolbox](https://github.com/SteveMacenski/slam_toolbox).
|
| 233 |
+
- **Point Cloud Library (PCL)** — used for the SOR/ROR filtering pipeline in `go2_navigation`.
|
| 234 |
+
- **twist_mux** — [ros-teleop/twist_mux](https://github.com/ros-teleop/twist_mux),
|
| 235 |
+
used to arbitrate teleop/VLA vs. Nav2 velocity commands.
|
| 236 |
+
- **aiortc** — vendored WebRTC implementation used by the Go2 driver.
|
| 237 |
+
|
| 238 |
+
## License
|
| 239 |
+
|
| 240 |
+
BSD 2-Clause — see [`LICENSE`](LICENSE). Note: some vendored/derived source
|
| 241 |
+
files under `go2_navigation/` carry a BSD-3-Clause header inherited from
|
| 242 |
+
upstream; if you plan to redistribute, reconcile this with project counsel
|
| 243 |
+
before publishing rather than assuming one license governs the whole tree.
|
docker/Dockerfile
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Go2 ROS 2 workspace image: driver + navigation (Nav2/SLAM) + local VLA stack (vlm).
|
| 2 |
+
#
|
| 3 |
+
# Targets the same distro this project is developed/tested against (see README).
|
| 4 |
+
# GPU-backed inference (local Qwen2.5-VL brain, YOLO) needs the NVIDIA Container
|
| 5 |
+
# Toolkit on the host and a GPU reservation at `docker run`/`docker compose` time —
|
| 6 |
+
# no CUDA base image is required since the pip wheels ship their own CUDA runtime.
|
| 7 |
+
#
|
| 8 |
+
# NaVILA is intentionally NOT part of this image: it needs its own conda env,
|
| 9 |
+
# hand-patched transformers build, and a ~16GB checkpoint pulled at setup time —
|
| 10 |
+
# see navila/setup_navila_blackwell.sh and run it on bare metal.
|
| 11 |
+
FROM ros:jazzy-ros-base
|
| 12 |
+
|
| 13 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 14 |
+
|
| 15 |
+
# --- System packages (stable layer, only invalidated by this list changing) ---
|
| 16 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 17 |
+
curl \
|
| 18 |
+
gnupg2 \
|
| 19 |
+
lsb-release \
|
| 20 |
+
software-properties-common \
|
| 21 |
+
python3-pip \
|
| 22 |
+
clang \
|
| 23 |
+
portaudio19-dev \
|
| 24 |
+
mesa-utils \
|
| 25 |
+
libgl1-mesa-dev \
|
| 26 |
+
ffmpeg \
|
| 27 |
+
ros-${ROS_DISTRO}-rviz2 \
|
| 28 |
+
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
|
| 29 |
+
ros-${ROS_DISTRO}-image-tools \
|
| 30 |
+
ros-${ROS_DISTRO}-vision-msgs \
|
| 31 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 32 |
+
|
| 33 |
+
WORKDIR /ros2_ws
|
| 34 |
+
|
| 35 |
+
# --- Python deps in their own layer: only rebuilt when requirements.txt changes ---
|
| 36 |
+
COPY requirements.txt src/requirements.txt
|
| 37 |
+
# Ubuntu 24.04 marks the system interpreter "externally managed" (PEP 668); this
|
| 38 |
+
# image is disposable so overriding that guard is the pragmatic choice here.
|
| 39 |
+
RUN pip install --no-cache-dir --break-system-packages 'numpy<2.0.0' && \
|
| 40 |
+
pip install --no-cache-dir --break-system-packages -r src/requirements.txt
|
| 41 |
+
|
| 42 |
+
# --- Workspace source + ROS deps + build ---
|
| 43 |
+
COPY . src/
|
| 44 |
+
RUN . /opt/ros/${ROS_DISTRO}/setup.sh && \
|
| 45 |
+
rosdep update && \
|
| 46 |
+
rosdep install --from-paths src --ignore-src -r -y && \
|
| 47 |
+
colcon build --symlink-install
|
| 48 |
+
|
| 49 |
+
RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /root/.bashrc && \
|
| 50 |
+
echo "source /ros2_ws/install/setup.bash" >> /root/.bashrc && \
|
| 51 |
+
sed --in-place --expression \
|
| 52 |
+
'$isource "/ros2_ws/install/setup.bash"' \
|
| 53 |
+
/ros_entrypoint.sh
|
| 54 |
+
|
| 55 |
+
# Connection defaults — override at `docker run -e` / compose `environment:`,
|
| 56 |
+
# never bake real robot IPs or tokens into the image.
|
| 57 |
+
ENV ROBOT_IP=""
|
| 58 |
+
ENV ROBOT_TOKEN=""
|
| 59 |
+
ENV CONN_TYPE="webrtc"
|
| 60 |
+
ENV WEBRTC_SERVER_HOST="0.0.0.0"
|
| 61 |
+
ENV WEBRTC_SERVER_PORT="9991"
|
| 62 |
+
|
| 63 |
+
CMD ["ros2", "launch", "go2_navigation", "bringup.launch.py"]
|
docker/docker-compose.yml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
# Driver + navigation (Nav2/SLAM). Default profile — `docker compose up go2`.
|
| 3 |
+
go2:
|
| 4 |
+
build:
|
| 5 |
+
context: ..
|
| 6 |
+
dockerfile: docker/Dockerfile
|
| 7 |
+
image: go2-nav-vla:latest
|
| 8 |
+
environment:
|
| 9 |
+
- ROBOT_IP=${ROBOT_IP:?set ROBOT_IP to your Go2's LAN address}
|
| 10 |
+
- ROBOT_TOKEN=${ROBOT_TOKEN:-}
|
| 11 |
+
- CONN_TYPE=${CONN_TYPE:-webrtc}
|
| 12 |
+
- DISPLAY=${DISPLAY:-}
|
| 13 |
+
volumes:
|
| 14 |
+
- /tmp/.X11-unix:/tmp/.X11-unix:ro # X11 forwarding, e.g. for rviz2
|
| 15 |
+
- ${HOME}/.Xauthority:/root/.Xauthority:rw
|
| 16 |
+
network_mode: host # required: ROS 2 DDS discovery + Go2 WebRTC live on the LAN
|
| 17 |
+
privileged: true # required: joystick/input device access
|
| 18 |
+
devices:
|
| 19 |
+
- /dev/input:/dev/input
|
| 20 |
+
restart: unless-stopped
|
| 21 |
+
command: ["ros2", "launch", "go2_navigation", "bringup.launch.py"]
|
| 22 |
+
|
| 23 |
+
# Local VLA brain (Qwen2.5-VL) + web console, port 8001. Opt-in:
|
| 24 |
+
# docker compose --profile vla up vlm
|
| 25 |
+
# Requires the NVIDIA Container Toolkit on the host for GPU access.
|
| 26 |
+
vlm:
|
| 27 |
+
extends: go2
|
| 28 |
+
profiles: ["vla"]
|
| 29 |
+
working_dir: /ros2_ws/src
|
| 30 |
+
deploy:
|
| 31 |
+
resources:
|
| 32 |
+
reservations:
|
| 33 |
+
devices:
|
| 34 |
+
- driver: nvidia
|
| 35 |
+
count: all
|
| 36 |
+
capabilities: [gpu]
|
| 37 |
+
command: ["./vlm/scripts/run_demo1.sh"]
|
docker/entrypoint.sh
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -e
|
| 3 |
+
|
| 4 |
+
# Source ROS2 environment
|
| 5 |
+
source /opt/ros/${ROS_DISTRO}/setup.bash
|
| 6 |
+
source /ros2_ws/install/setup.bash
|
| 7 |
+
|
| 8 |
+
# Execute the command passed to docker run
|
| 9 |
+
exec "$@"
|
go2_control/go2_control/__init__.py
ADDED
|
File without changes
|
go2_control/go2_control/keyboard_teleop.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Điều khiển Go2 bằng bàn phím (giữ phím = đi, buông = dừng).
|
| 2 |
+
|
| 3 |
+
Bắn TwistStamped vào /cmd_vel_joy (qua twist_mux, priority cao -> đè Nav2).
|
| 4 |
+
|
| 5 |
+
Phím (KHÔNG cần Enter):
|
| 6 |
+
↑ / ↓ tiến / lùi (vx)
|
| 7 |
+
← / → đi ngang trái/phải (vy) — Go2 hỗ trợ
|
| 8 |
+
q / e xoay trái / phải (yaw)
|
| 9 |
+
space dừng ngay
|
| 10 |
+
x / Ctrl-C thoát
|
| 11 |
+
|
| 12 |
+
Cơ chế: terminal ở chế độ raw nên nhận phím tức thời. GIỮ phím -> hệ điều hành
|
| 13 |
+
tự lặp phím liên tục -> vận tốc được giữ. BUÔNG phím -> hết lặp -> sau
|
| 14 |
+
`hold_timeout` giây robot tự dừng (dead-man). Bấm phím ngược chiều -> đảo vận
|
| 15 |
+
tốc ngay (hãm/lùi lại). Tốc độ chỉnh qua ROS param.
|
| 16 |
+
"""
|
| 17 |
+
import os
|
| 18 |
+
import sys
|
| 19 |
+
import select
|
| 20 |
+
import termios
|
| 21 |
+
import tty
|
| 22 |
+
import time
|
| 23 |
+
|
| 24 |
+
import rclpy
|
| 25 |
+
from rclpy.node import Node
|
| 26 |
+
from geometry_msgs.msg import TwistStamped
|
| 27 |
+
|
| 28 |
+
HELP = __doc__
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class KeyboardTeleop(Node):
|
| 32 |
+
def __init__(self):
|
| 33 |
+
super().__init__("go2_keyboard_teleop")
|
| 34 |
+
|
| 35 |
+
self.declare_parameter("cmd_topic", "/cmd_vel_joy")
|
| 36 |
+
self.declare_parameter("frame_id", "base_link")
|
| 37 |
+
self.declare_parameter("lin_speed", 0.4) # m/s tiến/lùi
|
| 38 |
+
self.declare_parameter("lat_speed", 0.3) # m/s đi ngang
|
| 39 |
+
self.declare_parameter("ang_speed", 0.8) # rad/s xoay
|
| 40 |
+
self.declare_parameter("hold_timeout", 0.3) # s không thấy phím -> dừng
|
| 41 |
+
self.declare_parameter("publish_rate", 50.0) # Hz
|
| 42 |
+
|
| 43 |
+
gp = self.get_parameter
|
| 44 |
+
self.topic = gp("cmd_topic").get_parameter_value().string_value
|
| 45 |
+
self.frame_id = gp("frame_id").get_parameter_value().string_value
|
| 46 |
+
self.lin = gp("lin_speed").get_parameter_value().double_value
|
| 47 |
+
self.lat = gp("lat_speed").get_parameter_value().double_value
|
| 48 |
+
self.ang = gp("ang_speed").get_parameter_value().double_value
|
| 49 |
+
self.hold = gp("hold_timeout").get_parameter_value().double_value
|
| 50 |
+
self.dt = 1.0 / max(gp("publish_rate").get_parameter_value().double_value, 1.0)
|
| 51 |
+
|
| 52 |
+
self.pub = self.create_publisher(TwistStamped, self.topic, 10)
|
| 53 |
+
self._vx = self._vy = self._wz = 0.0
|
| 54 |
+
self._last_key = 0.0
|
| 55 |
+
|
| 56 |
+
self.get_logger().info(
|
| 57 |
+
f"Keyboard teleop -> {self.topic} "
|
| 58 |
+
f"(lin={self.lin} lat={self.lat} ang={self.ang}, dead-man={self.hold}s)")
|
| 59 |
+
|
| 60 |
+
def _apply(self, vx, vy, wz):
|
| 61 |
+
self._vx, self._vy, self._wz = vx, vy, wz
|
| 62 |
+
self._last_key = time.monotonic()
|
| 63 |
+
|
| 64 |
+
def _handle(self, keys):
|
| 65 |
+
"""keys: chuỗi byte đã đọc trong tick này (đã drain hết)."""
|
| 66 |
+
i, n = 0, len(keys)
|
| 67 |
+
while i < n:
|
| 68 |
+
c = keys[i]
|
| 69 |
+
if c == "\x1b" and i + 2 < n + 1 and keys[i + 1:i + 2] == "[":
|
| 70 |
+
seq = keys[i + 2:i + 3]
|
| 71 |
+
if seq == "A":
|
| 72 |
+
self._apply(self.lin, 0.0, 0.0)
|
| 73 |
+
elif seq == "B":
|
| 74 |
+
self._apply(-self.lin, 0.0, 0.0)
|
| 75 |
+
elif seq == "D":
|
| 76 |
+
self._apply(0.0, self.lat, 0.0)
|
| 77 |
+
elif seq == "C":
|
| 78 |
+
self._apply(0.0, -self.lat, 0.0)
|
| 79 |
+
i += 3
|
| 80 |
+
continue
|
| 81 |
+
if c in ("q", "Q"):
|
| 82 |
+
self._apply(0.0, 0.0, self.ang)
|
| 83 |
+
elif c in ("e", "E"):
|
| 84 |
+
self._apply(0.0, 0.0, -self.ang)
|
| 85 |
+
elif c == " ":
|
| 86 |
+
self._apply(0.0, 0.0, 0.0)
|
| 87 |
+
elif c in ("x", "X", "\x03"):
|
| 88 |
+
raise KeyboardInterrupt
|
| 89 |
+
i += 1
|
| 90 |
+
|
| 91 |
+
def _publish(self):
|
| 92 |
+
# dead-man: quá lâu không thấy phím -> dừng (buông phím = dừng)
|
| 93 |
+
if time.monotonic() - self._last_key > self.hold:
|
| 94 |
+
self._vx = self._vy = self._wz = 0.0
|
| 95 |
+
msg = TwistStamped()
|
| 96 |
+
msg.header.stamp = self.get_clock().now().to_msg()
|
| 97 |
+
msg.header.frame_id = self.frame_id
|
| 98 |
+
msg.twist.linear.x = self._vx
|
| 99 |
+
msg.twist.linear.y = self._vy
|
| 100 |
+
msg.twist.angular.z = self._wz
|
| 101 |
+
self.pub.publish(msg)
|
| 102 |
+
|
| 103 |
+
def run(self):
|
| 104 |
+
if not sys.stdin.isatty():
|
| 105 |
+
self.get_logger().error(
|
| 106 |
+
"stdin không phải terminal -> không đọc được phím. "
|
| 107 |
+
"Chạy trực tiếp `ros2 run go2_control keyboard_teleop` trong terminal.")
|
| 108 |
+
return
|
| 109 |
+
print(HELP)
|
| 110 |
+
fd = sys.stdin.fileno()
|
| 111 |
+
old = termios.tcgetattr(fd)
|
| 112 |
+
try:
|
| 113 |
+
tty.setcbreak(fd) # tức thời, không cần Enter
|
| 114 |
+
while rclpy.ok():
|
| 115 |
+
# drain mọi byte đang chờ trong tick này
|
| 116 |
+
buf = ""
|
| 117 |
+
while select.select([fd], [], [], 0)[0]:
|
| 118 |
+
ch = os.read(fd, 1).decode(errors="ignore")
|
| 119 |
+
if not ch:
|
| 120 |
+
break
|
| 121 |
+
buf += ch
|
| 122 |
+
if buf:
|
| 123 |
+
self._handle(buf)
|
| 124 |
+
self._publish()
|
| 125 |
+
rclpy.spin_once(self, timeout_sec=0)
|
| 126 |
+
time.sleep(self.dt)
|
| 127 |
+
except KeyboardInterrupt:
|
| 128 |
+
pass
|
| 129 |
+
finally:
|
| 130 |
+
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
| 131 |
+
# gửi vài lệnh dừng cho chắc
|
| 132 |
+
for _ in range(3):
|
| 133 |
+
self._apply(0.0, 0.0, 0.0)
|
| 134 |
+
self._publish()
|
| 135 |
+
time.sleep(0.01)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def main(args=None):
|
| 139 |
+
rclpy.init(args=args)
|
| 140 |
+
node = KeyboardTeleop()
|
| 141 |
+
try:
|
| 142 |
+
node.run()
|
| 143 |
+
finally:
|
| 144 |
+
if rclpy.ok():
|
| 145 |
+
node.destroy_node()
|
| 146 |
+
rclpy.shutdown()
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
if __name__ == "__main__":
|
| 150 |
+
main()
|
go2_control/package.xml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0"?>
|
| 2 |
+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
| 3 |
+
<package format="3">
|
| 4 |
+
<name>go2_control</name>
|
| 5 |
+
<version>0.0.0</version>
|
| 6 |
+
<description>Keyboard teleop for Unitree Go2 (arrows = move, q/e = rotate) publishing TwistStamped to /cmd_vel_joy</description>
|
| 7 |
+
<maintainer email="dsclabs.contact@gmail.com">dsc-labs</maintainer>
|
| 8 |
+
<license>BSD-3-Clause</license>
|
| 9 |
+
|
| 10 |
+
<exec_depend>rclpy</exec_depend>
|
| 11 |
+
<exec_depend>geometry_msgs</exec_depend>
|
| 12 |
+
|
| 13 |
+
<test_depend>ament_copyright</test_depend>
|
| 14 |
+
<test_depend>ament_flake8</test_depend>
|
| 15 |
+
<test_depend>ament_pep257</test_depend>
|
| 16 |
+
<test_depend>python3-pytest</test_depend>
|
| 17 |
+
|
| 18 |
+
<export>
|
| 19 |
+
<build_type>ament_python</build_type>
|
| 20 |
+
</export>
|
| 21 |
+
</package>
|
go2_control/resource/go2_control
ADDED
|
File without changes
|
go2_control/setup.cfg
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[develop]
|
| 2 |
+
script_dir=$base/lib/go2_control
|
| 3 |
+
[install]
|
| 4 |
+
install_scripts=$base/lib/go2_control
|
go2_control/setup.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from setuptools import find_packages, setup
|
| 2 |
+
|
| 3 |
+
package_name = 'go2_control'
|
| 4 |
+
|
| 5 |
+
setup(
|
| 6 |
+
name=package_name,
|
| 7 |
+
version='0.0.0',
|
| 8 |
+
packages=find_packages(exclude=['test']),
|
| 9 |
+
data_files=[
|
| 10 |
+
('share/ament_index/resource_index/packages',
|
| 11 |
+
['resource/' + package_name]),
|
| 12 |
+
('share/' + package_name, ['package.xml']),
|
| 13 |
+
],
|
| 14 |
+
install_requires=['setuptools'],
|
| 15 |
+
zip_safe=True,
|
| 16 |
+
maintainer='dsc-labs',
|
| 17 |
+
maintainer_email='dsclabs.contact@gmail.com',
|
| 18 |
+
description='Keyboard teleop for Unitree Go2 (publishes TwistStamped to /cmd_vel_joy)',
|
| 19 |
+
license='BSD-3-Clause',
|
| 20 |
+
entry_points={
|
| 21 |
+
'console_scripts': [
|
| 22 |
+
'keyboard_teleop = go2_control.keyboard_teleop:main',
|
| 23 |
+
],
|
| 24 |
+
},
|
| 25 |
+
)
|
go2_interfaces/CMakeLists.txt
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cmake_minimum_required(VERSION 3.8)
|
| 2 |
+
project(go2_interfaces)
|
| 3 |
+
|
| 4 |
+
# Fix for CMake policy CMP0148 warning
|
| 5 |
+
if(POLICY CMP0148)
|
| 6 |
+
cmake_policy(SET CMP0148 OLD)
|
| 7 |
+
endif()
|
| 8 |
+
|
| 9 |
+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
| 10 |
+
add_compile_options(-Wall -Wextra -Wpedantic)
|
| 11 |
+
endif()
|
| 12 |
+
|
| 13 |
+
# find dependencies
|
| 14 |
+
find_package(ament_cmake REQUIRED)
|
| 15 |
+
find_package(geometry_msgs REQUIRED)
|
| 16 |
+
find_package(rosidl_default_generators REQUIRED)
|
| 17 |
+
# uncomment the following section in order to fill in
|
| 18 |
+
# further dependencies manually.
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
rosidl_generate_interfaces(${PROJECT_NAME}
|
| 22 |
+
# Original go2_interfaces messages
|
| 23 |
+
"msg/Go2Cmd.msg"
|
| 24 |
+
"msg/Go2State.msg"
|
| 25 |
+
"msg/Go2Move.msg"
|
| 26 |
+
"msg/Go2RpyCmd.msg"
|
| 27 |
+
"msg/IMU.msg"
|
| 28 |
+
|
| 29 |
+
# Merged from unitree_go
|
| 30 |
+
"msg/AudioData.msg"
|
| 31 |
+
"msg/BmsCmd.msg"
|
| 32 |
+
"msg/BmsState.msg"
|
| 33 |
+
"msg/Error.msg"
|
| 34 |
+
"msg/Go2FrontVideoData.msg"
|
| 35 |
+
"msg/HeightMap.msg"
|
| 36 |
+
"msg/InterfaceConfig.msg"
|
| 37 |
+
"msg/LidarState.msg"
|
| 38 |
+
"msg/LowCmd.msg"
|
| 39 |
+
"msg/LowState.msg"
|
| 40 |
+
"msg/MotorCmd.msg"
|
| 41 |
+
"msg/MotorCmds.msg"
|
| 42 |
+
"msg/MotorState.msg"
|
| 43 |
+
"msg/MotorStates.msg"
|
| 44 |
+
"msg/PathPoint.msg"
|
| 45 |
+
"msg/Req.msg"
|
| 46 |
+
"msg/Res.msg"
|
| 47 |
+
"msg/SportModeCmd.msg"
|
| 48 |
+
"msg/SportModeState.msg"
|
| 49 |
+
"msg/TimeSpec.msg"
|
| 50 |
+
"msg/UwbState.msg"
|
| 51 |
+
"msg/UwbSwitch.msg"
|
| 52 |
+
"msg/VoxelMapCompressed.msg"
|
| 53 |
+
"msg/VoxelHeightMapState.msg"
|
| 54 |
+
"msg/WebRtcReq.msg"
|
| 55 |
+
"msg/WirelessController.msg"
|
| 56 |
+
|
| 57 |
+
DEPENDENCIES geometry_msgs # Add packages that above messages depend on
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
ament_package()
|
go2_interfaces/msg/AudioData.msg
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint64 time_frame
|
| 2 |
+
uint8[] data
|
go2_interfaces/msg/BmsCmd.msg
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 off
|
| 2 |
+
uint8[3] reserve
|
go2_interfaces/msg/BmsState.msg
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 version_high
|
| 2 |
+
uint8 version_low
|
| 3 |
+
uint8 status
|
| 4 |
+
uint8 soc
|
| 5 |
+
int32 current
|
| 6 |
+
uint16 cycle
|
| 7 |
+
int8[2] bq_ntc
|
| 8 |
+
int8[2] mcu_ntc
|
| 9 |
+
uint16[15] cell_vol
|
go2_interfaces/msg/Error.msg
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint32 source
|
| 2 |
+
uint32 state
|
go2_interfaces/msg/Go2Cmd.msg
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
uint16 cmd
|
go2_interfaces/msg/Go2FrontVideoData.msg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Time frame as a 64-bit unsigned integer
|
| 2 |
+
uint64 time_frame
|
| 3 |
+
|
| 4 |
+
# Resolution as a 16-bit signed integer
|
| 5 |
+
int16 resolution
|
| 6 |
+
|
| 7 |
+
# Data as a sequence of bytes (octets)
|
| 8 |
+
uint8[] data
|
go2_interfaces/msg/Go2Move.msg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float32 x
|
| 2 |
+
float32 y
|
| 3 |
+
float32 z
|
go2_interfaces/msg/Go2RpyCmd.msg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float32 roll
|
| 2 |
+
float32 pitch
|
| 3 |
+
float32 yaw
|
go2_interfaces/msg/Go2State.msg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 mode
|
| 2 |
+
int32 progress
|
| 3 |
+
uint8 gait_type
|
| 4 |
+
float32 foot_raise_height
|
| 5 |
+
float32[3] position
|
| 6 |
+
float32 body_height
|
| 7 |
+
float32[3] velocity
|
| 8 |
+
float32[4] range_obstacle
|
| 9 |
+
int16[4] foot_force
|
| 10 |
+
float32[12] foot_position_body
|
| 11 |
+
float32[12] foot_speed_body
|
| 12 |
+
|
go2_interfaces/msg/HeightMap.msg
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Header
|
| 2 |
+
float64 stamp # timestamp
|
| 3 |
+
string frame_id # world frame id
|
| 4 |
+
|
| 5 |
+
# Map info
|
| 6 |
+
float32 resolution # The map resolution [m/cell]
|
| 7 |
+
uint32 width # Map width along x-axis [cells]
|
| 8 |
+
uint32 height # Map height alonge y-axis [cells]
|
| 9 |
+
float32[2] origin # Map frame origin xy-position [m], the xyz-axis direction of map frame is aligned with the world frame
|
| 10 |
+
|
| 11 |
+
# Map data, in x-major order, starting with [0,0], ending with [width, height]
|
| 12 |
+
# For a cell whose 2d-array-index is [ix, iy],
|
| 13 |
+
# its position in world frame is: [ix * resolution + origin[0], iy * resolution + origin[1]]
|
| 14 |
+
# its cell value is: data[width * iy + ix]
|
| 15 |
+
float32[] data
|
go2_interfaces/msg/IMU.msg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float32[4] quaternion
|
| 2 |
+
float32[3] gyroscope
|
| 3 |
+
float32[3] accelerometer
|
| 4 |
+
float32[3] rpy
|
| 5 |
+
int8 temperature
|
go2_interfaces/msg/InterfaceConfig.msg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 mode
|
| 2 |
+
uint8 value
|
| 3 |
+
uint8[2] reserve
|
go2_interfaces/msg/LidarState.msg
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float64 stamp
|
| 2 |
+
string firmware_version
|
| 3 |
+
string software_version
|
| 4 |
+
string sdk_version
|
| 5 |
+
float32 sys_rotation_speed
|
| 6 |
+
float32 com_rotation_speed
|
| 7 |
+
uint8 error_state
|
| 8 |
+
float32 cloud_frequency
|
| 9 |
+
float32 cloud_packet_loss_rate
|
| 10 |
+
uint32 cloud_size
|
| 11 |
+
uint32 cloud_scan_num
|
| 12 |
+
float32 imu_frequency
|
| 13 |
+
float32 imu_packet_loss_rate
|
| 14 |
+
float32[3] imu_rpy
|
| 15 |
+
float64 serial_recv_stamp
|
| 16 |
+
uint32 serial_buffer_size
|
| 17 |
+
uint32 serial_buffer_read
|
go2_interfaces/msg/LowCmd.msg
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8[2] head
|
| 2 |
+
uint8 level_flag
|
| 3 |
+
uint8 frame_reserve
|
| 4 |
+
uint32[2] sn
|
| 5 |
+
uint32[2] version
|
| 6 |
+
uint16 bandwidth
|
| 7 |
+
MotorCmd[20] motor_cmd
|
| 8 |
+
BmsCmd bms_cmd
|
| 9 |
+
uint8[40] wireless_remote
|
| 10 |
+
uint8[12] led
|
| 11 |
+
uint8[2] fan
|
| 12 |
+
uint8 gpio
|
| 13 |
+
uint32 reserve
|
| 14 |
+
uint32 crc
|
| 15 |
+
|
go2_interfaces/msg/LowState.msg
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8[2] head
|
| 2 |
+
uint8 level_flag
|
| 3 |
+
uint8 frame_reserve
|
| 4 |
+
uint32[2] sn
|
| 5 |
+
uint32[2] version
|
| 6 |
+
uint16 bandwidth
|
| 7 |
+
IMU imu_state
|
| 8 |
+
MotorState[20] motor_state
|
| 9 |
+
BmsState bms_state
|
| 10 |
+
int16[4] foot_force
|
| 11 |
+
int16[4] foot_force_est
|
| 12 |
+
uint32 tick
|
| 13 |
+
uint8[40] wireless_remote
|
| 14 |
+
uint8 bit_flag
|
| 15 |
+
float32 adc_reel
|
| 16 |
+
int8 temperature_ntc1
|
| 17 |
+
int8 temperature_ntc2
|
| 18 |
+
float32 power_v
|
| 19 |
+
float32 power_a
|
| 20 |
+
uint16[4] fan_frequency
|
| 21 |
+
uint32 reserve
|
| 22 |
+
uint32 crc
|
go2_interfaces/msg/MotorCmd.msg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 mode
|
| 2 |
+
float32 q
|
| 3 |
+
float32 dq
|
| 4 |
+
float32 tau
|
| 5 |
+
float32 kp
|
| 6 |
+
float32 kd
|
| 7 |
+
uint32[3] reserve
|
go2_interfaces/msg/MotorCmds.msg
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
MotorCmd[] cmds
|
go2_interfaces/msg/MotorState.msg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 mode
|
| 2 |
+
float32 q
|
| 3 |
+
float32 dq
|
| 4 |
+
float32 ddq
|
| 5 |
+
float32 tau_est
|
| 6 |
+
float32 q_raw
|
| 7 |
+
float32 dq_raw
|
| 8 |
+
float32 ddq_raw
|
| 9 |
+
int8 temperature
|
| 10 |
+
uint32 lost
|
| 11 |
+
uint32[2] reserve
|
go2_interfaces/msg/MotorStates.msg
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
MotorState[] states
|
go2_interfaces/msg/PathPoint.msg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float32 t_from_start
|
| 2 |
+
float32 x
|
| 3 |
+
float32 y
|
| 4 |
+
float32 yaw
|
| 5 |
+
float32 vx
|
| 6 |
+
float32 vy
|
| 7 |
+
float32 vyaw
|
go2_interfaces/msg/Req.msg
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
string uuid
|
| 2 |
+
string body
|
go2_interfaces/msg/Res.msg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
string uuid
|
| 2 |
+
uint8[] data
|
| 3 |
+
string body
|
go2_interfaces/msg/SportModeCmd.msg
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8 mode
|
| 2 |
+
uint8 gait_type
|
| 3 |
+
uint8 speed_level
|
| 4 |
+
float32 foot_raise_height
|
| 5 |
+
float32 body_height
|
| 6 |
+
float32[2] position
|
| 7 |
+
float32[3] euler
|
| 8 |
+
float32[2] velocity
|
| 9 |
+
float32 yaw_speed
|
| 10 |
+
BmsCmd bms_cmd
|
| 11 |
+
PathPoint[30] path_point
|
| 12 |
+
|
| 13 |
+
|
go2_interfaces/msg/SportModeState.msg
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
TimeSpec stamp
|
| 2 |
+
uint32 error_code
|
| 3 |
+
IMU imu_state
|
| 4 |
+
uint8 mode
|
| 5 |
+
float32 progress
|
| 6 |
+
uint8 gait_type
|
| 7 |
+
float32 foot_raise_height
|
| 8 |
+
float32[3] position
|
| 9 |
+
float32 body_height
|
| 10 |
+
float32[3] velocity
|
| 11 |
+
float32 yaw_speed
|
| 12 |
+
float32[4] range_obstacle
|
| 13 |
+
int16[4] foot_force
|
| 14 |
+
float32[12] foot_position_body
|
| 15 |
+
float32[12] foot_speed_body
|
| 16 |
+
|
| 17 |
+
|
go2_interfaces/msg/TimeSpec.msg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Time indicates a specific point in time, relative to a clock's 0 point.
|
| 2 |
+
# The seconds component, valid over all int32 values.
|
| 3 |
+
int32 sec
|
| 4 |
+
# The nanoseconds component, valid in the range [0, 10e9).
|
| 5 |
+
uint32 nanosec
|
go2_interfaces/msg/UwbState.msg
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
uint8[2] version
|
| 2 |
+
uint8 channel
|
| 3 |
+
uint8 joy_mode
|
| 4 |
+
float32 orientation_est
|
| 5 |
+
float32 pitch_est
|
| 6 |
+
float32 distance_est
|
| 7 |
+
float32 yaw_est
|
| 8 |
+
float32 tag_roll
|
| 9 |
+
float32 tag_pitch
|
| 10 |
+
float32 tag_yaw
|
| 11 |
+
float32 base_roll
|
| 12 |
+
float32 base_pitch
|
| 13 |
+
float32 base_yaw
|
| 14 |
+
float32[2] joystick
|
| 15 |
+
uint8 error_state
|
| 16 |
+
uint8 buttons
|
| 17 |
+
uint8 enabled_from_app
|
| 18 |
+
|
| 19 |
+
|
go2_interfaces/msg/UwbSwitch.msg
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
uint8 enabled
|
go2_interfaces/msg/VoxelHeightMapState.msg
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Timestamp (in seconds since epoch)
|
| 2 |
+
float64 stamp
|
| 3 |
+
|
| 4 |
+
# Timestamp for the point cloud (in seconds)
|
| 5 |
+
float64 stamp_cloud
|
| 6 |
+
|
| 7 |
+
# Timestamp for odometry (in seconds)
|
| 8 |
+
float64 stamp_odom
|
| 9 |
+
|
| 10 |
+
# Size of the height map
|
| 11 |
+
uint32 height_map_size
|
| 12 |
+
|
| 13 |
+
# Size of the voxel map
|
| 14 |
+
uint32 voxel_map_size
|
go2_interfaces/msg/VoxelMapCompressed.msg
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Timestamp (in seconds since epoch)
|
| 2 |
+
float64 stamp
|
| 3 |
+
|
| 4 |
+
# Frame ID for the coordinate frame
|
| 5 |
+
string frame_id
|
| 6 |
+
|
| 7 |
+
# Resolution of the voxel map
|
| 8 |
+
float64 resolution
|
| 9 |
+
|
| 10 |
+
# Origin of the voxel map (x, y, z)
|
| 11 |
+
float64[3] origin
|
| 12 |
+
|
| 13 |
+
# Width of the voxel map in each dimension (x, y, z)
|
| 14 |
+
int16[3] width
|
| 15 |
+
|
| 16 |
+
# Source size of the compressed data
|
| 17 |
+
uint64 src_size
|
| 18 |
+
|
| 19 |
+
# Compressed voxel data
|
| 20 |
+
uint8[] data
|
| 21 |
+
|
go2_interfaces/msg/WebRtcReq.msg
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# message header id. if 0, it will be assigned automatically
|
| 2 |
+
int64 id
|
| 3 |
+
# topic name on dog's side including rt/ prefix
|
| 4 |
+
string topic
|
| 5 |
+
# api_id, see https://wiki.theroboverse.com/en/unitree-go2-app-console-commands#sending-commands-to-go2
|
| 6 |
+
int64 api_id
|
| 7 |
+
# payload for specific api_id
|
| 8 |
+
string parameter
|
| 9 |
+
# priority of the message. 0 non-priority, 1 priority
|
| 10 |
+
uint8 priority
|
go2_interfaces/msg/WirelessController.msg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
float32 lx
|
| 2 |
+
float32 ly
|
| 3 |
+
float32 rx
|
| 4 |
+
float32 ry
|
| 5 |
+
uint16 keys
|