Skip to content
🤖 AI 助手 / 自动化工具:先读 《AI 助手先读》 《Agent 开发指引》 《生成前信息采集清单》;机器可读入口 /llms.txt;技能包(SKILL)直链:SKILL.md

使用 servo_move() 来进行跟踪运动 ​

servo_move(SOCKETFD socketFd,ServoMovePara servoMove) 可以接收一组点,然后将接收到的点位根据 timeStamp 做平滑处理后下发到伺服运动。

⚠️ 安全警告

以下代码会导致机器人实际运动。执行前必须确认:

  • 人员安全: 机器人工作空间内无人员或障碍物
  • 急停可用: 急停按钮在可触及范围内
  • 伺服使能: 确认伺服已正确使能
  • 速度限制: 首次运行将速度设置为较低值(建议 ≤ 最大速度的 20%)
  • 坐标系与单位: 关节运动单位为度(°),直线运动单位为毫米(mm)

建议先在仿真环境或空载低速条件下测试,确认无误后再用于实际生产。

cpp
struct ServoMovePara {
  ///< 传输参数
  bool clearBuffer;                         ///< 是否清除之前发送的,未开始插补计算的点位
  int targetMode;                           ///< 0-独立点 1-连续轨迹
  int sendMode;                             ///< 0-一次传输完全部轨迹 1-一次传输部分点位
  int runMode;                              ///< 0-接收完再运动 1-边接受边运动
  int sum;                                  ///< 总传输次数
  int count;                                ///< 当前是第几次传输
  ///< 运动参数
  int coord;                                ///< 0-关节 1-直角
  int size;                                 ///< 本次传输的点位数
  std::vector<std::vector<double>> pos;     ///< 二维数组,一维表示本次传输的点位数,二维长度为7,各个关节角度或笛卡尔坐标
  std::vector<std::vector<double>> axisvel; ///< 二维数组,一维表示本次传输的点位数,二维长度为7,各个轴的速度
  std::vector<std::vector<double>> axisacc; ///< 二维数组,一维表示本次传输的点位数,二维长度为7,各个轴的加速度
  std::vector<double> timeStamp;            ///< 长度为本次传输的点位数,表示到达该点位的时间,单位ms
};

使用前提:需要作业文件配合 ​

servo_move() 不能脱离作业文件单独使用:控制器侧必须有一个正在运行的作业,作业中写有外部点(伺服跟踪)指令,上位机经 7000 端口下发的点位才会被执行。

典型用法是在一段固定流程的作业中夹杂上位机实时生成的轨迹:作业负责流程骨架(回原点、取放料、IO 时序等固定动作),到需要随传感器 / 视觉结果变化的那一段,改由上位机实时生成点位并经 servo_move() 下发。

机器人示教器上运行外部点指令的循环程序(ADSA 文件),当 I001 信号为 0 时持续执行关节运动

在示教器上启动运行该作业文件后,再从上位机调用 servo_move() 下发点位。

参数取值(以头文件注释为准) ​

参数取值说明
targetMode0 / 10-独立点,1-连续轨迹
sendMode0 / 10-一次传输完全部轨迹点位,1-一次传输部分点位
runMode0 / 10-接收完再运动,1-边接收边运动
coord0 / 10-关节,1-直角
clearBuffertrue / false是否清除之前发送的、未开始插补计算的点位

下面两个示例都用 targetMode = 0(独立点)、sendMode = 0(一次传输完本帧全部点位);若要让点与点之间按连续轨迹衔接,把 targetMode 置 1。

示例一:逐帧持续发送点位来进行遥操作 ​

cpp
#include <iostream>
#include <vector>
#include <chrono>
#include "cpp_interface/nrc_api.h"


