在四足机器人开发中,高层运动控制是实现灵活动作与自主移动的核心环节。Unitree Go2机器人基于SDK2提供了丰富的高层运动控制接口,涵盖基础姿态控制、速度控制、轨迹跟踪及特色动作执行等功能,为开发者提供了便捷的二次开发入口。本文将从运动模式分类、例程结构、代码解析、实战操作等维度,全方位拆解Go2高层运动控制的技术细节,助力开发者快速实现机器人运动功能定制。

一、高层运动控制概述:核心定位与适用场景

1. 核心架构

Go2的高层运动控制基于Unitree SDK2构建,通过C++例程封装了各类运动接口,开发者可通过修改配置参数或二次开发,实现对机器人的精细化运动控制。其核心设计逻辑是:通过枚举test_mode指定运动模式,由sport_client对象调用SDK接口执行动作,同时通过回调函数实时获取机器人运动状态,形成"指令下发-状态反馈"的闭环控制。

2. 适用场景

该套控制接口适用于教育科研、机器人演示、动作编程等场景,支持基础运动调试、特殊动作编排、轨迹跟踪等开发需求。使用前需注意:

  • 场地要求:执行运动(尤其是特殊动作)时需保证场地空旷,无障碍物干扰
  • 操作前提:需通过遥控器让Go2进入运动模式,避免硬件冲突
  • 开发环境:需安装Unitree SDK2,支持C++编译环境(兼容ROS生态)

二、运动模式全解析:基础运动与特殊动作

Go2的高层运动模式分为基础运动控制特殊动作两大类,共包含19种具体模式,通过枚举test_mode定义,开发者可修改TEST_MODE变量指定运行模式。

1. 基础运动控制:核心功能与参数说明

基础运动涵盖机器人核心姿态与移动控制,支持持续运行或状态切换,是机器人运动的基础能力。

运动模式 功能说明 关键参数/特性
normal_stand 正常站立 关节锁定,保持固定站高,为默认基础状态
balance_stand 平衡站立 站立时维持机体姿态平衡,支持欧拉角与机身高度调节
velocity_move 速度控制 按指定x、y、yaw速度移动,参考坐标系为机体坐标系
trajectory_follow 轨迹跟踪控制 跟踪预设参考轨迹,参考坐标系为绝对坐标系(程序启动位置为原点)
stand_down 趴下 关节锁定,机体贴合地面
stand_up 站高 关节锁定,提升机体高度至默认值(0.33m)
damp 阻尼模式 所有电机进入阻尼状态,优先级最高,相当于"软急停"
recovery_stand 恢复站立 从翻倒或趴下状态自动恢复至站立状态
stop_move 停止运动 终止所有当前执行的运动指令,回归 idle 状态
关键参数限制(平衡站立模式):
  • 欧拉角范围:roll(横滚)[-0.75, 0.75]、pitch(俯仰)[-0.75, 0.75]、yaw(偏航)[-0.6, 0.6](单位:rad)
  • 机身高度:相对于默认状态(0.33m)的调节范围为[-0.18, 0.03](负值降低高度,正值升高高度)

2. 特殊动作:特色功能与执行规则

特殊动作是Go2的亮点功能,涵盖仿生动作、互动动作等,需注意:所有特殊动作在短时间内仅能执行一次,需通过标志位flag控制执行状态。

特殊动作 功能说明 执行特性
sit 坐下 仿生坐姿,执行后维持该姿态
rise_sit 坐姿恢复 从坐下状态恢复至之前的运动状态
stretch 伸懒腰 机体舒展动作,增强互动性
wallow 打滚 机身绕轴线翻滚,需足够场地空间
content 开心 仿生开心动作(如摆尾、机身晃动)
pose 摆姿势 预设造型动作,参数true指定动作类型
scrape 拜年作揖 仿生作揖动作,适用于演示场景
front_flip 前空翻 高危动作,需确保场地空旷无遮挡
front_jump 前跳 向前短距离跳跃,跳跃高度与距离固定
front_pounce 向前扑人 仿生扑击动作,移动速度较快

三、例程快速上手:环境准备与编译运行

1. 核心文件与依赖

  • 例程路径:unitree_sdk2/example/go2/go2_sport_client.cpp
  • 依赖环境:Unitree SDK2(需提前安装配置)、C++编译器(支持C++11及以上)、CMake构建工具

2. 编译与运行步骤

(1)选择运动模式

修改例程中TEST_MODE变量,指定需测试的运动模式,例如测试速度控制:

const int TEST_MODE = velocity_move; // 枚举值对应目标运动模式
(2)编译例程

在SDK目录下执行编译指令:

