跳到主要内容

Bumi 综合使用文档

一、关于Bumi

(一)部件信息

信息

Bumi 整机具备 21 个自由度。单臂拥有 4 个自由度,包括(左手坐标系):

  1. 肩关节pitch
  2. 肩关节roll
  3. 上臂关节yaw
  4. 手肘关节pitch

单腿拥有 6 个自由度,包括:

  1. 胯关节pitch
  2. 髋关节roll
  3. 大腿关节yaw
  4. 膝关节pitch
  5. 踝关节pitch
  6. 踝关节roll

腰关节拥有 1 个自由度,包括:

  1. 腰关节yaw

拥有多个关节电机自由度,使得Bumi机器人能够实现精确的运动控制和姿态控制。

详细信息如下:

参数BumiBumi-教育版
高宽厚(站立)98cm35cm20cm
带电池重量约17kg
总自由度21
单腿自由度6
单手臂自由度4
腰部自由度1
算力模块/

NVIDIA Jetson Orin(Nano Super / NX)


【个别型号无算力模块】

关节通讯方式Ethercat & Canfd
关节最大扭矩70N.m
小腿&大腿长度约513mm
手臂臂展约379mm
供电方式锂电池
基础算力6 Tops6 + 67 / 117 Tops
相机型号DC_V93Realsense D435ICB(EDU_Air除外)
感知传感器IMU、相机
麦克风阵列标配
扬声器标配
智能电池快拆电池
图像传输App内有开发中可直接在算力板上访问硬件
充电器
手机APP
OTA升级
续航时间2~3H
二次开发(highcontroller)
二次开发(lowcontroller)/
部件介绍图

(二)外观件尺寸

(三)电气接口

在Bumi背面,提供电气接口如下:

序号类型说明数量
1RJ45交换机 1000 BASE-T1
2USB运控板/算力板 USB 3.02
3HDMI运控板/算力板 高清显示线1
提示

带算力板的Bumi 后背接口为算力板的接口,不带算力板的Bumi,后背接口为运控板的接口

(四)机载计算机

类型型号用户密码IP算力频率内存
运控板瑞星微 RK3576运控板不对用户开放运控板不对用户开放192.168.55.1026 Tops2.4GHz8+64GB
二开算力板NVIDIA Jetson orin nano supernoetixbumi192.168.55.10167 Tops1.7GHz8+128GB
二开算力板NVIDIA Jetson orin NXnoetixbumi192.168.55.101117 Tops2.0GHz16+128GB
危险

运控板(瑞星微 RK3576)不面向用户开放,如果用户私自访问运控板,导致机器人运控程序失控,造成损失与我司无关

(五)相机信息

Bumi-EDU:Realsense D435i

英特尔® 实感™ 深度摄像头 D435i - 产品规格 | 英特尔

Bumi-标准:DC_V93

(六)电池信息

参数信息
品牌深圳格瑞普
型号GRP6752097-13S1P
容量5100mAh
电压48V

(七)充电器规格参数

参数信息
产品型号TA300 Robot
输入100-240V~50/60Hz 4.5A
电池类型LiPo/LiFe/LiHV 13S-16S
尺寸1729746mm
产品名称Smart charger智能充电器
输出35-72V ⎓ 7.5A 350W Max
工作模式Charge/充电
重量510g±10g

二、使用说明

(一)启动设备及注意事项

信息

一、设备取出与放置

  1. 将 Bumi 从收纳位置取出。
  2. 将其扶稳,使其坐于地面

二、电池安装

  1. 将电池插入 Bumi 后背电池仓。
  2. 确认电池安装到位(卡扣锁定)。

三、设备开机

  1. 短按一次电池开关,确认电池指示灯亮起。
  2. 随后长按电池开关,直至出现流水灯效果
  3. 等待机器人完成开机。

四、初始化姿态调整

  1. 将 Bumi 面朝上平躺于地面要确地面平坦不打滑,Bumi脚底板无其他异物,且周围无杂物,避免Bumi执行自动起身的时候被周围杂物影响而失败

五、系统初始化说明

  1. 开机后,Bumi 会自动进入全身使能模式
    • 所有关节将自动运动至零位
    • 过程中请勿干预或阻挡关节运动

⚠️ 注意事项

  • 开机过程中避免触碰关节,防止夹伤或干扰初始化
  • 确保地面平整,避免姿态异常
  • 电池未正确安装时禁止开机

(二)Bumi连接方式

危险

连接 Bumi 后,请勿在系统设置中选择‘遗忘设备’,否则会清除蓝牙记录,导致该设备无法再次连接。如误操作,请联系售后。

(三)手机APP连接设备及操作控制

Noetix run App下载:

Android:

iOSNOETIX Run App - App Store

Noetix run App使用说明: BUMI机器人使用说明

(四)设备关机及电池充电

信息

一、设备收纳准备

  1. 在 APP 中执行 一键收纳操作。
  2. 收纳完成后,将 Bumi 扶稳,使其坐于地面

