TCPServerResource TCP服远程控制服务资源
TCPServerResource 算子属于资源类线程算子,用于在 RVS 的分线程中启动一个 TCP server 服务器。
客户端可以通过该算子对 RVS 中的数据进行读写。通信数据是以字符串形式表达的 json 格式。
-
客户端发送更改算子参数的消息。发送字符串格式为:
{"SetPara":[ {"node_name":"算子名称","para_name":"要更改的参数名称","para_value":"要更改的值"}, ... ]}+delimiter(消息结束符)
如果发送消息的格式不合法,则本算子会回复:
ParseJson;0
如果参数设置失败,则本算子会回复 :
SetPara;0
如果参数设置成功,则本算子会回复:
SetPara;1
-
客户端想读取算子的输出端口的值。发送字符串格式为:
{"GetOutput":[ {"node_name":"算子名称","index":int_value,"type":"算子类型"}, ... ]}+delimiter(消息结束符)
注意
1. 上文中的 index 表示某个算子的所有数据输出端口从上往下(从0开始)排列的端口序号。排序时不包含 finished 和 failed 等控制端口。
2. 当前的 GetOutput 仅支持 String 和 Pose 两种算子类型,也可以支持 StringList 以及 PoseList ,但是这里的 type 统一填写成 String 以及 Pose 。
3. 同时获取多个输出端口的回复值时,回复内容通过分号隔开。
如果发送消息的格式不合法,则本算子会回复:
ParseJson;0
如果数据读取失败(找不到对应算子,或找不到算子对应端口,或算子对应端口属性不匹配),则本算子会回复:
GetOutput;0
如果参数设置成功,则本算子会回复对应的读取内容。
算子参数
-
自动启动/auto_start
:自动运行。如果勾选该选项,则 RVS 第一次运行后,会自动触发该算子执行。算子运行后,开始创建 TCP 服务端,创建成功后监听服务端口并等待客户端访问。 -
启动/start
:勾选后,开始触发算子执行。算子运行后,开始创建 TCP 服务端,创建成功后监听服务端口并等待客户端访问。 -
停止/stop
:勾选后,开始停止 TCP 服务端的监听。 -
重置reset
:在该资源算子已经运行后,如果重新更改了端口
、连接数量
、服务器模式
、分隔符
4个参数中的任意一个之后,若需要生效,都必须勾选重置
选项进行资源重置,然后重新勾选启动
运行。 -
端口/port
:创建 TCP server 服务器所使用的本机服务端口。说明:实际运行时,如果提示 TCP 服务端创建失败,往往是所选取的端口已经被其他服务所占用,更换端口即可。如果在同一个 RVS 软件中,创建多个TCP 服务端算子,彼此的端口也要互斥。
-
连接数量/connections
:可同时支持的最大客户端连接数量。 -
服务器模式/server_mode
:运行模式。-
Once:表示完成一次 TCP 对话以后自动断开同客户端的链接(比如客户端首先同该算子建立了 TCP 连接,然后第一次发送了消息请求之后,继续发送就会报错)。
-
Continous:表示客户端建立连接后可以无限次数的对话。
-
-
分隔符/delimiter
:消息结束符,包含 RT 换行符、“;”、“#”、“$”。当选择了其中某一种时,另外三种就会被视作普通字符随意使用 。服务端在接收客户端发送的消息时,会捕获第一个消息结束符之前的所有消息。说明:由于不同的通信软件、电脑系统软件、机器人操作系统软件对回车换行的定义不一致,容易导致信息发送或者接收失败,所以一般不建议选择 RT 作为消息结束符。
功能演示
下面分别针对读写 2 类通讯信号,进行通讯演示。
在选用演示所用的 TCP 客户端时,由于 RVS 自带的 CommonTCPClient 算子在使用时要求服务端返回的信息必须以四类固定字符结尾,而 TCPServerResource 算子在作为 TCP 的服务端时,返回给 TCP Client 的信息是固定的并且没有额外添加上述四类固定结尾字符,所以这里不再选用 CommonTCPClient 算子作为客户端。
说明:这里的演示案例是基于 ubuntu 系统给出的,使用了 "echo + nc " 的指令方式实现 TCP 客户端的功能;如果是在 Windows 版本,建议使用通讯助手等工具。
步骤1:算子准备
添加 Trigger 、Emit (2个)、Concatenate 、TCPServerResource 算子至算子图。
步骤2:设置算子参数
设置 TCPServerResource 算子参数:
-
自动启动 → 是
-
分隔符 → #
-
服务器模式 → Once
步骤3:连接算子
打开 RVS 软件界面,在算子图拖入 TCPServerResource 算子以及拖入两个 Emit 算子如下图所示。TCPServerResource 选用了 “echo + nc” 的指令方式,所以这里每发送-接收一次消息后都要断开连接,所以选择了 Once 模式。
步骤4:运行及运行结果
-
打开 RVS 的运行按钮,TCPServerResource 算子会自动触发,并变为蓝色,日志栏会同时打印算子运行说明如下图所示,表示 TCP 的服务端已经建立完毕。
-
重新打开一个终端,输入命令:
echo "{\"SetPara\":[{\"node_name\":\"Emit\",\"para_name\":\"type\",\"para_value\":\"String\"},{\"node_name\":\"Emit_1\",\"para_name\":\"type\",\"para_value\":\"Pose\"}]}#" | nc localhost 2014
并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
注意:windows版本使用通讯工具发送:{"SetPara":[{"node_name":"Emit","para_name":"type","para_value":"String"},{"node_name":"Emit_1","para_name":"type","para_value":"Pose"}]}#。
-
但是 RVS 执行结束后,对应的两个 Emit 算子属性以及端口都没有进行更改如下图所示。
-
此时需要我们手动分别单击一下两个 Emit 算子,然后发现其属性栏已经更新,更新后如下图所示。
Emit
Emit_1
-
然而两个算子的输入输出端口没有更新,则我们需要单击算子图左侧的更新按钮(下图左侧红色标注的按钮)。更新后如下图所示。
Emit
Emit_1
-
在终端中,继续输入命令
echo "{\"SetPara\":[{\"node_name\":\"Emit\",\"para_name\":\"string\",\"para_value\":\"demo_test_string\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_x\",\"para_value\":\"0.1\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_y\",\"para_value\":\"0.2\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_z\",\"para_value\":\"0.3\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_rx\",\"para_value\":\"1.57\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_ry\",\"para_value\":\"-1.57\"},{\"node_name\":\"Emit_1\",\"para_name\":\"pose_rz\",\"para_value\":\"3.14\"}]}#" | nc localhost 2014
并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
注意:windows版本使用通讯工具发送:{"SetPara":[{"node_name":"Emit","para_name":"string","para_value":"demo_test_string"},{"node_name":"Emit_1","para_name":"pose_x","para_value":"0.1"},{"node_name":"Emit_1","para_name":"pose_y","para_value":"0.2"},{"node_name":"Emit_1","para_name":"pose_z","para_value":"0.3"},{"node_name":"Emit_1","para_name":"pose_roll","para_value":"1.57"},{"node_name":"Emit_1","para_name":"pose_pitch","para_value":"-1.57"},{"node_name":"Emit_1","para_name":"pose_yaw","para_value":"3.14"}]}#。
-
然而两个算子的对应属性值不会立刻更新,需要我们手动各自单击一下两个 Emit 算子。更改后的属性显示如下。
Emit
Emit_1
-
在终端中,继续输入
echo "{\"GetOutput\":[{\"node_name\":\"Emit\",\"index\":0,\"type\":\"String\"},{\"node_name\":\"Emit_1\",\"index\":0,\"type\":\"Pose\"}]}#" | nc localhost 2014
命令并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
注意:windows版本使用通讯工具发送:{"GetOutput":[{"node_name":"Emit","index":0,"type":"String"},{"node_name":"Emit_1","index":0,"type":"Pose"}]}#。
-
发现得到的回复值并非刚才设置的数值而是这些参数的默认值 (string 默认为空字符,pose默认为全零)。这是因为两个Emit算子尚未被触发,其数据输出端口尚未更新。此时单击 RVS 的 stop,将一个 Trigger 算子拖入到算子图中,连接触发两个 Emit 算子,然后重新单击 RVS 的运行,并触发执行 Trigger。此时重新发送上述命令,可以得到回复如下:
-
之后单击 RVS 的 stop,将一个 Concatenate 算子拖入到算子图中,更改其
类型
为 pose ,更改其输入数量
为 2 ,更改列表输入数量
为 0,并按照下图连接算子。 -
重新单击 RVS 的运行,并触发执行 Trigger,此时 Concatenate 算子的输出端口会获得实际数值。
-
然后在终端中,继续输入命令
echo "{\"GetOutput\":[{\"node_name\":\"Concatenate\",\"index\":0,\"type\":\"Pose\"}]}#" | nc localhost 2014
并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。
注意,对于List的回复,最后会附加List中含有的目标总数,如下图的 2 。
注意:windows版本使用通讯工具发送:{"GetOutput":[{"node_name":"Concatenate","index":0,"type":"Pose"}]}#。