# 进入例程目录(根据实际路径调整)
cd unitree_sdk2/example/go2
# 创建编译目录
mkdir build && cd build
# 构建工程
cmake ..
# 编译生成可执行文件
make
(3)运行测试程序
  1. 通过遥控器让Go2进入运动模式,放置于空旷场地
  2. 在终端执行运行指令(指定网卡名称,如eth0wlan0):
    ./sportmode_test [网卡名称]
    
  3. 程序启动后等待1秒(获取稳定初始状态),机器人将执行指定动作
  4. Ctrl+C终止程序,机器人停止运动

四、核心代码解析:例程架构与控制逻辑

Go2高层运动控制例程的核心架构分为初始化模块状态回调模块运动控制模块主程序模块,各模块协同实现运动指令的下发与状态反馈。

1. 初始化模块:Custom类构造函数

Custom类封装了运动控制的核心逻辑,构造函数完成sport_client初始化与状态订阅:

Custom()
{
  // 初始化运动客户端,设置请求超时时间(10秒)
  sport_client.SetTimeout(10.0f);
  sport_client.Init();

  // 订阅高层状态话题(TOPIC_HIGHSTATE),绑定回调函数获取机器人状态
  suber.reset(new unitree::robot::ChannelSubscriber<unitree_go::msg::dds_::SportModeState_>(TOPIC_HIGHSTATE));
  suber->InitChannel(std::bind(&Custom::HighStateHandler, this, std::placeholders::_1), 1);
};

2. 状态回调模块:实时获取运动状态

HighStateHandler为状态回调函数,实时接收机器人的运动状态数据(如位置、IMU信息)并存储到state变量,供控制逻辑调用:

void HighStateHandler(const void *message)
{
  // 将接收的消息转换为运动状态类型
  state = *(unitree_go::msg::dds_::SportModeState_ *)message;
  // 打印位置信息(x, y, z)
  std::cout << "Position: " << state.position()[0] << ", " << state.position()[1] << ", " << state.position()[2] << std::endl;
  // 打印IMU欧拉角(roll, pitch, yaw)
  std::cout << "IMU rpy: " << state.imu_state().rpy()[0] << ", " << state.imu_state().rpy()[1] << ", " << state.imu_state().rpy()[2] << std::endl;
};

3. 初始状态获取:统一坐标系原点

GetInitState函数获取程序启动时机器人的位置(px0, py0)和偏航角(yaw0),作为绝对坐标系的原点,确保轨迹跟踪等功能的准确性:

void GetInitState()
{
  px0 = state.position()[0];   // 初始x坐标
  py0 = state.position()[1];   // 初始y坐标
  yaw0 = state.imu_state().rpy()[2]; // 初始偏航角
  std::cout << "initial position: x0: " << px0 << ", y0: " << py0 << ", yaw0: " << yaw0 << std::endl;
};

4. 主程序流程:启动控制线程

主程序完成网卡初始化、等待状态稳定、启动运动控制线程,实现持续运动控制:

int main(int argc, char **argv)
{
  // 检查参数(需传入网卡名称)
  if (argc < 2)
  {
    std::cout << "Usage: " << argv[0] << " networkInterface" << std::endl;
    exit(-1);
  }

  // 初始化通道工厂(指定网卡)
  unitree::robot::ChannelFactory::Instance()->Init(0, argv[1]);
  Custom custom;

  sleep(1); // 等待1秒,获取稳定的初始状态
  custom.GetInitState(); // 记录初始状态

  // 创建循环线程,按固定周期(dt)调用RobotControl执行运动控制
  unitree::common::ThreadPtr threadPtr = unitree::common::CreateRecurrentThread(custom.dt * 1000000, std::bind(&Custom::RobotControl, &custom));

  // 保持程序运行
  while (1)
  {
    sleep(10);
  }
  return 0;
}

五、关键运动模式实战:代码解析与参数配置

1. 基础运动:平衡站立与速度控制

(1)平衡站立(balance_stand)

支持欧拉角与机身高度调节,适用于姿态校准场景:

case balance_stand:                                 
  // 设置欧拉角(roll=0.1rad, pitch=0.2rad, yaw=0.3rad)
  sport_client.Euler(0.1, 0.2, 0.3);
  // 设置机身相对高度(0对应默认0.33m,可在[-0.18, 0.03]范围内调整)
  sport_client.BodyHeight(0.0);
  // 启动平衡站立
  sport_client.BalanceStand();
  break;
(2)速度控制(velocity_move)

按指定速度移动,参数分别为x轴速度、y轴速度、yaw角速度(机体坐标系):

case velocity_move:                                  
  // 示例:x轴速度0.3m/s,y轴速度0,yaw角速度0.3rad/s(顺时针旋转)
  sport_client.Move(0.3, 0, 0.3);
  break;

2. 高级运动:轨迹跟踪控制(trajectory_follow)

实现圆形轨迹跟踪,核心逻辑是生成局部坐标系下的圆轨迹点,转换为绝对坐标系后下发:

