E1 SDK开发指南
一、关于E1
(一)部件名称
E1 整机分为上半身和下半身,具备个23自由度。单臂拥有5个自由度,包括(右手坐标系):
肩关节pitch肩关节roll上臂关节yaw手肘关节pitch下臂关节yaw
单腿拥有6个自由度,包括:
胯关节yaw髋关节roll髋关节pitch膝关节pitch踝关节pitch踝关节roll
腰关节拥有一个自由度,包括:
腰关节yaw
拥有多个关节电机自由度,使得E1机器人能够实现精确的运动和姿态控制。
详细信息如下
| 正面视图 | 背面视图 |
| 参数 | E1 | E1 -教育版 |
|---|---|---|
| 高宽厚(站立) | 1400mm*485mm*320mm | 1400mm*485mm*320mm |
| 带电池重量 | 约40kg | 约40kg |
| 总自由度 | 23~28 | 23~28 |
| 单腿自由度 | 6 (可加选2自由度) | 6 (可加选2自由度) |
| 单手臂自由度 | 5 | 5 |
| 腰部自由度 | 1 | 1 |
| 算力模块 | / | Jetson Orin Nano Super |
| 关节通讯方式 | Ethercat & Canfd | Ethercat & Canfd |
| 关节电机通信波特率 | 1M | 1M |
| 关节最大扭矩 | 150N.m | 150N.m |
| 小腿+大腿长度 | 约0.7M | 约0.7M |
| 手臂臂展 | 约0.6M | 约0.6M |
| 关节编码器 | 双编码器 | 双编码器 |
| 散热系统 | 局部风冷散热 | 局部风冷散热 |
| 供电方式 | 锂电池 | 锂电池 |
| 基础算力 | 6Tops | 6+67Tops |
| 感知传感器 | IMU 深度相机 | IMU 深度相机 |
| 麦克风阵列 | 标配 | 标配 |
| 扬声器 | 标配 | 标配 |
| 高算力模组 | / | NVIDIA Jetson Orin |
| 智能电池(快拆) | 快拆电池 48v 10.5 Ah | 快拆电池 48v 10.5 Ah |
| 充电器 | 有 | 有 |
| 遥控手柄 | 有 | 有 |
| 续航时间 | 2~4H | 2~4H |
| 二次开发 | / | 有 |
(二)电气接口
在E1背面,提供电气接口如下:
| 类型 | 数量 |
|---|---|
| 以太网 | 1 |
| USB | 2 |
| Type-C | 1 |
| HDMI | 1 |
| XT30 对外供电12V(MAX 5A) | 1 |
其中HDMI接口接到的是运控板(RK3588S)上面,如果用户购买的是教育版本,目前只能通过ssh访问二开算力板(NVIDIA jetson orin nano super)
(三)机载计算机
| 类型 | 型号 | 用户 | 密码 | IP | 算力 | 频率 | 内存 |
|---|---|---|---|---|---|---|---|
| 运控板 | 瑞星微 RK3588S | 运控板不对用户开放 | 运控板不对用户开放 | 192.168.55.102 | 6 Tops | 2.4GHz | 8+64GB |
| 二开算力板 | NVIDIA Jetson orin nano super | noetix | e1 | 192.168.55.101 | 67 Tops | 1.7GHz | 8+128GB |
二开算力板仅教育版本的E1特有
运控板(瑞星微 RK3588S)不面向用户开放,如果用户私自访问运控板,导致机器人运控程序失控,造成损失与我司无关
(四)相机信息
英特尔® 实感™ 深度摄像头 D435i - 产品规格 | 英特尔
(五)电池信息
| 参数 | 信息 |
|---|---|
| 品牌 | 深圳格瑞普 |
| 型号 | GRP6752097-13S1P |
| 容量 | 5100mAh |
| 电压 | 48V |
二、使用说明
(一)使用流程及注意事项
建议您在日常演示,尤其是二次开发中,全程使用保护支架悬挂E1,以更好的保护E1设备
原厂运控功能暂不支持上下楼梯,请在平坦开阔处操作E1机器人,同时请远离人群,避免摔倒伤人、损坏机器哦
使用流程
将机器人从包装箱中取出,推荐将机器人吊在架子上启动,或者也可以让机器人躺/趴在地上启动
安装电池
安装电池:双手同时按住电池把手上的红色按钮提起把手,将电池放入电池仓(电池指示灯在下),将电池完全放入后(卡扣卡紧)按住把手红色按钮将把手放下锁住电池。
注意事项:放电池时注意电池方向,按钮在上指示灯在下 (看下方电池示意图)
安装手柄接收器
安装手柄接收器:将手柄USB接收器 插入机器人背后任意一个USB接口,确保不虚接不松动。
启动机器
电池插入机器人背部后,先短按电池上的开机按钮,等指示灯亮起之后,长按按钮,此时会有流水灯的效果,观察机器人各部位指示灯亮起,标识开机。
配对手柄
如果手柄和接收器第一次配对时候,需要在机器人开机状态并已经插上手柄接收器后,长按手柄上面的home按键,直至指示灯常亮,此时松手,指示灯快速闪烁进入配对模式。当手柄震动后,并且下面三个指示灯常亮后代表配对成功
已经配对过之后,后续可以直接点按home按键可直接记忆配对
以下操作以澳加狮手柄举例
进入行走模式
机器人开机后,等待10秒左右会自动进入使能模式(阻尼模式)
待机器人进入使能模式后,使机器人站直于地面,按 LB & - 让机器人进入准备模式
观察机器人是否出现双腿微屈的情况,出现后 按 LB & X 进入走路模式,如果未出现双腿弯曲,重复上一步
注意:机器人不能走高于5cm的楼梯或者障碍,不能走大于20度的斜坡(有倒地风险)
后续操作请看下面按键功能图表
后续操作请看下面流程图与按键功能图表
关机流程
使用完后,此时需要扶住机器人按 LB & - 让机器人回到准备模式,此时机器失去自主站立的能力,需要人扶住。
将机器人吊起或者放平躺(趴)后,按 + 号键,让机器人进入失能模式
然后长按电机开关,关机后取下电池即可。
使用流程图:

