python编程控制硬件_用Python控制硬件52-编程调试CANopen协议

续上文,mcush库中ShellLabCAN类完成了can命令的封装,让我们能用Python代码控制到底层总线,但这还不够。CAN的应用协议层是非常开放的,各行各业总结出了不少行业标准,如果能再抽象封装一层,直接调用行业标准接口,就能无缝对接现有的众多优秀产品。

这篇介绍的CANopen就是非常优秀的协议,设计灵活性和扩展性都很好,由于有一个官方非盈利性组织CiA(CAN in Automation)的运作,已发布了在众多行业领域的应用规范模板,参照这些规范诞生了大量的接口统一的工业产品,因此也成了事实上的行业标准。

本篇不对CANopen的细节展开,有兴趣请自行搜索相关资料,也可参考知乎上一些优秀的教程介绍,例如:CANOpen系列教程​zhuanlan.zhihu.com

回到mcush库,从ShellLabCAN类派生出的ShellLabCANopen类,通过调用底层读写函数实现了用SDO报文控制对象字典,对于固定类型(字节、双字节、长整数、浮点)的对象,控制起来就非常方便了。

下面是Shell Lab测试台软件自带的示例“CANopen scan”,用于扫描所有设备:

s = ShellLabCANopen(PORT)

#s.canBaudrate( 1000000 )

s.canResetInput() # clear all pending messages

getLogPanel(switch=True, clear=True)

# scan all CAN-IDs

found = []

for id in range(1, 0x7F):

info( 'Scan ID:%d'% id )

# send node guarding request

s.writeNodeGuardRequest( id )

#time.sleep(0.1)

# check for response

for cid, ext, rtr, dat in s.canRead():

#logAdd( 'id=0x%X, ext=%d, rtr=%d, dat=%s'% (cid, ext, rtr, dat) )

if ((cid&0x780)==NDGRD) and (not rtr) and (len(dat)==1):

status = s2B(dat[0]) & 0x7F

if status == STATUS_PRE_OPERATIONAL:

status_str = 'pre_operational'

elif status == STATUS_OPERATIONAL:

status_str = 'operational'

elif status == STATUS_STOPPED:

status_str = 'stopped'

elif status == STATUS_CONNECTING:

status_str = 'connecting'

else:

status_str = 'unknown'

logAdd( 'id=0x%X, status=0x%X,%s'% (cid&0x7F, status, status_str) )

found.append( cid&0x7F )

info( 'Found%ddevices'% len(found) )

for id in found:

logAdd( '===== CAN-ID 0x%Xdevice info ====='% id )

val = s.readUINT32(id, 0x1000, 0)

logAdd( 'device type: 0x%08X(%d)'% (val, val&0xFFFF) )

val = s.readUINT8(id, 0x1001, 0)

logAdd( 'device error: 0x%02X'% val )

val = s.readUINT32(id, 0x1002, 0)

logAdd( 'status: 0x%08X'% val )

val = s.readObject(id, 0x1008, 0)

logAdd( 'device name:%s'% val )

val = s.readObject(id, 0x1009, 0)

logAdd( 'hardware ver:%s'% val )

val = s.readObject(id, 0x100A, 0)

logAdd( 'software ver:%s'% val )

val = s.readUINT16(id, 0x100C, 0)

logAdd( 'guard time: 0x%04X'% val )

val = s.readUINT8(id, 0x100D, 0)

logAdd( 'life time factor: 0x%02X'% val )

val = s.readUINT32(id, 0x1018, 1)

logAdd( 'vendor id: 0x%08X'% val )

val = s.readUINT32(id, 0x1018, 2)

logAdd( 'product code: 0x%08X'% val )

val = s.readUINT32(id, 0x1018, 3)

logAdd( 'revision number: 0x%08X'% val )

val = s.readUINT32(id, 0x1018, 4)

logAdd( 'serial number: 0x%08X'% val )

代码先是扫描所有ID,发送网络管理报文,等待对方回应,解析回应报文,获取对方设备状态(正常、停止、设置)。然后对扫描到的设备依次“体检”:对常规项(设备类型、软硬件版本号等)查询一遍,并打印出日志。

连上一块CANopen数字IO卡,扫描结果如下:

对这块数字量输出卡,下面的示例脚本循环将所有IO输出端口翻转:

ID = 0x20 # 必须指定从设备地址

s = ShellLabCANopen(PORT)

#s.canBaudrate( 1000000 )

#s.resetNode( ID )

s.startNode( ID ) # 确认进入工作状态

counter = 0

bytes = s.readUINT8(ID, 0x6200, 0) # 读出端口对应多少个控制字节

while True:

info( 'Count:%d'% counter )

#s.writeRPDO1( ID, '\xFF' ) # 通过PDO方式控制开

for i in range(bytes):

s.writeUINT8(ID, 0x6200, i+1, 0xFF) # 控制所有字节,打开各个字节对应的8个端口

time.sleep(0.5)

#s.writeRPDO1( ID, '\x00' ) # 通过PDO方式控制关

for i in range(bytes):

s.writeUINT8(ID, 0x6200, i+1, 0x00) # 控制所有字节,关闭各个字节对应的8个端口

time.sleep(0.2)

counter += 1

上面的代码用SDO报文控制相应的输出对象字典,实现了所有端口的翻转,除此之外也能使用RPDO消息报文来控制,效率会更高(但各个设备定义可能不同)。

同理也可以读取数字输入板卡的输入对象字典,获取输入端口的状态。

注:

mcush库安装方式:sudo pip install mcush

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值