| 版本 | 修订日期 | 修改内容 | 备注 |
|---|---|---|---|
| V0.1 | 20260415 | 初稿 | |
| V0.2 | 20260726 | 主控制器 V2.1.24 升级更新及此前错误修正 |
1 SDK 概述
名词解释:
- 底层运动控制接口:在底层开发模式下,您可以使用 python、C++ 等调用机器人底层接口,实现例如直接控制关节运动等底层操作。
- 上层应用开发接口:在上层开发模式下,您可以基于LimX内置运控算法从而控制机器人运动完成任务,例如双臂操作、机器人前后移动、机器人灯光管理等。
1.1 通讯架构图
下图呈现了机器人本体通信架构组成及交互关系。运控电脑部分涵盖运控算法节点和软件业务逻辑实现模块,通过 上层应用开发接口 和 底层运动控制开发接口 的数据通讯方式控制机器人本体的运动。机器人本体由数据交换机、主站及各类硬件组件构成,运控电脑负责协调各组件运行。
1.2 查看/设置机器人型号
在编译和运行控制算法及仿真器程序时,选择正确的机器人型号至关重要。
您可以通过查看机器人型号并将其设置到环境变量 ROBOT_TYPE 中,确保在不同任务中准确识别并应用相应的机器人构型。以下是查看和配置机器人型号的步骤。
-
请选择并连接您机器人的 Wi-Fi 热点,密码为:
12345678在浏览器中输入http://10.192.1.2:8080可以进入“机器人信息页”,并查看机器人信息。如下图所示,页面中显示的 SN (序列号) 为 WF_TRON2A_001,其中 WF_TRON2A 是机器人型号类型。


