跳到主要内容

介绍

1. SDK 介绍

NRC_HOST SDK 提供了一套快速集成的网络接口,让开发者无需关注底层协议细节,提高开发效率,支持 Linux、Windows 平台,以及多种高级开发语言,方便开发者选择最适合自己的平台进行开发。

2. 兼容性说明

类别兼容范围
系统支持 x86,x86_64,arm,arm64 架构
开发环境针对自己的开发语言使用对应的 QT,Python,C#推荐的 IDE,如 Qtcreator, VS Studio,VSCode 等

3. SDK 集成包目录结构

├── Demo:NRC_HOST 的使用 DEMO,DEMO 中已经集成了 SDK,你可以参考 DEMO,集成 SDK。集成前,请先测通 DEMO,了解调用原理。
├── SDK:NRC_HOST SDK
│ └── libnrc_host.so
└── NRC_HOST 文档:SDK 集成文档.pdf

4. 接口调用流程图

快速开始流程图

5. SDK 工程配置

下文都将以 Linux 平台 QT 工程讲解如何配置,如果你的项目是 Python 或 C#,请看 Python 快速集成或 C#快速集成。

新建一个 QT 工程,在工程目录下新建一个 lib 目录,将 libnrc_host.so 库放在 lib 目录下,将 interface.h 文件放在项目工程目录下。

工程示例

右键点击工程名,选择“添加现有文件”,选择刚刚的 interface.h 文件,添加完后再右键点击工程名,选择“添加库”将 libnrc_host.so 库添加到项目中。完成后的 pro 文件如下。 pro文件

可以发现相比初始 pro 文件,多了以下两行代码。

interface.h

LIBS += -L$$PWD/lib -lnrc_host

当然,熟悉 pro 工程,也可以直接在 pro 文件中添加上述两行代码,与右键添加是一样的效果。

6. 快速集成


6.1 连接到控制器

int connect_robot(const char* ip,const char* port,const char* robotName);

连接机器人参数说明:

参数名类型说明是否必填
ipconst char*控制器的 ip 地址,控制器出厂默认 ip 为 192.168.1.13
portconst char*控制器的服务端口号,6001
robotNameconst char*自定义的控制器名称

连接机器人返回值:0:连接成功,非 0:连接失败,请根据具体返回值参考错误码章节查询原因。

我们打开 mainwindow.cpp 文件,在其构造函数中添加如下代码,连接我们的控制器。

const char robot_ip[] = "192.168.1.15";
const char robot_port[] = "6001";
const char robot_name[] = "myRobotNo1";

if(connect_robot(robot_ip,robot_port,robot_name) == 0)
{
std::cout << "连接成功" << std::endl;
} else {
std::cout << "连接失败" << std::endl;
}

注意 connect_robot 函数是非异步的,这意味着程序会阻塞在这一行,直到 connect_robot 返回连接结果。

6.2 控制器的基本状态

6.2.1 连接状态

int get_connection_status(const char* robotName);

连接机器人参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

连接机器人返回值:1:已连接,0:未连接,-2:robotName 不存在。


6.2.2 伺服状态

控制器定义了四种伺服状态,分别是停止状态,就绪状态,报警状态,运行状态。注意,任何关于移动的指令都需要在运行状态下才能使用。

本小节将会涉及到的函数


1.获取伺服状态函数

int get_servo_state(const char* robotName);

函数参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

函数返回值:0:停止状态,1:就绪状态,2:报警状态,3:运行状态,-1:获取状态等待超时,-2:目标控制器不存在。

2.设置伺服状态函数

int set_servo_state(int state,const char* robotName);

函数参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |state|int|0 将伺服设置为停止状态,1 将伺服设置为就绪状态|是| |robotName|const char*|自定义的控制器名称|是|

函数返回值:返回 get_servo_state()的结果。

int set_servo_poweron(const char* robotName);

设置机器人上电函数参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

设置机器人上电函数返回值:返回 get_servo_state()的结果。

3.设置机器人下电函数

int set_servo_poweroff(const char* robotName);

函数参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

函数返回值:返回 get_servo_state()的结果。

4.清除伺服警报函数

int clear_error(const char* robotName);

函数参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

函数返回值:0:清除成功,-1:伺服未在警报状态下,-2,目标控制器不存在。

下面这段代码展示了如何让机器人在示教模式上电

//robot_name为连接机器人时的参数
clear_error(robot_name);
int state = get_servo_state(robot_name);
if(state == 0)
{
std::cout << "伺服状态为(停止状态),将先执行就绪操作后上电." << std::endl;
set_servo_state(1,robot_name);
set_servo_poweron(robot_name);
} else if(state == 1)
{
std::cout << "伺服状态为(就绪状态),将执行上电操作." << std::endl;
set_servo_poweron(robot_name);
}else if(state == 2) {
std::cout << "伺服处于报警状态,请调用清错函数clear_error." << std::endl;
} else if(state == 3) {
std::cout << "伺服已经处于运行状态." << std::endl;
}

6.2.3 简单的运动

上小节我们展示了如何将机器人上电,接下来,我们将讲解如何让机器人进行运动。

本小节将会涉及到的函数

1.关节插补函数

int robot_movej(double *pos,int vel,int coord,int acc, int dec,const char* robotName);

参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |pos|double|点位数组 长度 7|是| |vel|int|关节插补速度 [1,100], 单位:%|是| |coord|int|坐标系 0:关节,1:直角,2:工具,3:用户|是| |acc|int|加速度 [1,100]|是| |dec|int|减速度 [1,100]|是| |robotName|const char|自定义的控制器名称|是|

