1. LinuxCNC与PLC通信基础配置
任务目标
本案例完成LinuxCNC与PLC之间基于Modbus TCP的通信基础配置,实现双向数据交换:LinuxCNC读取PLC保持寄存器中的数值,并将自身状态写入PLC线圈。通过本案例,你将得到一个可独立运行的Modbus TCP通信配置,并验证数据读写是否成功。
环境与依赖
- LinuxCNC 2.8+(已安装
hal组件) - Python 3.6+,安装
pymodbus库:pip install pymodbus - Modbus TCP从站设备或模拟器(如
diagslave,或使用本案例附带的简易从站脚本)
实现方案
采用LinuxCNC的hal用户空间组件方式:编写一个Python HAL组件,通过Modbus TCP协议周期性地与PLC交换数据。该组件注册两个HAL引脚:plc-input(float,从PLC读取的值)和plc-output(bit,写入PLC的状态)。通信参数(IP、端口、寄存器地址、周期)通过命令行参数传入,便于与HAL配置文件集成。
关键完整代码
#!/usr/bin/env python3
# modbus_hal_io.py - LinuxCNC HAL component for Modbus TCP I/O
import hal, time, sys
from pymodbus.client import ModbusTcpClient
# --- HAL component setup ---
h = hal.component("modbus_io")
h.newpin("plc-input", hal.HAL_FLOAT, hal.HAL_IN)
h.newpin("plc-output", hal.HAL_BIT, hal.HAL_OUT)
h.ready()
# --- Parse arguments: ip port read_addr write_addr period_ms ---
if len(sys.argv) != 6:
print("Usage: modbus_io <ip> <port> <read_addr> <write_addr> <period_ms>")
sys.exit(1)
ip, port = sys.argv[1], int(sys.argv[2])
read_addr, write_addr = int(sys.argv[3]), int(sys.argv[4])
period = float(sys.argv[5]) / 1000.0
client = ModbusTcpClient(ip, port=port)
if not client.connect():
print("ERROR: Cannot connect to Modbus device")
sys.exit(1)
try:
while True:
# Read holding register (16-bit) from PLC
rr = client.read_holding_registers(read_addr, 1)
if rr.isError():
print("Read error")
else:
h["plc-input"] = float(rr.registers[0])
# Write current HAL pin state to PLC coil
out_val = int(h["plc-output"])
client.write_coil(write_addr, out_val)
h.ready() # update HAL
time.sleep(period)
except KeyboardInterrupt:
pass
finally:
client.close()
h.exit()
运行与集成
将上述代码保存为modbus_hal_io.py并赋予执行权限。在LinuxCNC的HAL配置文件中(如custom.hal)添加以下内容加载组件:
loadusr -W python /path/to/modbus_hal_io.py 192.168.1.100 502 0 0 100
参数含义:PLC IP为192.168.1.100,端口502,读取保持寄存器地址0,写入线圈地址0,通信周期100ms。启动LinuxCNC后,HAL引脚modbus_io.plc-input和modbus_io.plc-output即被创建。
验证方法
使用Modbus从站模拟器(如diagslave -m tcp -p 502)或真实PLC作为对端。验证步骤如下:
- 在从站端将保持寄存器0设为
1234,在LinuxCNC的HAL终端执行getp modbus_io.plc-input,应输出1234.0。 - 在HAL终端执行
setp modbus_io.plc-output 1,观察从站端线圈0状态变为ON。 - 若上述两项均符合预期,则通信配置成功。
预期输出:getp modbus_io.plc-input返回从站寄存器值(如1234.0);从站线圈状态随setp命令变化。此结果由代码逻辑直接推出,非实测数据。
常见问题
- 连接失败:确认IP/端口正确,从站已启动,防火墙未阻断TCP 502端口。
- 读取值不变:检查寄存器地址是否匹配从站映射表,部分PLC地址从1开始,需在代码中做偏移。
- HAL引脚未出现:确认
loadusr路径正确,且Python脚本无语法错误(可先手动运行脚本测试)。