-
设置机器人型号:打开 Bash 终端,输入以下 Shell 命令来设置机器人型号。这样在编译和运行 RL 训练、控制算法以及仿真器程序时,算法将能获取到正确的机器人型号信息。
echo 'export ROBOT_TYPE=WF_TRON2A' >> ~/.bashrc && source ~/.bashrc
1.3 开发拓展模块电脑
开发拓展模块内置电脑主要用于开发机器人相关算法及应用程序。您可以通过 WiFi或有线网络连接到机器人本体系统从而登录到开发者电脑,具体步骤如下:
- 请选择并连接您机器人的 Wi-Fi 热点,密码为:
12345678 - 通过 SSH 登录开发者电脑系统
- 登录地址为:
10.192.1.4 - 登录密码为:
123456 - 在终端中输入以下命令(首次连接需确认命令):
ssh guest@10.192.1.4 - 开发者电脑系统配置:
- 操作系统:Ubuntu 22.04.6 LTS
- ROS2:系统默认安装ROS2 Humble版本机器人系统
- ROS1:系统默认安装ROS1 Noetic 版本机器人系统
- 登录地址为:
2 底层运动控制接口
跨平台底层运动控制开发接口库提供统一的C++/Python API,兼容ROS1、ROS2及非ROS系统,实现运动控制算法的快速移植与部署。
2.1 C++ 运动控制开发接口
2.1.1 概述
底层运动控制开发接口通过硬件抽象层和标准化通信协议,开发者可无缝切换仿真与真实硬件环境,显著降低多平台适配成本。
2.1.2 安装运动控制开发库
- Linux x86_64 环境
git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/amd64/limxsdk-*-py3-none-any.whl
- Linux aarch64 环境
git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/aarch64/limxsdk-*-py3-none-any.whl
- Windows 环境
git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/win/limxsdk-*-py3-none-any.whl
2.1.3 getInstance 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | getInstance |
| 函数原型 | static Tron2* getInstance(); |
| 功能概述 | 获取 Tron2 机器人类单例实例的指针 |
| 参数 | 无 |
| 返回值 | Tron2*,指向 Tron2 实例的指针 |
| 备注 | 使用了单例模式,确保 Tron2 类只有一个实例存在于程序中 |
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.4 init 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | init |
| 函数原型 | bool init(const std::string& robot_ip_address = "127.0.0.1"); |
| 功能概述 | 初始化lowlevel-sdk的通信运行环境,在主函数中调用其它接口之前调用,完成初始化工作。 |
| 参数 | robot_ip_address:机器人的 IP 地址。对于仿真,通常设置为 "127.0.0.1",而对于真实机器人,设置为 "10.192.1.2"。 |
| 返回值 | 如果初始化成功,则返回 true;否则返回 false。 |
| 备注 | 无 |
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.5 getMotorNumber 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | getMotorNumber |
| 函数原型 | uint32_t getMotorNumber(); |
| 功能概述 | 获取机器人的电机数量。 |
| 参数 | 无 |
| 返回值 | 返回一个无符号整数,表示机器人中的总电机数量。 |
| 备注 | 例如,双轮足形态下的电机数量为 10 个。 |
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 获取机器人中的电机数量
uint32_t motor_num = robot->getMotorNumber();
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.6 subscribeImuData 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeImuData |
| 函数原型 | void subscribeImuData(std::function<void(const ImuDataConstPtr&)> cb); |
| 功能概述 | 订阅机器人的 IMU 数据,并在接收到新的 IMU 数据时调用指定的回调函数。 |
| 参数 | cb:用于处理新 IMU 数据的回调函数。 |
| 返回值 | 无 |
备注:
ImuData 数据结构原型如下:
/**
* @struct ImuData
*
* @brief 表示基于传感器反馈的机器人 IMU 数据的结构体。
*
* 此结构体封装了 IMU 数据,包括加速度计、陀螺仪和四元数。
*/
struct ImuData {
uint64_t stamp; // 时间戳,以纳秒为单位,表示记录此数据时的时间。
float acc[3]; // 用于存储 IMU 加速度计数据,采集沿三个轴(X、Y、Z)的线性加速度。
float gyro[3]; // 用于存储 IMU 陀螺仪数据,采集沿三个轴(X、Y、Z)的角速度。
float quat[4]; // 用于存储 IMU 四元数数据,使用四元数表示在三维空间中的方向(w、x、y、z)。
};
// 智能指针类型别名
typedef std::shared_ptr<ImuData> ImuDataPtr;
typedef std::shared_ptr<ImuData const> ImuDataConstPtr;
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 订阅机器人 IMU 数据,并指定回调函数
robot->subscribeImuData([](const ImuDataConstPtr& msg) {
// 在这里处理接收到的 IMU 数据
// 例如:可以进行姿态结算等工作
});
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.7 subscribeRobotState 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeRobotState |
| 函数原型 | void subscribeRobotState(std::function<void(const RobotStateConstPtr&)> cb); |
| 功能概述 | 订阅并接收关于机器人状态的更新。 |
| 参数 | cb:回调函数,当接收到机器人状态更新时将被调用。回调函数参数指向 RobotState 对象的常量指针。 |
| 返回值 | 无 |
备注
RobotState 数据结构原型如下:
/**
* @struct RobotState
*
* @brief 代表基于传感器反馈的机器人状态的结构体。
*
* 此结构封装了各种数据点,可用于监控和控制机器人,包括 IMU 数据(加速度计、陀螺仪、四元数)、输出扭矩、当前角度和速度等。
*/
struct RobotState {
// 默认构造函数
RobotState() { }
// 带参数的构造函数,用于初始化向量大小为 motor_num 的 tau、q、dq 向量,初始值均为 0.0
RobotState(int motor_num)
: tau(motor_num, 0.0)
, q(motor_num, 0.0)
, dq(motor_num, 0.0) { }
uint64_t stamp; // 时间戳,通常表示记录或生成这些数据的时间,以纳秒为单位
std::vector<float> tau; // 用于存储当前估计的输出扭矩(以牛顿米为单位)的向量
std::vector<float> q; // 用于存储当前角度(以弧度为单位)的向量
std::vector<float> dq; // 用于存储当前速度(以弧度每秒为单位)的向量
};
// 智能指针类型别名
typedef std::shared_ptr<RobotState> RobotStatePtr;
typedef std::shared_ptr<RobotState const> RobotStateConstPtr;
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 订阅机器人状态更新,并指定回调函数
robot->subscribeRobotState([](const RobotStateConstPtr& msg) {
// 在这里处理接收到的 RobotState 数据
// 例如:读取关节角度、速度、力矩、IMU 等状态信息
});
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.8 publishRobotCmd 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | publishRobotCmd |
| 函数原型 | bool publishRobotCmd(const RobotCmd& cmd); |
| 功能概述 | 发布一个命令来控制机器人的关节。 |
| 参数 | cmd:表示所需机器人命令的 RobotCmd 对象。 |
| 返回值 | 无 |
| 备注 |
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 获取机器人中的电机数量
uint32_t motor_num = robot->getMotorNumber();
// 创建一个包含机器人电机数量的 RobotCmd 对象
RobotCmd cmd(motor_num);
// 发布控制指令
robot->publishRobotCmd(cmd);
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.9 subscribeSensorJoy 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeSensorJoy |
| 函数原型 | void subscribeSensorJoy(std::function<void(const SensorJoyConstPtr&)> cb); |
| 功能概述 | 在真机部署中,该方法用于订阅来自机器人遥控器的数据。当机器人接收到遥控器数据时,将会调用指定的回调函数,并传递包含遥控器数据的 SensorJoy 结构体常量指针给回调函数进行处理。 |
| 参数 | cb:表示回调函数,用于接收机器人遥控器的数据。回调函数的参数类型为 SensorJoyConstPtr,即指向 SensorJoy 结构体常量的共享指针。 |
| 返回值 | 无 |
| 备注 |
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 订阅机器人遥控器数据
robot->subscribeSensorJoy([](const SensorJoyConstPtr& joy) {
// L1 和 R1 按下
if (joy->buttons[4] == 1 && joy->buttons[7] == 1)
{
// 在这里执行相关操作
}
// 处理摇杆数据
double axes_left_horizontal = joy->axes[0];
double axes_left_vertical = joy->axes[1];
double axes_right_horizontal = joy->axes[2];
double axes_right_vertical = joy->axes[3];
});
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.10 subscribeDiagnosticValue 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeDiagnosticValue |
| 函数原型 | void subscribeDiagnosticValue(std::function<void(const DiagnosticValueConstPtr&)> cb); |
| 功能概述 | 在真机部署中,该方法用于订阅机器人的诊断值和状态信息。当机器人发出诊断值时,系统会调用指定的回调函数,并传递包含诊断值的 DiagnosticValue 结构体常量指针给回调函数进行处理。这可以帮助实时监控机器人的健康状态,并及时做出反应以处理可能的问题。 |
| 参数 | cb:用于接收机器人诊断值的回调函数,其参数类型为 DiagnosticValueConstPtr,即指向 DiagnosticValue 结构体常量的共享指针。DiagnosticValue 结构体包含机器人诊断值的信息,包括时间戳、级别、名称、代码和消息字段。 |
| 返回值 | 无 |
| 备注 |
代码示例:
#include <thread>
#include <iostream>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 订阅机器人诊断数据
robot->subscribeDiagnosticValue([](const DiagnosticValueConstPtr& msg) {
// 在这里处理机器人诊断值
// 例如,可以根据诊断级别和消息内容进行打印或处理
std::cout << "Diagnostic Value: " << msg->name << std::endl;
std::cout << "Level: " << msg->level << std::endl;
std::cout << "Code: " << msg->code << std::endl;
std::cout << "Message: " << msg->message << std::endl;
});
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.11 setRobotLightEffect 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | setRobotLightEffect |
| 函数原型 | bool setRobotLightEffect(int effect); |
| 功能概述 | 在真机部署中,该方法用于设置机器人的灯光效果。 |
| 参数 | effect:一个整数,表示所需的机器人灯光效果,具体定义见 Tron2::LightEffect 枚举。 |
| 返回值 | bool:指示机器人灯光效果是否成功设置。 |
备注 - 灯光效果枚举说明:
enum LightEffect : int {
STATIC_RED = 0, // 静态红光
STATIC_GREEN, // 静态绿光
STATIC_BLUE, // 静态蓝光
STATIC_CYAN, // 静态青光
STATIC_PURPLE, // 静态紫光
STATIC_YELLOW, // 静态黄光
STATIC_WHITE, // 静态白光
LOW_FLASH_RED, // 红光闪烁(慢闪)
LOW_FLASH_GREEN, // 绿光闪烁(慢闪)
LOW_FLASH_BLUE, // 蓝光闪烁(慢闪)
LOW_FLASH_CYAN, // 青光闪烁(慢闪)
LOW_FLASH_PURPLE, // 紫光闪烁(慢闪)
LOW_FLASH_YELLOW, // 黄光闪烁(慢闪)
LOW_FLASH_WHITE, // 白光闪烁(慢闪)
FAST_FLASH_RED, // 红光闪烁(快闪)
FAST_FLASH_GREEN, // 绿光闪烁(快闪)
FAST_FLASH_BLUE, // 蓝光闪烁(快闪)
FAST_FLASH_CYAN, // 青光闪烁(快闪)
FAST_FLASH_PURPLE, // 紫光闪烁(快闪)
FAST_FLASH_YELLOW, // 黄光闪烁(快闪)
FAST_FLASH_WHITE // 白光闪烁(快闪)
};
代码示例:
#include <thread>
// 包含 limxsdk::Tron2 头文件,用于引入 Tron2 类
#include "limxsdk/tron2.h"
// 使用 limxsdk 命名空间,简化对 Tron2 类的引用
using namespace limxsdk;
int main(int argc, char *argv[]){
// 获取 Tron2 类的单例实例
Tron2* robot = Tron2::getInstance();
// 默认机器人 IP 地址
std::string robot_ip = "10.192.1.2";
if (argc > 1)
{
// 如果提供了命令行参数,则使用命令行参数作为机器人 IP 地址
robot_ip = argv[1];
}
// 初始化运动控制算法程序的通信运行环境
if (!robot->init(robot_ip))
{
// 如果初始化失败,则退出程序
exit(1);
}
// 设置机器人灯光效果为静态红光
robot->setRobotLightEffect(limxsdk::Tron2::STATIC_RED);
// 无限循环以保持程序运行
while (true)
{
// 休眠 1000 毫秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
2.1.12 参考例程(Coming Soon)
2.2 Python 运动控制开发接口
2.2.1 概述
提供与 C++ 相同功能的 Python 运动控制算法开发接口,使得不熟悉 C++ 编程语言的开发者能够使用 Python 进行运动控制算法的开发。
Python 语言易于学习,具有简洁清晰的语法和丰富的第三方库,使开发者能够更快速地上手并迅速实现算法。通过 Python 接口,开发者可以利用 Python 的动态特性进行快速原型设计和实验验证,加速算法的迭代和优化过程。同时,Python 的跨平台性和强大的生态系统支持,使得运动算法能够更广泛地应用于不同平台和环境。
此外,算法模型快速部署到仿真和真机环境中也得益于 Python 的灵活性,开发者可以使用 Python 轻松地将算法模型集成到各种仿真平台和真实硬件中,实现快速迭代和验证算法的性能。
2.2.2 安装运动控制开发库
- Linux x86_64 环境
git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/amd64/limxsdk-*-py3-none-any.whl
- Linux aarch64 环境
git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/aarch64/limxsdk-*-py3-none-any.whl
- Windows 环境
git clone git clone https://github.com/limxdynamics/limxsdk-lowlevel.git
pip install limxsdk-lowlevel/python3/win/limxsdk-*-py3-none-any.whl
2.2.3 __init__ 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | __init__ |
| 函数原型 | def __init__(self, robot_type: robot.RobotType) |
| 功能概述 | 在初始化时,指定机器人的类型,并创建一个相应类型的本地机器人实例。 |
| 参数 | robot_type:表示机器人类型的枚举值,类型为 RobotType.Tron2。 |
| 返回值 | 无 |
| 备注 | 无 |
代码示例:
import sys
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
if __name__ == '__main__':
# 创建一个类型为 Tron2 的 Robot 实例
robot = Robot(RobotType.Tron2)
2.2.4 init 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | init |
| 函数原型 | def init(self, robot_ip: str = "127.0.0.1") |
| 功能概述 | 初始化运动控制算法程序的通信运行环境,通常在主函数中调用其它接口之前调用,完成初始化工作。 |
| 参数 | robot_ip:机器人的 IP 地址。对于仿真,通常设置为 "127.0.0.1";对于真实机器人,应当设置为 "10.192.1.2"。 |
| 返回值 | 成功返回 True,失败返回 False。 |
| 备注 | 无 |
代码示例:
import sys
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了命令行参数作为机器人IP
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用IP地址初始化机器人的通信运行环境
if not robot.init(robot_ip):
sys.exit()
2.2.5 getMotorNumber 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | getMotorNumber |
| 函数原型 | def getMotorNumber(self, timeout: float = -1.0) |
| 功能概述 | 获取机器人中的电机数量。 |
| 参数 | 无 |
| 返回值 | 返回一个无符号整数,表示机器人中的总电机数量。 |
| 备注 | 通常情况下,双臂形态的电机数量应当为 14 个。 |
代码示例:
import sys
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 获取机器人中的电机数量
motor_number = robot.getMotorNumber()
2.2.6 subscribeImuData 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeImuData |
| 函数原型 | def subscribeImuData(self, callback: Callable[[datatypes.ImuData], Any]) |
| 功能概述 | 订阅机器人的 IMU 数据,并在接收到新的 IMU 数据时调用指定的回调函数。 |
| 参数 | callback:用于处理新 IMU 数据的回调函数。 |
| 返回值 | 成功返回 True,并循环打印 IMU 数据;失败返回 False。 |
备注:
datatypes.ImuData 数据结构原型如下:
import sys
from functools import partial
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
class RobotReceiver:
# 订阅机器人的 IMU数据
def imuDataCallback(self, imu: datatypes.ImuData):
print("\n------\nrobot_state:" + \
"\n stamp: " + str(imu.stamp) + \
"\n acc: " + str(imu.acc) + \
"\n gyro: " + str(imu.gyro) + \
"\n quat: " + str(imu.quat))
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 创建一个 RobotReceiver 实例来处理回调
receiver = RobotReceiver()
# 创建回调函数的 partial 函数
imuDataCallback = partial(receiver.imuDataCallback)
# 订阅机器人IMU数据
robot.subscribeImuData(imuDataCallback)
# 休眠 1 秒,防止程序退出
import time
while True:
time.sleep(1)
2.2.7 subscribeRobotState 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeRobotState |
| 函数原型 | def subscribeRobotState(self, callback: Callable[[datatypes.RobotState], Any]) |
| 功能概述 | 订阅接收关于机器人状态的更新。 |
| 参数 | callback:回调函数,当接收到机器人状态更新时将被调用。回调函数参数指向 datatypes.RobotState 对象。 |
| 返回值 | 成功返回 True,失败返回 False。 |
| 备注 | 无 |
代码示例:
import sys
from functools import partial
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
class RobotReceiver:
# 用于接收机器人状态的回调函数
def robotStateCallback(self, robot_state: datatypes.RobotState):
print("\n------\nrobot_state:" + \
"\n stamp: " + str(robot_state.stamp) + \
"\n tau: " + str(robot_state.tau) + \
"\n q: " + str(robot_state.q) + \
"\n dq: " + str(robot_state.dq))
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 创建一个 RobotReceiver 实例来处理回调
receiver = RobotReceiver()
# 创建回调函数的 partial 函数
robotStateCallback = partial(receiver.robotStateCallback)
# 订阅机器人状态
robot.subscribeRobotState(robotStateCallback)
# 休眠 1 秒,防止程序退出
import time
while True:
time.sleep(1)
2.2.8 publishRobotCmd 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | publishRobotCmd |
| 函数原型 | def publishRobotCmd(self, cmd: datatypes.RobotCmd) |
| 功能概述 | 发布一个命令来控制机器人的动作。 |
| 参数 | cmd:表示所需机器人命令的 datatypes.RobotCmd 对象。 |
| 返回值 | 成功返回 True,失败返回 False。 |
| 备注 | 无 |
代码示例:
import sys
import time
import limxsdk.robot.Rate as Rate
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
if __name__ == '__main__':
# 创建一个 Robot 实例
robot = Robot(RobotType.Tron2)
# 对于仿真,通常设置为 "127.0.0.1",而对于真实机器人,设置为 "10.192.1.2"
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 获取电机数量信息
motor_number = robot.getMotorNumber()
# 主循环以连续发布机器人命令
rate = Rate(300) # 300Hz
cmd_msg = datatypes.RobotCmd()
while True:
# 设置时间戳、控制模式、关节位置、速度、力矩、Kp 和 Kd 的默认值
# motor_names 对应您要控制的关节名称
# 注意以下仅为格式示例,在实际使用过程中应填充具体参数
cmd_msg.stamp = time.time_ns()
cmd_msg.mode = [0.0 for _ in range(16)] # 实际使用无需改变
cmd_msg.q = [0.0 for _ in range(16)] # 填充您规划的角度,控制频率300hz
cmd_msg.dq = [0.0 for _ in range(16)] # 实际使用无需改变
cmd_msg.tau = [0.0 for _ in range(16)] # 实际使用无需改变
cmd_msg.Kp = [420,420,300,300,200,200,200,420,420,300,300,200,200,200]
cmd_msg.Kd = [12,12,15,15,10,10,10,12,12,15,15,10,10,10,3,3]
cmd_msg.motor_names = ["" for _ in range(16)] # 实际使用无需改变
robot.publishRobotCmd(cmd_msg) # 发布 机器人命令
rate.sleep() # 控制循环频率
2.2.9 subscribeSensorJoy 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeSensorJoy |
| 函数原型 | def subscribeSensorJoy(self, callback: Callable[[datatypes.SensorJoy], Any]) |
| 功能概述 | 在真机部署中,该方法用于订阅来自机器人遥控器的数据。当机器人接收到遥控器数据时,将会调用指定的回调函数,并传递包含遥控器数据的 datatypes.SensorJoy 结构体对象给回调函数进行处理。 |
| 参数 | callback:表示回调函数,用于接收机器人遥控器的数据。回调函数的参数类型为 datatypes.SensorJoy。 |
| 返回值 | 成功返回 True,失败返回 False。 |
| 备注 | 无 |
代码示例:
import sys
import time
from functools import partial
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
class RobotReceiver:
# 用于接收遥控器数据的回调函数
def sensorJoyCallback(self, sensor_joy: datatypes.SensorJoy):
print("\n------\nsensor_joy:" + \
"\n stamp: " + str(sensor_joy.stamp) + \
"\n axes: " + str(sensor_joy.axes) + \
"\n buttons: " + str(sensor_joy.buttons))
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 创建一个 RobotReceiver 实例来处理回调
receiver = RobotReceiver()
# 创建回调函数的 partial 函数
sensorJoyCallback = partial(receiver.sensorJoyCallback)
# 订阅机器人遥控数据
robot.subscribeSensorJoy(sensorJoyCallback)
# 休眠 1 秒,防止程序退出
import time
while True:
time.sleep(1)
2.2.10 subscribeDiagnosticValue 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | subscribeDiagnosticValue |
| 函数原型 | def subscribeDiagnosticValue(self, callback: Callable[[datatypes.DiagnosticValue], Any]) |
| 功能概述 | 在真机部署中,该方法用于订阅机器人的诊断值和状态信息。当机器人发出诊断值时,系统会调用指定的回调函数,并传递包含诊断值的 datatypes.DiagnosticValue 结构体对象给回调函数进行处理。这可以帮助实时监控机器人的健康状态,并及时做出反应以处理可能的问题。 |
| 参数 | callback:用于接收机器人诊断值的回调函数,其参数类型为 datatypes.DiagnosticValue。datatypes.DiagnosticValue 结构体包含机器人诊断值的信息,包括时间戳、级别、名称、代码和消息字段。 |
| 返回值 | 成功返回 True,失败返回 False。 |
| 备注 | 无 |
代码示例:
import sys
from functools import partial
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
class RobotReceiver:
# 用于接收诊断值的回调函数
def diagnosticValueCallback(self, diagnostic_value: datatypes.DiagnosticValue):
print("\n------\ndiagnostic_value:" + \
"\n stamp: " + str(diagnostic_value.stamp) + \
"\n name: " + diagnostic_value.name + \
"\n level: " + str(diagnostic_value.level) + \
"\n code: " + str(diagnostic_value.code) + \
"\n message: " + diagnostic_value.message)
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 创建一个 RobotReceiver 实例来处理回调
receiver = RobotReceiver()
# 创建回调函数的 partial 函数
diagnosticValueCallback = partial(receiver.diagnosticValueCallback)
# 订阅机器人诊断信息
robot.subscribeDiagnosticValue(diagnosticValueCallback)
# 休眠 1 秒,防止程序退出
import time
while True:
time.sleep(1)
返回值: |
/home/damon/PyCharmMiscProject/.venv/bin/python /home/damon/PyCharmMiscProject/testsdk.py
INFO: RobotIPAddress - "10.192.1.2"
------
diagnostic_value:
stamp: 980020701021
name: battery
level: 0
code: 100
message: 100
------
diagnostic_value:
stamp: 980016991896
name: battery_charge
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 980016965062
name: battery_cost
level: 0
code: 0
message: 100
------
diagnostic_value:
stamp: 980016998021
name: battery_voltage
level: 0
code: 0
message: 56
------
diagnostic_value:
stamp: 590572955807
name: controller
level: 0
code: 1
message: manipulation_damping controller is ready
------
diagnostic_value:
stamp: 980017064521
name: current_12v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 980017054604
name: current_15v
level: 0
code: 0
message: 2
------
diagnostic_value:
stamp: 980017043229
name: current_24v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 13302781672
name: ecm_version
level: 0
code: 0
message: 1.0.25
------
diagnostic_value:
stamp: 24524362677
name: ethercat
level: 0
code: 0
message: ethercat ok!
------
diagnostic_value:
stamp: 14114416512
name: imu
level: 0
code: 0
message: OK
------
diagnostic_value:
stamp: 14059836923
name: lan_index
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 24534264177
name: left end-effector
level: 0
code: 3
message: limx 2F gripper
------
diagnostic_value:
stamp: 980017021646
name: motor1_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 980017015812
name: motor1_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 980017032437
name: motor2_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 980017027187
name: motor2_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 980017010854
name: motor_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 23464742635
name: motor_version
level: 0
code: 0
message: 1: 1.2.23; 2: 1.2.23; 3: 1.2.23; 4: 1.2.23; 5: 1.2.23; 6: 1.2.23; 7: 1.2.23; 8: 1.2.23; 9: 1.2.23; 10: 1.2.23; 11: 1.2.23; 12: 1.2.23; 13: 1.2.23; 14: 1.2.23; 15: 1.2.18; 16: 1.2.18;
------
diagnostic_value:
stamp: 980017005604
name: motor_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 24543136677
name: right end-effector
level: 0
code: 3
message: limx 2F gripper
------
diagnostic_value:
stamp: 13993435499
name: rotate_status
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 13983715707
name: version
level: 0
code: 0
message: robot-tron2-r-1.2.20.20251225182226
------
diagnostic_value:
stamp: 980017059562
name: voltage_12v
level: 0
code: 0
message: 12
------
diagnostic_value:
stamp: 980017049646
name: voltage_15v
level: 0
code: 0
message: 16
------
diagnostic_value:
stamp: 980017037687
name: voltage_24v
level: 0
code: 0
message: 25
------
diagnostic_value:
stamp: 14044807630
name: vr_follow_head
level: 0
code: 0
message: disable vr follow head
------
diagnostic_value:
stamp: 50767494403
name: working_mode
level: 0
code: 0
message: developer_mode
------
diagnostic_value:
stamp: 1010017039577
name: battery_cost
level: 0
code: 0
message: 100
------
diagnostic_value:
stamp: 1010017068743
name: battery_charge
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 1010017076910
name: battery_voltage
level: 0
code: 0
message: 56
------
diagnostic_value:
stamp: 1010017083035
name: motor_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1010017088577
name: motor_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1010017093243
name: motor1_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1010017099077
name: motor1_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1010017104327
name: motor2_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1010017108993
name: motor2_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1010017114243
name: voltage_24v
level: 0
code: 0
message: 25
------
diagnostic_value:
stamp: 1010017119785
name: current_24v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1010017125618
name: voltage_15v
level: 0
code: 0
message: 16
------
diagnostic_value:
stamp: 1010017130285
name: current_15v
level: 0
code: 0
message: 2
------
diagnostic_value:
stamp: 1010017134952
name: voltage_12v
level: 0
code: 0
message: 12
------
diagnostic_value:
stamp: 1010017139618
name: current_12v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1010020746952
name: battery
level: 0
code: 100
message: 100
------
diagnostic_value:
stamp: 1040017682549
name: battery_cost
level: 0
code: 0
message: 100
------
diagnostic_value:
stamp: 1040017712591
name: battery_charge
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 1040017719008
name: battery_voltage
level: 0
code: 0
message: 56
------
diagnostic_value:
stamp: 1040017725424
name: motor_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1040017730966
name: motor_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1040017736216
name: motor1_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1040017741758
name: motor1_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1040017747299
name: motor2_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1040017752549
name: motor2_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1040017758674
name: voltage_24v
level: 0
code: 0
message: 25
------
diagnostic_value:
stamp: 1040017763924
name: current_24v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1040017769174
name: voltage_15v
level: 0
code: 0
message: 16
------
diagnostic_value:
stamp: 1040017774133
name: current_15v
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 1040017779091
name: voltage_12v
level: 0
code: 0
message: 12
------
diagnostic_value:
stamp: 1040017783758
name: current_12v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1040021298341
name: battery
level: 0
code: 100
message: 100
------
diagnostic_value:
stamp: 1070017263855
name: battery_cost
level: 0
code: 0
message: 100
------
diagnostic_value:
stamp: 1070017288647
name: battery_charge
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 1070017295064
name: battery_voltage
level: 0
code: 0
message: 56
------
diagnostic_value:
stamp: 1070017301480
name: motor_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1070017307022
name: motor_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1070017311980
name: motor1_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1070017317522
name: motor1_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1070017323939
name: motor2_voltage
level: 0
code: 0
message: 55
------
diagnostic_value:
stamp: 1070017328605
name: motor2_current
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1070017333855
name: voltage_24v
level: 0
code: 0
message: 25
------
diagnostic_value:
stamp: 1070017339105
name: current_24v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1070017344064
name: voltage_15v
level: 0
code: 0
message: 16
------
diagnostic_value:
stamp: 1070017348730
name: current_15v
level: 0
code: 0
message: 1
------
diagnostic_value:
stamp: 1070017353980
name: voltage_12v
level: 0
code: 0
message: 12
------
diagnostic_value:
stamp: 1070017358939
name: current_12v
level: 0
code: 0
message: 0
------
diagnostic_value:
stamp: 1070020944689
name: battery
level: 0
code: 100
message: 100
Process finished with exit code 130 (interrupted by signal 2:SIGINT)
2.2.11 setRobotLightEffect 接口介绍
| 项目 | 内容 |
|---|---|
| 函数名 | setRobotLightEffect |
| 函数原型 | def setRobotLightEffect(self, effect: datatypes.LightEffect) |
| 功能概述 | 在真机部署中,该方法用于设置机器人的灯光效果。 |
| 参数 | effect:表示所需机器人灯光效果的枚举值,具体定义见 datatypes.LightEffect。 |
| 返回值 | 成功返回 True,失败返回 False。 |
备注
Tron2::LightEffect 枚举定义:
enum LightEffect : int {
STATIC_RED = 0, // 静态红光
STATIC_GREEN, // 静态绿光
STATIC_BLUE, // 静态蓝光
STATIC_CYAN, // 静态青光
STATIC_PURPLE, // 静态紫光
STATIC_YELLOW, // 静态黄光
STATIC_WHITE, // 静态白光
LOW_FLASH_RED, // 红光闪烁(慢闪)
LOW_FLASH_GREEN, // 绿光闪烁(慢闪)
LOW_FLASH_BLUE, // 蓝光闪烁(慢闪)
LOW_FLASH_CYAN, // 青光闪烁(慢闪)
LOW_FLASH_PURPLE, // 紫光闪烁(慢闪)
LOW_FLASH_YELLOW, // 黄光闪烁(慢闪)
LOW_FLASH_WHITE, // 白光闪烁(慢闪)
FAST_FLASH_RED, // 红光闪烁(快速闪)
FAST_FLASH_GREEN, // 绿光闪烁(快速闪)
FAST_FLASH_BLUE, // 蓝光闪烁(快速闪)
FAST_FLASH_CYAN, // 青光闪烁(快速闪)
FAST_FLASH_PURPLE, // 紫光闪烁(快速闪)
FAST_FLASH_YELLOW, // 黄光闪烁(快速闪)
FAST_FLASH_WHITE // 白光闪烁(快速闪)
};
代码示例:
import sys
from functools import partial
import limxsdk.robot.Robot as Robot
import limxsdk.robot.RobotType as RobotType
import limxsdk.datatypes as datatypes
class RobotReceiver:
if __name__ == '__main__':
# 创建一个类型为Tron2的Robot实例
robot = Robot(RobotType.Tron2)
robot_ip = "10.192.1.2"
# 检查是否提供了机器人 IP 的命令行参数
if len(sys.argv) > 1:
robot_ip = sys.argv[1]
# 使用 robot_ip 初始化机器人
if not robot.init(robot_ip):
sys.exit()
# 设置机器人灯光效果为静态红光
robot.setRobotLightEffect(datatypes.LightEffect.STATIC_RED)
2.2.12 参考例程(Coming Soon)
3 上层应用开发接口
3.1 概述
在上层开发者模式下机器人通过WebSocket通信端口5000来接收用户端请求指令,例如让机器人站起、蹲下、行走等。WebSocket是一种实时通信协议,在机器人和用户端之间建立长连接,以便快速有效地传输控制信息和数据。如下图所示:

3.2 通信协议格式
当机器人通过 WebSocket 接收客户端指令时,采用 JSON 数据协议进行信息传递。这种方式具有显著优势:WebSocket 是一种全双工通信协议,能够在客户端与服务器之间建立实时、低延迟的连接,特别适合频繁交互的应用场景。JSON 数据协议则以其简洁、可读性强的结构,确保数据传输直观明了,且具有跨平台、跨语言的兼容性。WebSocket 与 JSON 的结合不仅与编程语言无关,适用于各种设备和系统,还能提升开发的灵活性和维护的便利性。
- 请求数据格式包含以下字段:
accid:机器人序列号,注意修为您机器人的序列号;title:指令名称,以“request_”为前缀;timestamp:指令发出时间戳,单位为毫秒;guid:指令的唯一标识符,用于区分不同的请求指令。如果是同步接口,则需要在“response_xxx”响应消息中通过guid字段将值带回给客户端。客户端接收到响应消息后,可以通过比较guid字段的值是否与请求指令中的值相同来判断指令是否执行完成;data:存放请求指令的数据内容。可以根据具体需求包含多个子字段,以存放请求指令所需的数据内容,例如执行动作的参数、发送消息的文本内容等等;- 示例如下:
{
"accid": "WF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号
"title": "request_xxx", // 指令名称,以“request_”为前缀
"timestamp": 1672373633989, // 指令发出时间戳,单位为毫秒
"guid": "746d937cd8094f6a98c9577aaf213d98", // 指令的唯一标识符,用于区分不同的请求指令
"data": {} // 存放请求指令的数据内容
}
- 响应数据格式包含以下字段:
accid:机器人序列号,注意修为您机器人的序列号;title:指令名称,以“response_”为前缀;timestamp:指令发出时间戳,单位为毫秒;guid:与对应请求指令的guid值相同;data:至少应该包含一个“result”子字段,用于存放请求指令的执行结果数据。如果有需要,还可以包含其他子字段,例如错误码、错误信息等用于描述操作结果的信息;- 示例如下:
{
"accid": "WF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号
"title": "response_xxx", // 指令名称,以“response_”为前缀
"timestamp": 1672373633989, // 指令发出时间戳,单位为毫秒
"guid": "746d937cd8094f6a98c9577aaf213d98", // 与对应请求指令的guid值相同
"data": { # 存放响应指令的具体数据内容
"result": "success" // “result” 用于存放请求指令处理是否成功,它的值为:“success 或 fail_xxx”
}
}
- 消息推送:它是机器人主动向客户端发送信息的过程。这些信息可以包括机器人的序列号、当前运行状态、执行的操作等数据。通过及时地向客户端发送这些信息,机器人可以帮助客户端更好地理解它的工作状态,从而更好地使用它提供的服务。它的数据格式包含以下字段:
accid:机器人序列号,注意修为您机器人的序列号;title:指令名称,以“notify_”为前缀;timestamp:消息发出时间戳,单位为毫秒;guid:消息的 guid 值,唯一标识这条消息;data:存放消息数据内容。可以根据具体需求包含多个子字段,以存放请求指令所需的数据内容;- 示例如下:
{
"accid": "WF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号
"title": "notify_xxx", // 消息名称,以“notify_”为前缀
"timestamp": 1672373633989, // 消息发出时间戳,单位为毫秒
"guid": "746d937cd8094f6a98c9577aaf213d98", // 消息的guid值,唯一标识这条消息
"data": { } // 存放消息数据内容
}
3.3 查看软件序列号(ACCID)
- 连接机器人无线网络
-
机器人开机完成后,使用个人电脑连接机器人 Wi-Fi,名称格式通常为「WF_TRON2A_xxx」
-
输入 Wi-Fi 密码:
12345678
-
- 在浏览器中输入
http://10.192.1.2:8080可以进入“机器人信息页”,并查看机器人信息。如下图所示,页面中显示的 SN (序列号) 为 SF_TRON2A_127,其中 SF_TRON2A_127 便是此机器人的软件序列号。

3.4 通信测试方法
Postman 是一个流行的 API 测试软件,可以用于测试 WebSocket 接口。使用 Postman 测试 WebSocket 接口,请按照以下步骤操作:
- 安装postman,下载地址:https://www.postman.com/downloads/?utm_source=postman-home;
- 打开Postman,并创建一个WebSocket的请求;
- 连接机器人无线网络
- 机器人开机完成后,使用个人电脑连接机器人Wi-Fi,名称格式通常为「TRON2A_xxx」
- 输入Wi-Fi密码:12345678
- 在请求的URL中输入WebSocket接口的地址,例如,“ws://10.192.1.2:5000”;
- 在“Message”中,输入要发送的指令请求;
- 单击“Send”按钮,发送请求指令;
- 发送指令后,可以从服务器接收响应消息。使用Postman的响应窗口查看服务器返回的数据,并检查是否符合预期结果。

3.5 通用协议接口定义
该机器人接口设计遵循与遥控器操控一致的流程和状态流转,确保调用顺序、响应时序及状态过渡与遥控器控制逻辑严格对齐。用户通过接口调用可获得如同使用遥控器的直观体验,同时支持遥控器与接口间的无缝切换,实现统一、稳定的机器人操控效果。
3.5.1 全局消息
3.5.1.1 机器人基本信息
机器人基本信息每秒上报一次,包含以下内容:
- accid:机器人序列号
- title:notify_robot_info
- timestamp:消息发出时间戳,单位为毫秒
- guid:消息的guid值,唯一标识这条消息
- data:存放消息内容,示例如下:
示例:
{
"accid": "WF_TRON2A_001",
"title": "notify_robot_info",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"accid": "WF_TRON2A_001",
"sw_version": "robot-tron2-2.0.10.20241111103012",
"imu": "OK", // 机器人IMU诊断信息
"camera": "OK", // 机器人相机诊断信息
"motor": "OK", // 机器人电机诊断信息
"battery": 95, // 机器人电量
"status": "WALK" // 机器人运行模式
}
}
| 字段 | 说明 |
|---|---|
accid |
机器人序列号 |
sw_version |
机器人本体软件版本信息 |
imu |
机器人 IMU 诊断信息 |
camera |
机器人相机诊断信息 |
motor |
机器人电机诊断信息 |
battery |
机器人电池电量 |
status |
机器人运行模式,例如 STAND、WALK、SIT、DAMPING、ROTATE、STAIR、ERROR_FALLOVER(摔倒)、RECOVER(摔倒恢复中)、ERROR_RECOVER(摔倒恢复失败) |
3.5.1.2 非法指令消息
当机器人收到非法格式的请求指令时,发送此消息,包含以下内容:
- accid:机器人序列号
- title:notify_invalid_request
- timestamp:消息发出时间戳,单位为毫秒
- guid:消息的guid值,唯一标识这条消息
- data:存放消息内容
- 示例如下:
{
"accid": "WF_TRON2A_001",
"title": "notify_invalid_request",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": "返回原请求指令内容,便于客户端排查问题"
}
3.5.2 连接Wifi热点
3.5.2.1 请求:request_connect_wifi
本协议用于向机器人路由器发起请求,指令路由器连接到指定 SSID 的 WiFi 热点并返回连接结果。
{
"accid": "WF_TRON2A_001",
"title": "request_connect_wifi",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"wifi_band": 0, // WiFi频段:0=5GHz,1=2.4GHz
"wifi_ssid": "Limx-Guests", // 目标WiFi的SSID(WiFi名称),区分大小写,需与实际热点一致
"wifi_password": "LimX2024", // 目标WiFi的密码,WPA2-PSK加密方式的密码
"router_admin_password": "12345678" // 机器人路由器的管理员密码
}
}
3.5.2.2 响应:response_connect_wifi
{
"accid": "WF_TRON2A_001",
"title": "response_connect_wifi",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功
// fail_no_wifi_band: 没有指定频段
// fail_no_wifi_ssid: 没有指定ssid
// fail_no_wifi_password: 没有指定密码
// fail_no_router_admin_password: 没有指定密码
}
}
3.5.2.3 消息推送:无
3.5.3 查询 Wifi 连接状态
3.5.3.1 请求:request_wifi_connection_status
本协议用于客户端向机器人路由器发起 WiFi 连接状态查询请求,路由器接收请求后反馈当前已连接 WiFi 的核心状态信息,包括关联 SSID、信号强度及连接结果,支撑客户端实时感知设备网络连接状态。客户端发起 WiFi 连接状态查询,需携带机器人路由器管理员密码完成身份校验。
{
"accid": "WF_TRON2A_001",
"title": "request_wifi_connection_status",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"router_admin_password": "12345678" // 机器人路由器的管理员密码
}
}
3.5.3.2 响应:response_wifi_connection_status
机器人路由器接收查询请求后,返回当前 WiFi 实际连接状态,供客户端解析展示或后续业务处理。
{
"accid": "WF_TRON2A_001",
"title": "response_wifi_connection_status",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"ssid": "Limx-Guests",
"signal": -56, // 单位dBm
"result": "success" // success: 成功
// fail_disconnected
}
}
3.5.3.3 消息推送:无
3.5.4 设置灯效
3.5.4.1 请求:request_light_effect
{
"accid": "WF_TRON2A_001",
"title": "request_light_effect",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"effect": 1
}
}
请求参数说明:
| 参数名 | 类型 | 描述 |
|---|---|---|
data.effect |
数字 |
灯光效果的编号,对应不同的灯光显示模式,具体映射关系如下: 1: STATIC_RED(静态红色)2: STATIC_GREEN(静态绿色)3: STATIC_BLUE(静态蓝色)4: STATIC_CYAN(静态青色)5: STATIC_PURPLE(静态紫色)6: STATIC_YELLOW(静态黄色)7: STATIC_WHITE(静态白色)8: LOW_FLASH_RED(低频闪烁红色)9: LOW_FLASH_GREEN(低频闪烁绿色)10: LOW_FLASH_BLUE(低频闪烁蓝色)11: LOW_FLASH_CYAN(低频闪烁青色)12: LOW_FLASH_PURPLE(低频闪烁紫色)13: LOW_FLASH_YELLOW(低频闪烁黄色)14: LOW_FLASH_WHITE(低频闪烁白色)15: FAST_FLASH_RED(高频闪烁红色)16: FAST_FLASH_GREEN(高频闪烁绿色)17: FAST_FLASH_BLUE(高频闪烁蓝色)18: FAST_FLASH_CYAN(高频闪烁青色)19: FAST_FLASH_PURPLE(高频闪烁紫色)20: FAST_FLASH_YELLOW(高频闪烁黄色)21: FAST_FLASH_WHITE(高频闪烁白色)
|
3.5.4.2 响应:response_light_effect
{
"accid": "DACH_TRON2A_001",
"title": "response_light_effect",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_light_effect: 失败
}
}
3.5.4.3 消息推送:无
3.5.5 紧急停止
提示:
需要在空闲模式下调用,运动过程中无法响应
3.5.5.1 请求:request_emgy_stop
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_emgy_stop",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.5.5.2 响应:response_emgy_stop
{
"accid": "DACH_TRON2A_001",
"title": "response_emgy_stop",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.5.5.3 消息推送:无
3.6 双臂形态协议接口定义
3.6.1 MoveJ 接口介绍
3.6.1.1 请求:request_movej
注意:moveJ 调用时会判断每个关节的关节角是否到达限位,如果超过限位,则会报错超限,本次调用不执行moveJ 关节限位(按照左臂关节上到下-> 右臂关节上到下的顺序,单位 rad)
上限:[2.6005, 3.1940, 1.4835, 0.2618, 1.3963, 0.7854, 1.5708, 2.6005, 0.2618, 3.6652, 0.2618, 1.7453, 0.7854, 1.5708]
下限:[-3.1416, -0.2618, -3.6652, -2.6180, -1.7453, -0.7854, -1.5708, -3.1416, -3.1940, -1.4835, -2.6180, -1.3963, -0.7854, -1.5708]
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_movej",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"time": 2, // 2秒运动到指定位置
"joint": [] //14个joint值, 单位rad
}
}
3.6.1.2 响应:response_movej
{
"accid": "DACH_TRON2A_001",
"title": "response_movej",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_invalid_cmd:错误的命令(缺少字段)
}
}
3.6.1.3 示例
{
"accid": "DACH_TRON2A_026",
"title": "request_movej",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"time": 5,
"joint": [0,0,0,-1.6,0,0,0,0,0,0,-1.6,0,0,0]
}
}
3.6.2 MoveH 接口介绍
此接口为控制头部二自由度
上限:[1.04 ,1.57]
下限:[-0.78, -1.57]
3.6.2.1 请求:request_moveh
{
"accid": "DACH_TRON2A_026",
"title": "request_moveh",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"time": 5,
"joint": [0.5,0.5] //pitch,yaw
}
}
3.6.2.2 响应:response_moveh
{
"accid": "DACH_TRON2A_001",
"title": "response_moveh",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_invalid_cmd:错误的命令(缺少字段)
}
}
3.6.3 MoveP 接口介绍
3.6.3.1 请求:request_movep
参考坐标系如下,坐标系原点位于基座下平面中心,手臂末端基准位于手臂最后一个关节中心
注意:moveP 调用时会判断左右手的末端位置是否在可达范围内,如果超过限位,则会报错超限,本次调用不执行
moveP 关节限位(按照 x_min, x_max, y_min, y_max, z_min, z_max,单位 m)
左臂:[[0.250, 0.732], [-0.213, 0.900], [-0.673, 0.5]]
右臂:[[0.250, 0.732], [-0.900, 0.213], [-0.673, 0.5]]
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_movep",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"time": 1, //1秒运动到该位置
"pos": [] //[LEFT_POS(3)、wxyzPOSE(4) + RIGHT_POS(3)、wxyzPOSE(4)]
}
3.6.3.2 响应:response_movep
{
"accid": "DACH_TRON2A_001",
"title": "response_movep",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_invalid_cmd:错误的命令(缺少字段)
}
}
3.6.3.3 示例
{
"accid": "DACH_TRON2A_001",
"title": "request_movep",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"time": 5,
"pos": [
0.4580509662628174,
0.16909821331501007,
-0.29940998554229736,
0.7004575729370117,
0.00024424970615655184,
-0.7136882543563843,
0.002872260520234704,
0.4594138264656067,
-0.16968265175819397,
-0.29671144485473633,
0.6979202032089233,
-0.0008072110940702259,
-0.7161515355110168,
-0.005805497523397207
]
}
}
3.6.4 ServoJ 控制指令
3.6.4.1 请求:request_servoj
- 推荐在实时系统中按控制频率 >= 500Hz 要求来控制机械臂运动,以保证控制效果和稳定性,否则可能损坏机器。
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_servoj",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"filter_ratio": 1.0,//范围是0到1,1表示完全信任真值(无滤波)
"q": [ ], // 各个关节的位置,填写16维数据;
}
}
// 请注意将以上参数更换为实际参数
3.6.4.2 响应:无
3.6.4.3 消息推送:notify_servoJ
当 ServoJ 控制操作执行失败时,服务器会主动推送此消息,告知客户端失败原因。
{
"accid": "WF_TRON2A_001",
"title": "notify_servoJ",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "fail_invalid_cmd" # fail_invalid_cmd: 非法指令, fail_motor: 电机错误
}
}
3.6.5 ServoP 控制指令
3.6.5.1 请求:request_servop
持续发送左右手的 pos 数据
{
"accid": "DACH_TRON2A_026", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_servop",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"left_pos": [],
"right_pos": [],
}
}
3.6.5.2 响应:无
3.6.5.3 消息推送:notify_servop
3.6.6 获取双臂末端位姿
3.6.6.1 请求:request_get_move_pose
通过此接口获取机器人双臂的末端位姿信息。
{
"accid": "DACH_TRON2A_036", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_get_move_pose",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.6.6.2 响应:response_get_move_pose
接收到请求后,返回双臂当前位姿的相关信息。
{
"accid": "WF_TRON2A_001",
"title": "response_get_move_pose",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"timestamp": 1672373633989, // 表示数据时戳,单位为毫秒
"left_position": [0.0, 0.0, 0.0], // 表示左臂末端的位置,单位为米,顺序为 x, y, z
"left_quat": [1.0, 0.0, 0.0, 0.0], // 表示左臂末端的姿态,以四元数表示,顺序为 w, x, y, z
"right_position": [0.0, 0.0, 0.0], // 表示右臂末端的位置,单位为米,顺序为 x, y, z
"right_quat": [1.0, 0.0, 0.0, 0.0], // 表示右臂末端的姿态,以四元数表示,顺序为 w, x, y, z
"result": "success" // fail_not_data
}
}
3.6.7 获取机器人关节状态
3.6.7.1 请求:request_get_joint_state
此请求用于获取机器人的各个关节状态。
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_get_joint_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.6.7.2 响应:response_get_joint_state
接收到请求后,返回机器人各个关节当前状态。
{
"accid": "DACH_TRON2A_001",
"title": "response_get_joint_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"names": [], // 各个关节的名称
"q": [], // 各个关节的位置
"dq": [], // 各个关节的速度
"tau": [], // 各个关节的扭矩
"result": "success" // fail_not_data
}
}
3.6.7.3 消息推送:无
3.6.8 柔顺控制
3.6.8.1 开启/关闭柔顺控制
请求:request_set_compliant_enable
{
"accid": "DACH_TRON2A_001",
"title": "request_set_compliant_enable",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"enable": true
}
}
响应:response_set_compliant_enable
{
"accid": "DACH_TRON2A_001",
"title": "response_set_compliant_enable",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"enable": true
}
}
3.6.8.2 查询柔顺控制开关
请求:request_get_compliant_enable
{
"accid": "DACH_TRON2A_001",
"title": "request_get_compliant_enable",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
响应:response_get_compliant_enable
{
"accid": "DACH_TRON2A_001",
"title": "response_get_compliant_enable",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"enable": false
}
}
3.6.8.3 设置柔顺控制参数
请求:request_set_compliant_param
{
"accid": "DACH_TRON2A_001",
"title": "request_set_compliant_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"title": "joint_impedance_kp", //joint_impedance_kp/cart_impedance_kp
"data": [ /* joint 14 项 / cart 12 项 */ ]
}
}
响应:response_set_compliant_param
{
"accid": "DACH_TRON2A_001",
"title": "response_set_compliant_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"title": "joint_impedance_kp"
}
}
3.6.8.4 查询柔顺控制参数
请求:request_get_compliant_param
{
"accid": "DACH_TRON2A_001",
"title": "request_get_compliant_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"title": "joint_toque" // 可选;缺省时同时返回 joint_toque(14) 与 cart_force(12)。
}
}
响应:response_get_compliant_param
{
"accid": "DACH_TRON2A_001",
"title": "response_get_compliant_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"title": "joint_toque",
"data": [ /* ... */ ]
}
}
缺省 title 时响应:
{
"data": {
"result": "success",
"joint_toque": [ /* 14 */ ],
"cart_force": [ /* 12 */ ]
}
}
3.6.9 负载辨识
3.6.9.1 设置机械臂负载参数
请求:request_set_payload_param
{
"accid": "DACH_TRON2A_001",
"title": "request_set_payload_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"arm": 0, //0=左臂,1=右臂;data:真实物理量 [m(kg), mcx, mcy, mcz(kg·m)]。
"data": [0.5, 0.0, 0.0, 0.01]
}
}
响应:response_set_payload_param
{
"accid": "DACH_TRON2A_001",
"title": "response_set_payload_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"arm": 0
}
}
3.6.9.2 查询双臂负载参数
请求:request_get_payload_param
{
"accid": "DACH_TRON2A_001",
"title": "request_get_payload_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
响应:response_get_payload_param
{
"accid": "DACH_TRON2A_001",
"title": "response_get_payload_param",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"data": [ /* m_L,mcx_L,mcy_L,mcz_L, m_R,mcx_R,mcy_R,mcz_R */ ]
}
}
3.6.10 拖动示教
3.6.10.1 进入拖动示教
请求:request_enter_drag_teach
{
"accid": "DACH_TRON2A_001",
"title": "request_enter_drag_teach",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
响应:response_enter_drag_teach
{
"accid": "DACH_TRON2A_001",
"title": "response_enter_drag_teach",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"success": true,
"message": ""
}
}
3.6.10.1 拖动示教轨迹管理
请求:request_drag_teach_manage
{
"accid": "DACH_TRON2A_001",
"title": "request_drag_teach_manage",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"cmd": "start_record", //status/list/start_record/stop_record/play/delete/rename/gripper/exit
"arg": "" //play/delete=文件名;rename="old|newlabel";gripper=open/close/toggle
}
}
响应:response_drag_teach_manage
{
"accid": "DACH_TRON2A_001",
"title": "response_drag_teach_manage",
"timestamp": 1762771300000,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success",
"success": true,
"message": "",
"cmd": "start_record"
}
}
仅当cmd == "list" 时,额外返回 files 数组:
{
"data": {
"result": "success",
"success": true,
"cmd": "list",
"files": ["traj_1", "traj_2"]
}
}
3.6.11 获取升降台状态(仅适用于移动版双臂)
3.6.11.1 请求:request_lifter_state
{
"accid": "DACH_TRON2A_001",
"title": "request_lifter_state",
"guid": "6f5d2f3c27ac4ef89a4f2c31e8b7f402",
"timestamp": 1762771201000,
"data": {}
}
3.6.11.2 响应:response_lifter_state
{
"accid": "DACH_TRON2A_001",
"title": "response_lifter_state",
"guid": "6f5d2f3c27ac4ef89a4f2c31e8b7f402",
"timestamp": 1762771201000,
"data": {
"result": "success",
"q": [0.12],
"v": [0.00]
}
}
3.6.12 升降台绝对位置控制(仅适用于移动版双臂)
3.6.12.1 请求:request_set_lifter_position
{
"accid": "DACH_TRON2A_001",
"title": "request_set_lifter_position",
"guid": "8b9d7caa48d44b9b9e0d6b2f2b30a101",
"timestamp": 1762771300000,
"data": {
"position": 200.5, //目标位置,单位 mm
"duration": 2000 //到达时间,单位 ms,整数;绝对位置控制允许 0,表示最快速度到达
}
}
3.6.12.2 响应:response_set_lifter_position
{
"accid": "DACH_TRON2A_001",
"title": "response_set_lifter_position",
"guid": "8b9d7caa48d44b9b9e0d6b2f2b30a101",
"timestamp": 1762771300000,
"data": {
"result": "success"
}
}
3.6.13 升降台速度控制(仅适用于移动版双臂)
3.6.13.1 请求:request_set_lifter_velocity
{
"accid": "DACH_TRON2A_001",
"title": "request_set_lifter_velocity",
"guid": "8b9d7caa48d44b9b9e0d6b2f2b30a101",
"timestamp": 1762771300000,
"data": {
"velocity": 50, //升降台速度,单位 mm/s,有符号,正数/负数分别表示不同方向
"duration": 2000 //速度控制持续时间,单位 ms,整数,必须 > 0
}
}
3.6.13.2 响应:response_set_lifter_velocity
{ "accid": "DACH_TRON2A_001",
"title": "response_set_lifter_velocity",
"guid": "8b9d7caa48d44b9b9e0d6b2f2b30a101",
"timestamp": 1762771300000,
"data": {
"result": "success"
}
}
3.6.14 查询升降台当前位置(仅适用于移动版双臂)
3.6.14.1 请求:request_get_lifter_position
{
"accid": "DACH_TRON2A_001",
"title": "request_get_lifter_position",
"guid": "8b9d7caa48d44b9b9e0d6b2f2b30a101",
"timestamp": 1762771300000,
"data": {
}
}
3.6.14.2 响应:response_get_lifter_position
{ "accid": "DACH_TRON2A_001",
"title": "response_get_lifter_position",
"guid": "...",
"timestamp": 1762771300000,
"data": {
"result": "success",
"position": 200.3,
"q": -254.4,
"q_per_mm": 0.6224,
"timestamp": 1762771300000
}
}
3.6.15 获取底盘状态(仅适用于移动版双臂)
3.6.15.1 请求:request_chassis_state
{
"accid": "DACH_TRON2A_001",
"title": "request_chassis_state",
"guid": "b6d6f4d2-6f0f-4f0b-8d8e-8f2f3a5a1c01",
"timestamp": 1762771200000,
"data": {}
}
3.6.15.2 响应:response_chassis_state
{
"accid": "DACH_TRON2A_001",
"title": "response_chassis_state",
"guid": "b6d6f4d2-6f0f-4f0b-8d8e-8f2f3a5a1c01",
"timestamp": 1762771200000,
"data": {
"result": "success",
"data": [0.25, -0.10, 0.03] //inear_velocity,angular_velocity,steering_angle;
}
}
3.6.16 设置底盘运动模式(仅适用于移动版双臂)
3.6.16.1 请求:request_set_chassis_mode
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_set_chassis_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"move_mode": "ackerman" //ackerman,parallel,park,spinning,emergency_stop
}
}
3.6.16.2 响应:response_set_chassis_mode
{
"accid": "DACH_TRON2A_001",
"title": "response_set_chassis_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功
}
}
3.6.17 控制底盘运动(仅适用于移动版双臂)
3.6.17.1 请求:request_chassis_move
{
"accid": "DACH_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_chassis_move",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"x": 0.3, //速度值,范围-1到1
"y": 0.0, //速度值,范围-1到1
"yaw": 0.0 //转弯角速度,范围-1到1
}
}
3.6.17.2 响应:response_chassis_move
{
"accid": "DACH_TRON2A_001",
"title": "response_chassis_move",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.7 双臂形态协议接口调用示例
3.7.1 C++ 示例实现
环境准备
以 Ubuntu 22.04 系统为例,安装 websocketpp、nlohmann/json 和 boost 依赖:
sudo apt-get install libboost-all-dev libwebsocketpp-dev nlohmann-json3-dev
编译代码
g++ -std=c++11 -o websocket_client websocket_client.cpp -lssl -lcrypto -lboost_system -lpthread
运行程序
./websocket_client
** websocket_client.cpp 实现**
#include <iostream>
#include <atomic>
#include <string>
#include <thread>
#include <chrono>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio.hpp>
#include <nlohmann/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using json = nlohmann::json;
using websocketpp::client;
using websocketpp::connection_hdl;
// Replace this value with the actual serial number (SN) of the robot.
static std::string ACCID = "";
// Replace it with the real IP address of the robot.
// Usually, for simulation, it is: 127.0.0.1
// for a real machine, it is: 10.192.1.2
const std::string ROBOT_IP = "10.192.1.2";
// WebSocket client instance
static client<websocketpp::config::asio> ws_client;
// Atomic flag for graceful exit
static std::atomic<bool> should_exit(false);
// Connection handle for sending messages
static connection_hdl current_hdl;
// Generate dynamic GUID
static std::string generate_guid()
{
boost::uuids::random_generator gen;
boost::uuids::uuid u = gen();
return boost::uuids::to_string(u);
}
// Send WebSocket request with title and data
static void send_request(const std::string &title, const json &data = json::object())
{
json message;
message["accid"] = ACCID;
message["title"] = title;
message["timestamp"] = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
message["guid"] = generate_guid();
message["data"] = data;
std::string message_str = message.dump();
ws_client.send(current_hdl, message_str, websocketpp::frame::opcode::text);
}
// Handle user commands
void handle_commands()
{
std::cout << "Enter command ('movej', 'movep', 'light', 'stop') or 'exit' to quit:\n";
while (!should_exit)
{
std::string command;
std::cin >> command;
if (command == "exit")
{
should_exit = true;
return;
}
else if (command == "movej")
{
json data = {
{"joint", {-0.5, 0.3, -0.2, 0.2, 0.2, 0.2, 0.2,
-0.5, -0.3, -0.2, 0.2, 0.2, 0.2, 0.2}},
{"time", 2}};
send_request("request_movej", data);
}
else if (command == "movep")
{
json data = {
{"pos", {0.3, 0.2, -0.3, 1, 0, 0, 0, 1, 0, 0, 0, 1,
0.3, -0.2, -0.3, 1, 0, 0, 0, 1, 0, 0, 0, 1}},
{"time", 2}};
send_request("request_movep", data);
}
else if (command == "light")
{
send_request("request_light_effect", {{"effect", 1}});
}
else if (command == "stop")
{
send_request("request_emgy_stop");
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Enter command ('movej', 'movep', 'light', 'stop') or 'exit' to quit:\n";
}
}
// WebSocket open callback
static void on_open(connection_hdl hdl)
{
std::cout << "Connected!" << std::endl;
current_hdl = hdl;
std::thread(handle_commands).detach();
}
// WebSocket TCP initialization handler
static void on_tcp_init(connection_hdl hdl)
{
auto con = ws_client.get_con_from_hdl(hdl);
auto &socket = con->get_socket().lowest_layer();
try
{
boost::system::error_code ec;
const size_t sendBufferSize = 2 * 1024 * 1024;
socket.set_option(websocketpp::lib::asio::socket_base::send_buffer_size(sendBufferSize), ec);
if (ec)
{
printf("Failed to set send buffer size: %s", ec.message().c_str());
}
const size_t recvBufferSize = 2 * 1024 * 1024;
socket.set_option(websocketpp::lib::asio::socket_base::receive_buffer_size(recvBufferSize), ec);
if (ec)
{
printf("Failed to set receive buffer size: %s", ec.message().c_str());
}
socket.set_option(websocketpp::lib::asio::ip::tcp::no_delay(true), ec);
if (ec)
{
printf("Failed to disable Nagle's algorithm: %s", ec.message().c_str());
}
}
catch (const std::exception &e)
{
printf("Socket configuration exception: %s", e.what());
}
}
// WebSocket message callback
static void on_message(connection_hdl hdl, client<websocketpp::config::asio>::message_ptr msg)
{
json data = json::parse(msg->get_payload());
if (data.contains("accid") && data["accid"].is_string() && ACCID.empty())
{
ACCID = data["accid"].get<std::string>();
}
if (msg->get_payload().find("notify_robot_info") == std::string::npos)
{
std::cout << "Received message: " << msg->get_payload() << std::endl;
}
}
// WebSocket close callback
static void on_close(connection_hdl hdl)
{
std::cout << "Connection closed." << std::endl;
}
// Close WebSocket connection
static void close_connection(connection_hdl hdl)
{
ws_client.close(hdl, websocketpp::close::status::normal, "Normal closure");
}
int main()
{
ws_client.init_asio();
ws_client.set_access_channels(websocketpp::log::alevel::none);
ws_client.set_open_handler(&on_open);
ws_client.set_message_handler(&on_message);
ws_client.set_close_handler(&on_close);
ws_client.set_tcp_init_handler(&on_tcp_init);
std::string server_uri = "ws://" + ROBOT_IP + ":5000";
websocketpp::lib::error_code ec;
client<websocketpp::config::asio>::connection_ptr con = ws_client.get_connection(server_uri, ec);
if (ec)
{
std::cout << "Error: " << ec.message() << std::endl;
return 1;
}
ws_client.connect(con);
std::cout << "Press Ctrl+C to exit." << std::endl;
ws_client.run();
return 0;
}
3.7.2 Python 示例实现
环境准备
以 Ubuntu 22.04 系统、Python 3.10.4 版本为例,安装下面依赖:
sudo apt install python3-dev python3-pip
pip3 install websocket-client
运行脚本
python3 websocket_client.py
websocket_client.py 实现
import json
import uuid
import threading
import time
import websocket
# Replace this ACCID value with your robot's actual serial number (SN)
ACCID = None
# Replace it with the real IP address of the robot.
# for a real machine, it is: 10.192.1.2
ROBOT_IP = "10.192.1.2"
# Atomic flag for graceful exit
should_exit = False
# WebSocket client instance
ws_client = None
# Generate dynamic GUID
def generate_guid():
return str(uuid.uuid4())
# Send WebSocket request with title and data
def send_request(title, data=None):
global ACCID
if data is None:
data = {}
message = {
"accid": ACCID,
"title": title,
"timestamp": int(time.time() * 1000),
"guid": generate_guid(),
"data": data
}
message_str = json.dumps(message)
if ws_client:
ws_client.send(message_str)
# Handle user commands
def handle_commands():
global should_exit
while not should_exit:
command = input("Enter command ('movej', 'movep', 'light', 'stop') or 'exit' to quit:\n")
if command == "exit":
should_exit = True
break
elif command == "movej":
send_request("request_movej", {
"joint": [
-0.5, 0.3, -0.2, 0.2, 0.2, 0.2, 0.2,
-0.5, -0.3, -0.2, 0.2, 0.2, 0.2, 0.2
],
"time": 2
})
elif command == "movep":
send_request("request_movep", {
"pos": [
0.3, 0.2, -0.3, 1, 0, 0, 0, 1, 0, 0, 0, 1,
0.3, -0.2, -0.3, 1, 0, 0, 0, 1, 0, 0, 0, 1
],
"time": 2
})
elif command == "light":
send_request("request_light_effect", {
"effect": 1
})
elif command == "stop":
send_request("request_emgy_stop", {})
# WebSocket on_open callback
def on_open(ws):
print("Connected!")
threading.Thread(target=handle_commands, daemon=True).start()
# WebSocket on_message callback
def on_message(ws, message):
global ACCID
root = json.loads(message)
title = root.get("title", "")
if ACCID is None:
ACCID = root.get("accid", None)
if title != "notify_robot_info":
print(f"Received message: {message}")
# WebSocket on_close callback
def on_close(ws, close_status_code, close_msg):
print("Connection closed.")
# Close WebSocket connection
def close_connection(ws):
ws.close()
def main():
global ws_client
ws_client = websocket.WebSocketApp(
f"ws://{ROBOT_IP}:5000",
on_open=on_open,
on_message=on_message,
on_close=on_close
)
print("Press Ctrl+C to exit.")
ws_client.run_forever()
if __name__ == "__main__":
main()
3.8 双足/双轮足协议接口定义
该机器人接口设计遵循与遥控器操控一致的流程和状态流转,确保调用顺序、响应时序及状态过渡与遥控器控制逻辑严格对齐。用户通过接口调用可获得如同使用遥控器的直观体验,同时支持遥控器与接口间的无缝切换,实现统一、稳定的机器人操控效果。

3.8.1 起立状态
3.8.1.1 请求:request_stand_mode
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_stand_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
}
}
3.8.1.2 响应:response_stand_mode
{
"accid": "SF_TRON2A_001",
"title": "response_stand_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
3.8.1.3 消息推送:notify_stand_mode
机器人站起过程失败或完成后,主动推送此消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_stand_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.2 行走状态
3.8.2.1 请求:request_walk_mode
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_walk_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
}
}
3.8.2.2 响应:response_walk_mode
{
"accid": "SF_TRON2A_001",
"title": "response_walk_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
3.8.2.3 消息推送:notify_walk_mode
机器人站起过程失败或完成后,主动推送此消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_walk_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.3 控制行走
3.8.3.1 请求:request_twist
请按 30Hz 及以上发送指令。
- 掌足模式下按如下规则:
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_twist",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"x": 0.0, // 前进后退速度比值,取值范围[-1, 1]
"y": 0.0, // 横向行走速度比值,取值范围[-1, 1]
"z": 0.0 // 旋转角速度比值,取值范围[-1, 1]
}
}
- 轮足模式下按如下规则:
{
"accid": "WF_TRON1A_075", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_twist",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"x": 0.0, // 前进后退速度(m/s),取值范围[-3.0, 3.0];同时注意,楼梯模式下发速度需要大于1.5,否则上不了楼梯
"y": 0.0, // 横向行走速度为0.0(m/s),轮足模式下不支持横向移动
"z": 0.0 // 旋转角速度(m/s),取值范围[-1.5, 1.5]
}
}
3.8.3.2 响应:无
3.8.3.3 消息推送:notify_twist
机器人行走失败时,主动推送此消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_twist",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "fail_motor" // fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.4 调整机器身高
3.8.4.1 请求:request_base_height
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_base_height",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"direction": -1 // 1:表示升高,-1:表示降低
// 每次调用此请求会使机器人身高相应升高或降低 5cm
}
}
3.8.4.2 响应:response_base_height
{
"accid": "SF_TRON2A_001",
"title": "response_base_height",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_status: 则表示机器人当前状态不允许调整身高
}
}
3.8.4.3 消息推送:无
3.8.5 蹲下
3.8.5.1 请求:request_sitdown
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_sitdown",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.8.5.2 响应:response_sitdown
{
"accid": "SF_TRON2A_001",
"title": "response_sitdown",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.5.3 消息推送:notify_sitdown
机器人蹲下过程失败或完成后,主动推送此消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_sitdown",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.6 开启楼梯模式(仅适用于双轮足形态)
3.8.6.1 请求:request_stair_mode
{
"accid": "WF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_stair_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"enable": true // true: 开启楼梯模式, false: 关闭楼梯模式
}
}
3.8.6.2 响应:response_stair_mode
{
"accid": "WF_TRON2A_001",
"title": "response_stair_mode",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.6.3 消息推送:无
3.8.7 紧急停止
3.8.7.1 请求:request_emgy_stop
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_emgy_stop",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.8.7.2 响应:response_emgy_stop
{
"accid": "SF_TRON2A_001",
"title": "response_emgy_stop",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU 错误, fail_motor: 电机错误
}
}
3.8.7.3 消息推送:无
3.8.8 开启 IMU 数据
3.8.8.1 请求:request_enable_imu
该功能用于开启 IMU 数据推送,开启后系统将主动推送 IMU 数据。
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_enable_imu",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"enable": true // true: 开启IMU, false: 禁用IMU
}
}
3.8.8.2 响应:response_enable_imu
{
"accid": "SF_TRON2A_001",
"title": "response_enable_imu",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_imu: IMU
}
}
3.8.8.3 消息推送:notify_imu
开启 IMU 数据后,系统将主动推送包含 IMU 状态的消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_imu",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"euler": [0.0, 0.0, 0.0], // 欧拉角 [roll, pitch, yaw] in degrees
"acc": [0.0, 0.0, 0.0], // 加速度 [x, y, z] in m/s²
"gyro": [0.0, 0.0, 0.0], // 陀螺仪角速度 [x, y, z] in rad/s
"quat": [0.0, 0.0, 0.0, 0.0] // 四元数 [w, x, y, z]
}
}
3.8.9 摔倒恢复
3.8.9.1 请求:request_recover
当机器人摔倒后,可以调用此接口让机器人自动爬起来并恢复到行走模式。
{
"accid": "SF_TRON2A_001", // 机器人序列号,注意修为您机器人的序列号;
"title": "request_recover",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {}
}
3.8.9.2 响应:response_recover
{
"accid": "SF_TRON2A_001",
"title": "response_recover",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功收到指令,开始恢复爬起, fail_no_fallover: 当前没摔倒
}
}
3.8.9.3 消息推送:notify_recover
完成恢复爬起后,推送此消息。
{
"accid": "SF_TRON2A_001",
"title": "notify_recover",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 摔倒恢复成功, fail_recover: 摔倒恢复失败
}
}
3.9 双足/双轮足协议接口调用示例
3.9.1 Linux C++ 示例实现
环境准备
以 Ubuntu 20.04 系统为例,安装 websocketpp、nlohmann/json 和 boost 依赖:
sudo apt-get install libboost-all-dev libwebsocketpp-dev nlohmann-json3-dev
编译代码
g++ -std=c++11 -o websocket_client websocket_client.cpp -lssl -lcrypto -lboost_system -lpthread
运行程序
./websocket_client
websocket_client.cpp 实现
#include <iostream>
#include <atomic>
#include <string>
#include <thread>
#include <chrono>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio.hpp>
#include <nlohmann/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
using json = nlohmann::json;
using websocketpp::client;
using websocketpp::connection_hdl;
// Replace this ACCID value with your robot's actual serial number (SN)
static std::string ACCID = "";
// WebSocket client instance
static client<websocketpp::config::asio> ws_client;
// Atomic flag for graceful exit
static std::atomic<bool> should_exit(false);
// Connection handle for sending messages
static connection_hdl current_hdl;
// Generate dynamic GUID
static std::string generate_guid()
{
boost::uuids::random_generator gen;
boost::uuids::uuid u = gen();
return boost::uuids::to_string(u);
}
// Send WebSocket request with title and data
static void send_request(const std::string& title, const json& data = json::object())
{
json message;
message["accid"] = ACCID;
message["title"] = title;
message["timestamp"] = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
message["guid"] = generate_guid();
message["data"] = data;
std::string message_str = message.dump();
ws_client.send(current_hdl, message_str, websocketpp::frame::opcode::text);
}
// Handle user commands
static void handle_commands()
{
while (!should_exit)
{
std::string command;
std::cout << "Enter command ('stand', 'walk', 'twist', 'sit', 'stair', 'stop', 'imu') or 'exit' to quit:" << std::endl;
std::getline(std::cin, command);
if (command == "exit")
{
should_exit = true;
break;
}
else if (command == "stand")
{
send_request("request_stand_mode");
}
else if (command == "walk")
{
send_request("request_walk_mode");
}
else if (command == "twist")
{
float x, y, z;
std::cout << "Enter x, y, z values:" << std::endl;
std::cin >> x >> y >> z;
std::cin.ignore();
send_request("request_twist", {
{"x", x},
{"y", y},
{"z", z}
});
}
else if (command == "sit")
{
send_request("request_sitdown");
}
else if (command == "stair")
{
std::string enable;
std::cout << "Enable stair mode (true/false):" << std::endl;
std::cin >> enable;
std::cin.ignore();
send_request("request_stair_mode", {
{"enable", enable == "true"}
});
}
else if (command == "stop")
{
send_request("request_emgy_stop");
}
else if (command == "imu")
{
std::string enable;
std::cout << "Enable IMU (true/false):" << std::endl;
std::cin >> enable;
std::cin.ignore();
send_request("request_enable_imu", {
{"enable", enable == "true"}
});
}
}
}
// WebSocket open callback
static void on_open(connection_hdl hdl)
{
std::cout << "Connected!" << std::endl;
current_hdl = hdl;
std::thread(handle_commands).detach();
}
// WebSocket message callback
static void on_message(connection_hdl hdl, client<websocketpp::config::asio>::message_ptr msg)
{
json data = json::parse(msg->get_payload());
if (data.contains("accid") && data["accid"].is_string() && ACCID.empty())
{
ACCID = data["accid"].get<std::string>();
}
std::cout << "Received: " << msg->get_payload() << std::endl;
}
// WebSocket close callback
static void on_close(connection_hdl hdl)
{
std::cout << "Connection closed." << std::endl;
}
// Close WebSocket connection
static void close_connection(connection_hdl hdl)
{
ws_client.close(hdl, websocketpp::close::status::normal, "Normal closure");
}
int main()
{
ws_client.init_asio();
ws_client.set_open_handler(&on_open);
ws_client.set_message_handler(&on_message);
ws_client.set_close_handler(&on_close);
std::string server_uri = "ws://10.192.1.2:5000";
websocketpp::lib::error_code ec;
client<websocketpp::config::asio>::connection_ptr con = ws_client.get_connection(server_uri, ec);
if (ec)
{
std::cout << "Error: " << ec.message() << std::endl;
return 1;
}
connection_hdl hdl = con->get_handle();
ws_client.connect(con);
std::cout << "Press Ctrl+C to exit." << std::endl;
ws_client.run();
return 0;
}
3.9.2 Python 示例实现
环境准备
以 Ubuntu 20.04 系统为例,安装下面依赖:
sudo apt install python3-dev python3-pip
pip3 install websocket-client
运行脚本
python3 websocket_client.py
websocket_client.py 实现
import json
import uuid
import threading
import time
import websocket
# Replace this ACCID value with your robot's actual serial number (SN)
ACCID = None
# Atomic flag for graceful exit
should_exit = False
# WebSocket client instance
ws_client = None
# Generate dynamic GUID
def generate_guid():
return str(uuid.uuid4())
# Send WebSocket request with title and data
def send_request(title, data=None):
global ACCID
global ws_client
if data is None:
data = {}
# Create message structure with necessary fields
message = {
"accid": ACCID,
"title": title,
"timestamp": int(time.time() * 1000),
"guid": generate_guid(),
"data": data
}
message_str = json.dumps(message)
# Send the message through WebSocket if client is connected
if ws_client:
ws_client.send(message_str)
# Handle user commands
def handle_commands():
global should_exit
while not should_exit:
command = input(
"Enter command ('stand', 'walk', 'twist', 'sit', 'stair', 'stop', 'imu') or 'exit' to quit:\n"
)
if command == "exit":
should_exit = True
break
elif command == "stand":
send_request("request_stand_mode")
elif command == "walk":
send_request("request_walk_mode")
elif command == "twist":
# Get twist values from user
x = float(input("Enter x value: "))
y = float(input("Enter y value: "))
z = float(input("Enter z value: "))
# Send twist command at 30 Hz for 1 second
for _ in range(30):
send_request("request_twist", {
"x": x,
"y": y,
"z": z
})
time.sleep(1 / 30)
elif command == "sit":
send_request("request_sitdown")
elif command == "stair":
# Get stair mode enable flag from user
enable = input("Enable stair mode (true/false): ").strip().lower() == "true"
send_request("request_stair_mode", {
"enable": enable
})
elif command == "stop":
send_request("request_emgy_stop")
elif command == "imu":
# Get IMU enable flag from user
enable = input("Enable IMU (true/false): ").strip().lower() == "true"
send_request("request_enable_imu", {
"enable": enable
})
# WebSocket on_open callback
def on_open(ws):
print("Connected!")
# Start handling commands in a separate thread
threading.Thread(target=handle_commands, daemon=True).start()
# WebSocket on_message callback
def on_message(ws, message):
global ACCID
root = json.loads(message)
ACCID = root.get("accid", None)
print(f"Received message: {message}")
# WebSocket on_close callback
def on_close(ws, close_status_code, close_msg):
print("Connection closed.")
# Close WebSocket connection
def close_connection(ws):
ws.close()
def main():
global ws_client
# Create WebSocket client instance
ws_client = websocket.WebSocketApp(
"ws://10.192.1.2:5000",
on_open=on_open,
on_message=on_message,
on_close=on_close
)
# Run WebSocket client loop
print("Press Ctrl+C to exit.")
ws_client.run_forever()
if __name__ == "__main__":
main()
4 外接部件开发接口
4.1 头部和腕部相机
4.2 腰部相机
我们在机器人上安装了RealSense D435i相机,它是一款强大的深度摄像头,可提供深度和图像数据,主要用于地形感知。摄像头视角范围如下:
通过本章介绍,您可以学习如何使用ROS的Noetic版本获取D435i相机数据。具体步骤如下:
- 确认您的电脑安装了ROS的Noetic版本系统(请参考文档:- ,选择“ros-noetic-desktop-full”进行安装)。
- 配置网络连接:确保您的开发电脑与机器人本体通过外置网口连接。设置您的电脑IP地址为:10.192.1.200,并通过Shell命令ping 10.192.1.2 能够正常ping通。如下图所示对您的开发电脑进行IP设置:

