Skip to content

Tracking Motion with servo_move()

servo_move(SOCKETFD socketFd, ServoMovePara servoMove) can receive a set of points, then smooth the received points based on timeStamp and dispatch them to the servo for motion.

cpp
struct ServoMovePara {
  ///< Transfer parameters
  bool clearBuffer;                         ///< Whether to clear previously sent points that haven't started interpolation
  int targetMode;                           ///< 0-discrete points 1-continuous trajectory
  int sendMode;                             ///< 0-send all trajectory points at once 1-send partial points at a time
  int runMode;                              ///< 0-start motion after receiving all 1-start motion while receiving
  int sum;                                  ///< Total number of transfers
  int count;                                ///< Current transfer number
  ///< Motion parameters
  int coord;                                ///< 0-joint 1-Cartesian
  int size;                                 ///< Number of points in this transfer
  std::vector<std::vector<double>> pos;     ///< 2D array: first dimension = number of points in this transfer, second dimension = 7 for joint angles or Cartesian coordinates
  std::vector<std::vector<double>> axisvel; ///< 2D array: first dimension = number of points in this transfer, second dimension = 7 for axis velocities
  std::vector<std::vector<double>> axisacc; ///< 2D array: first dimension = number of points in this transfer, second dimension = 7 for axis accelerations
  std::vector<double> timeStamp;            ///< Length = number of points in this transfer, representing the time to reach each point, in ms
};

Prerequisites: Run the External Point Instruction on the Teach Pendant

Teach pendant showing the External Point Instruction job file that must be started before running servo_move remote tracking

Start and run this job file.

Example 1: Remote Operation Using Continuous Point Trajectory with Partial Point Transfers

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


int main() {
  ServoMovePara param;


  // Target point data
  double axis1_pos = 1;
  double axis2_pos = 2;
  
  // Query position before motion
  std::vector<double> pos(7);
  get_current_position(fd, 0, pos);
  std::cout << "Joint position before motion: " << pos[0] << " " << pos[1] << " " << pos[2] << " " 
            << pos[3] << " " << pos[4] << " " << pos[5] << " "  << pos[6] << std::endl;
  
  for (int k = 0; k < 4000; k++) {
      // Generate target point data
      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]});      // Target point data
          std::cout << "Joint angle=" << 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 << "Size=" << param.pos.size() << std::endl;
  
      // Set velocity for each axis
      for (int i = 0; i < param.pos.size(); i++) {
          param.axisvel.push_back({1, 1, 1, 1, 1, 50, 1});     // Velocity for each axis to reach the target point, in degrees per second
      }
  
      // Set acceleration for each axis
      for (int i = 0; i < param.pos.size(); i++) {
          param.axisacc.push_back({1, 1, 1, 1, 1, 50, 1});       // Acceleration for each axis to reach the target point
      }
  
      // Set timestamps
      double times = 5;     // Time relative to the starting point when reaching this point
      for (int i = 0; i < param.pos.size(); i++) {
          param.timeStamp.push_back(times);
          times += 5;        // Assume each subsequent point is 5ms later than the previous one. Final timeStamp array = {5, 10, 15, 20...}
      }
  
      // Set parameters
      param.clearBuffer = true;  // When using continuous motion, clearBuffer, targetMode, sendMode, runMode must use this fixed format
      param.targetMode = 0;   // Continuous trajectory
      param.sendMode = 0;     // Send all trajectory points at once
      param.runMode = 0;
      param.coord = 0;        // Joint coordinates
      param.sum = 100000;        // Since points need to be sent continuously, assume a very large total transfer count
      param.count = 100000;        // Since points need to be sent continuously, assume a very large total transfer count
      param.extMove = 0;
      param.size = param.pos.size();
  
      // Call the motion interface
      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;
  
      // Delay compensation
      if (t_duration.count() < times / 1000 + 0.01) {
          std::this_thread::sleep_for(std::chrono::duration<double>(times / 1000 + 0.01 - t_duration.count()));
      }
  
      // Clear parameters
      param.pos.clear();
      param.axisvel.clear();
      param.axisacc.clear();
      param.timeStamp.clear();
  }
  return 0;
}

Example 2: Using Discrete Point Trajectory, Sending All Trajectory Points at Once (No Smoothing)

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


int main() {
  ServoMovePara param;


// Target point data
double axis1_pos = 1;
double axis2_pos = 2;


// Query position before motion
std::vector<double> pos(7);
get_current_position(fd, 0, pos);
std::cout << "Joint position before motion: " 
          << pos[0] << " " << pos[1] << " " << pos[2] << " " 
          << pos[3] << " " << pos[4] << " " << pos[5] << " " 
          << pos[6] << std::endl;


for (int k = 0; k < 4000; k++) {
    // Generate target point data
    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]});      // Target point data
        std::cout << "Joint angle=" << 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 << "Size=" << param.pos.size() << std::endl;


    // Set velocity for each axis
    for (int i = 0; i < param.pos.size(); i++) {
        param.axisvel.push_back({1, 1, 1, 1, 1, 50, 1});     // Velocity for each axis to reach the target point, in degrees per second
    }


    // Set acceleration for each axis
    for (int i = 0; i < param.pos.size(); i++) {
        param.axisacc.push_back({1, 1, 1, 1, 1, 50, 1});       // Acceleration for each axis to reach the target point
    }


    // Set timestamps
    double times = 5;     // Time relative to the starting point when reaching this point
    for (int i = 0; i < param.pos.size(); i++) {
        param.timeStamp.push_back(times);
        times += 5;        // Assume each subsequent point is 5ms later than the previous one. Final timeStamp array = {500, 550, 600, 650...}
    }


    // Set parameters
    param.robotNum = 1;
    param.clearBuffer = true;  // When using continuous motion, clearBuffer, targetMode, sendMode, runMode must use this fixed format
    param.targetMode = 0;   // Discrete points
    param.sendMode = 0;     // Send all trajectory points at once
    param.runMode = 0;
    param.coord = 0;        // Joint coordinates
    param.size = param.pos.size();
    // Call the motion interface
    std::cout << "servo_move return: " << servo_move(fd, param) << std::endl;
    // Delay 5ms
    std::this_thread::sleep_for(std::chrono::milliseconds(5));


    // Clear parameters
    param.pos.clear();
    param.axisvel.clear();
    param.axisacc.clear();
    param.timeStamp.clear();
}
  return 0;
}