3. RTDE数据接口总览
RTDE(Real-Time Data Exchange)是UR控制器对外开放的一条双向实时通道。它不像Dashboard那样以“命令—应答”为主,也不像Modbus那样只暴露有限的寄存器视图,而是把控制器内部的一组“可订阅变量”和“可写入变量”组织成两个方向的数据流:控制器按协商频率把实时数据推给上位机,上位机则把控制量写回控制器。理解RTDE,关键是先分清它到底提供了哪几类接口,以及这些接口各自解决什么问题。
一、四类接口对象:输入寄存器、输出寄存器、实时数据包与配方
RTDE在概念上把数据分成四个可配置的集合,它们通过一个JSON格式的“配方(Recipe)”文件统一声明:
- 输入寄存器(Input Registers):方向是“上位机 → 控制器”。上位机写入的变量放在这里,例如
input_double_register_0、input_bit_register_0、input_int_register_0。它们本身不会直接改变机器人运动,必须由UR程序(URScript或Polyscope程序)读取后再决定如何使用。 - 输出寄存器(Output Registers):方向是“控制器 → 上位机”。由UR程序写入,例如
output_double_register_0、output_bit_register_0,上位机通过RTDE读取。它常用于把程序内部状态、计算结果或自定义标志位回传给上位机。 - 实时数据包(Real-Time Data):控制器周期性推送的一组“只读”变量,例如关节位置
actual_q、关节速度actual_qd、TCP位姿actual_TCP_pose、TCP速度actual_TCP_speed、数字输入actual_digital_input_bits、机器人模式robot_mode、安全状态safety_status等。这些变量由控制器直接产生,不需要UR程序干预。 - 配方配置(Recipe):一个JSON文件,声明本次RTDE连接要订阅哪些实时数据字段、要使用哪些输入/输出寄存器。控制器根据配方决定“推什么、收什么”,上位机根据配方决定“怎么解析”。
这四类对象的关系可以用下面的结构图表示。图中左侧是上位机侧,右侧是UR控制器侧,中间是RTDE连接;箭头方向表示数据流向,配方则作为两侧共同遵守的“契约”横跨在连接之上。
二、频率协商:谁决定数据多久来一次
RTDE连接建立后,上位机通过 setFrequency() 请求一个推送频率,控制器返回实际可用的频率。这个“协商”不是简单的取最小值,而是受控制器负载、当前已连接客户端数量、以及所选字段数量共同影响。常见做法是请求125Hz或500Hz,但实际能否达到取决于控制器型号和当前运行状态。
频率协商的结果直接决定实时数据包的时间间隔。例如请求500Hz,理想间隔是2ms;如果控制器返回125Hz,实际间隔就是8ms。上位机在解析数据时,必须用实际协商频率来推算时间戳或做积分运算,不能假设自己请求的频率一定被满足。一个实用的检查方法是:在连接建立后打印 getFrequency() 的返回值,并与请求值对比;若差异较大,应降低请求频率或减少订阅字段。
三、数据同步机制:输入寄存器与实时数据包如何配合
RTDE的输入寄存器和实时数据包是两条独立通道,它们之间没有硬性的“同一时刻”保证。上位机写入输入寄存器后,控制器在下一次UR程序扫描周期才能读到;而实时数据包中的 actual_q 等字段反映的是控制器当前状态。因此,如果上位机做“读当前位置 → 计算 → 写输入寄存器”的闭环,必须意识到:写入的控制量生效时,机器人已经又运动了一小段。
为了缓解这个问题,常见做法有三种:一是提高实时数据包频率,让上位机更快看到状态变化;二是在UR程序侧用 input_double_register 做增量式控制,而不是绝对位置控制;三是利用输出寄存器做“握手”——UR程序写完输出寄存器后,上位机读到该标志位再发下一组输入。第三种方式牺牲了部分实时性,但换来了明确的同步点,适合对时序要求不极端但要求逻辑正确的场景。
四、接口选择原则:什么时候用寄存器,什么时候用实时数据包
选择接口时,先问两个问题:这个数据是控制器“本来就有的”,还是“需要UR程序参与才能产生的”?
- 如果是控制器本来就有的(关节角、TCP位姿、数字输入、机器人模式、安全状态),优先用实时数据包。它由控制器直接推送,不需要UR程序写任何代码,延迟最低,字段最稳定。
- 如果是需要UR程序计算或判断后才能产生的(例如“工件已抓取”“允许进入下一工位”“自定义计数”),用输出寄存器。UR程序写,上位机读。
- 如果是上位机要告诉UR程序“做什么”的(目标位置、使能标志、配方编号、速度倍率),用输入寄存器。上位机写,UR程序读。
- 如果只是临时调试、改一个参数、启动一个程序,优先考虑Dashboard或URScript端口,不必占用RTDE的寄存器资源。
五、一个可参考的配方配置示例
下面是一个RTDE配方JSON的简化示例,声明了实时数据包字段和输入/输出寄存器。字段顺序就是数据包中字节的顺序,上位机解析时必须严格按此顺序读取。
{
"frequency": 125,
"variables": [
"actual_q",
"actual_qd",
"actual_TCP_pose",
"actual_TCP_speed",
"robot_mode",
"safety_status",
"input_double_register_0",
"input_double_register_1",
"input_bit_register_0",
"output_double_register_0",
"output_bit_register_0"
]
}
在这个示例中,actual_q 是6个double(48字节),actual_qd 是6个double,actual_TCP_pose 是6个double,actual_TCP_speed 是6个double,robot_mode 和 safety_status 各是1个int(4字节),输入/输出寄存器按double和bit分别占8字节和1字节。上位机解析时,先按顺序读取,再按类型转换。如果字段顺序写错,后续所有数据都会错位,这是RTDE调试中最常见的错误之一。
总结来说,RTDE的接口选择并不复杂:实时数据包负责“看”,输入寄存器负责“说”,输出寄存器负责“答”,配方负责“约定”。频率协商决定“多快”,同步机制决定“什么时候算数”。把这四类对象和两条通道的关系理清,后续的编程和调试就有了稳定的基础。