servoJ 与 7000 端口共用
servoJ 的喂点、队列模式、状态查询与状态回调都走 7000 端口。很多客户会问「要不要为 servoJ 再开一条连接」「7000 上能不能同时挂状态回调」,本页给出连接组织方式与完整示例。
一句话结论
一根 7000 连接就够用:servoJ 喂点、servoJ 队列、get_robot_state、robot_state_callback 都在 7000 上;而清错、上下电、伺服使能、读坐标必须回到 6001。
一、两个端口各管什么
| 端口 | 承载 | 典型接口 |
|---|---|---|
| 6001 | 命令 / 状态通道 | connect_robot、clear_error、set_servo_state、set_servo_poweron、get_servo_state、get_current_position、get_current_mode |
| 7000 | 伺服跟踪 / 上位机服务 | open_servoJ、set_servoJ_pos、close_servoJ、open_servoJ_queue_mode、append_servoJ_pos_to_queue、close_servoJ_queue_mode、get_robot_state、robot_state_callback |
servoJ 系列接口只接受 7000 句柄,传 6001 的句柄会返回 -2(DISCONNECT),这是最常见的失败原因。
二、连接与调用顺序
cpp
SOCKETFD fdCmd = connect_robot(ip, "6001"); // 命令 / 状态
SOCKETFD fdServo = connect_robot(ip, "7000"); // servoJ + 7000 侧功能
clear_error(fdCmd); // 1. 清错
set_servo_state(fdCmd, 1); // 2. 就绪
set_servo_poweron(fdCmd); // 3. 上电(返回 0 不等于已上电)
// 4. 轮询 get_servo_state(fdCmd) 到 3
open_servoJ(fdServo, vmax, amax, jmax); // 5. 打开跟踪
// 6. 逐点 set_servoJ_pos(fdServo, q) 或队列 append
close_servoJ(fdServo); // 7. 退出跟踪(必须先关)
set_servo_poweroff(fdCmd); // 8. 下电顺序不能颠倒:open_servoJ 之前控制器必须已经处于运行状态(3),否则会返回状态类错误。
三、7000 上同时挂状态回调 + 喂点
cpp
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
#include "cpp/interface/nrc_api.h"
std::atomic<int> g_robotState{-1};
// 状态回调:只记录,不做耗时操作、不下发命令
void onRobotState(int state)
{
g_robotState.store(state);
}
int main()
{
SOCKETFD fdCmd = connect_robot("192.168.1.13", "6001");
SOCKETFD fdServo = connect_robot("192.168.1.13", "7000");
if (fdCmd <= 0 || fdServo <= 0) { return 1; }
// 1) 上电到状态 3(略,见「上电与下电流程」)
// 2) 7000 上先挂状态回调,再打开 servoJ —— 两者共用同一句柄
robot_state_callback(fdServo, onRobotState);
std::vector<double> vmax(7, 10.0), amax(7, 50.0), jmax(7, 200.0);
open_servoJ(fdServo, vmax, amax, jmax);
// 3) 同一句柄上按周期喂点
std::vector<double> q(7, 0.0);
int coord = 0;
get_current_position(fdCmd, coord, q); // 起点取实际位置
const int cycleMs = 10;
const double stepDeg = 0.05; // ≤ vmax * cycleMs/1000
for (int i = 0; i < 200; ++i) {
q[0] += stepDeg;
set_servoJ_pos(fdServo, q);
std::this_thread::sleep_for(std::chrono::milliseconds(cycleMs));
}
close_servoJ(fdServo);
disconnect_robot(fdServo);
disconnect_robot(fdCmd);
return 0;
}回调签名以你的包内
nrc_interface.h为准;本页只用来说明「同一 7000 句柄可以既挂回调又喂点」。
四、队列模式:一次给一组点
逐点喂点要求上位机严格定时;点已经算好一段(视觉给轮廓、离线插补结果)时改用队列模式:
cpp
open_servoJ(fdServo, vmax, amax, jmax); // 必须先打开跟踪
open_servoJ_queue_mode(fdServo, 10); // 每点 10 ms
std::vector<std::vector<double>> pts; // 每个内层 7 个元素(度)
append_servoJ_pos_to_queue(fdServo, pts);
close_servoJ_queue_mode(fdServo);
close_servoJ(fdServo);每点位移要跟周期配套:每点位移(°) ≤ vmax(°/s) × cycle_time_ms / 1000。
| 周期 | vmax=10°/s 时每点最大位移 | 说明 |
|---|---|---|
| 10 ms | 0.1° | 官方示例的默认节奏 |
| 20 ms | 0.2° | 点少一半,轨迹更粗 |
| 5 ms | 0.05° | 需要很高采样率时用 |
五、停止与完成判定
| 你以为的 | 实际含义 |
|---|---|
set_servoJ_pos 返回 0 | 命令已写进 socket,不代表控制器已收、更不代表在动 |
close_servoJ 返回 0 | 退出跟踪模式,机器人停在当前位置并保持使能(这是唯一确定的「停」) |
| 「运动完成」 | servoJ 没有完成回调;只能读 get_current_position 与目标比对,误差进入容差且连续若干周期不变才算到位 |
六、常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
open_servoJ 返回 -2 | 用了 6001 句柄,或 7000 没连上 | 确认 connect_robot(ip, "7000") 成功 |
| 返回 0 但不动 | 伺服未到状态 3;每周期增量太小;没连续发 | 先轮询状态 3,再小步长试跑 |
| 状态回调收不到 | 回调注册在 6001 句柄上,或没先连接成功 | 状态回调走 7000 句柄 |
| 开第二条 7000 连接后异常 | 并发连接数限制未明确([待核]) | 优先复用同一根连接 |
| 跑完还在跟踪模式 | 只关了队列模式,没关 close_servoJ | 两个都要关 |
七、待核
- 控制器对 7000 并发连接数是否有限制、一根连接上同时跑 servoJ 与状态回调是否有线程安全要求。
- 「错误 / 警告消息回调」(
set_receive_error_or_warnning_message_callback)应注册在哪个端口,文档未明确。