函数返回值:0:调用成功,-2:目标控制器不存在。

2.直线插补函数

int robot_movel(double *pos,int vel,int coord,int acc, int dec,const char* robotName);

参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |pos|double|点位数组 长度 7|是| |vel|int|直线插补速度 [1,笛卡尔参数设置的最大速度], 单位:mm/s|是| |coord|int|坐标系 0:关节,1:直角,2:工具,3:用户|是| |acc|int|加速度 [1,100]|是| |dec|int|减速度 [1,100]|是| |robotName|const char|自定义的控制器名称|是|

函数返回值:0:调用成功,-2:目标控制器不存在。

3.获取机器人运行状态函数

int get_robot_running_state(const char* robotName);

参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |robotName|const char*|自定义的控制器名称|是|

函数返回值:0:停止,1:暂停,2:运行,-1,等待控制器回复超时,-2:目标控制器不存在。

4.获取机器人当前位置函数

int get_current_position(double* pos, int coord,const char* robotName);

参数说明: |参数名|类型|说明|是否必填| |:--:|:--:|:--|:--:| |pos|double|返回值点位数组 长度 7|是| |coord|int|要查询坐标的坐标系|是| |robotName|const char|自定义的控制器名称|是|

函数返回值:-1,等待控制器回复超时,-2:目标控制器不存在。

下面这段代码展示了在 6.2.2 小节上电的基础上,如何让机器人在示教模式下运动

//robot_name为连接机器人时的参数
double pos[7] = {0};
//将机器人移动至0点
robot_movej(pos, 50 /*vel*/, 0 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}
std::cout << "当前关节点位: " << std::endl;
get_current_position(pos,0,robot_name);
for(int i = 0;i < 7;i++)
{
std::cout << i+1 << "轴角度: " <<pos[i] << "; " ;
}
std::cout << std::endl;
//在当前关节角度下,将1轴减50度
pos[0] -= 50;
robot_movej(pos, 50 /*vel*/, 0 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
//等待robot_movej执行完毕
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}
std::cout << "运动完成后关节点位: " << std::endl;
get_current_position(pos,0,robot_name);
for(int i = 0;i < 7;i++)
{
std::cout << i+1 << "轴角度: " <<pos[i] << "; ";
}
std::cout << std::endl;

连接成功
伺服已经处于运行状态.
当前关节点位:
1轴角度: 98.1972; 2轴角度: 0; 3轴角度: 0; 4轴角度: 0; 5轴角度: 0; 6轴角度: 0; 7轴角度: 0;
运动完成后关节点位:
1轴角度: 48.197; 2轴角度: 0; 3轴角度: 0; 4轴角度: 0; 5轴角度: 0; 6轴角度: 0; 7轴角度: 0;

如果我们想要进行在直角坐标下的关节插补又该如何做呢?

我们只需要把 pos 的坐标值改成直角坐标就可以了 依旧是同样的代码,只是我们在获取坐标的时候获取的是直角坐标

//robot_name为连接机器人时的参数
double pos[7] = {0};
//将机器人移动至0点
robot_movej(pos, 50 /*vel*/, 0 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}
std::cout << "当前直角点位: " << std::endl;
get_current_position(pos,1,robot_name);
std::cout << "[x]:" << pos[0] << "; [Y]:" << pos[1] << "; [Z]:" <<pos[2] << "[A]:" << pos[3] << "; [B]:" << pos[4] << "; [C]:" <<pos[5] << std::endl;
//X方向在当前基础上减20
pos[0] -= 20;
robot_movej(pos, 50 /*vel*/, 1 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}

std::cout << "运动完成后直角点位: " << std::endl;
get_current_position(pos,1,robot_name);
std::cout << "[x]:" << pos[0] << "; [Y]:" << pos[1] << "; [Z]:" <<pos[2] << "[A]:" << pos[3] << "; [B]:" << pos[4] << "; [C]:" <<pos[5] << std::endl;

连接成功
伺服已经处于运行状态.
当前直角点位:
[x]:127.285; [Y]:-151.678; [Z]:198[A]:3.14156; [B]:3.08149e-05; [C]:0.872667
运动完成后直角点位:
[x]:107.287; [Y]:-151.678; [Z]:198.002[A]:3.14153; [B]:4.15234e-05; [C]:0.872667

上面的 movej 函数能够让我们运动到目标位置,但在空间中运动的轨迹并不是一条直线的,如何在空间中走直线运动呢?我们可以使用 robot_movel 函数。

//robot_name为连接机器人时的参数
double pos[7] = {0};
//将机器人移动至0点
robot_movej(pos, 50 /*vel*/, 0 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}
std::cout << "当前直角点位: " << std::endl;
get_current_position(pos,1,robot_name);
std::cout << "[x]:" << pos[0] << "; [Y]:" << pos[1] << "; [Z]:" <<pos[2]
<< "[A]:" << pos[3] << "; [B]:" << pos[4] << "; [C]:" <<pos[5] << std::endl;
//X方向在当前基础上减20
pos[0] -= 20;
robot_movel(pos, 800 /*vel*/, 1 /*coord*/, 80 /*acc*/, 80/*dec*/, robot_name);
QThread::msleep(100);
while(get_robot_running_state(robot_name) == 2)
{
QThread::msleep(100);
}
std::cout << "运动完成后直角点位: " << std::endl;
get_current_position(pos,1,robot_name);
std::cout << "[x]:" << pos[0] << "; [Y]:" << pos[1] << "; [Z]:" <<pos[2]
<< "[A]:" << pos[3] << "; [B]:" << pos[4] << "; [C]:" <<pos[5] << std::endl;

更多接口介绍请看 api 页面