- 配置ROS环境以获取相机数据。
为了使您的电脑通过ROS接收到机器人的相机数据,您需要设置ROS的环境变量:- 设置 ROS_MASTER_URI 和 ROS_IP,以确保您的电脑能够正确连接到机器人的ROS主节点:您可以将下述命令添加到您电脑的 .bashrc 文件中,这样每次启动终端时都会自动应用设置。
export ROS_MASTER_URI=http://10.192.1.2:11311
export ROS_IP=10.192.1.200 - 通过ROS查看D435i相机发布的数据主题:此命令将列出所有相机发布的主题,您可以订阅感兴趣的主题来查看数据。
- 设置 ROS_MASTER_URI 和 ROS_IP,以确保您的电脑能够正确连接到机器人的ROS主节点:您可以将下述命令添加到您电脑的 .bashrc 文件中,这样每次启动终端时都会自动应用设置。
rostopic list
- 使用rqt或rviz可视化相机数据
可以使用 rqt_image_view 或 rviz 来可视化D435i相机的图像和深度数据:- 安装 rqt_image_view 工具:
sudo apt install ros-<ros版本>-rqt-image-view
然后启动该工具并选择相机主题查看数据:
rqt_image_view
- 使用 rviz 可视化工具查看深度数据:
rviz
在rviz中添加相应的 Image 和 PointCloud2 类型显示器,选择相机相关主题以进行可视化。
4.3 逐际二指夹爪
4.3.1 夹爪控制指令
4.3.1.1 请求:request_set_limx_2fclaw_cmd
此协议控制夹爪的抓取动作。
{
"accid": "DACH_TRON2A_001",
"title": "request_set_limx_2fclaw_cmd",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
// 如您同时给出以下数据,则会控制左夹爪运动
"left_opening": 50, // 开口度,0-100,无量纲(0对应最小闭合,100对应张开到最大)
"left_speed": 50, // 夹爪速度,0~100 无量纲(数值越大速度越快)
"left_force": 50, //力,夹爪夹持力,0~100 无单位(数值越大力越大)
// 如您同时给出以下数据,则会控制右夹爪运动
"right_opening": 50, // 开口度,0-100,无量纲(0对应最小闭合,100对应张开到最大)
"right_speed": 50, // 夹爪速度,0~100 无量纲(数值越大速度越快)
"right_force": 50 //力,夹爪夹持力,0~100 无单位(数值越大力越大)
}
}
4.4.1.2 响应:response_set_limx_2fclaw_cmd
{
"accid": "DACH_TRON2A_001",
"title": "response_set_limx_2fclaw_cmd",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_motor: 电机错误,
}
}
4.4.1.3 消息推送:无
4.4.2 获取夹爪状态信息
4.4.2.1 请求:request_get_limx_2fclaw_state
{
"accid": "DACH_TRON2A_001",
"title": "request_get_limx_2fclaw_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
}
}
4.4.2.2 响应:response_get_limx_2fclaw_state
返回夹爪状态信息
{
"accid": "DACH_TRON2A_001",
"title": "response_get_limx_2fclaw_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"timestamp": 1672373633989, // 表示数据时戳,单位为毫秒
"left_opening": 50, // 开口度,0-100,无量纲(0对应最小闭合,100对应张开到最大)
"left_speed": 50, // 夹爪速度,0~100 无量纲(数值越大速度越快)
"left_force": 50, //力,夹爪夹持力,0~100 无单位(数值越大力越大)
"right_opening": 50, // 开口度,0-100,无量纲(0对应最小闭合,100对应张开到最大)
"right_speed": 50, // 夹爪速度,0~100 无量纲(数值越大速度越快)
"right_force": 50, //力,夹爪夹持力,0~100 无单位(数值越大力越大)
"result": "success" // success: 成功, fail_motor: 电机错误
}
}
4.4.2.3 消息推送:无
4.4 强脑 Revo 2 灵巧手(基础版)
4.4.1.1 灵巧手控制指令
4.4.1.1.1 请求:request_set_brainco2_hand_cmd
{
"accid": "DACH_TRON2A_001",
"title": "request_set_brainco2_hand_cmd",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
// 左手:
// 索引从0-5分别对应:拇指尖、拇指根、食指、中指、无名指、小指
// left_mode: 控制模式
// 0:退出控制
// 1:位置时间模式, 必须指定 left_pos、left_time 的值
// 2:位置速度模式, 必须指定 left_pos、left_vel 的值
// 3:力控模式, 必须指定 left_current 的值
// left_pos: 每个手指的目标位置, 单位为rad
// 范围分别为0-1.0297、0-1.5707、0-1.4137、0-1.4137、0-1.4137、0-1.4137
// left_vel: 每个手指的目标速度, 单位为rad/s
// 范围分别为0-2.5367、0-2.6180、0-2.2689、0-2.2689、0-2.2689、0-2.2689
// left_current: 每个手指的目标电流, 单位为mA, 范围为±1000mA
// left_time: 每个手指的控制时间, 单位为ms, 范围为1-2000ms
"left_mode": 1,
"left_pos": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"left_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"left_current": [500, 500, 500, 500, 500, 500],
"left_time": [1000, 1000, 1000, 1000, 1000, 1000],
// 右手:
// 索引从0-5分别对应:拇指尖、拇指根、食指、中指、无名指、小指
// right_mode: 控制模式
// 0:退出控制
// 1:位置时间模式, 必须指定 right_pos、right_time 的值
// 2:位置速度模式, 必须指定 right_pos、right_vel 的值
// 3:力控模式, 必须指定 right_current 的值
// right_pos: 每个手指的目标位置, 单位为rad
// 范围分别为0-1.0297、0-1.5707、0-1.4137、0-1.4137、0-1.4137、0-1.4137
// right_vel: 每个手指的目标速度, 单位为rad/s
// 范围分别为0-2.5367、0-2.6180、0-2.2689、0-2.2689、0-2.2689、0-2.2689
// right_current: 每个手指的目标电流, 单位为mA, 范围为±1000mA
// right_time: 每个手指的控制时间, 单位为ms, 范围为1-2000ms
"right_mode": 1,
"right_pos": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_current": [500, 500, 500, 500, 500, 500],
"right_time": [1000, 1000, 1000, 1000, 1000, 1000]
}
}
4.4.1.1.2 响应:response_set_brainco2_hand_cmd
{
"accid": "DACH_TRON2A_001",
"title": "response_set_brainco2_hand_cmd",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"result": "success" // success: 成功, fail_motor: 电机错误, fail_invalid_cmd: 非法指令
}
}
4.4.1.1.3 控制示例
{
"accid": "DACH_TRON2A_069",
"title": "request_set_brainco2_hand_cmd",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"left_mode": 1,
"left_pos": [0.5, 0.5, 0.5, 1, 0.5, 0.5],
"left_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"left_current": [500, 500, 500, 500, 500, 500],
"left_time": [1000, 1000, 1000, 1000, 1000, 1000],
"right_mode": 1,
"right_pos": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_current": [500, 500, 500, 500, 500, 500],
"right_time": [1000, 1000, 1000, 1000, 1000, 1000]
}
}
4.4.1.2 获取灵巧手状态
4.4.1.2.1 请求:request_get_brainco2_hand_state
{
"accid": "DACH_TRON2A_001",
"title": "request_get_brainco2_hand_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
}
}
4.4.0.2.2 响应:response_get_brainco2_hand_state
{
"accid": "DACH_TRON2A_001",
"title": "response_get_brainco2_hand_state",
"timestamp": 1672373633989,
"guid": "746d937cd8094f6a98c9577aaf213d98",
"data": {
"timestamp": 1672373633989,
"left_mode": 1,
"left_pos": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"left_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"left_current": [500, 500, 500, 500, 500, 500],
"left_time": [1000, 1000, 1000, 1000, 1000, 1000],
"right_mode": 1,
"right_pos": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_vel": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
"right_current": [500, 500, 500, 500, 500, 500],
"right_time": [1000, 1000, 1000, 1000, 1000, 1000]
}
}
5 数字资产
5.1 机器人 urdf
https://github.com/limx-tron2/robot-description
6 常见问题
| 序号 | 问题 | 常见原因 | 解决方式 |
|---|---|---|---|
| 1 | 访问 http://10.192.1.2:8080 没反应 |
电脑不在 10.192.1.2 同网段 | 1. 先 ping10.192.1.2,通了清除下浏览器数据,或者换浏览器重新访问 2. 没 ping 通就修改本机地址,关闭 dhcp,DNS 为 223.5.5.5 或者 8.8.8.8 |
| 2 | 如何配置相机 sn 号 | 相机 SN 配置方法 | |
| 3 | |||
| 4 | |||
| 5 |
深圳逐际动力科技有限公司
**地址:**深圳市南山区沙河西路 3157 号南山智谷产业园 E 栋 15 层
网址:https://limxdynamics.com/