- 黑色往左的箭头为正常关机流程
- 紫色往右的箭头为正常使用流程
- 除了失能模式在其他任何模式下按下急停(+号)都会进入失能模式,使用的时候注意,避免误触
手柄按键功能表格
- 基本功能
| 前置条件 | 键位 | 功能 | 备注 |
|---|---|---|---|
| 失能/使能模式 | + | 使能和失能 | 机器人开机后自动进入使能模式,非关机操作不用按 |
| 使能模式 | LB & - | 屈腿准备模式 | 此时不能自主平衡需人工保持站立 |
| 准备模式 | LB & X | 走路模式 | 执行完手部动作后,进入走路模式可以复位 |
| 走路模式 | A | 预设握手动作 | 重新进入走路模式复位 |
| 走路模式 | B | 预设打招呼动作 | 重新进入走路模式复位 |
| 走路模式 | Y | 预设欢呼动作 | 重新进入走路模式复位 |
| 走路模式 | LB & Y | 跑步模式 | 请预留足够的空间和停止一米左右提前量 |
| 走路/跑步模式 | 左摇杆 | 前进和后退 | |
| 走路/跑步模式 | 右摇杆 | 左右转向 |
澳加狮手柄的“+”按键是控制机器人使能/失能,也可以用于在紧急状态下急停机器人 在机器人正常运行状态下,注意不要按下或误触“+”键,否则机器人会立刻失能倒地,避免造成损失
手柄按键功能图
下图按键功能 没有前后关系,不是顺序操作

- 示教功能
键位 | 前置条件 | 功能 | 备注 |
|---|---|---|---|
RB & Y | 走路模式 | 进入示教状态 | |
RB & B | 示教状态 | 结束示教 | |
RB & X | 结束示教 | 保存示教 | 接下来按 [A, B, X, Y]保存到对应的按键上 |
RB & LB + \[A, B, X, Y\] | 走路模式 | 播放对应按键下保存的示教动作 | 播放完切忌要切换到走路模式 |