二、设备关机

  1. 长按电池开关,直至 Bumi 完全关机。

三、电池拆卸

  1. 按住电池卡扣。
  2. 从 Bumi 后背电池仓中取出电池

四、电池充电

  1. 将电池放置于电池底座上,并确保连接到位。
  2. 将充电适配器接入电池底座。
  3. 将适配器插入 220V 电源

五、充电状态确认

  1. 观察电池指示灯:
  • 指示灯闪烁:正在充电
  • 无指示:电池已充满

(五)操作教程视频

1. 安装APP

2. 开机

3. 激活绑定

4. 连接BUMI

  1. 蓝牙连接
  • 蓝牙组网和WIFI连接
危险

连接 Bumi 后,请勿在系统设置中选择‘遗忘设备’,否则会清除蓝牙记录,导致该设备无法再次连接。如误操作,请联系售后。

5. 一键起身

危险

使用Bumi的一键起身功能时 要确地面平坦不打滑,且周围无杂物,避免Bumi执行自动起身的时候被周围杂物影响而失败

6. 移动

7. 基本动作

8. 示教模式

9. 舞蹈模式

10. 图传模式

(无算力板版本Bumi有)

11. 语音交互

12. 一键收纳

危险

在 APP 中执行 一键收纳 前,要确保地面平坦不打滑且周围无杂物。

13. 关机

14. 电池充电

(六)常见问题及设备日常维护

  1. 设备防水系数不高

请勿在雨雪天气室外或者潮湿的环境中使用

三、Bumi开发指南

提示

SDK介绍

本文档介绍Bumi基于 DDS消息中间件 通信开发,本SDK采用 C/S架构,在隔离机制下,使 Bumi 机器人的 二次开发算力板部署DDS客户端程序 与机器人上作为服务器的 运控板的运控程序500HZ 的频率下发控制命令,并持续获取当前机器人状态。dds采用的是 CYCLONEDDS 0.11.0

(一)系统架构图

(二)开发接口

DDS C++ Python

(三)获取SDK

https://github.com/Noetix-Robotics/noetix_sdk_bumi

(四)URDF文件

meshes.rar

(五)应用开发 Highcontrol

提示

应用开发介绍

Highcontrol 基于原厂运动控制策略进行上层调度开发,在不改变底层控制逻辑的前提下,实现机器人自动化应用的快速构建,并支持与大模型集成,打造定制化智能行为系统。

典型应用包括:

  • 结合视觉算法与原厂运控系统,实现自主感知与自主行进
  • 结合语音交互模块,实现自然语言控制
  • 接入大模型,根据输入动态生成并调用原厂控制动作(具备一定风险,需要严格安全策略)
  • 配合外挂感知雷达,实现定位导航巡检系统

简而言之,HighControl 通过对原厂控制能力的高层调度封装,实现对遥控器或 APP 可控行为的自动化与程序化调用,并在此基础上拓展部分自主化与智能化能力。

1. Highcontrol架构图

(1)状态上报机制

