HandEyeTCPServer 手眼标定TCP服务器
HandEyeTCPServer 算子属于线程类算子,用于在 RVS 的分线程中启动一个 TCP server 服务器。
该算子主要应用于手眼协作过程(当前用的最多的是拆垛场景)中, RVS 同机械手(或其他工控机程序)的通信。该服务器仅能接收固定的 8 类字符串信息并对应的回复固定字符串。
8 类字符串分别以 8 个命令作为起始值,分别是 ROBOT_TCP 、ROBOT_JOINTS 、CAPTURE 、CAPTURE_MESSAGE 、GET_JOINT 、GET_POSE 、GET_POSES 、GET_POSES_NEXT 。
说明:代码块中命令参数设置:command_delimiter →space、delimiter → RT,均为默认值。请根据实际场景进行调整。
其中,如果客户希望获得多个目标 pose 姿态列表,可以修改 HandEyeTCPServer 的 number_port
属性数量。客户端仍然按照下述
GET_POSES
的方式发送消息,但是此时回复的消息起始位就不再是 1 ,而是 poselist 的数量,后面跟每一个 poselist 中包含的 pose 数量。
GET_POSES \n
-
客户端发送以命令字符
ROBOT_TCP
开始的消息,要求在该ROBOT_TCP
命令字符后紧跟command_delimiter+'x y z rx ry rz'+delimiter
。接收到该信息后,该算子(即服务端)会将命令字符后续的x y z rx ry rz
字符内容转换为 6 个 float 数值,进而赋值给一个 pose 。如果上述字符串消息可以合法转换为 6 个 float 则会触发执行该算子右下侧的 tcp 数据端口,并通过算子右下侧的 tcp 端口输出所得的 pose,如果字符串消息不合法,则不进行任何后续响应。
我们实际使用时,需要将该算子右下侧 ROBOT_TCP 端口后续的触发结束信号返还连接到该算子的左侧 ROBOT_TCP 端口,因为只有成功触发该端口才会执行 TCP 服务端的消息回复。
对于命令字符
ROBOT_TCP”
开始的消息访问,最终统一回复ROBOT_TCP
。客户端发送:
ROBOT_TCP x y z rx ry rz \n
算子右侧 tcp 端口输出:
x y z rx ry rz
服务端回复:
ROBOT_TCP
-
客户端发送以命令字符
ROBOT_JOINTS
开始的消息,要求在该ROBOT_JOINTS
命令字符后紧跟command_delimiter+'J1 J2 J3 J4 J5 J6'+delimiter
。接收到该信息后,服务端会将命令字符后续的
J1 J2 J3 J4 J5 J6
字符内容转换为 6 个 float 数值,进而赋值给一个 JointArray 。如果上述字符串消息可以合法转换为 6 个 float 则会触发执行该算子右下侧的 joints 数据端口,并通过算子右下侧的 joints 端口输出所得的 JointArray ,如果字符串消息不合法,则不进行任何后续响应。
我们实际使用时,需要将该算子右下侧 ROBOT_JOINTS 端口后续的触发结束信号返还连接到该算子的左侧 ROBOT_JOINTS 端口,因为只有成功触发该端口才会执行 TCP 服务端的消息回复。
对于命令字符
ROBOT_JOINTS
开始的消息访问,最终统一回复ROBOT_JOINTS
。客户端发送:
ROBOT_JOINTS J1 J2 J3 J4 J5 J6 \n
算子右侧 joints 端口输出:
J1 J2 J3 J4 J5 J6
服务端回复:
ROBOT_JOINTS
-
客户端发送以命令字符
CAPTURE
开始的消息,要求在该CAPTURE
命令字符后紧跟command_delimiter+ 任意内容 +delimiter
。接收到该信息后,该算子会自动触发右下侧的 CAPTURE 端口,进而触发其他后续算子进行运算。
我们实际使用时,需要将该算子右下侧 CAPTURE 端口后续的触发结束信号返还连接到该算子的左侧 CAPTURE 端口,因为只有成功触发该端口才会执行 TCP 服务端的消息回复。
对于命令字符
CAPTURE
开始的消息访问,服务端对命令字符后续的其他字符内容不做任何处理,并最终统一回复 “CAPTURE” 字符串消息。客户端发送:
CAPTURE \n 或者 CAPTURE any other message\n
服务端回复:
CAPTURE
-
如果需要在
CAPTURE
命令字符消息中发送一些其他字符串给 RVS ,则需要使用CAPTURE_MESSAGE
,并要求在该CAPTURE_MESSAGE
命令字符后紧跟command_delimiter+ 其他内容 +delimiter
。使用原理同上述第 3 条 ,不同的是,这些从客户端发来的
其他内容
的字符串会通过算子右下侧的 capture_str 端口传递到 RVS 。假设项目现场有两台相机一左一右。
通过给RVS 发送以下命令表示拍摄左侧相机:
CAPTURE_MESSAGE 0 \n
通过给RVS 发送以下命令表示拍摄右侧相机:
CAPTURE_MESSAGE 1 \n
-
客户端发送以命令字符
GET_JOINT
开始的消息,要求在该GET_JOINT
命令字符后紧跟command_delimiter+ 其他内容 +delimiter
。接收到该信息后,该算子会自动触发右下侧的 GET_JOINT 端口,进而触发其他后续算子进行运算。我们实际使用时,需要将该算子右下侧 GET_JOINT 端口后续的触发结束信号返还连接到该算子的左侧 GET_JOINT 端口,因为只有成功触发该端口才会执行 TCP 服务端的消息回复。
对于命令字符
GET_JOINT
开始的消息访问,服务端对命令字符后续的其他字符内容不做任何处理。当左侧 GET_JOINT 端口被触发执行消息回复时,如果算子左侧的 all_finished 端口已被触发,则会回复000000000 000000000 000000000 000000000 000000000 000000000 2
字符串信息,如果算子左侧的 detect_error 端口已被触发,则会回复000000000 000000000 000000000 000000000 000000000 000000000 3
字符串信息,如果算子左侧的 all_finished 端口和 detect_error 端口均未被触发,则算子内部会检查算子左侧的 joint 端口是否被连接,如果该 joint 端口有连接并且数值有效,则会回复J1 J2 J3 J4 J5 J6 1
给客户端。注意
末尾的1,所有回复字符串的末尾均是标志位。
1 表示获得正常数值。
2 表示虽然回复结果无效但是成功结束。
3 表示回复结果无效且失败。
另外,字符串前面的六位数值都保留 9 位有效数字,所以为了对齐字符串长度,所有无效数值也都用九个 0 表示。单位:弧度制。
如果 joint 端口没有连接或者数值无效,则会回复 `000000000 000000000 000000000 000000000 000000000 000000000 3` 给客户端。以command_delimiter 参数设置为逗号,delimiter 参数设置为分号为例,左侧 joint 端口输入 JointArrayJ(0 0 0 3.14159 -1.5709 0) ,则当客户端发送 `GET_JOINT,;` 时,则最终服务端会回复 `+0.000000 +0.000000 +0.000000 +3.141590 -1.570900 +0.000000 1` ,算上中间的空格,字符串总长度是 61 位。
客户端发送:
GET_JOINT 其他内容 \n
-
客户端发送以命令字符
GET_POSE
开始的消息,原理同上述第 5 点GET_JOINT
的说明相同。客户端发送:
GET_POSE command_delimiter 其他内容 delimiter
-
客户端发送以命令字符
GET_POSES
开始的消息,要求在该GET_POSES
命令字符后紧跟command_delimiter+ 其他内容 +delimiter
。接收到该信息后,该算子会自动触发右下侧的 GET_POSES 端口,进而触发其他后续算子进行运算。我们实际使用时,需要将该算子右下侧 GET_POSES 端口后续的触发结束信号返还连接到该算子的左侧 GET_POSES 端口,因为只有成功触发该端口才会执行 TCP 服务端的消息回复。对于命令字符
GET_POSES
开始的消息访问,服务端对命令字符后续的其他字符内容不做任何处理。GET_POSES 其他内容 \n
该命令字符的作用:通过 RVS 软件的服务端将一个乃至多个 PoseList 发送给客户端。具体的 PoseList 的数量可以根据算子属性
number_port
进行设置,该属性默认是 1,对应算子左侧的 poses_1 端口。一旦更新该属性比如更改为 3 ,则算子左侧会新增 poses_2 、poses_3 端口。服务端最终回复的信息格式是:
PoseList 的总个数 每个 PoseList 的 pose 个数 所有 pose 的实际数值 标志位
最后的标志位包含 0、1、2、3 四种情形。
-
0:数据正常且发送完毕
-
1:数据正常但尚未发送完
-
2:数据无效但正常运行
-
3:数据无效且运行异常
当总共有 3 组 PoseList (各自含有2、1、2个 pose )需要发送时,最后回复给客户端的字符串为:
3 2 1 2 poselist1_pose1_x poselist1_pose1_y poselist1_pose1_z poselist1_pose1_rotated_x poselist1_pose1_rotated_y poselist1_pose1_rotated_z ...... poselist3_pose2_x poselist3_pose2_y poselist3_pose2_z poselist3_pose2_rotated_x poselist3_pose2_rotated_y poselist3_pose2_rotated_z 0
但是由于传送的数据量比较大,所以算子设置了每次回传信息的最大字节长度,对应算子属性 receive_byte_length 。
-
当上述字符串字节 (不包含末尾的空格和 0 )总长度小于等于 receive_byte_length-2 时,即直接回复上述字符串。
-
若大于receive_byte_length-2 ,则会将上述字符串拆分,仅截取字符串前面长度为 receive_byte_length-2 的一段,然后在该截取片段的末尾加上空格和 1 回复给客户端。客户端接收到末尾为 1 的字符串后,需要立刻继续向本算子发送 GET_POSES_NEXT 的请求,此时服务端会将上述字符串剩余的部分继续截取一段长度为 receive_byte_length-2 的字符串并补充空格和 1 ,继续回复给客户端,循环该过程直到发送完成为止,最后一次发送的字符串长度不一定是 receive_byte_length ,但是其末尾一定是补充的空格和 0 。
根据上述规则,当左侧 GET_POSES 端口被触发执行消息回复时,如果算子左侧的 all_finished 端口已被触发,则会回复
0 2
字符串信息,如果算子左侧的 detect_error 端口已被触发,则会回复0 3
字符串信息,如果算子左侧的 all_finished 端口和 detect_error 端口均未被触发,则算子内部会检查算子左侧从poses_1 端口到 pose_n 端口中是否有连接以及有效数据,如果有至少一个端口有有效数据,则会按照上述过程回复客户端,如果所有端口都没有有效数值,则会回复0 3
给客户端。 -
-
客户端发送以命令字符
GET_POSES_NEXT
开始的消息,要求在该GET_POSES_NEXT
命令字符后紧跟command_delimiter+ 其他内容 +delimiter
。这里的其他内容
为无效数值。该 GET_POSES_NEXT 命令字符是 GET_POSES 命令字符的补充,直接单独发送该命令字符串没有意义,使用方法详见上述 GET_POSES 的使用介绍。GET_POSES_NEXT 其他内容 \n
算子参数
-
端口/port
:创建TCP server服务器所使用的本机服务端口。说明:实际运行时,如果提示 TCP 服务端创建失败,往往是所选取的端口已经被其他服务所占用,更换端口即可。如果在同一个 RVS 软件中,创建多个 TCP 服务端算子,彼此的 port 也要互斥。
-
连接数量/connections
:可支持同时连接的客户端数量。 -
服务器模式/server_mode
:运行模式。-
Once:表示完成一次 TCP 对话以后自动断开同客户端的连接(比如客户端首先同该算子建立了 TCP 连接,然后第一次发送了 ROBOT_TCP 命令的字符串之后,继续发送 ROBOT_JOINTS 命令的字符串,此时就会报错)。
-
Continous: 表示客户端建立链接后可以无限次数的对话。
-
-
分割符/delimiter
:消息结束符。包含 RT 换行符、“;”、“#”、“$”。当选择了其中某一种时,另外三种就会被视作普通字符随意使用 。服务端在接收客户端发送的消息时,会捕获第一个消息结束符之前的所有消息。注意:由于不同的通信软件、电脑系统软件、机器人操作系统软件对回车换行的定义不一致,一般不建议选择RT作为消息结束符。
-
命令分割符/command_delimiter
:命令结束符。当选择了其中某一种时,另外一种就会被视作普通字符随意使用。服务端在接收客户端发送的消息时,会将第一个命令结束符之前的所有消息视为命令字符,之后的消息视为内容信息。如果命令字符不是上述功能总结部分的 8个命令中的任意一个,则是无效命令,不做任何后续处理与响应。-
Space:空格。
-
, :逗号。
-
-
回复结束符/arc_eof
:回传值结束符。当输入该值时,在回传值结尾添加结束符。默认为空。 -
机器人TCP/tcp
:设置通过 ROBOT_TCP 命令消息接收到的 pose 可视化属性。-
打开 pose 可视化。
-
关闭 pose 可视化。
-
设置坐标的尺寸大小。取值范围:[0.001,10] 。默认值:0.1 。
-
-
拍摄信息/capture_str
:设置曝光属性。打开后则可以将 capture_str 输出端口的内容绑定到交互面板上的文本框并输出显示。-
打开曝光。
-
关闭曝光。
-
-
输入数量/number_port
: 仅供发送 GET_POSES 命令字符串时使用,详见上述功能总结部分的第7条。 -
接受字节长度/receive_byte_length
:仅供发送 GET_POSES 命令字符串时使用,详见上述功能总结部分的第7条。默认值:1024。单位:byte。取值范围:[1,+∞]。
注意:在算子运行后,重新更改了 port 、connections 、server_mode 、delimiter 、command_delimiter、arc_eof 6个属性中的任意一个之后,如果需要生效,都必须重启或者重置 RVS 。
控制信号输入输出
输入:
-
start
:-
触发 start 信号端口运行算子,开始创建 TCP 服务端,创建成功后监听服务端口并等待客户端访问。
说明:本算子仅需要初始化运行一次即可。
-
-
stop
:-
触发 stop 信号端口后,开始停止 TCP 服务端的监听。
-
-
reset
:-
该功能保留。
-
输出:
-
finished
:-
该功能保留。
-
-
failed
:-
算子运行失败后触发该端口。
-
-
started
:-
算子成功建立TCP服务端后触发该端口。
-
-
processing
:-
该功能保留。
-
-
stopped
:-
算子成功停止TCP服务端的监听后触发该端口。
-
-
reset
:-
该功能保留。
-
功能演示
下面分别针对 8 类命令,进行通讯演示。
在选用演示所用的 TCP 客户端时,由于 RVS 自带的 CommonTCPClient 算子在使用时要求服务端返回的信息必须以四类固定字符结尾,而 HandEyeTCPServer 算子在作为 TCP 的服务端时,返回给 TCP Client 的信息是固定的并且没有额外添加上述四类固定结尾字符,所以这里不再选用 CommonTCPClient 算子作为客户端。
说明:这里的演示案例是基于ubuntu系统给出的,使用了"echo + nc "的指令方式实现TCP客户端的功能;如果是在Windows版本,建议使用通讯助手等工具。
步骤1:算子准备
右击创建新 Group ,添加 Trigger、Emit、Concatenate、HandEyeTCPServer 算子至 Group 算子图。
步骤2:设置算子参数
-
设置 Trigger 算子参数:
-
类型 → InitTrigger
-
-
设置 HandEyeTCPServer 算子参数:
-
分隔符 → ;
-
命令分隔符 → ,
-
回复结束符 → end
-
-
设置 Concatenate 算子参数:
-
类型→ pose
-
输入数量 → 3
-
-
设置 Emit 算子参数:
-
算子名称 → Message
-
类型 → String
-
步骤3:连接算子
打开RVS软件界面,在算子图拖入下图所述算子并连接。由于选用了“echo + nc”的指令方式,所以这里每发送-接收一次消息后都要断开连接,所以选择了Once模式。
步骤3:运行与结果
-
打开 RVS 的运行按钮,HandEyeTCPServer 算子会被 Trigger 算子自动触发,并变为蓝色,日志栏会同时打印算子运行说明如下图所示,表示TCP的服务端已经建立完毕。
-
重新打开一个终端,输入命令 echo “ROBOT_TCP,0.1 0.2 0.1 3.14159 1.5709 1;” | nc localhost 2013 并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
-
同时 RVS 的运行日志如下。
-
-
在终端中,继续输入命令echo “ROBOT_JOINTS,0 0 0 3.14159 1.5709 0;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
-
同时RVS的运行日志如下。
-
-
在终端中,继续输入命令echo “CAPTURE,;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
-
同时RVS的运行日志如下。
-
-
在终端中,继续输入命令echo “CAPTURE_MESSAGE,0;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
-
同时RVS的运行日志如下。
-
-
在终端中,继续输入命令echo “GET_JOINT,;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
-
同时RVS的运行日志如下
-
-
在终端中,继续输入命令echo “GET_POSE,;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示,同时RVS的运行日志如下。
-
同时RVS的运行日志如下
-
-
在终端中,继续输入命令echo “GET_POSES,;” | nc localhost 2013并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示
-
同时RVS的运行日志如下
-