3. EKI软件架构解析

EKI(Ethernet KRL Interface)并不是一个“打开端口收发字符串”的简单函数库,而是一套由内核、配置、解释器和 KRL 接口四层协作构成的通信子系统。理解它的分层结构,是后续写出稳定 EKI 程序的前提。很多初学者在 EKI_Init 之后直接调用 EKI_Send 却发现数据发不出去,或者收到的报文无法被 KRL 变量接收,根本原因往往不是代码写错,而是没有弄清“谁在解析 XML、谁在搬运数据、谁在触发 KRL 侧动作”。

一、四层架构与职责边界

EKI 的软件结构可以拆成四个相互衔接的部分:EKI 内核负责底层以太网连接与数据搬运;EKI XML 配置描述通信对象、字段结构和触发条件;EKI 解释器在运行时读取 XML,把字节流翻译成 KRL 可识别的变量;KRL 接口层则通过系统变量和专用函数,让机器人程序能够读写这些数据。四者不是并列关系,而是“配置驱动解释、解释驱动内核、内核服务 KRL”的链式依赖。

EKI 四层软件架构与数据流 外部设备 / 上位机 TCP Client / Server EKI 内核 Socket 管理 · 收发缓冲 EKI XML 配置 External · Send · Receive EKI 解释器 XML 解析 · 字段映射 KRL 接口层 EKI_* 函数 · 系统变量 KRL 用户程序 .src / .dat 变量读写 字节流 原始数据 配置规则 变量赋值 读写 发送路径:KRL 写入 → 内核发出 关键系统变量 $EKI_Status $EKI_Connection $EKI_Received $EKI_Sent $EKI_Error $EKI_Timeout (示例变量名,以实际系统为准) 图例 接收数据流 发送数据流 配置驱动

二、EKI 内核:连接与缓冲的实际行为

EKI 内核运行在控制器后台,负责建立 TCP 连接、维护收发缓冲区、处理超时与断线。它对外暴露的不是“立即发送”语义,而是“把数据放入发送缓冲,由内核按配置时机发出”。这意味着 EKI_Send 返回成功,只代表数据已进入缓冲,并不代表对方已经收到。判断真实发送结果,需要观察 $EKI_Sent 计数或对方回执。

内核的连接角色由 XML 中 <EXTERNAL> 节点的属性决定。例如配置为 Client 时,机器人主动连接上位机 IP 和端口;配置为 Server 时,机器人监听端口等待对方接入。这个角色一旦在 XML 中确定,KRL 程序无法在运行时切换,必须修改配置并重新初始化。

三、EKI XML 配置:通信契约的载体

XML 文件是 EKI 的“通信契约”,它同时描述了三件事:连接参数、报文结构、触发条件。一个典型的接收配置片段如下:

<RECEIVE>
  <ELEMENT Tag="Pos.X" Type="REAL" />
  <ELEMENT Tag="Pos.Y" Type="REAL" />
  <ELEMENT Tag="Pos.Z" Type="REAL" />
  <ELEMENT Tag="Grip" Type="INT" />
</RECEIVE>

解释器会按 Tag 名称在 KRL 侧寻找同名变量并赋值。这里有一个容易踩的坑:Tag 中的点号表示层级,KRL 侧必须存在对应的结构体变量,例如 DECL Pos {X, Y, Z}。如果 KRL 中只声明了 Pos 而没有展开成员,解释器无法完成映射,变量保持原值且不报错,表现为“数据收到了但变量没变”。

触发条件由 <TRIGGER> 或 Type="STREAM" 等属性控制。常见做法是让接收在后台持续进行,KRL 主程序通过轮询 $EKI_Received 判断是否有新报文到达,再决定是否读取变量。这种“后台收、前台取”的模式,比在运动指令中间阻塞等待更安全。

四、EKI 解释器:从字节到变量的翻译过程

解释器是 EKI 中最容易被忽视的一层。它不产生数据,只做格式转换。当内核收到一帧字节流后,解释器按 XML 中定义的顺序和类型逐字段解析:先匹配报文头或分隔符,再按 Type 把 ASCII 或二进制片段转换成 REAL、INT、BOOL 等 KRL 类型,最后写入对应变量。

如果报文格式与 XML 不一致,解释器可能只解析出前几个字段就停止,后续变量保持旧值。排查这类问题时,应优先核对三处:字段数量是否一致、分隔符是否匹配、数值格式(小数点、正负号、单位)是否符合 Type 要求。例如 XML 声明 Type="REAL",而对方发送的是整数 100,通常可以解析为 100.0;但若发送的是带千分位的 1,000,解释器会把它当作两个字段处理。

五、EKI 与 KRL 程序交互机制

KRL 侧通过一组专用函数与 EKI 交互,典型调用顺序是:EKI_Init 加载配置并建立连接,EKI_Open 打开指定通道,随后在循环中使用 EKI_Receive 或直接读取变量,发送时调用 EKI_Send,结束时 EKI_Close 关闭通道。这些函数本身不搬运业务数据,业务数据始终通过 XML 中定义的变量传递。

因此,KRL 程序与 EKI 的耦合点只有两个:变量名和调用时机。变量名必须与 XML 的 Tag 严格一致;调用时机决定了数据是“最新一帧”还是“被覆盖后的帧”。如果主程序循环周期较长,而对方发送频率很高,中间帧会被覆盖,KRL 只能读到最后一帧。需要逐帧处理时,应在 XML 中启用缓冲或由对方等待回执后再发下一帧。

六、系统变量与数据流走向

EKI 提供了一组系统变量用于状态监视和流程控制,常见的有连接状态、接收计数、发送计数、错误码和超时标志。它们的作用不是传递业务数据,而是让 KRL 程序能够判断“现在能不能发”“刚才那帧收到没有”“连接是否还活着”。

完整的数据流可以概括为两条方向相反的路径。接收方向:外部设备 → 内核缓冲 → 解释器解析 → KRL 变量 → 用户程序读取。发送方向:用户程序写入 KRL 变量 → 调用发送函数 → 解释器按 XML 组装报文 → 内核缓冲 → 外部设备。两条路径共用同一份 XML 配置,但使用不同的节点定义,因此配置时必须同时检查 <SEND> 和 <RECEIVE> 两侧的字段是否与对方约定一致。

在实际调试中,建议先用 $EKI_Received 和 $EKI_Sent 的计数变化确认链路是否通,再检查变量值是否正确。计数在涨但变量不变,问题在解释器与 XML 映射;计数不涨,问题在内核连接或对方发送端。按这个顺序排查,可以避免在 KRL 代码里反复修改却找不到根因。