case trajectory_follow:
  time_seg = 0.2; // 轨迹时间步长(0.2秒/点)
  time_temp = ct - time_seg;

  // 生成30个轨迹点(覆盖6秒轨迹)
  for (int i = 0; i < 30; i++)
  {
    time_temp += time_seg;
 
    // 局部坐标系(程序启动原点)下的圆轨迹参数
    px_local = 0.5 * sin(0.5 * time_temp); // 圆半径0.5m
    py_local = 0.5 * cos(0.5 * time_temp) - 1;
    yaw_local = 0; // 偏航角保持0
    // 局部速度参数
    vx_local = 0.25 * cos(0.5 * time_temp);
    vy_local = -0.25 * sin(0.5 * time_temp);
    vyaw_local = 0;
 
    // 转换为绝对坐标系(基于初始位置和偏航角)
    path_point_tmp.timeFromStart = i * time_seg;
    path_point_tmp.x = px_local * cos(yaw0) - py_local * sin(yaw0) + px0;
    path_point_tmp.y = px_local * sin(yaw0) + py_local * cos(yaw0) + py0;
    path_point_tmp.yaw = yaw_local + yaw0;
    path_point_tmp.vx = vx_local * cos(yaw0) - vy_local * sin(yaw0);
    path_point_tmp.vy = vx_local * sin(yaw0) + vy_local * cos(yaw0);
    path_point_tmp.vyaw = vyaw_local;
    path.push_back(path_point_tmp);
  }
  // 下发轨迹跟踪指令
  sport_client.TrajectoryFollow(path);
  break;

3. 特殊动作:前空翻与拜年作揖

特殊动作通过标志位flag控制单次执行,避免重复触发:

(1)前空翻(front_flip)
case front_flip:
  if (flag == 0) // flag=0表示未执行过
  {
    sport_client.FrontFlip(); // 调用前空翻接口
    flag = 1; // 置1锁定,避免重复执行
  }
  break;
(2)拜年作揖(scrape)
case scrape:
  if (flag == 0)
  {
    sport_client.Scrape(); // 调用作揖接口
    flag = 1;
  }
  break;

六、运动状态获取:关键参数与调用示例

通过state变量可获取机器人的实时运动状态,涵盖位置、姿态、速度、障碍物信息等,支持运动闭环控制与故障排查。

1. 核心状态参数

状态参数 数据类型 功能说明
position() std::array<float, 3> 三维位置(x, y, z)
imu_state().rpy() std::array<float, 3> IMU欧拉角(roll, pitch, yaw)
mode() uint8_t 运动模式(0=idle, 1=balanceStand等,见文档枚举)
gaitType() uint8_t 步态类型(0=idle, 1=trot, 2=run等)
velocity() std::array<float, 3> 三维速度(x, y, z)
rangeObstacle() std::array<float, 4> 障碍物距离(四个方向)
footForce() std::array<int16_t, 4> 四足端力反馈

2. 状态调用示例

// 打印机器人当前位置
std::cout << "Current Position: " << custom.state.position()[0] << ", " << custom.state.position()[1] << std::endl;

// 打印当前运动模式(需映射为对应名称)
uint8_t currentMode = custom.state.mode();
std::cout << "Current Motion Mode: " << currentMode << std::endl;

// 打印障碍物距离(四个方向)
std::cout << "Obstacle Distance: " << custom.state.rangeObstacle()[0] << ", " << custom.state.rangeObstacle()[1] << std::endl;

七、注意事项与常见问题排查

1. 关键注意事项

  • 安全第一:执行前空翻、打滚等动作时,必须确保场地空旷,避免机器人碰撞损坏
  • 模式冲突:特殊动作单次执行后需重置flag才能再次触发,否则无法重复运行
  • 坐标系区分:速度控制基于机体坐标系,轨迹跟踪基于绝对坐标系,开发时需避免混淆
  • 状态稳定:程序启动后需等待1秒获取初始状态,否则可能导致轨迹跟踪偏差

2. 常见问题排查

  • 程序无法运行:检查网卡名称是否正确,SDK是否安装配置完成
  • 机器人无响应:确认遥控器已切换至运动模式,场地是否满足动作执行要求
  • 动作执行异常:检查TEST_MODE枚举值是否正确,参数是否超出限制(如欧拉角范围)
  • 状态获取失败:排查话题订阅是否成功,回调函数是否绑定正确

总结

Unitree Go2的高层运动控制接口通过SDK2封装了丰富的运动功能,兼具易用性与灵活性,既支持新手快速上手测试预设动作,也为进阶开发者提供了二次开发的空间。本文通过对运动模式、例程架构、代码逻辑的深度解析,为开发者提供了完整的技术指南。

在实际开发中,建议先通过预设例程测试基础运动,熟悉坐标系与参数规则后,再进行轨迹跟踪或特殊动作的定制开发。同时,需重点关注运动安全与状态反馈,确保机器人运动的稳定性与可靠性。对于复杂场景的运动控制,可基于该接口扩展路径规划、障碍物避障等功能,进一步提升机器人的自主运动能力。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