TCPServerResource TCP服务器资源

TCPServerResource 算子属于资源类线程算子,用于在 RVS 的分线程中启动一个 TCP server 服务器。

客户端可以通过该算子对 RVS 中的数据进行读写。通信数据是以字符串形式表达的 json 格式。

  1. 客户端发送更改算子参数的消息。发送字符串格式为:

    {"SetPara":[
    
    {"node_name":"算子名称","para_name":"要更改的参数名称","para_value":"要更改的值"},
    
    ...
    
    ]}+delimiter(消息结束符)
    

    如果发送消息的格式不合法,则本算子会回复:

    ParseJson;0
    

    如果参数设置失败,则本算子会回复 :

    SetPara;0
    

    如果参数设置成功,则本算子会回复:

     SetPara;1
    
  2. 客户端想读取算子的输出端口的值。发送字符串格式为:

    {"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 模式。

Resource_TCPServerResource_1

步骤4:运行及运行结果

  1. 打开 RVS 的运行按钮,TCPServerResource 算子会自动触发,并变为蓝色,日志栏会同时打印算子运行说明如下图所示,表示 TCP 的服务端已经建立完毕。

    Communication_TCPServerResource_result1

  2. 重新打开一个终端,输入命令:

     echo "{\"SetPara\":[{\"node_name\":\"Emit\",\"para_name\":\"type\",\"para_value\":\"String\"},{\"node_name\":\"Emit_1\",\"para_name\":\"type\",\"para_value\":\"Pose\"}]}#" | nc localhost 2014
    

    并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。

    Resource_TCPServerResource_3

    注意:windows版本使用通讯工具发送:{"SetPara":[{"node_name":"Emit","para_name":"type","para_value":"String"},{"node_name":"Emit_1","para_name":"type","para_value":"Pose"}]}#。

  3. 但是 RVS 执行结束后,对应的两个 Emit 算子属性以及端口都没有进行更改如下图所示。

    Resource_TCPServerResource_5

  4. 此时需要我们手动分别单击一下两个 Emit 算子,然后发现其属性栏已经更新,更新后如下图所示。

    Resource_TCPServerResource_4

  5. 然而两个算子的输入输出端口没有更新,则我们需要单击算子图左侧的更新按钮(下图左侧红色标注的按钮)。更新后如下图所示。

    Resource_TCPServerResource_6

  6. 在终端中,继续输入命令

    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_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\"}]}#" | nc localhost 2014 
    

    并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。

    Resource_TCPServerResource_7

    注意: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"}]}#。

  7. 然而两个算子的对应属性值不会立刻更新,需要我们手动各自单击一下两个 Emit 算子。更改后的属性显示如下。

    Resource_TCPServerResource_8

  8. 在终端中,继续输入

    echo "{\"GetOutput\":[{\"node_name\":\"Emit\",\"index\":0,\"type\":\"String\"},{\"node_name\":\"Emit_1\",\"index\":0,\"type\":\"Pose\"}]}#" | nc localhost 2014
    

    命令并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。

    image-20230619160434454

    注意:windows版本使用通讯工具发送:{"GetOutput":[{"node_name":"Emit","index":0,"type":"String"},{"node_name":"Emit_1","index":0,"type":"Pose"}]}#。

  9. 发现得到的回复值并非刚才设置的数值而是这些参数的默认值 (string 默认为空字符,pose默认为全零)。这是因为两个Emit算子尚未被触发,其数据输出端口尚未更新。此时单击 RVS 的 stop,将一个 Trigger 算子拖入到算子图中,连接触发两个 Emit 算子,然后重新单击 RVS 的运行,并触发执行 Trigger。此时重新发送上述命令,可以得到回复如下:

    Resource_TCPServerResource_9

  10. 之后单击 RVS 的 stop,将一个 Concatenate 算子拖入到算子图中,更改其类型为 pose ,更改其 输入数量 为 2 ,更改 列表输入数量 为 0,并按照下图连接算子。

    Resource_TCPServerResource_10

  11. 重新单击 RVS 的运行,并触发执行 Trigger,此时 Concatenate 算子的输出端口会获得实际数值。

  12. 然后在终端中,继续输入命令

    echo "{\"GetOutput\":[{\"node_name\":\"Concatenate\",\"index\":0,\"type\":\"Pose\"}]}#" | nc localhost 2014 
    

    并单击回车键,运行结束后,我们会在这个终端窗口看到回复字符串如下图所示。

    注意,对于List的回复,最后会附加List中含有的目标总数,如下图的 2 。

Resource_TCPServerResource_11

注意:windows版本使用通讯工具发送:{"GetOutput":[{"node_name":"Concatenate","index":0,"type":"Pose"}]}#。