在工业自动化与机器人开发中,“如何控制电机” 始终是一个核心话题。传统的控制方式往往受限于物理接线长度(USB/串口),或者受困于繁琐的寄存器操作。
今天,我们将展示一套纯 Python 解决方案:利用 ZLG 的以太网 CAN 适配器(CANET-2E-U),结合强大的 canopen 开源库,实现对 PMC006CX 一体化步进驱动器 的远程、高层级控制。
set_max_speed),极大地降低了开发门槛。Python 的 canopen 库原生支持 SocketCAN、Kvaser、Vector 等设备,但默认并不支持 ZLG 的 TCP 模式。
为了解决这个问题,我们编写了 zlgcanadapter.py。这是一个硬件抽象层,它继承自 can.BusABC。它的作用是欺骗 canopen 库,让它以为自己连接的是一个标准的本地 CAN 卡,但实际上所有数据都通过 TCP 网络流向了 ZLG 适配器
关键代码解析 (zlgcanadapter.py):
# 核心机制:拦截 send 和 recv
class ZLGCanNetBus(can.BusABC):
def __init__(self, ip, port, ...):
# 初始化 ZLG SDK,建立 TCP 连接
self.zcanlib = ZCAN()
self.device_handle = self.zcanlib.OpenDevice(ZCAN_CANETTCP, 0, 0)
# 配置 IP 和 端口...
def send(self, msg, timeout=None):
# 将 python-can 的 Message 对象转换为 ZLG 的 C 结构体并发送
z_msg = ...
self.zcanlib.Transmit(self.chn_handle, z_msg, 1)
def _recv_internal(self, timeout):
# 从 ZLG SDK 读取数据,封装回 python-can 的 Message 对象
rcv_msg = self.zcanlib.Receive(...)
return msg, False
有了这个文件,我们就可以无缝对接 canopen 的高层功能了。
直接操作 SDO(例如 node.sdo[0x6003].raw = 50000)虽然可行,但不够直观。我们在 pusican.py 中构建了一个 Canopen_ku 类,将复杂的 CANopen 对象字典地址(Index/SubIndex)映射为人类可读的函数。
看看封装前后的对比:
原始方式:
# 想要设置加速度,你需要查阅手册找到 0x6008
node.sdo[0x6008].raw = 5
封装后 (pusican.py):
# 直接调用语义化函数
def set_acce_speed(self, node_id, a_speed):
self.node_map[node_id].sdo[0x6008].raw = a_speed
该库通过检测 bustype 参数,自动判断是加载标准的 CAN 接口,还是加载我们自定义的 ZLG 网络接口:
if self.bustype1 == 'zlgcanet':
# 自动加载我们写的适配器,解决 connect 报错问题
zlgcannet_bus = ZLGCanNetBus(ip=ip, port=port)
self.network.bus = zlgcannet_bus
万事俱备,现在我们来编写一个主程序 motor_controller.py。假设电机的 Node-ID 为 3,CANET 的 IP 为 192.168.1.200,端口 4001。
我们将演示PP模式(点对点位置控制),让电机转动指定的步数。
import time
from pusican import Canopen_ku
def main():
# 1. 连接设备
# 格式:类型, IP:端口, 波特率, [节点ID列表]
print("正在连接 CANET 设备...")
driver = Canopen_ku('zlgcanet', '192.168.1.200:4001', baud1=125000, node_ids=[3])
node_id = 3
# 2. 设置运动参数 (PP模式 - 位置控制)
# 设置工作模式为 4 (PP Mode - Point to Point)
driver.set_work_mode(node_id, 4)
# 设置最大速度
driver.set_pp_speed(node_id, 100000) # 设置最大速度
# 3. 执行运动指令
target_step = 20000 # 目标步数
print(f"开始运动:目标 {target_step} 步")
driver.set_pp_step(node_id, target_step)
driver.set_pp_control_word(node_id, 16)
# 模拟运行一段时间
time.sleep(3)
# 4. 读取实时状态
pos = driver.read_motor_position(node_id)
print(f"当前电机位置: {pos}")
# 关闭连接
driver.network.disconnect()
print("连接已断开")
if __name__ == '__main__':
main()
运行预期结果:
通过引入 ZLGCanNetBus 类,我们成功让 canopen 库与ZLG CANET 设备之间连接。配合 pusican.py 的封装,整套系统具备了以下优势:
bustype 参数即可,业务代码无需变动。canopen 库的 SYNC/PDO 机制扩展即可。附件:
这套方案非常适合实验室自动化、AGV 小车原型验证以及远程设备维护场景。只需一根网线,你的 Python 代码就能掌控一切动力。