int main() {
  ServoMovePara param;


  // 目标点位数据
  double axis1_pos = 1;
  double axis2_pos = 2;
  
  // 查询运动前坐标
  std::vector<double> pos(7);
  get_current_position(fd, 0, pos);
  std::cout << "关节运动前坐标:" << pos[0] << " " << pos[1] << " " << pos[2] << " " 
            << pos[3] << " " << pos[4] << " " << pos[5] << " "  << pos[6] << std::endl;
  
  for (int k = 0; k < 4000; k++) {
      // 生成目标点位数据
      for (int i = 0; i < 2; i++) {
          param.pos.push_back({pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6]});      //目标点位数据
          std::cout << "关节角=" << param.pos[i][6] << std::endl;
  
          if (k < 100) {
              pos[5] += 0.05;
          } else if (k >= 100 && k < 200) {
              pos[5] -= 0.05;
          } else if (k >= 200 && k < 300) {
              pos[5] += 0.05;
          } else {
              pos[5] -= 0.05;
          }
  
          std::cout << "k=" << k << std::endl;
      }
  
      std::cout << "大小=" << param.pos.size() << std::endl;
  
      // 设置每个轴的速度
      for (int i = 0; i < param.pos.size(); i++) {
          param.axisvel.push_back({1, 1, 1, 1, 1, 50, 1});     //到达目标点位的每个轴的速度,单位度每秒
      }
  
      // 设置每个轴的加速度
      for (int i = 0; i < param.pos.size(); i++) {
          param.axisacc.push_back({1, 1, 1, 1, 1, 50, 1});       //到达目标点位的每个轴的加速度
      }
  
      // 设置时间戳
      double times = 5;     //运行到该点位时,相对于起始点的时间
      for (int i = 0; i < param.pos.size(); i++) {
          param.timeStamp.push_back(times);
          times += 5;        //假设后续每一个点位都相较于上一个点多5ms,最终timeStamp数组是{5,10,15,20...}
      }
  
      // 设置参数
      param.clearBuffer = true;  // 清除上一帧未开始插补计算的点位
      param.targetMode = 0;   // 0-独立点,1-连续轨迹
      param.sendMode = 0;     // 0-一次传输完全部轨迹点位,1-一次传输部分点位
      param.runMode = 0;      // 0-接收完再运动,1-边接收边运动
      param.coord = 0;        // 关节坐标
      param.sum = 100000;        // 因为需要持续发送点位,我们假设总的发送次数很大
      param.count = 100000;        // 因为需要持续发送点位,我们假设总的发送次数很大
      param.extMove = 0;
      param.size = param.pos.size();
  
      // 调用运动接口
      auto t_start = std::chrono::high_resolution_clock::now();
      std::cout << "servo_move return: " << servo_move(fd, param) << std::endl;
  
      auto t_stop = std::chrono::high_resolution_clock::now();
      auto t_duration = std::chrono::duration<double>(t_stop - t_start);
      std::cout << "t_duration: " << t_duration.count() << std::endl;
  
      // 延时补偿
      if (t_duration.count() < times / 1000 + 0.01) {
          std::this_thread::sleep_for(std::chrono::duration<double>(times / 1000 + 0.01 - t_duration.count()));
      }
  
      // 清空参数
      param.pos.clear();
      param.axisvel.clear();
      param.axisacc.clear();
      param.timeStamp.clear();
  }
  return 0;
}

示例二:使用独立点位轨迹,,一次性传输完全部轨迹点位(没有平滑) ​

cpp
#include <iostream>
#include <vector>
#include <chrono>
#include "cpp_interface/nrc_api.h"


int main() {
  ServoMovePara param;


// 目标点位数据
double axis1_pos = 1;
double axis2_pos = 2;


// 查询运动前坐标
std::vector<double> pos(7);
get_current_position(fd, 0, pos);
std::cout << "关节运动前坐标:" 
          << pos[0] << " " << pos[1] << " " << pos[2] << " " 
          << pos[3] << " " << pos[4] << " " << pos[5] << " " 
          << pos[6] << std::endl;


for (int k = 0; k < 4000; k++) {
    // 生成目标点位数据
    for (int i = 0; i < 2; i++) {
        param.pos.push_back({pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6]});      //目标点位数据
        std::cout << "关节角=" << param.pos[i][6] << std::endl;


        if (k < 100) {
            pos[5] += 0.05;
        } else if (k >= 100 && k < 200) {
            pos[5] -= 0.05;
        } else if (k >= 200 && k < 300) {
            pos[5] += 0.05;
        } else {
            pos[5] -= 0.05;
        }


        std::cout << "k=" << k << std::endl;
    }


    std::cout << "大小=" << param.pos.size() << std::endl;


    // 设置每个轴的速度
    for (int i = 0; i < param.pos.size(); i++) {
        param.axisvel.push_back({1, 1, 1, 1, 1, 50, 1});     //到达目标点位的每个轴的速度,单位度每秒
    }


    // 设置每个轴的加速度
    for (int i = 0; i < param.pos.size(); i++) {
        param.axisacc.push_back({1, 1, 1, 1, 1, 50, 1});       //到达目标点位的每个轴的加速度
    }


    // 设置时间戳
    double times = 5;     //运行到该点位时,相对于起始点的时间
    for (int i = 0; i < param.pos.size(); i++) {
        param.timeStamp.push_back(times);
        times += 5;        //假设后续每一个点位都相较于上一个点多5ms,最终timeStamp数组是{500,550,600,650...}
    }


    // 设置参数
    param.robotNum = 1;
    param.clearBuffer = true;  // 清除上一帧未开始插补计算的点位
    param.targetMode = 0;   // 0-独立点,1-连续轨迹
    param.sendMode = 0;     // 0-一次传输完全部轨迹点位,1-一次传输部分点位
    param.runMode = 0;      // 0-接收完再运动,1-边接收边运动
    param.coord = 0;        // 关节坐标
    param.size = param.pos.size();
    // 调用运动接口
    std::cout << "servo_move return: " << servo_move(fd, param) << std::endl;
    // 延时5ms
    std::this_thread::sleep_for(std::chrono::milliseconds(5));


    // 清空参数
    param.pos.clear();
    param.axisvel.clear();
    param.axisacc.clear();
    param.timeStamp.clear();
}
  return 0;
}