十一、视觉工艺(nrc_craft_vision.h)
视觉工艺接口提供视觉系统的基本参数配置、视觉范围设置、坐标参数配置、视觉标定及标定数据查询、手眼标定计算等功能。支持单机器人和多机器人(_robot 后缀)两种调用方式。
数据结构
VisionParam —— 视觉基本参数
struct VisionParam {
CameraList cameraList; // 相机列表
Protocol protocol; // 通讯协议配置
Socket socket; // Socket 通讯配置
Trigger trigger; // 触发配置
int userCoordNum; // 用户坐标编号
};子结构体说明:
CameraList:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| currentName | string | "customize" | 当前相机名称 |
| listNum | int | 0 | 相机列表数量 |
Protocol(通讯协议):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| addDataInitialPara | string | "GD001" | 附加数据初始参数 |
| addDataNum | int | 0 | 附加数据数量 |
| angleUnit | int | 1 | 角度单位 |
| endMark | string | "$" | 结束标志 |
| failFlag | string | "NG" | 失败标志 |
| frameHeader | string | "" | 帧头 |
| hasTCS | bool | false | 是否有TCS |
| hasUCS | bool | false | 是否有UCS |
| separator | string | "," | 分隔符 |
| singleTarget | bool | true | 单目标 |
| successFlag | string | "OK" | 成功标志 |
| timeOut | int | 30 | 超时时间 |
| type | int | 1 | 协议类型 |
Socket(Socket 通讯配置):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| IP | string | "192.168.1.120" | IP地址 |
| cameraDataType | int | 0 | 相机数据类型 |
| portNum | int | 1 | 端口号 |
| portOne | int | 5050 | 端口1 |
| portTwo | int | 5051 | 端口2 |
| server | bool | true | 是否为服务器 |
Trigger(触发配置):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| IOPort | int | 0 | IO端口 |
| duration | int | 1000 | 持续时间(ms) |
| intervals | int | 35 | 间隔时间(ms) |
| triggerMode | int | 2 | 触发模式:1=IO,2=EtherCAT |
| triggerOnce | bool | true | 单次触发 |
| triggerStr | string | "TRG" | 触发字符串 |
VisionRange —— 视觉范围
struct VisionRange {
std::string maxX; // 最大X坐标
std::string maxY; // 最大Y坐标
std::string maxZ; // 最大Z坐标
std::string minX; // 最小X坐标
std::string minY; // 最小Y坐标
std::string minZ; // 最小Z坐标
};VisionPositionParam —— 视觉坐标参数
struct VisionPositionParam {
Position position; // 位置数据
int protocol; // 协议类型
};Position 子结构体包含: 视角方向(angleDirection)、相机数据(cameraData)、相机点位(cameraPoint,长度14)、参考点位(datumPoint,长度14)、偏移量(Excursion:X/Y/Z 偏移 + 角度)、接收点类型(recvPointsType)、样本数据(sampleData)、比例(scale)。
VisionCalibrationData —— 视觉标定数据
struct VisionCalibrationData {
int visionNum; // 视觉编号
Calibration calibration; // 校准数据(含标定点列表,默认点数6,范围[6,30])
};Calibration 包含: calibrated(是否已校准)、point(标定点列表)、point_num(点数量)。
CalibrationPoint 包含: pixel_pos(像素位置,长度7)、pixel_pos_deg(像素位置角度,长度7)、robot_pos(机器人位置,长度7)、robot_pos_deg(机器人位置角度,长度7)。
11.1 基本参数配置
vision_set_basic_parameter / vision_set_basic_parameter_robot
设置视觉系统的基本参数,包括相机列表、通讯协议、Socket 配置和触发方式。
函数签名:
Result vision_set_basic_parameter(SOCKETFD socketFd, int visionNum, VisionParam vsPamrm);
Result vision_set_basic_parameter_robot(SOCKETFD socketFd, int robotNum, int visionNum, VisionParam vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionParam | 输入 | 视觉基本参数结构体 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
// 配置视觉系统基本参数
VisionParam param;
// 设置相机名称
param.cameraList.currentName = "camera_01";
param.cameraList.listNum = 1;
// 设置通讯协议
param.protocol.addDataInitialPara = "GD001";
param.protocol.endMark = "$";
param.protocol.failFlag = "NG";
param.protocol.successFlag = "OK";
param.protocol.separator = ",";
param.protocol.timeOut = 30;
param.protocol.type = 1;
// 设置Socket通讯
param.socket.IP = "192.168.1.120";
param.socket.portOne = 5050;
param.socket.portTwo = 5051;
param.socket.server = true;
// 设置触发方式
param.trigger.triggerMode = 2; // EtherCAT触发
param.trigger.duration = 1000;
param.trigger.intervals = 35;
param.trigger.triggerStr = "TRG";
// 设置用户坐标
param.userCoordNum = 1;
Result result = vision_set_basic_parameter(fd, 1, param);
if (result == 0) {
printf("视觉基本参数设置成功\n");
}vision_get_basic_parameter / vision_get_basic_parameter_robot
查询视觉系统已配置的基本参数。
函数签名:
Result vision_get_basic_parameter(SOCKETFD socketFd, int visionNum, VisionParam& vsPamrm);
Result vision_get_basic_parameter_robot(SOCKETFD socketFd, int robotNum, int visionNum, VisionParam& vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionParam& | 输出 | 接收视觉基本参数 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
VisionParam param;
Result result = vision_get_basic_parameter(fd, 1, param);
if (result == 0) {
printf("视觉基本参数:\n");
printf(" 相机名称: %s\n", param.cameraList.currentName.c_str());
printf(" IP地址: %s\n", param.socket.IP.c_str());
printf(" 端口1: %d\n", param.socket.portOne);
printf(" 触发模式: %d\n", param.trigger.triggerMode);
printf(" 用户坐标编号: %d\n", param.userCoordNum);
}11.2 视觉范围配置
vision_set_range / vision_set_range_robot
设置视觉识别的空间范围(包围盒),用于限定视觉检测的有效区域。
函数签名:
Result vision_set_range(SOCKETFD socketFd, int visionNum, VisionRange vsPamrm);
Result vision_set_range_robot(SOCKETFD socketFd, int robotNum, int visionNum, VisionRange vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionRange | 输入 | 视觉范围参数(min/max XYZ) |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
// 设置视觉检测范围:X[0,500], Y[-200,200], Z[0,300]
VisionRange range;
range.minX = "0";
range.maxX = "500";
range.minY = "-200";
range.maxY = "200";
range.minZ = "0";
range.maxZ = "300";
Result result = vision_set_range(fd, 1, range);
if (result == 0) {
printf("视觉范围设置成功\n");
}vision_get_range / vision_get_range_robot
查询视觉已配置的空间范围参数。
函数签名:
Result vision_get_range(SOCKETFD socketFd, int visionNum, VisionRange& vsPamrm);
Result vision_get_range_robot(SOCKETFD socketFd, int robotNum, int visionNum, VisionRange& vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionRange& | 输出 | 接收视觉范围参数 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
VisionRange range;
Result result = vision_get_range(fd, 1, range);
if (result == 0) {
printf("视觉范围:\n");
printf(" X: [%s, %s]\n", range.minX.c_str(), range.maxX.c_str());
printf(" Y: [%s, %s]\n", range.minY.c_str(), range.maxY.c_str());
printf(" Z: [%s, %s]\n", range.minZ.c_str(), range.maxZ.c_str());
}11.3 坐标参数配置
vision_set_position_parameter / vision_set_position_parameter_robot
设置视觉坐标参数,包括拍照位置、参考点位、偏移量和样本数据格式等。
函数签名:
Result vision_set_position_parameter(SOCKETFD socketFd, int visionNum, VisionPositionParam vsPamrm);
Result vision_set_position_parameter_robot(SOCKETFD socketFd, int robotNum, int visionNum, VisionPositionParam vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionPositionParam | 输入 | 视觉坐标参数 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
VisionPositionParam posParam;
// 设置协议类型
posParam.protocol = 0;
// 设置位置数据
posParam.position.angleDirection = 0;
posParam.position.cameraData = "";
posParam.position.recvPointsType = 0;
posParam.position.sampleData = "x,y,Rz,h,$";
posParam.position.scale = 1.0;
// 设置偏移量
posParam.position.excursion.Xexcursion = 0.0;
posParam.position.excursion.Yexcursion = 0.0;
posParam.position.excursion.Zexcursion = 0.0;
posParam.position.excursion.angle = 0.0;
Result result = vision_set_position_parameter(fd, 1, posParam);
if (result == 0) {
printf("视觉坐标参数设置成功\n");
}vision_get_position_parameter / vision_get_position_parameter_robot
查询视觉已配置的坐标参数。
函数签名:
Result vision_get_position_parameter(SOCKETFD socketFd, int visionId, VisionPositionParam& vsPamrm);
Result vision_get_position_parameter_robot(SOCKETFD socketFd, int robotNum, int visionId, VisionPositionParam& vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionId | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionPositionParam& | 输出 | 接收视觉坐标参数 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
VisionPositionParam posParam;
Result result = vision_get_position_parameter(fd, 1, posParam);
if (result == 0) {
printf("视觉坐标参数:\n");
printf(" 协议类型: %d\n", posParam.protocol);
printf(" 样本数据格式: %s\n", posParam.position.sampleData.c_str());
printf(" 偏移: X=%.2f Y=%.2f Z=%.2f Angle=%.2f\n",
posParam.position.excursion.Xexcursion,
posParam.position.excursion.Yexcursion,
posParam.position.excursion.Zexcursion,
posParam.position.excursion.angle);
}11.4 视觉标定
vision_calibrate / vision_calibrate_robot
执行视觉标定操作,设置标定相关的点位数据。
函数签名:
Result vision_calibrate(SOCKETFD socketFd, int visionId, VisionCalibrationData vsPamrm);
Result vision_calibrate_robot(SOCKETFD socketFd, int robotNum, int visionId, VisionCalibrationData vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionId | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionCalibrationData | 输入 | 标定数据,含像素位置和机器人位置 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
注意事项: 标定前需确保视觉基本参数和坐标参数已正确配置。标定点数默认为 6,范围 [6, 30],点数越多标定精度越高。
使用示例:
// 创建标定数据(默认6个标定点)
VisionCalibrationData calibData(6);
calibData.visionNum = 1;
// 添加标定点(示例:第1个点)
CalibrationPoint point1;
// 像素位置(x, y, z, rx, ry, rz, 保留)
point1.pixel_pos = {100.0, 200.0, 0.0, 0.0, 0.0, 0.0, 0.0};
// 机器人实际位置
point1.robot_pos = {400.0, 150.0, 50.0, 180.0, 0.0, 0.0, 0.0};
calibData.calibration.addCalibrationPoint(point1);
// ... 继续添加其余5个标定点
// 执行标定
Result result = vision_calibrate(fd, 1, calibData);
if (result == 0) {
printf("视觉标定完成\n");
}vision_get_calibrate_data / vision_get_calibrate_data_robot
查询已保存的视觉标定数据。
函数签名:
Result vision_get_calibrate_data(SOCKETFD socketFd, int visionId, VisionCalibrationData& vsPamrm);
Result vision_get_calibrate_data_robot(SOCKETFD socketFd, int robotNum, int visionId, VisionCalibrationData& vsPamrm);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionId | int | 输入 | 视觉ID编号 |
| vsPamrm | VisionCalibrationData& | 输出 | 接收标定数据 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
使用示例:
VisionCalibrationData calibData;
Result result = vision_get_calibrate_data(fd, 1, calibData);
if (result == 0) {
printf("视觉标定数据(视觉编号=%d):\n", calibData.visionNum);
printf(" 已校准: %s\n", calibData.calibration.calibrated ? "是" : "否");
printf(" 标定点数: %d\n", calibData.calibration.point_num);
for (int i = 0; i < calibData.calibration.point_num; i++) {
auto pt = calibData.calibration.getPoint(i);
printf(" 点%d: 像素(%.1f,%.1f) -> 机器人(%.1f,%.1f,%.1f)\n",
i + 1,
pt.pixel_pos[0], pt.pixel_pos[1],
pt.robot_pos[0], pt.robot_pos[1], pt.robot_pos[2]);
}
}vision_hand_eye_calibration_calculation / vision_hand_eye_calibration_calculation_robot
执行手眼标定计算。在标定点数据全部录入后,调用此接口计算手眼关系矩阵。
函数签名:
Result vision_hand_eye_calibration_calculation(SOCKETFD socketFd, int visionNum);
Result vision_hand_eye_calibration_calculation_robot(SOCKETFD socketFd, int robotNum, int visionNum);参数说明:
| 参数 | 类型 | 输入/输出 | 说明 |
|---|---|---|---|
| socketFd | SOCKETFD | 输入 | 连接句柄 |
| robotNum | int | 输入 | 机器人编号(仅 _robot 版本) |
| visionNum | int | 输入 | 视觉ID编号 |
返回值: Result 枚举,0 表示成功,-1 表示等待消息失败,-2 表示找不到指定的客户端。
注意事项: 手眼标定计算前需确保所有标定点(像素位置和对应的机器人位置)已通过 vision_calibrate 录入。计算完成后,视觉系统即可将相机识别到的像素坐标转换为机器人坐标系下的空间位置。
使用示例:
// 标定点全部录入后,执行手眼标定计算
Result result = vision_hand_eye_calibration_calculation(fd, 1);
if (result == 0) {
printf("手眼标定计算完成,视觉系统已校准\n");
} else {
printf("手眼标定计算失败,请检查标定点数据\n");
}11.5 完整视觉标定流程示例
#include "nrc_craft_vision.h"
#include "nrc_interface.h"
#include <stdio.h>
int main() {
SOCKETFD fd = connect_robot("192.168.1.15", "6001");
if (fd <= 0) {
printf("连接失败\n");
return -1;
}
// 1. 配置视觉基本参数
VisionParam visionParam;
visionParam.cameraList.currentName = "camera_01";
visionParam.cameraList.listNum = 1;
visionParam.socket.IP = "192.168.1.120";
visionParam.socket.portOne = 5050;
visionParam.socket.portTwo = 5051;
visionParam.socket.server = true;
visionParam.trigger.triggerMode = 2; // EtherCAT触发
visionParam.userCoordNum = 1;
Result ret = vision_set_basic_parameter(fd, 1, visionParam);
if (ret != 0) { printf("视觉基本参数配置失败\n"); return -1; }
// 2. 设置视觉范围
VisionRange range;
range.minX = "0"; range.maxX = "500";
range.minY = "-200"; range.maxY = "200";
range.minZ = "0"; range.maxZ = "300";
vision_set_range(fd, 1, range);
// 3. 设置坐标参数
VisionPositionParam posParam;
posParam.protocol = 0;
posParam.position.sampleData = "x,y,Rz,h,$";
posParam.position.scale = 1.0;
vision_set_position_parameter(fd, 1, posParam);
// 4. 执行6点标定
VisionCalibrationData calibData(6);
calibData.visionNum = 1;
// 标定点采集(此处为示意,实际需移动机器人到各标定点)
for (int i = 0; i < 6; i++) {
printf("请移动机器人到标定点%d...\n", i + 1);
// robot_movel(fd, ...); // 移动到目标位置
CalibrationPoint point;
// 从相机获取像素坐标
point.pixel_pos = {100.0 * i, 200.0, 0, 0, 0, 0, 0};
// 获取当前机器人位置
point.robot_pos = {400.0, 150.0 + i * 50, 50.0, 180.0, 0, 0, 0};
calibData.calibration.addCalibrationPoint(point);
printf("标定点%d已采集\n", i + 1);
sleep(1);
}
// 5. 提交标定数据
ret = vision_calibrate(fd, 1, calibData);
if (ret != 0) { printf("标定数据提交失败\n"); return -1; }
// 6. 执行手眼标定计算
ret = vision_hand_eye_calibration_calculation(fd, 1);
if (ret == 0) {
printf("手眼标定完成!\n");
} else {
printf("手眼标定计算失败\n");
return -1;
}
printf("视觉标定流程结束\n");
return 0;
}