- 舞蹈功能
使用舞蹈功能请遵循以下几点:
- 请按照备注要求预留足够大的活动空间,路面一定平整不打滑
- 电池电量在2格电及以上
- 跳舞过程中不要用力牵着机器人,不要让机器人收到外部力量干扰
- 部分舞蹈可以中途在接近站立时切走路模式打断 但不要在跳舞中弯腰动作时切到走路模式 PS: 请避免在光滑地面和高低不平地面使用,使用舞蹈时应有足够的施展空间运行动作。因操作环境和操作失误导致的机器人损坏,不在保修范围内。
若您收到机器人后需要测试舞蹈,首次测试需人保护,牵绳(仅做保护不向吊装绳施加额外的力),另外留出足够大的演示空间,以便您清楚了解大致使用空间后再进行后续演示,若第一次测试即出现问题,请及时联系客服人员
| 键位 | 前置条件 | 功能 | 备注 |
|---|---|---|---|
LB & B | 走路模式 | 播放太极动作(不稳定,暂未开放) | 请预留 6 * 6(米)的空间 |
手柄遥感漂移:
当手柄按键飘移或功能失灵时请参考官方使用手册进行重置或校准操作确保功能正常(请拔出接收器进行操作): https://mp.weixin.qq.com/s/cL3EBsndt2_ChM5iNgraSQ(正常情况下无需关注此手册)
注意事项:当感觉手柄失灵时 请先联系技术支持人员判断是机器人还是手柄的问题。
(二)关节电机信息
E1机器人关节电机状态数据由SDK接口获取,获取到的顺序固定,如下:
| ID | 名称 | 关节 | 扭矩 | 角度范围 | 弧度范围 |
|---|---|---|---|---|---|
| 0 | arm_l1_joint | 左臂肩pitch关节 | 27N.m | [-163, 163] | [-2.84, 2.84] |
| 1 | arm_l2_joint | 左臂肩roll关节 | 27N.m | [0, 135] | [0, 2.36] |
| 2 | arm_l3_joint | 左臂大臂yaw关节 | 27N.m | [-150, 150] | [-2.62, 2.62] |
| 3 | arm_l4_joint | 左臂肘pitch关节 | 27N.m | [-130, 10] | [-2.27, 0.17] |
| 4 | arm_l5_joint | 左小臂yaw关节 | 27N.m | [-160, 160] | [-2.79, 2.79] |
| 5 | leg_l1_joint | 左腿髋yaw关节 | 90N.m | [-40, 53] | [-0.70, 0.92] |
| 6 | leg_l2_joint | 左腿髋roll关节 | 90N.m | [-40, 35] | [-0.70, 0.61] |
| 7 | leg_l3_joint | 左腿大腿pitch关节 | 150N.m | [-85, 50] | [-1.48, 0.87] |
| 8 | leg_l4_joint | 左腿膝关节pitch关节 | 150N.m | [0, 135] | [0, 2.36] |
| 9 | leg_l5_joint | 左腿小腿pitch踝关节 | 70N.m | [-58, 24] | [-1.01, 0.42] |
| 10 | leg_l6_joint | 左腿小腿roll踝环节 | 70N.m | [-90, 90] | [-1.57, 1.57] |
| 11 | arm_r1_joint | 右臂肩pitch关节 | 27N.m | [-163, 163] | [-2.84, 2.84] |
| 12 | arm_r2_joint | 右臂肩roll关节 | 27N.m | [-135, 0] | [-2.36, 0] |
| 13 | arm_r3_joint | 右臂大臂yaw关节 | 27N.m | [-150, 150] | [-2.62, 2.62] |
| 14 | arm_r4_joint | 右臂肘pitch关节 | 27N.m | [-130, 10] | [-2.27, 0.17] |
| 15 | arm_l5_joint | 右小臂yaw关节 | 27N.m | [-160, 160] | [-2.79, 2.79] |
| 16 | leg_r1_joint | 右腿髋yaw关节 | 90N.m | [-53, 40] | [40, 0.70] |
| 17 | leg_r2_joint | 右腿髋roll关节 | 90N.m | [-35, 40] | [-0.61, 0.70] |
| 18 | leg_r3_joint | 右腿大腿pitch关节 | 150N.m | [-85, 50] | [-1.48, 0.87] |
| 19 | leg_r4_joint | 右腿膝关节pitch关节 | 150N.m | [0, 135] | [0, 2.36] |
| 20 | leg_r5_joint | 右腿小腿pitch踝关节 | 70N.m | [-58, 24] | [-1.01, 0.42] |
| 21 | leg_r6_joint | 右腿小腿roll关节 | 70N.m | [-15, 15] | [-0.26, 0.26] |
| 22 | waist_1_joint | 腰部yaw关节 | 70N.m | [-90, 90] | [-1.57, 1.57] |
| 23 | 备用 | 备用 | 备用 |
(三)手柄按键数据映射
澳加狮手柄。button[]和按键映射表如下:
| 键位描述 | Button index |
|---|---|
| 右肩键 | 1 |
| 左肩键 | 2 |
| X | 5 |
| Y | 6 |
| B | 7 |
| A | 8 |
| + | 9 |
| - | 10 |
| 无 | 11 |
| 左遥感按下 | 12 |
手柄摇杆数据范围
| 最小值 | 最大值 |
|---|---|
| -1 | 1 |
(四)视频教程
- 使用教程
- 装箱教程
三、E1开发指南
SDK介绍
本文档介绍E1基于DDS消息中间件通信开发,本SDK采用 C/S架构,在隔离机制下,使 E1机器人的 二次开发算力板部署DDS客户端程序 与机器人上作为服务器的 运控板的运控程序 以 500HZ 的频率下发控制命令,并持续获取当前机器人状态。dds采用的是 CYCLONEDDS 0.11.0。
注意
仅配有算力板版本的E1可以使用此SDK开发
(一)系统架构图

