TRON 2 SDK 开发指南

TRON 2 EDU版July 21, 2026
版本 修订日期 修改内容 备注
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.DiagnosticValuedatatypes.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 机器人运行模式,例如 STANDWALKSITDAMPINGROTATESTAIRERROR_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 系统为例,安装 websocketppnlohmann/jsonboost 依赖:

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 系统为例,安装 websocketppnlohmann/jsonboost 依赖:

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相机发布的数据主题:此命令将列出所有相机发布的主题,您可以订阅感兴趣的主题来查看数据。
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/
图片