学习CANopen --- [3] NMT报文

本文主要讲述CANopen中的NMT报文,即网络管理(Network ManagemenT),该服务可以用于启动网络和监控设备。

NMT报文由NMT主机发送,对从机进行启动、监控和重启,在CANopen网络中只允许有一个活动的NMT主机。如果网络中有多个设备可以配置成主机,那么同一时刻只有一个可以配置成主机。


一 NMT报文及功能

NMT报文属于Master/Slave模式

1. 模块控制报文

该报文用于对Slave从机进行各种控制,报文格式如下,
在这里插入图片描述
必须由NMT Master发给NMT Slave(s),报文的COB-ID是0x000

报文数据段传输的第0个字节是CS (Command Specifier),用于表示控制命令,具体有以下5个命令,
在这里插入图片描述
PS:NMT Service这一列里有个Remote Node,即远程节点,其实就是Slave节点,这是相对于NMT Master来说的。如果NMT Master也是个CAN设备,那么NMT Master自身可以叫做Local Node

报文数据段传输的第1个字节是Slave从机的Node Id,如果为0,表示网内所有Slave设备都会收到这个报文。

2. 设备监控报文

该功能主要用于监控Slave设备的当前状态,分为Node Guarding和Heartbeat两种方式。

2.1 Node Guarding

NMT Master主动向Slave发送一个CAN远程帧(没有数据段),如下图,
在这里插入图片描述
然后Slave会返回一个指定格式的消息给Master,如下图,
在这里插入图片描述
Byte0包含一个toggle位(bit7),每一次Node Guard请求都会在0和1之间进行翻转(第一次值为0),翻转的目的是为了区分设备当前状态值和历史状态值;bit 6-0用来表示Slave的当前状态,有以下几种状态,
在这里插入图片描述
PS:状态0永远不会出现在Node Guarding的reply里,因为在Initialising状态下,不会对Node Guarding请求做出响应。

2.2 Heartbeat

也叫做心跳报文,由NMT Slave主动发送,NMT Master接收,无需response,这种模式也叫做生产者/消费者模式,NMT Slave是生产者,NMT Master是消费者
在这里插入图片描述
有以下4种状态,
在这里插入图片描述
当一个使用Heartbeat的CAN设备启动,其第一条心跳报文就是Boot-up,
在这里插入图片描述

2.3 小结

Node Guarding和Heartbeat都可以实现设备监控的目的,同一时刻只能使用其中一种,推荐使用Heartbeat,更加简单,另外Node Guarding需要用到远程帧,不是所有CAN设备都支持远程帧。

3. 启动报文

当NMT Slave设备启动时,都会发送这条报文,用来告知Master自己已经从 Initialising状态切换到Pre-operational状态。
在这里插入图片描述
启动报文和Heartbeat中的Boot-up有点重合,当一个使用Heartbeat的CAN设备启动,其第一条心跳报文就是Boot-up,但如果使用的是Node Guarding,那么CAN设备启动后发送的第一条报文就是启动报文,后续就是Node Guarding请求了。


二 代码实战

学习了理论后,再通过实践来加深理解。

首先,通过下面的Slave代码,创建1个Slave节点,id是6,初始化完成后自动进入Pre-operational状态,

import signal
import canopen


running = True

def sigint_handler(signum, frame):
	global running
	print('')
	running = False
	exit(0)

# 处理按键发送的信号,优雅的关闭程序
signal.signal(signal.SIGINT,  sigint_handler)
signal.signal(signal.SIGHUP,  sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)

# 创建一个网络用来表示CAN总线
network = canopen.Network()

# 连接到CAN总线
network.connect(bustype='socketcan', channel='vcan0')

# 创建slave节点,其id是6,对象字典为CANopenSocket.eds
node = network.create_node(6, 'CANopenSocket.eds')



# node向CAN总线上发送启动消息
node.nmt.send_command(0)

# node进入PRE-OPERATIONAL状态
node.nmt.state = 'PRE-OPERATIONAL'

# node发送心跳报文,每隔1s发送一次
node.nmt.start_heartbeat(1000) # 1000ms




# 循环
while running:
	pass

运行后在candump窗口下观察如下,
在这里插入图片描述
0x7F是127,表示can节点进入了Pre-operational状态。

下面是master代码,会把所有NMT的命令都执行一遍,具体可以看注释,

import time
import canopen

# 创建一个网络用来表示CAN总线
network = canopen.Network()

# 添加slave节点,其id是6,对象字典为CANopenSocket.eds
node = canopen.RemoteNode(6, 'CANopenSocket.eds')
network.add_node(node)



# 连接到CAN总线
network.connect(bustype='socketcan', channel='vcan0')


sleep_sec = 2 # 2秒

# 发送'Start Remode Node'命令,把slave设置为OPERATIONAL状态
node.nmt.state = 'OPERATIONAL'


time.sleep(sleep_sec)

# 发送'Reset Node'命令,把slave设置为Initialising状态
node.nmt.state = 'RESET'


time.sleep(sleep_sec)

# 发送'Enter Pre-operational State'命令,把slave设置为PRE-OPERATIONAL状态
node.nmt.state = 'PRE-OPERATIONAL'


time.sleep(sleep_sec)

# 发送'Start Remode Node'命令,把slave设置为OPERATIONAL状态
node.nmt.state = 'OPERATIONAL'


time.sleep(sleep_sec)

# 发送'Stop Remode Node'命令,把slave设置为STOPPED状态
node.nmt.state = 'STOPPED'


time.sleep(sleep_sec)

# 发送'Reset Communication'命令,把slave设置为Initialising状态
node.nmt.send_command(0x82)


time.sleep(sleep_sec)

# 发送'Enter Pre-operational State'命令,把slave设置为PRE-OPERATIONAL状态
node.nmt.state = 'PRE-OPERATIONAL'


time.sleep(sleep_sec)

# 发送'Start Remode Node'命令,把slave设置为OPERATIONAL状态
node.nmt.state = 'OPERATIONAL'

运行master.py后,在candump窗口可以看到如下状态变化,
在这里插入图片描述
已上状态切换完全是按照CANopen DS301中规定的状态机进行的,如下图,
在这里插入图片描述


三 总结

本文主要讲述CANopen协议中的NMT报文,并以代码实战展示了如何使用NMT报文以及对应的状态切换。

如果有写的不对的地方,希望能留言指正,谢谢阅读。

猜你喜欢

转载自blog.csdn.net/whahu1989/article/details/105613189
nmt
今日推荐