(二)开发接口
DDS C++ Python
(三)获取SDK
https://github.com/Noetix-Robotics/noetix_sdk_e1
(四)URDF文件
请登录松延动力售后平台下载
(五)语音功能介绍
语音功能介绍:带语音交互功能的机器人头部装有环形6麦拾音器,AI声卡和扬声器,立体声音频格式为 2CH,采样率 16KHz,采样精度 16bits,并接入讯飞AI大模型(讯飞星火Spark4.0Ultra)提供问答功能。唤醒词“你好小E”,唤醒距离3M内,休眠等待时间30s,主控内置运营商专用4G-SIM卡,月流量100G,自出厂激活日起提供一年网络服务。 注意事项:语音模块使用运营商务联SIM卡,默认自激活起提供一年流量服务,后续使用需客户自行购买数据流量服务,我司提供SIM卡号和必要的技术支持,因SIM卡损毁、或违规使用造成的后果客户自负责任。对于使用期间由运营商造成的网络连接故障等问题我司免责。
语音SDK说明
语音唤醒词“你好小E”,回答我在后 即可问答 语音二次开发(此手册只限于EDU版): https://noetixrobotics.feishu.cn/wiki/M6gkwQMXji9jEFkK8uvcIYLHnfd https://noetixrobotics.feishu.cn/docx/BdJddzSwqoDhd9xixobcXj9XnAe 注意事项:自行注册的AIUI平台应用有交互次数限制
(六)应用开发 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)
系统启动后完成以下初始化流程:
- 建立客户端与机器人运控程序之间的通信连接
- 注册机器人状态数据接收回调函数
(2) 状态数据回调机制
运控程序持续向客户端推送机器人状态数据。
回调函数接收到数据后进行封装,并分别存入缓冲区及全局状态变量:
motor_state_buffer_:电机状态缓冲区imu_buffer_:IMU 状态缓冲区joy_buffer_:手柄数据缓冲区curmode:当前运控策略模式(全局变量)
该阶段仅负责数据接收与缓存,不进行控制决策计算。
3. HighController参数表及常用接口使用
| 接口名称 | 接口描述 | 返回类型 |
|---|---|---|
| instance | 获取HighController单例指针 | 对象指针 |
| init | HighController对象初始化 | 无 |
| 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, double yaw, 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 | | 0 | WALK | 走路模式(LB & X) |
| 1 | SWING | 出厂预设动作挥手(B) | ||
| 2 | SHAKE | 出厂预设动作握手(A) | ||
| 3 | CHEER | 出厂预设动作欢呼(Y) | ||
| 4 | RUN | 跑步模式(LB & Y) | ||
| 5 | START | 使能/失能(及停) | ||
| 6 | SWITCH | 准备模式(LB & —) | ||
| 7 | STARTTEACH | 开始示教(RB & Y) | ||
| 8 | SAVETEACH | 保存示保存示教(RB & B and RB & X)
ps: 目前下发SAVETEACH,会先发送ENDTEACH在发送SAVETEACH,相等于将两个步骤简化为了一个
保存文件根据参数file_index,具体可以参考HighController::set_axes接口 | ||
| 9 | ENDTEACH | 结束示教(RB & B) | ||
| 10 | PLAYTEACH | 播放示教(RB & LB &file_index)
根据file_index播放对应文件示教动作 | ||
| 11 | DEFAULT | 空指令 |
DEFAULT空模式使用目的
整个机器人线程会循环执行process控制函数是周期循环执行的,如果在其中持续下发action = ControlCmd::CHEER; 等动作或者切换模式的命令的话,机器人会在欢呼动作尚未完成时不断收到新的CHEER指令,导致动作被反复打断,表现为机器人“卡住、无反应”。
正确做法
CHEER 属于一次性触发指令(事件),应只发送一次;后续循环发送 DEFAULT(空指令),避免重复触发。
示例代码(修正后)
if (is_first) {
action = ControlCmd::CHEER; // 只触发一次
is_first = false;
} else {
action = ControlCmd::DEFAULT;
}
效果
- 收到
CHEER→ 触发并完整执行欢呼动作 - 后续
DEFAULT→ 不再打断动作 - 机器人行为正常、可预期 动作类指令要“边沿触发”,不能在控制循环里持续下发。
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 为以下模式时:
PLAYTEACH / WALK / SWING / CHEER / SHAKE / DEFAULT
参数 x 和 yaw 才会生效,用于控制机器人运动;在其他模式下,x 和 yaw 无效。
获取当前机器人策略模式
| 函数名 | get_mode |
|---|---|
| 函数原型 | int get_mode() |
| 功能概述 | 获取DDS机器人当前策略模式 |
| 参数 | 无 |
| 返回值 | int |
| 备注 |
C++示例:
int curmode = ctrl->get_mode();
Python示例:
curmode = ctrl.get_mode()
get_mode 返回数据对应表
| workmode值 | 说明 |
|---|---|
| 0 | 使能模式 |
| 1 | 准备模式 |
| 2 | 走路模式 |
| 3 | 跑步模式 |
| 7 | 出厂预设动作打招呼 |
| 8 | 出厂预设动作握手 |
| 9 | 出厂预设动作欢呼 |
| 10 | 开始示教 |
| 11 | 结束示教 |
| 27 | 播放示教 |
| 13 | 保存示教1 |
| 28 | 太极动作 |
| 26 | 保存示教2 |
| 29 | 失能模式 |
保存示教
SDK向机器人发送 SAVETEACH 后,机器人会陆续返回 退出示教 保存示教1 保存示教2 三个状态
保护模式 在处于站立控制策略(走路,示教,舞蹈等下,运控程序会对 IMU 姿态数据进行持续监测。 当检测到姿态偏离站立稳定区间,并超过预设阈值时,系统将立即触发保护机制,强制切换至安全模式。 在保护模式下:
- 全身关节进入失能状态(电机停止主动输出)
- 终止当前运动控制策略
- 阻断进一步动作指令执行 该机制的目的在于:
- 防止机器人在跌倒或失稳过程中持续输出控制力矩
- 避免四肢失控摆动造成二次损伤
- 降低对设备本体及周围环境的潜在损害 该保护逻辑属于底层安全防护机制,具有最高优先级,不受上层控制指令影响。
获取DDS订阅的手柄数据
| 函数名 | from_dds_get_joydata |
|---|---|
| 函数原型 | const joydata from_dds_get_joydata() |
| 功能概述 | 获取DDS手柄输入数据 |
| 参数 | 无 |
| 返回值 | joydata结构体 |
| 备注 |
| 参数名称 | 定义原型 | 示例值 | 说明 |
|---|---|---|---|
| joydata | | axes | 遥控器遥感线性数值 |
| button | 遥控器按键按下映射 数值 1 被按下,0 正常 |
| 手柄摇杆映射 | 映射说明 | 范围 |
|---|---|---|
| axes[0] | 右摇杆左右推动值 | [-1, 1] |
| axes[1] | 左摇杆前后推动值 | [-1, 1] |
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 | | 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, 24> get_joint_state() |
| 功能概述 | 获取机器人电机状态数据 |
| 参数 | 无 |
| 返回值 | MotorState结构体数组 |
| 备注 |
| 参数名称 | 定义原型 | 示例值 | 说明 |
|---|---|---|---|
| MotorState | | pos | 电机位置 |
| vel | 电机转速 | ||
| tau | 电机扭矩 | ||
| motor_id | 电机ID | ||
| error | 电机错误码:
| ||
| temperature | 温度 |
C++示例:
std::array<MotorState, 24> joint_state = ctrl->get_joint_state();
for (int i = 0; i < 24; 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(24):
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.运控状态切换流程图

注意:使用highcontrol开发过程中,模式切换请遵循上述流程图以确保合理安全
5.Demo例程介绍
SDK 文件夹中的 example_high.cpp 与 test_high.py 提供了一个示例 Demo,用于解析澳加狮手柄输入数据,并根据手柄操作生成对应控制指令发送至机器人。
(七)运控开发 Lowcontrol
运控开发介绍 Lowcontrol 将运控程序中的电机控制接口开放至 SDK,允许用户以 500Hz 的控制频率直接调节底层电机参数。结合强化学习算法部署,可实现对 Bumi 运动能力的深度定制,使其完成多样化的新动作与舞蹈等复杂行为。
1. E1训练框架
https://github.com/Noetix-Robotics/noetix_e1_lab.git
2. Lowcontrol架构图

(1) 状态数据上报
当客户端 SDK 与机器人运控程序建立连接后,运控程序会持续向客户端推送机器人实时状态信息,包括:
- 全身电机参数数据(pos位置、vel速度、tau扭矩、kp、kd、temperature 温度、error 错误信息)
- IMU 状态数据
- 澳加狮手柄数据(用于同步人工输入或辅助控制)
(2) 客户端侧控制计算
客户端结合自身算法(通常为强化学习模型)进行实时策略计算,生成各电机的目标期望值(如目标位置等),并将电机控制指令数组写入缓冲区后下发至运控程序。
(3) 运控程序转发机制
运控程序接收到客户端下发的电机指令数组后,不进行高层策略计算,而是直接将控制参数转发至硬件控制层。
(4) 硬件执行层
硬件层接收电机目标参数后执行控制指令,驱动电机完成期望动作。
在 LowControl 模式下:
- 强化学习模型部署在客户端侧
- 用户可直接参与电机级控制
- 运控程序主要承担通信与安全转发职责
- 控制频率可达 500Hz 该模式具备更高的控制自由度与灵活性,但同时也意味着:
- 对算法稳定性要求更高
- 对实时性与系统安全性的要求更严格
- 若控制策略不稳定,可能直接影响机器人运动安全
3. Lowcontrol运行流程图

(1)初始化阶段(init)
系统启动后完成以下初始化步骤:
a. 建立客户端与机器人运控程序之间的通信连接
b. 注册机器人状态数据接收回调函数
c. 创建 send_thread :数据发送线程
(2)状态数据回调机制
运控程序持续向客户端推送机器人状态数据。 回调函数接收数据后进行封装,并存入对应缓冲区或全局变量:
motor_state_buffer_:电机状态缓冲区imu_buffer_:IMU 状态缓冲区joy_buffer_:手柄数据缓冲区 该阶段仅负责数据接收与缓存,不参与控制策略计算。
(3)send_thread(数据发送线程)
数据发送线程同样以 2ms 周期运行:
- 若
motor_cmd_buffer_不为空 - 读取最新电机控制指令
- 将电机目标数组发送至运控程序 运控程序仅负责数据转发至硬件层,不参与高层控制决策。
(4)架构特征
Lowcontrol 模式的核心特征是:
- 客户端直接参与电机级控制
- 强化学习或自定义控制算法运行在客户端
- 运控程序不再负责高层策略计算,仅承担通信与安全转发职责
- 控制频率可达 500Hz 该模式提供更高的控制自由度与算法可塑性,但同时对:
- 实时性
- 算法稳定性
- 线程安全与调度精度 提出更高要求。
4. 关节电机信息
| ID | 名称 | 关节 | 扭矩 | 角度范围 | 弧度范围 |
|---|---|---|---|---|---|
| 0 | arm_l1_joint | 左臂肩pitch关节 | 27N.m | [-163, 163] | [-2.84, 2.84] |
| 1 | arm_l2_joint | 左臂肩roll关节 | 27N.m | [0, 135] | [0, 2.36] |
| 2 | arm_l3_joint | 左臂大臂yaw关节 | 27N.m | [-150, 150] | [-2.62, 2.62] |
| 3 | arm_l4_joint | 左臂肘pitch关节 | 27N.m | [-130, 10] | [-2.27, 0.17] |
| 4 | arm_l5_joint | 左小臂yaw关节 | 27N.m | [-160, 160] | [-2.79, 2.79] |
| 5 | leg_l1_joint | 左腿髋yaw关节 | 90N.m | [-40, 53] | [-0.70, 0.92] |
| 6 | leg_l2_joint | 左腿髋roll关节 | 90N.m | [-40, 35] | [-0.70, 0.61] |
| 7 | leg_l3_joint | 左腿大腿pitch关节 | 150N.m | [-85, 50] | [-1.48, 0.87] |
| 8 | leg_l4_joint | 左腿膝关节pitch关节 | 150N.m | [0, 135] | [0, 2.36] |
| 9 | leg_l5_joint | 左腿小腿pitch踝关节 | 70N.m | [-58, 24] | [-1.01, 0.42] |
| 10 | leg_l6_joint | 左腿小腿roll踝环节 | 70N.m | [-90, 90] | [-1.57, 1.57] |
| 11 | arm_r1_joint | 右臂肩pitch关节 | 27N.m | [-163, 163] | [-2.84, 2.84] |
| 12 | arm_r2_joint | 右臂肩roll关节 | 27N.m | [-135, 0] | [-2.36, 0] |
| 13 | arm_r3_joint | 右臂大臂yaw关节 | 27N.m | [-150, 150] | [-2.62, 2.62] |
| 14 | arm_r4_joint | 右臂肘pitch关节 | 27N.m | [-130, 10] | [-2.27, 0.17] |
| 15 | arm_l5_joint | 右小臂yaw关节 | 27N.m | [-160, 160] | [-2.79, 2.79] |
| 16 | leg_r1_joint | 右腿髋yaw关节 | 90N.m | [-53, 40] | [40, 0.70] |
| 17 | leg_r2_joint | 右腿髋roll关节 | 90N.m | [-35, 40] | [-0.61, 0.70] |
| 18 | leg_r3_joint | 右腿大腿pitch关节 | 150N.m | [-85, 50] | [-1.48, 0.87] |
| 19 | leg_r4_joint | 右腿膝关节pitch关节 | 150N.m | [0, 135] | [0, 2.36] |
| 20 | leg_r5_joint | 右腿小腿pitch踝关节 | 70N.m | [-58, 24] | [-1.01, 0.42] |
| 21 | leg_r6_joint | 右腿小腿roll关节 | 70N.m | [-15, 15] | [-0.26, 0.26] |
| 22 | waist_1_joint | 腰部yaw关节 | 70N.m | [-90, 90] | [-1.57, 1.57] |
| 23 | 备用 | 备用 | 备用 |
5. 澳加狮手柄数据映射
澳加狮手柄。button[]和按键映射表如下:
| 键位描述 | Button index |
|---|---|
| 右肩键 | 1 |
| 左肩键 | 2 |
| X | 5 |
| Y | 6 |
| B | 7 |
| A | 8 |
| + | 9 |
| - | 10 |
| 无 | 11 |
| 左遥感按下 | 12 |
| 手柄摇杆映射 | 映射说明 | 范围 |
|---|---|---|
| axes[0] | 右摇杆左右推动值 | [-1, 1] |
| axes[1] | 左摇杆前后推动值 | [-1, 1] |
手柄摇杆数据范围
| 最小值 | 最大值 |
|---|---|
| -1 | 1 |
6. LowController常用接口及使用例程
| 接口名称 | 接口描述 | 返回类型 |
|---|---|---|
| instance | 获取LowController单例指针 | 对象指针 |
| init | LowController对象初始化 | 无 |
| 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, 24> motorcmd) |
| 功能概述 | 设置关节数据 |
| 参数 | - motorcmd 电机命令结构体 |
| 返回值 | 无 |
| 备注 |
| 参数名称 | 定义原型 | 示例值 | 说明 |
|---|---|---|---|
| MotorCmd | | pos | 电机位置 |
| vel | 电机转速 | ||
| tau | 电机扭矩 | ||
| kp | PID参数 | ||
| kd | PID参数 | ||
| motor_id | 电机ID |
电机控制命令下发请严格参考 关节电机信息 中的指定参数范围
C++示例:
std::array<MotorCmd, 24> motorcmd;
// 省略算法逻辑 ...
ctrl->set_joint(motorcmd);
Python示例:
cmds = [MotorCmd() for _ in range(24)]
# 省略算法逻辑 ...
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 |
| axes | 遥控器遥杆线性数值 |
| button | 遥控器按键按下映射 数值 1 被按下,0 正常 |
| 手柄摇杆映射 | 映射说明 | 范围 |
|---|---|---|
| axes[0] | 右摇杆左右推动值 | [-1, 1] |
| axes[1] | 左摇杆前后推动值 | [-1, 1] |
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 | | 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, 24> get_joint_state() |
| 功能概述 | 获取机器人电机状态数据 |
| 参数 | 无 |
| 返回值 | MotorState结构体数组 |
| 备注 |
| 参数名称 | 定义原型 | 示例值 | 说明 |
|---|---|---|---|
| MotorState | | pos | 电机位置 |
| vel | 电机转速 | ||
| tau | 电机扭矩 | ||
| motor_id | 电机ID | ||
| error | 电机错误码:
| ||
| temperature | 温度 |
C++示例:
std::array<MotorState, 24> joint_state = ctrl->get_joint_state();
for (int i = 0; i < 24; 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(24):
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) |
| 功能概述 | 初始化手柄设备端口 |
| 参数 |
|
| 返回值 |
|
| 备注 |
| 函数名 | 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.cpp和 中运行了一个E1的24个自由度的走路策略(policy/policy.onnx)的sim2real(算法模型实机部署)的代码,根据策略提供了部分强化学习部署接口
| 函数名 | 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 | 进入策略控制走路模式 |
(八)快速开发
以下所有操作都是在E1算力板上进行,算力板本身已经安装好所需编译环境,也可以通过docker部署编译环境
外挂开发部署环境请看:https://noetixrobotics.feishu.cn/docx/PP2BdXkSUoQ2VOxctJKcEdHanAg
外挂开发介绍
由于人形产品的运控板不对外开放,用户程序无法直接部署在运控板上运行,因此需要额外的计算载体来执行用户程序。 如果用户购买的机型未配备算力板,则需采用“外挂开发”方式:用户自备算力板或主机,通过网线连接 E1后背接口,与运控板通信。 由于运控板仅允许与原版算力板的固定 IP 通信,且通信基于内部交换机的有线连接,因此外挂设备需配置为与原版算力板相同的 IP,以模拟原始算力板完成接入。
有线连接算力板 SSH登录
ssh noetix@192.168.55.101
1. SDK目录结构
.
├── build.sh # 编译脚本
├── CMakeLists.txt
├── config # 模型配置文件 DDS配置文件等
├── examples_cpp # C++ 示例代码
├── examples_py # python 示例代码
├── include # 头文件目录
├── lib # 库文件目录
├── LICENSE
├── policy # 模型策略文件目录
├── README.md
└── src # 源文件目录
2. docker开发环境镜像部署
注意:此镜像包为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
2.部署
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 是否存在
3.进入容器
docker exec -it noetix_dds /bin/bash
后续将DDS SDK 放入工作目录即可开始开发
3.编译SDK
cd noetix_sdk_E1
./build.sh # 一键编译脚本
编译成功后会在SDK根目录下生成可执行文件 example_low和 example_high ,并且在build目录下生成highcontrol_py 以及 lowcontrol_py pybind库,供python调用
4.启动程序
C++
cd noetix_sdk_E1
sudo ./build/example_high # or sudo ./build/example_low
Python
cd noetix_sdk_E1
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