拿到宇树Go1的第一天,最难的不是开箱,而是面对一堆GitHub仓库和文档时完全不知道从哪下手。官方SDK的README写得还算清楚,但真正搭开发环境的时候,ROS版本、Gazebo场景、SDK编译、网络配置全部搅在一起,任何一个环节出错,后面的demo就全部白搭。这篇文章我把从零部署Unitree SDK、再把Go1的ROS仿真环境跑通的完整过程整理出来,包括版本选型思路、每一步的关键命令、以及我踩过且觉得很有必要说明的坑。适合刚接触四足机器人、有基础Linux操作能力、打算在真机下手之前先在仿真里练手的开发者参考。
1. 先把技术账算清楚:Go1开发主机的版本选型逻辑
很多人在第一步就卡住了,不是不会装系统,而是不知道选哪个版本组合。我见过直接在Ubuntu 24上装ROS 2的、也有在Windows上硬跑Gazebo的,最后都回来重装。四足机器人开发没有那么多“新版更好”的余地,绝大多数官方工具链的测试矩阵停留在旧版本,选得太新反而是给自己挖坑。
先明确一个核心事实:Go1本体上一块NVIDIA Jetson Xavier NX,默认环境是Ubuntu 18.04 + ROS Melodic。但你在PC上做仿真开发,不需要跟本体系统保持一致,PC端的关键诉求是“跑得了Gazebo、能编译官方SDK、社区资料对得上”。满足这三点的最佳组合目前就是Ubuntu 20.04 + ROS Noetic。
1.1 三种常见版本组合的取舍
我这里直接给出对比,省得大家反复试错:
| 组合 | 适合场景 | 主要问题 |
|---|---|---|
| Ubuntu 18.04 + ROS Melodic | Go1本体Xavier NX上的机载开发 | 工具链偏旧,很多新Python库装不上,Gazebo版本也老 |
| Ubuntu 20.04 + ROS Noetic | PC端仿真开发,最推荐 | 几乎没有短板,唯一的“问题”是已经有新版本出来,诱惑你升级 |
| Ubuntu 22.04 + ROS 2 Humble | 新SDK版本、新项目 | unitree_ros老仓库里的包需要自己改package.xml和API,老demo基本不能直接catkin_make |
为什么Noetic这么稳?因为unitree_ros仓库里所有的launch文件、URDF模型、消息包定义,基本都是在Noetic下写的。你不需要做任何兼容性适配,clone下来编译就能过。而ROS 2 Humble下跑,你得自己搞定CMakeLists和Python节点的迁移,对新人来说完全没有必要在这个环节增加工作量。
1.2 本机开发与狗身开发的分工逻辑
还有一件事要提前想明白:你在PC上搭的环境,最终怎么和Go1对上?
Go1本体虽然有Xavier NX,但不建议在本体上做编译和密集仿真。嵌入式板卡的CPU和内存都有限,跑Gazebo会把资源吃满,本体的实时运动控制也会受影响。更合理的分工是:
- PC负责仿真、算法验证、训练、代码编写
- 本体只负责运行编译好的控制程序和SDK
- 通过SSH或者Git把代码同步到本体
SDK层面还有一个细节:真机模式下,PC和Go1需要在同一个局域网,Go1运动控制接口的默认地址是192.168.12.1,SDK源码里默认的本地地址是192.168.12.2。这些值在仿真模式里用不到,但你要知道它存在,否则后面做桥接时容易混淆。
2. 搭建Linux/ROS开发环境:一键脚本与手动排查的配合
系统装好之后,第一步是安装ROS。ROS安装最劝退新人的是那一大堆依赖和rosdep初始化,所以我直接用了鱼香ROS的一键安装脚本,这东西在社群里的口碑确实好,能把很多手动步骤合并掉。
安装命令很简单:
wget http://fishros.com/install -O fishros && . fishros脚本运行后会弹出一个交互菜单,你选择“安装ROS桌面版”或“安装ROS精简版”都可以。我建议第一次装选桌面版,因为Gazebo、rviz、TF工具链都会一并装好,省得后面缺一个包装一个包。
2.1 安装完之后的三件配置事
很多人以为脚本跑完就结束了,实际上还有三件事必须做,否则后面的编译大概率失败。
第一,把ROS环境变量写进.bashrc:
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc第二,处理rosdep。这个环节是我见过报错率最高的,rosdep init经常因为网络原因失败或者超时。如果你用的是鱼香ROS一键脚本,直接选择菜单里的“配置rosdep”选项,它能帮你把镜像源换好。不建议自己反复硬试rosdep init,那条路真的又枯燥又容易把人搞崩溃。
第三,创建工作空间并编译一次空包,验证整个工具链是否通:
sudo apt install python3-catkin-tools mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace cd ~/catkin_ws catkin build看到编译成功后,再执行:
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc source ~/.bashrc这一步跑通,说明ROS环境、catkin工具链、Python3接口都已经正常。
2.2 Gazebo依赖包的补齐
桌面版ROS会把Gazebo本体装好,但Gazebo和ROS的桥接包有时不会自动装全。我建议显式安装一遍,避免后面launch时提示找不到gazebo_ros:
sudo apt install ros-noetic-gazebo-ros ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros-control ros-noetic-teleop-twist-keyboard顺带说一下,如果你用的是虚拟机,Gazebo跑起来会很吃力,建议给虚拟机开启3D加速,或者在宿主机上直接跑。我在实体机上测试时很流畅,切到虚拟机就经常黑屏,排查了半天发现是OpenGL渲染问题。
3. Unitree SDK编译与源码结构拆解:先看懂再动手
SDK是宇树机器人的开发核心,官方仓库叫unitree_legged_sdk。我建议在编译之前先把目录结构大概翻一遍,别急着make,因为你至少要弄清楚这个SDK到底给你提供了什么。
3.1 拉取和编译官方SDK
git clone https://github.com/unitreerobotics/unitree_legged_sdk.git cd unitree_legged_sdk mkdir build && cd build cmake .. make编译过程一般不会有太大问题。唯一可能翻车的是LCM依赖,如果你在make阶段看到lcm相关报错,两种解决办法:
sudo apt install liblcm-dev或者使用SDK仓库里自带的lcm模块来编译,看官方README里的说明就行。
编译完成后,build目录下会生成可执行示例,常见的有example_velocity和example_position这两个。前者是速度控制示例,后者是位置控制示例。
3.2 你真正需要认识的四种数据结构
SDK的接口分两层,理解清楚这对后面控制仿真和真机都很关键。
高层控制使用HighCmd和HighState。HighCmd是你发给机器人的期望指令,里面有mode(模式)、gaitType(步态类型)、velocity(速度)、bodyHeight(机身高度)、footRaiseHeight(抬腿高度)这些字段。HighState是机器人回传的状态,包含IMU姿态、速度、位置、电量等。用高层控制时,你不需要关心每条腿的关节角度,只需要告诉机器人“往哪走、走多快”,内置控制器会帮你完成步态生成。
底层控制使用LowCmd和LowState,这是12个关节电机的直接控制接口。你需要给每个关节设置目标位置、目标速度和力矩增益。强化学习算法和自定义步态通常在这一层做,比如热词里经常有人提到的“go-m010-6关节电机调试”,本质上就是在和LowCmd打交道。
对第一次部署来说,先跑通高层控制就够了。底层控制在仿真的调试难度会高很多,我建议放到后续阶段再碰。
3.3 LCM在SDK里的作用
LCM是一个轻量级消息库,宇树的SDK里用它在模块之间传递数据。你用lcm-spy可以实时看到机器人发出的所有内部消息类型和频率。
这部分对新手来说不用深究,但要知道:如果你的工程里需要抓到比HighState更细粒度、比如关节力矩或者原始IMU数据,LCM就是那扇门。仿真环境里很多调试工具也依赖LCM通道,后面如果要做更深入的状态分析,可以回来研究它。
4. Gazebo仿真环境搭建:让Go1先活在你的桌面上
SDK编译好之后,接下来就是这个项目最有成就感的环节——在Gazebo里看到一条狗站起来的瞬间。
官方仿真仓库叫unitree_ros,把它拉到你之前的catkin工作空间里:
cd ~/catkin_ws/src git clone https://github.com/unitreerobotics/unitree_ros.git cd ~/catkin_ws catkin build source devel/setup.bash编译完成后,启动仿真:
roslaunch unitree_gazebo go1.launch启动之后,你会看到Gazebo窗口慢慢出现一个地形场景,然后一条白灰色的Go1出现在画面中。第一次启动可能会卡很久,这是正常现象,因为Gazebo要在线加载场景中使用的模型文件,具体怎么处理我在第六部分会专门说。
4.1 启动后有哪些值得关注的话题
仿真跑起来之后,打开另一个终端,执行:
rostopic list你会看到很多话题,其中这四类是最核心的:
/cmd_vel:速度控制入口,发布geometry_msgs/Twist消息即可控制机器人平移和旋转/odom:里程计数据,告诉位置和姿态/imu:IMU原始数据/joint_states:12个关节的实时角度信息
你可以用rqt_graph看一下当前节点图,能直观看到launch封装了哪些节点,比如机器人状态发布节点、Gazebo桥接节点、控制器节点。
4.2 用一条命令让狗走起来
确认话题正常后,发送一个前进加转向的控制指令:
rostopic pub -r 10 /cmd_vel geometry_msgs/Twist "linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}"在Gazebo里,你会看到Go1开始向前走,同时向左画一个弧线。想停下来的话,重新发一条全零速度,或者Ctrl+C中断发布。
更舒服的调试方式是用键盘控制:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py这个节点运行时,按i就是前进、j是左转、l是右转、k是停止。刚开始测试时建议把速度设定在小范围,先确认运动方向正确再加大,不然很容易出现仿真里撞墙、翻车的场面。
4.3 为什么Gazebo里的Go1能自己保持平衡
很多人第一次看到仿真狗站起来会好奇,URDF模型里明明只是零件加关节,为什么它不会倒?
其实这是Gazebo物理引擎和控制器共同作用的结果。unitree_ros仓库里带了默认的控制器配置,它实时读取关节状态,通过PD控制调节关节力矩,让模型维持身体姿态平衡。这跟真机上的整机控制器思路是一致的。理解这一点对后续开发很重要:仿真模型是自由落体还是稳定站立,完全取决于控制器有没有生效。
5. 控制链路打通:从ROS话题到SDK的高层控制
Gazebo能跑了,rostopic也能控制狗了,但你还没和SDK发生关系。SDK和ROS仿真打通,是实现完整开发链路的关键一步,这里有两种路线,看你最终要做的事情是什么。
5.1 路线A:直接用ROS话题控制,适合验证算法
如果你的目标是在仿真里验证导航、SLAM、避障算法,ROS话题就够了。你不需要启动SDK里的任何代码,算法节点直接发布/cmd_vel,视觉和感知节点订阅/odom和/imu,这是一个纯粹的ROS闭环。
这是我最推荐新手先走的路线。原因很简单:先把ROS侧的感知、规划、决策跑通,不要被SDK的底层细节干扰。等你确定算法逻辑没问题,再考虑怎么把它接到真实机器人上。
5.2 路线B:用SDK桥接节点控制Gazebo,适合SDK二次开发
如果你的目的是在SDK上做二次开发,比如自定义高层状态机、集成特殊的用户接口,那就需要在SDK和仿真之间搭一座桥。
SDK默认的通信方式是UDP,目标地址是192.168.12.1,但仿真里没有这个地址。桥接的基本思路是:把SDK里的HighCmd转成Twist消息发布到/cmd_vel,同时把/odom或/joint_states包装成HighState回传给SDK。核心结构可以这样理解:
#!/usr/bin/env python3 import rospy from geometry_msgs.msg import Twist def cmd_to_twist(vx, vy, vyaw): msg = Twist() msg.linear.x = vx msg.linear.y = vy msg.angular.z = vyaw return msg def on_sdk_command(sdk_data): twist = cmd_to_twist(sdk_data.vx, sdk_data.vy, sdk_data.vyaw) cmd_pub.publish(twist) rospy.init_node('sdk_sim_bridge') cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1) rospy.spin()这个代码只是一个概念框架,真正的桥接节点还要把odom数据实时回传、处理机器人的启停状态、同步步态参数。如果你只是想在仿真里看SDK的效果,可以搜索社区里现成的桥接包,不需要自己从头写。
5.3 仿真和真机在高频控制上最大的不同
我实测下来,仿真Gazebo里的Go1在收到过大速度指令时会有明显抖动,尤其是急起步和急停的时候,因为物理引擎的步长限制导致足端响应跟不上指令变化。真机Go1有整机控制器做平滑,起步和制动反而更柔和。
另一个差异是原地转身:仿真里转向很流畅,但真机因为地面摩擦和重量分布,同样的角速度参数会感觉更“沉”。这些都不算bug,而是仿真模型与实际物理属性不同导致的正常差距。
| 观察项 | Gazebo仿真 | 真机Go1 |
|---|---|---|
| 起步和急停 | 有明显顿挫、模型抖动 | 有整机控制器平滑,动作更柔和 |
| 原地转向 | 响应直接、流畅 | 受地面摩擦影响更明显 |
| 速度上限 | 模型不会主动限制 | 官方SDK有保护性限制 |
| 电量/温度保护 | 完全没有 | 有硬件和软件保护 |
6. 我踩过的坑:依赖、模型加载与仿真真机不一致问题
这一部分是我最想写的,整个部署过程中真正让人崩溃的往往不是逻辑,而是环境问题。下面几个坑是我实际遇到且找到解决方案的,按排查链路分享给大家。
6.1 rosdep初始化失败和GitHub拉取缓慢的处理
rosdep init失败是最经典的入门劝退问题。现象是终端卡在连接国外服务器超时,或者直接报错退出。很多初学者会在这一步反复重试,浪费大量时间。
我的建议是不要硬刚。直接用鱼香ROS一键脚本里的“配置rosdep”选项,或者手动把rosdep源改成国内镜像。改完之后rosdep update就能顺利跑完。
同理,git clone官方仓库时如果速度很慢,不一定要在上面死等。可以把仓库下载成zip压缩包再解压,或者找Gitee上维护者同步好的镜像仓库,速度会快很多。
6.2 Gazebo启动后场景空白、模型加载失败的完整排查链路
这个坑非常典型,现象是launch命令执行后,Gazebo窗口出来了,但地面和Go1模型迟迟不出现,终端里滚动输出HTTP请求失败的日志。
排查链路是这样的:
- 先看启动日志里有没有
Timeout、404、Unable to connect这类关键词 - 如果有,基本可以确认是场景模型文件没下载成功
- 检查
~/.gazebo/models目录下是否有对应模型文件夹 - 手动从模型库下载缺失的模型,或者把unitree_ros仓库自带的模型路径加入环境变量
echo "export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:~/catkin_ws/src/unitree_ros/unitree_gazebo/models" >> ~/.bashrc source ~/.bashrc配置完再重启launch,场景几乎秒开。
另外,如果你在虚拟机里遇到Gazebo黑屏或者模型花屏,可以试一下:
export LIBGL_ALWAYS_SOFTWARE=1软渲染虽然性能差点,但至少能出画面。实体机遇到这个问题的概率不大,优先检查显卡驱动。
6.3 Python 2和Python 3的兼容问题
Noetic的ROS环境默认是Python 3,但早期版本的unitree_legged_sdk里有一部分Python示例还是Python 2的写法。如果你的代码是从老仓库拷贝的,运行时可能会遇到print x或者xrange这样的语法报错,这不是你的问题,是代码本身没迁移。
解决方式有两种:如果官方SDK的新版本已经提供Python 3接口,直接换新;如果必须跑老代码,就单独建一个Python 2的虚拟环境来跑。不建议在系统层面把默认Python改成2,那会连带破坏ROS的其他工具链。
6.4 仿真里调好的参数不能直接搬到真机
这是我个人觉得最重要的一条经验。仿真环境是理想物理模型,不存在关节过热、电量下降、硬件限位这些问题。你在仿真里把速度调到1.0,狗跑得很欢,但真机上如果直接下发同样数值,轻则运动异常,重则损坏机构。
上真机之前,一定要在代码里加入安全保护:检查关节角度是否在允许范围、速度指令是否超过官方限制、紧急停止逻辑是否生效。Go1官方的速度上限在不同型号和协议版本里定义不同,务必去翻SDK源码里的配置,别只看仿真里能接受多大值。
我后来养成的习惯是:每次工作开始前,先看一眼launch文件和SDK里的IP、LOCALADDR配置,确认当前是仿真模式还是真机模式。上真机测试时,一定先用手扶住机器狗,发送一个微小的直线速度,确认运动方向符合预期后再松开手。这个动作看起来很基础,但我见过不少人在仿真里把速度方向调反,上了真机直接把机器怼上墙的例子。四足开发最难的不是某个API,而是建立起“仿真里的一切都是假的、但逻辑是真的”这种判断力。这个判断力一旦有了,后面再做B2、Go2、G1这些新机型,上手速度会快非常多。