当客户端 SDK 与机器人运控程序建立连接后,运控程序会持续向客户端推送机器人实时状态信息,包括:

  • 全身电机参数数据(pos 位置、vel 速度、tau 扭矩、kp、kd、temperature 温度、error 错误信息

  • IMU 状态数据

  • 当前工作模式(workmode,表示当前运行的控制策略)

  • 澳加狮手柄数据(用于同步人工输入或辅助控制)

  • 电池电量及相关系统状态信息


(2)客户端控制指令下发

客户端结合自身应用场景向运控程序发送控制指令,主要包括:

  • (x, y, z) 行进控制数据

    仅在特定模式下有效,例如走路模式、握手、打招呼、欢呼、示教模式等。

  • action 指令

    workmode 对应,用于切换或触发机器人当前运行的算法策略。

  • data 附加 DDS 数据

    通常在 PLAYTEACH(播放示教模式)下使用,用于指定示教文件索引等附加参数。


(3)运控程序内部处理流程

运控程序接收到客户端指令后:

  • 将控制参数传递给内部控制算法

  • 算法基于强化学习模型进行策略计算

  • 生成电机目标期望值(目标位置、速度或力矩)并发送到电机控制接口

  • 将计算结果下发至硬件控制层


(4)硬件执行层

硬件层接收目标控制数据后:

  • 执行电机控制指令

  • 完成对应的期望动作


在整个流程中,用户仅需下发部分高层控制参数。

具体的运动规划、动态平衡与电机级控制计算均由原厂运控程序中的黑盒算法完成。

因此,在 Highcontrol 模式 下,用户能够调用和自动化的能力范围,原则上不超过 APP 或手柄原本可实现的功能边界,但不开放底层电机级控制权限。

2. Highcontrol运行流程图

(1)初始化阶段(init)

系统启动后完成以下初始化流程:

  1. 建立客户端与机器人运控程序之间的通信连接

  2. 注册机器人状态数据接收回调函数


(2)DDS 回调线程持续接收回传状态

运控程序持续向客户端推送机器人状态数据。

回调函数接收到数据后进行封装,并分别存入缓冲区及全局状态变量:

  • motor_state_buffer_:电机状态缓冲区

  • imu_buffer_:IMU 状态缓冲区

  • joy_buffer_:手柄数据缓冲区

  • curmode:当前运控策略模式

  • curbattery:当前电池信息

3. HighController常用接口及参数表

HighController接口
接口名称接口描述返回类型
instance获取HighController单例指针对象指针
initHighController对象初始化
publish_cmd发布DDS控制命令数据
get_mode获取当前机器人策略模式int
from_dds_get_joydata从DDS订阅中获取手柄数据手柄数据结构体
get_imu_data从DDS订阅中获取imu数据IMU数据结构体
get_joint_state从DDS订阅中获取电机数据电机数据结构体数组

获取HighController对象单例

函数名instance
函数原型static HighController *Instance()
功能概述获取 HighController单例
参数
返回值HighController单例对象指针
备注

C++示例:

HighController *ctrl = HighController::Instance();

Python示例:

ctrl = HighController.instance()

HighController对象初始化

函数名init
函数原型bool init()
功能概述HighController对象初始化
参数
返回值bool
备注

C++示例:

ctrl->init()

Python示例:

ctrl.init()

发布机器人控制指令

函数名publish_cmd
函数原型void publish_cmd(double ver, double hor, ControlCmd action, uint16_t index)
功能概述使用HighController发送dds控制指令
参数
  • ver 范围: [-1, 1] ;机器人纵向移动值(>0 前进)
  • hor 范围: [-1, 1] ;机器人转向值(>0 左转)
  • action 机器人模式切换枚举
  • index 示教相关模式指定索引
返回值
备注此接口不能连续调用,否则机器人接收指令太快会无法响应,需要在每次指令发送至少添加2ms的延时

C++示例:

ctrl->publish_cmd(0, 0, ControlCmd.CHEER, 0);

Python示例:

ctrl.publish_cmd(0, 0, ControlCmd.CHEER, 0)

action参数表示切换机器人到对应模式

参数名称定义原型序号示例值说明
ControlCmd
enum class ControlCmd : uint8_t {
WALK,
SWING,
SHAKE,
CHEER,
RUN,
START,
SWITCH,
STARTTEACH,
SAVETEACH,
ENDTEACH,
PLAYTEACH,
DANCE,
FALLTOSTAND,
STANDTOFALL,
DANCE1,
DANCE2,
TEAR,
DEFAULT
};
0WALK走路模式
1SWING出厂预设动作挥手
2SHAKE出厂预设动作握手
3CHEER出厂预设动作欢呼
4RUN预留模式,当前版本不可用
5START使能/失能
6SWITCH准备模式
7STARTTEACH开始示教
8SAVETEACH保存示教
9ENDTEACH结束示教(弃用)
10PLAYTEACH播放示教
11DANCE舞蹈1模式
12FALLTOSTAND倒地起身
13STANDTOFALL起身倒地
14DANCE1舞蹈2模式
15DANCE2舞蹈3模式
16TEAR预设擦眼泪动作
17DEFAULT空模式
提示

DEFAULT空模式使用目的

整个机器人线程会循环执行process 控制函数是周期循环执行的,如果在其中持续下发

action = ControlCmd::PLAYTEACH; 等示教相关命令的话

机器人会在 示教播放动作未播放完的情况,导致动作被反复打断,表现为机器人“卡住、无反应”。

正确做法

PLAYTEACH 属于 一次性触发指令(事件),应 只发送一次;后续循环发送 DEFAULT(空指令),避免重复触发。

示例代码(修正后)

if (is_first) {
action = ControlCmd::`**`PLAYTEACH`**`; // 只触发一次`
is_first = false;
} else {
action = ControlCmd::DEFAULT;
}

效果

  • 收到 PLAYTEACH → 触发并完整执行示教动作

  • 后续 DEFAULT → 不再打断动作

  • 机器人行为正常、可预期

动作类指令要“边沿触发”,不能在控制循环里持续下发。

提示

START 使能/失能

workmode == 30,发送START使机器人进入使能模式

workmode != 30,发送START使机器人立刻进入失能模式

index用于在示教相关模式下指定示教文件索引

ctrl.publish_cmd(0, 0, ControlCmd.STARTTEACH, 0) # 开始示教
sleep(10# 录制示教动作
ctrl.publish_cmd(0, 0, ControlCmd.SAVETEACH, 1) # 结束并保存示教动作,指定索引为1
sleep(2) # 让运控程序执行完保存流程,防止被下条命令打断
ctrl.publish_cmd(0, 0, ControlCmd.PLAYTEACH, 1) # 播放示教文件1
提示

仅当 action 为以下模式时: TEAR / PLAYTEACH / WALK / SWING / CHEER / SHAKE / DEFAULT

参数 xyaw 才会生效,用于控制机器人运动;在其他模式下,xyaw 无效。

获取当前机器人策略模式

函数名get_mode
函数原型int get_mode()
功能概述获取DDS机器人当前策略模式
参数
返回值int
备注

C++示例:

int curmode = ctrl->get_mode();

Python示例:

curmode = ctrl.get_mode()

get_mode 返回数据对应表

int值说明
0使能模式
1准备模式
2走路模式
5舞蹈模式
8出厂预设动作 打招呼
9出厂预设动作 握手
10出厂预设动作 欢呼
11开始示教
12结束示教
14保存示教1
23播放示教
26保护模式
27倒地起身
28起身倒地
29保存示教2
30失能模式
31舞蹈模式1
32舞蹈模式2
33擦眼泪动作
提示

保存示教 SDK向机器人发送 SAVETEACH 后,机器人会陆续返回 退出示教 保存示教1 保存示教2 三个状态

警告

保护模式

在处于站立控制策略(走路,示教,舞蹈等)下,运控程序会对 IMU 姿态数据进行持续监测。

当检测到姿态偏离站立稳定区间,并超过预设阈值时,系统将立即触发保护机制,强制切换至安全模式。

在保护模式下:

  • 全身关节进入失能状态(电机停止主动输出)

  • 终止当前运动控制策略

  • 阻断进一步动作指令执行

该机制的目的在于:

  • 防止机器人在跌倒或失稳过程中持续输出控制力矩

  • 避免四肢失控摆动造成二次损伤

  • 降低对设备本体及周围环境的潜在损害

该保护逻辑属于底层安全防护机制,具有最高优先级,不受上层控制指令影响。

获取DDS订阅的手柄数据

函数名from_dds_get_joydata
函数原型const joydata from_dds_get_joydata()
功能概述获取DDS手柄输入数据
参数
返回值joydata结构体
备注
参数名称定义原型示例值说明
joydata
struct joydata {
double axes[2];
int button[14];
};
axes遥控器遥感线性数值
button遥控器按键按下映射数值 1 被按下 0 正常
手柄摇杆映射映射说明范围
axes[0]右摇杆左右推动值[-1, 1]
axes[1]左摇杆前后推动值[-1, 1]
提示

带算力板的Bumi 后背接口为算力板接口,运控板无法插入手柄接收器,所以DDS获取不到手柄数据,所以手柄数据需要直接算力板上获取,详细请看 算力板直接获取手柄数据

C++示例:

joydata jsdata = ctrl->from_dds_get_joydata();
for (int i = 0; i < 14; i++)
std::cout << jsdata.button[i] << std::endl;
std::cout << jsdata.axes[0] << std::endl;
std::cout << jsdata.axes[1] << std::endl;

Python示例:

jsdata = ctrl.from_dds_get_joydata()
for i in range(14):
print(jsdata.button[i])
print(jsdata.axes[0])
print(jsdata.axes[1])

获取DDS订阅IMU数据

函数名get_imu_data
函数原型const NingImuData get_imu_data()
功能概述获取imu数据
参数
返回值NingImuData结构体
备注
参数名称定义原型示例值说明
NingImuData
struct NingImuData {
double ori[4];
double ori_cov[9];
double angular_vel[3];
double angular_vel_cov[9];
double linear_acc[3];
double linear_acc_cov[9];
};
ori姿态四元数
ori_cov姿态协方差
angular_vel角速度
angular_vel_cov角速度协方差
linear_acc线加速度
linear_acc_cov线加速度协方差

C++示例:

NingImuData imu_data = ctrl->get_imu_data();

for (int i = 0; i < 4; i++)
std::cout << imu_data.ori[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.ori_cov[i] << std::endl;
for (int i = 0; i < 3; i++)
std::cout << imu_data.angular_vel[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.angular_vel_cov[i] << std::endl;
for (int i = 0; i < 3; i++)
std::cout << imu_data.linear_acc[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.linear_acc_cov[i] << std::endl;

Python示例:

imu_data = ctrl.get_imu_data()

for i in range(4):
print(imu_data.ori[i])
for i in range(9):
print(imu_data.ori_cov[i])
for i in range(3):
print(imu_data.angular_vel[i])
for i in range(9):
print(imu_data.angular_vel_cov[i])
for i in range(3):
print(imu_data.linear_acc[i])
for i in range(9):
print(imu_data.linear_acc_cov[i])

获取DDS订阅的电机信息数据

函数名get_joint_state
函数原型const std::array<MotorState, 21> get_joint_state()
功能概述获取机器人电机状态数据
参数
返回值MotorState结构体数组
备注
参数名称定义原型示例值说明
MotorState
struct MotorState {
double pos;
double vel;
double tau;
uint16_t motor_id;
uint8_t error;
int temperature;
};
pos电机位置
vel电机转速
tau电机扭矩
motor_id电机ID
error

电机错误码:

  • 02H:电机过流
  • 03H:电机电压过低
  • 04H:电机编码器错误
  • 06H:电机刹车电压过高
  • 07H:DRV驱动错误
  • 08H:超压
  • 09H:欠压
  • 0AH:过流
  • 0BH:MOS过温
  • 0CH:电机线圈过温
  • 0DH:通讯丢失
  • 0EH:过载
temperature温度

C++示例:

std::array<MotorState, 21> joint_state = ctrl->get_joint_state();

for (int i = 0; i < 21; i++) {
std::cout << joint_state[i].pos << std::endl;
std::cout << joint_state[i].vel << std::endl;
std::cout << joint_state[i].tau << std::endl;
std::cout << joint_state[i].motor_id << std::endl;
std::cout << static_cast<int>(joint_state[i].error) << std::endl;
std::cout << joint_state[i].temperature << std::endl;
}

Python示例:

joint_state = ctrl.get_joint_state()

for i in range(21):
print(joint_state[i].pos)
print(joint_state[i].vel)
print(joint_state[i].tau)
print(joint_state[i].motor_id)
print(joint_state[i].error)
print(joint_state[i].temperature)

4. 运控状态切换流程图

危险

注意:使用HighController开发过程中,模式切换请遵循上述流程图以确保合理安全

5. Demo例程介绍

SDK 文件夹中的 example_high.cppsrc/test_high.cpp 提供了一个示例 Demo,用于解析澳加狮手柄输入数据,并根据手柄操作生成对应控制指令发送至机器人。

(六)运控开发 LowController

提示

运控开发介绍

LowController 将运控程序中的电机控制接口开放至 SDK,允许用户以 500Hz 的控制频率直接调节底层电机参数。结合强化学习算法部署,可实现对 Bumi 运动能力的深度定制,使其完成多样化的新动作与舞蹈等复杂行为。

警告

注意:仅有EDU版本的Bumi可以开发LowController

1. Bumi训练框架

后续开放

2. LowController架构图

(1)状态数据上报

当客户端 SDK 与机器人运控程序建立连接后,运控程序会持续向客户端推送机器人实时状态信息,包括:

  • 全身电机参数数据(pos 位置、vel 速度、tau 扭矩、kp、kd、temperature 温度、error 错误信息

  • IMU 状态数据

  • 澳加狮手柄数据


(2)客户端侧控制计算

客户端结合自身算法(通常为强化学习模型)进行实时策略计算,生成各电机的目标期望值(如目标位置等),并将电机控制指令数组写入缓冲区后下发至运控程序。


(3)运控程序转发机制

运控程序接收到客户端下发的电机指令数组后,不进行高层策略计算,而是直接将控制参数转发至硬件控制层。


(4)硬件执行层

硬件层接收电机目标参数后执行控制指令,驱动电机完成期望动作。


在 LowController 模式下:

  • 强化学习模型部署在客户端侧

  • 用户可直接参与电机级控制

  • 运控程序主要承担通信与安全转发职责

  • 控制频率可达 500Hz

该模式具备更高的控制自由度与灵活性,但同时也意味着:

  • 对算法稳定性要求更高

  • 对实时性与系统安全性的要求更严格

  • 若控制策略不稳定,可能直接影响机器人运动安全

3. LowController运行流程图

(1)初始化阶段(init)

系统启动后完成以下初始化步骤:

  1. 建立客户端与机器人运控程序之间的通信连接

  2. 注册机器人状态数据接收回调函数

  3. 创建 send_thread数据发送线程


(2)状态数据回调机制

运控程序持续向客户端推送机器人状态数据。

回调函数接收数据后进行封装,并存入对应缓冲区或全局变量:

  • motor_state_buffer_:电机状态缓冲区

  • imu_buffer_:IMU 状态缓冲区

  • joy_buffer_:手柄数据缓冲区

该阶段仅负责数据接收与缓存,不参与控制策略计算。


(3)send_thread(数据发送线程)

数据发送线程同样以 2ms 周期运行

  • motor_cmd_buffer_ 不为空

  • 读取最新电机控制指令

  • 将电机目标数组发送至运控程序

运控程序仅负责数据转发至硬件层,不参与高层控制决策。


(4)架构特征

LowController 模式的核心特征是:

  • 客户端直接参与电机级控制

  • 强化学习或自定义控制算法运行在客户端

  • 运控程序不再负责高层策略计算,仅承担通信与安全转发职责

  • 控制频率可达 500Hz

该模式提供更高的控制自由度与算法可塑性,但同时对:

  • 实时性

  • 算法稳定性

  • 线程安全与调度精度

提出更高要求。

4. 关节电机信息

ID名称关节扭矩角度范围弧度范围
0arm_l1_joint左臂肩关节pitch5 N.m-135135-2.362.36
1arm_l2_joint左臂肩关节roll5 N.m-8111-0.141.94
2arm_l3_joint左臂关节yaw5 N.m-9090-1.571.57
3arm_l4_joint左臂肘关节pitch5 N.m-1290-2.260.00
4leg_l1_joint左腿髋关节pitch60 N.m-120120-2.092.09
5leg_l2_joint左腿髋关节roll60 N.m-3890-0.661.57
6leg_l3_joint左大腿关节yaw15 N.m-145145-2.532.53
7leg_l4_joint左腿膝关节pitch60 N.m01280.002.24
8leg_l5_joint左腿踝关节pitch30 N.m-5525-0.960.44
9leg_l6_joint左腿踝关节roll30 N.m-1010-0.170.17
10arm_r1_joint右臂肩关节pitch5 N.m-135135-2.362.36
11arm_r2_joint右臂肩关节roll5 N.m-1118-1.940.14
12arm_r3_joint右臂关节yaw5 N.m-9090-1.571.57
13arm_r4_joint右臂肘关节pitch5 N.m-1290-2.260.00
14leg_r1_joint右腿髋关节pitch60 N.m-120120-2.092.09
15leg_r2_joint右腿髋关节roll60 N.m-9038-1.570.66
16leg_r3_joint右大腿关节yaw15 N.m-145145-2.532.53
17leg_r4_joint右腿膝关节pitch60 N.m01280.002.24
18leg_r5_joint右腿踝关节pitch30 N.m-5525-0.960.44
19leg_r6_joint右腿踝关节roll30 N.m-1010-0.170.17
20waist_1_joint腰关节yaw27 N.m-9090-1.571.57

MotorCmd.pos 对应 弧度信息

5. 澳加狮手柄数据映射

澳加狮手柄。button[]和按键映射表如下:

键位描述Button index
右肩键1
左肩键2
X5
Y6
B7
A8
+9
-10
11
左摇杆按下12
手柄摇杆映射映射说明
axes[0]右摇杆Y方向值
axes[1]左摇杆X方向值

手柄摇杆数据范围

最小值最大值
-11

6. LowController常用接口及使用例程

LowController接口
接口名称接口描述返回类型
instance获取LowController单例指针对象指针
initLowController对象初始化
set_joint将电机控制命令写入缓冲区
get_mode获取当前机器人策略模式int
from_dds_get_joydata从DDS订阅中获取手柄数据手柄数据结构体
get_imu_data从DDS订阅中获取imu数据IMU数据结构体
get_joint_state从DDS订阅中获取电机数据电机数据结构体数组

获取LowController对象单例

函数名instance
函数原型static LowController *Instance()
功能概述获取 HighController单例
参数
返回值LowController单例对象指针
备注

C++示例:

LowController *ctrl = LowController::Instance();

Python示例:

ctrl = LowController.instance()

LowController对象初始化

函数名init
函数原型bool init()
功能概述LowController对象初始化
参数
返回值bool
备注

C++示例:

ctrl->init()

Python示例:

ctrl.init()

电机控制命令数组存入缓冲区

存入缓冲区后,会由send_thread 线程自动发送

函数名set_joint
函数原型void set_joint(std::array<MotorCmd, 21> motorcmd)
功能概述设置关节数据
参数motorcmd 电机命令结构体
返回值
备注
参数名称定义原型示例值说明
MotorCmd
struct MotorCmd {
double pos;
double vel;
double tau;
double kp;
double kd;
uint16_t motor_id;
};
pos电机位置
vel电机转速
tau电机扭矩
kppid参数
kdpid参数
motor_id电机ID
危险

电机控制命令下发请严格参考 关节电机信息 中的指定参数范围

C++示例:

std::array<MotorCmd, 21> motorcmd;
// 省略算法逻辑 ...
ctrl->set_joint(motorcmd);

Python示例:

cmds = [MotorCmd() for _ in range(21)]
# 省略算法逻辑 ...
ctrl.set_joint(cmds)

根据关节电机名称获取对应关节电机ID

函数名getJointsIndex
函数原型int getJointsIndex(std::string jointname)
功能概述根据关节电机名称获取对应关节电机ID
参数jointname: 关节电机名称
返回值int:对应关节电机ID
备注

C++示例:

int id = ctrl->getJointsIndex("arm_l1_joint");

Python示例:

id = ctrl.getJointsIndex("arm_l1_joint");
函数名from_dds_get_joydata
函数原型const joydata from_dds_get_joydata()
功能概述获取DDS手柄输入数据
参数
返回值joydata结构体
备注
参数名称定义原型示例值说明
joydata
struct joydata {
double axes[2];
int button[14];
};
axes遥控器遥杆线性数值
button遥控器按键按下映射数值 1 被按下 0 正常
手柄摇杆映射映射说明范围
axes[0]右摇杆左右推动值[-1, 1]
axes[1]左摇杆前后推动值[-1, 1]
提示

带算力板的Bumi 后背接口为算力板接口,运控板无法插入手柄接收器,所以DDS获取不到手柄数据,所以手柄数据需要直接算力板上获取,详细请算力板直接获取手柄数据

C++示例:

joydata jsdata = ctrl->from_dds_get_joydata();
for (int i = 0; i < 14; i++)
std::cout << jsdata.button[i] << std::endl;
std::cout << jsdata.axes[0] << std::endl;
std::cout << jsdata.axes[1] << std::endl;

Python示例:

jsdata = ctrl.from_dds_get_joydata()
for i in range(14):
print(jsdata.button[i])
print(jsdata.axes[0])
print(jsdata.axes[1])
函数名get_imu_data
函数原型const NingImuData get_imu_data()
功能概述获取imu数据
参数
返回值NingImuData结构体
备注
参数名称定义原型示例值说明
NingImuData
struct NingImuData {
double ori[4];
double ori_cov[9];
double angular_vel[3];
double angular_vel_cov[9];
double linear_acc[3];
double linear_acc_cov[9];
};
ori姿态四元数
ori_cov姿态协方差
angular_vel角速度
angular_vel_cov角速度协方差
linear_acc线加速度
linear_acc_cov线加速度协方差

C++示例:

NingImuData imu_data = ctrl->get_imu_data();

for (int i = 0; i < 4; i++)
std::cout << imu_data.ori[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.ori_cov[i] << std::endl;
for (int i = 0; i < 3; i++)
std::cout << imu_data.angular_vel[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.angular_vel_cov[i] << std::endl;
for (int i = 0; i < 3; i++)
std::cout << imu_data.linear_acc[i] << std::endl;
for (int i = 0; i < 9; i++)
std::cout << imu_data.linear_acc_cov[i] << std::endl;

Python示例:

imu_data = ctrl.get_imu_data()

for i in range(4):
print(imu_data.ori[i])
for i in range(9):
print(imu_data.ori_cov[i])
for i in range(3):
print(imu_data.angular_vel[i])
for i in range(9):
print(imu_data.angular_vel_cov[i])
for i in range(3):
print(imu_data.linear_acc[i])
for i in range(9):
print(imu_data.linear_acc_cov[i])
函数名get_joint_state
函数原型const std::array<MotorState, 21> get_joint_state()
功能概述获取机器人电机状态数据
参数
返回值MotorState结构体数组
备注
参数名称定义原型示例值说明
MotorState
struct MotorState {
double pos;
double vel;
double tau;
uint16_t motor_id;
uint8_t error;
int temperature;
};
pos电机位置
vel电机转速
tau电机扭矩
motor_id电机ID
error

电机错误码:

  • 02H:电机过流
  • 03H:电机电压过低
  • 04H:电机编码器错误
  • 06H:电机刹车电压过高
  • 07H:DRV驱动错误
  • 08H:超压
  • 09H:欠压
  • 0AH:过流
  • 0BH:MOS过温
  • 0CH:电机线圈过温
  • 0DH:通讯丢失
  • 0EH:过载
temperature温度

C++示例:

std::array<MotorState, 21> joint_state = ctrl->get_joint_state();

for (int i = 0; i < 21; i++) {
std::cout << joint_state[i].pos << std::endl;
std::cout << joint_state[i].vel << std::endl;
std::cout << joint_state[i].tau << std::endl;
std::cout << joint_state[i].motor_id << std::endl;
std::cout << static_cast<int>(joint_state[i].error) << std::endl;
std::cout << joint_state[i].temperature << std::endl;
}

Python示例:

joint_state = ctrl.get_joint_state()

for i in range(21):
print(joint_state[i].pos)
print(joint_state[i].vel)
print(joint_state[i].tau)
print(joint_state[i].motor_id)
print(joint_state[i].error)
print(joint_state[i].temperature)

获取澳加狮手柄数据(带算力板的Bumi 算力板直接获取)

AoLionDriver

AoLionDriver类接口
init初始化
getremotedata获取手柄数据
函数名init
函数原型bool init(std::string port, int baudrate)
功能概述初始化手柄设备端口
参数
  • port:设备端口号,默认为/dev/input/js0
  • baudrate:波特率,默认为115200
返回值

true:初始化成功


falese:初始化失败

备注
函数名getremotedata
函数原型const joydata getremotedata()
功能概述获取手柄数据
参数
返回值joydata:手柄数据结构体
备注

使用示例

C++

AoLionDriver aoliondriver;
joydata remote_data;
aoliondriver.init("/dev/input/js0", 115200);
const joydata jdata=aoliondriver.getremotedata();
for (int i = 0; i < 14; i++)
std::cout << jdata.button[i] << std::endl;
std::cout << jdata.axes[0] << std::endl;
std::cout << jdata.axes[1] << std::endl;

Python

al = AoLionDriver()
al.init("/dev/input/js0", 115200)
jdata = al.getremotedata()
for i in range(14):
print(jdata.button[i])
print(jdata.axes[0])
print(jdata.axes[1])

7. Demo例程介绍

examples_cpp/example_low.cppexamples_py/test_low.py中运行了一个Bumi的21个自由度跑步策略(policy/policy.onnxsim2real(算法模型实机部署)的代码,根据策略提供了部分强化学习部署接口

函数名loadModel
函数原型bool loadModel(std::string modelpath)
功能概述加载自有模型
参数
  • modelpath: 模型路径
返回值true:加载成功;false:加载失败
备注
函数名onnxdatainit
函数原型void onnxdatainit()
功能概述初始化onnx数据
参数
返回值
备注
函数名getmodelparam
函数原型bool getmodelparam()
功能概述从yaml文件中获取模型参数
参数
返回值true:读取yaml文件成功;false:读取yaml文件失败
备注
函数名setparameter
函数原型void setparameter(Command &cmd,bool* isfirst)
功能概述设置xyz整机控制参数
参数
  • cmd:设置指令
  • isfirst: 是否是第一次设置
返回值
备注
函数名updatestateestimation
函数原型bool updatestateestimation()
功能概述更新状态,包括关节角度,IMU数据等从yaml文件中获取模型参数
参数
返回值true:读取yaml文件成功;false:读取yaml文件失败
备注
函数名computeObservation
函数原型void computeObservation()
功能概述计算观测系数
参数
返回值
备注
函数名computeActions
函数原型void computeActions()
功能概述计算最终的动作
参数
返回值
备注

手柄操作流程

使用步骤
+全身关节回0位进入阻尼模式
LB & -四肢微微弯曲,进入策略前准备模式
LB & X进入策略控制跑步模式

(七)相机例程

信息

EDU版本Bumi(BumiEDU_Pro、BumiEDU_MAX、BumiEDU_Tailor)相机硬件直接到算力板上,可以直接访问算力板上硬件接口获取数据

Intel D435i 相机例程请参考: https://github.com/IntelRealSense/librealsense

(八)快速开发

以下所有操作都是在Bumi算力板上进行,算力板本身已经安装好所需编译环境也可以通过docker部署编译环境

外挂开发部署环境请看:SDK编译环境部署流程

有线连接算力板 SSH登录

ssh noetix@192.168.55.101

无线连接算力板 SSH登录(无线IP可通过手机AppWfii连接中查看,算力板使用的运控板的Wifi模块)

ssh -p 2222 noetix@[机器人WIFI-IP]

1. SDK目录结构

.
├── build.sh # 编译脚本
├── CMakeLists.txt
├── config # 模型配置文件 DDS配置文件等
├── examples_cpp # C++ 示例代码
├── examples_py # python 示例代码
├── include # 头文件目录
├── lib # 库文件目录
├── LICENSE
├── policy # 模型策略文件目录
├── README.md
└── src # 源文件目录

2. docker开发环境镜像部署

noetix_dds.tar.gz

注意:此镜像包为aarch64架构,仅在aarch64架构电脑上可部署

  1. 解压压缩包
tar -zxvf noetix_dds.tar.gz

解压出来后,压缩包内会有noetix_dds.tar 开发镜像文件 noetix_dds.yaml 配置部署文件

version: "3.8"

services:
noetix_dds:
image: noetix_dds:arm64
container_name: noetix_dds
network_mode: host
volumes:
- /home/noetix/work:/home/noetix/work:rw # 挂载工作目录
# /home/noetix/work 冒号前这部分要改成用户的工作目录,创建一个/home/noetix/work/路径目录
stdin_open: true
tty: true

  1. 部署
docker load -i noetix_dds.tar
docker images # 确认noetix_dds arm64 镜像是否存在
mkdir -p /home/noetix/work # 创建工作目录, 用户自行选择
docker compose -f noetix_dds.yaml up -d # 部署
docker ps # 检查 noetix_dds 是否存在

  1. 进入dock容器
docker exec -it noetix_dds /bin/bash

后续将DDS SDK 放入工作目录即可开始开发

3. 编译SDK

cd noetix_sdk_bumi
./build.sh # 一键编译脚本

编译成功后会在SDK根目录下生成可执行文件 example_lowexample_high并且在build目录下生成highcontrol_py 以及 lowcontrol_py pybind库,供python调用

4. 启动程序

C++

cd noetix_sdk_bumi
sudo ./build/example_high # or sudo ./build/example_low

Python

cd noetix_sdk_bumi
python3 examples_py/test_low.py # python3 examples_py/test_high.py
警告

调试过程中,请全程使用机器人吊架,以免错误程序失控造成损失

(九)常见问题及注意事项

  1. DDS客户端demo:运行报错(1)

ARM架构:

error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory

libssl1.1_1.1.1f-1ubuntu2.16_arm64.deb

sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2.16_arm64.deb

X86架构:

error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory

libssl1.1_1.1.1f-1ubuntu2_amd64.deb

sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb