#send_msg
#The CANlib library is initialized when the canlib module is imported. To be
# able to send a message, Frame also needs to be installed.
from canlib import canlib, Frame
# Firstly, open two CAN channels, one to send the message and one to receive.
# Note that there needs to be a channel to receive, as otherwise the message
# can not be sent. In this example the channels are named ch_a and ch_b. To
# open the channels call on the openChannel method inside of canlib and, as an
# input put in channel=0 and channel=1. Where 0 and 1 represents the two
# CANlib channels 0 and 1.
ch_a = canlib.openChannel(channel=0)
ch_b = canlib.openChannel(channel=1)
# After opening the channel, we need to set the bus parameters. Some
# interfaces keep their params from previous programs. This can cause problems
# if the params are different between the interfaces/channels. For now we will
# use setBusParams() to set the canBitrate to 250K.
ch_0.setBusParams(canlib.canBITRATE_250K)
ch_1.setBusParams(canlib.canBITRATE_250K)
# The next step is to Activate the CAN chip for each channel (ch_a and ch_b in
# this example) use .busOn() to make them ready to receive and send messages.
ch_a.busOn()
ch_b.busOn()
# To transmit a message with (11-bit) CAN id = 123 and contents (decimal) 72,
# 69, 76, 76, 79, 33, first create the CANFrame (CANmessage) and name it. In
# this example, the CANFrame is named frame. Then send the message by calling on
# the channel that will act as the sender and use .write() with the CANFrame
# as input. In this example ch_a will act as sender.
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
# To make sure the message was sent we will attempt to read the message. Using
# timeout, only 500 ms will be spent waiting to receive the CANFrame. If it takes
# longer the program will encounter a timeout error. read the CANFrame by calling
# .read() on the channel that receives the message, ch_b in this example. To
# then read the message we will use print() and send msg as the input.
msg = ch_b.read(timeout=500)
print(msg)
# After the message has been sent, received and read it is time to inactivate
# the CAN chip. To do this call .busOff() on both channels that went .busOn()
ch_a.busOff()
ch_b.busOff()
# Lastly, close all channels with close() to finish up.
ch_a.close()
ch_b.close()
# Depending on the situation it is not always necessary or preferable to go of
# the bus with the channels and, instead only use close(). But this will be
# talked more about later.
# send_msg_pyt
from canlib import canlib, Frame
# instead of opening the two channels and closing them one by one, we will use a
# with statement. Using the with statement to open one or more channels with
# canlib.openChannel(i) as ch_x. Within this with statement we will write the
# rest of the code.
with canlib.openChannel(2) as ch_a, canlib.openChannel(3) as ch_b:
# Instead of going on bus with "copy-paste" for each channel, we will use a
# for-loop. Within this loop we will go through a list of all channels opened
# using the with statement. Currently we only have two channels, which makes
# the for-loop somewhat unnecessary. However, when we start using more
# channels the for-loop will be preferred.
for ch in [ch_a, ch_b]:
ch.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
msg = ch_b.read(timeout=500)
print(msg)
# After we run out of code within the with statement and exit it, we don’t
# need to manually close it or go off bus. The channels that were open using
# the with statement will be automatically closed, and with the channels being
# closed they also went off the bus.
# send_msg_wait
from canlib import canlib, Frame
# We will now open three channels, two from the USBcan and one on
# the leaf pro which we will not connect to the T-cannector. We will use the
# leaf pro channel ch_c to send errorframes.
with canlib.openChannel(2) as ch_a, canlib.openChannel(3) as ch_b, canlib.openChannel(4) as ch_c:
for ch in [ch_a, ch_b, ch_c]:
ch.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
# Instead of using write we will now use writeWait(). We will attempt to send
# a message for 500 milliseconds, if the message is not sent we will receive a
# Timeout occured error.
ch_a.writeWait(frame, timeout=500)
# We will now try to send a message with the channel not connected to the
# T-cannector. This should result in a Timeout occurred error.
ch_c.writeWait(frame, timeout=500)
msg = ch_b.read(timeout=500)
print(msg)
# send_msgs_wait
from canlib import canlib, Frame
# We will now open three channels, two from the USBcan and one on the
# leaf pro which we will not connect to the T-cannector. We will use the
# leaf pro channel ch_c to send errorframes.
with canlib.openChannel(2) as ch_a, canlib.openChannel(3) as ch_b, canlib.openChannel(4) as ch_c:
for ch in [ch_a, ch_b, ch_c]:
ch.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
# We will now send 199 messages in a for-loop and after the loop use writeWait
# to send a last message, to make sure all previous messages were sent.
for i in range(199):
ch_a.write(frame)
ch_a.writeWait(frame, timeout=500)
msg = ch_b.read(timeout=500)
print(msg)
# We will now do the same with the ch_c channel not connected to the
# T-cannector. This should result in a timeout error.
for i in range(199):
ch_c.write(frame)
ch_c.writeWait(frame, timeout=100)
msg = ch_b.read(timeout=500)
print(msg)
所需硬件
作为本指南的第二部分,我们将需要至少三个通道。因此,在第一部分中我们使用的设备没有三个通道,我们则还需要另一个设备。在本指南中,将使用Kvaser Leaf Pro HS v2以及Kvaser USBcan Pro 2xHS v2。
# silent_mode
from canlib import canlib, Frame
ch_a = canlib.openChannel(channel=0)
ch_b = canlib.openChannel(channel=1)
# Using the setBusOutputControl method we set ch_a (channel 0) to normal. This
# line is not necessary, as normal is the default mode, but for the sake of
# clarity we will add it anyway. Then we do the same to the channel ch_b
# (channel 1) but set it to silent.
ch_a.setBusOutputControl(canlib.Driver.NORMAL)
# before setting the second channel, we need to make sure that the channel
# actually supports silent mode. For this we will use an if statement.
if canlib.ChannelCap.SILENT_MODE in ch_b.channel_data.channel_cap:
ch_b.setBusOutputControl(canlib.Driver.SILENT)
# If the channel does not support silent mode we will exit the program.
else:
exit()
# The rest of the code will remain unchanged.
ch_a.busOn()
ch_b.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
msg = ch_b.read(timeout=500)
print(msg)
ch_a.busOff()
ch_b.busOff()
ch_a.close()
ch_b.close()
> .\.venv\Scripts\activate
(pyproj) PS C:\Users\extac\Pyproj> py
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May 3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from canlib import canlib, Frame
>>> ch = canlib.openChannel(channel=1)
>>> ch.setBusOutputControl(canlib.Driver.SILENT)
>>> ch.busOn()
>>> frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
>>> for i in range(2000):
... ch.write(frame)
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\channel.py", line 718, in write
dll.canWrite(self.handle, frame.id, bytes(frame.data), frame.dlc, frame.flags)
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\dll.py", line 177, in _error_check
raise can_error(result)
canlib.canlib.exceptions.CanGeneralError: Transmit buffer overflow (-13)
请再次记住,完成后要关闭总线和通道。
>>> ch.busOff()
>>> ch.close()
对于下一个示例,我们需要添加第三个通道,以便能够发送报文,并使用静默通道读取报文。请注意,为了能够使用静默通道,必须至少有两个其他通道可以正常发送和接收报文。在本指南中,我们将添加一个Kvaser Leaf Pro HS v2,但任何其他至少有一个通道的CAN通讯仪都可以。要查看是否有两个以上的通道可用,请再次运行脚本check_ch,对于本示例,结果如下:
(pyproj)> py check_ch.py
Found 5 channels
0. Kvaser USBcan Pro 2xHS v2 (channel 0) (00752-9:13406/0)
1. Kvaser USBcan Pro 2xHS v2 (channel 1) (00752-9:13406/1)
2. Kvaser Leaf Pro HS v2 (channel 0) (00843-4:10012/0)
3. Kvaser Virtual CAN Driver (channel 0) (00000-0:0/0)
4. Kvaser Virtual CAN Driver (channel 1) (00000-0:0/1)
与上次运行check_ch时相比,虚拟通道已从2和3降至3和4。CAN通道2已被新添加的Kvaser Leaf Pro CAN通讯仪占用。
# silent_listen
from canlib import canlib, Frame
# Open a third channel (channel 2) and name it ch_c.
ch_a = canlib.openChannel(channel=0)
ch_b = canlib.openChannel(channel=1)
ch_c = canlib.openChannel(channel=2)
# Set ch_a and ch_b to normal, again unnecessary but to clarify,
ch_a.setBusOutputControl(canlib.Driver.NORMAL)
ch_b.setBusOutputControl(canlib.Driver.NORMAL)
# and ch_c to silent.
if canlib.ChannelCap.SILENT_MODE in ch_c.channel_data.channel_cap:
ch_c.setBusOutputControl(canlib.Driver.SILENT)
else:
exit()
# Put the third channel ch_c on the bus.
ch_a.busOn()
ch_b.busOn()
ch_c.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
# Add ch_c to read the message as the silent channel to read the message.
msg_c = ch_c.read(timeout=500)
msg_b = ch_b.read(timeout=500)
# Print both messages to compare them.
print("msg c:”)
print(msg_c)
print("msg b:”)
print(msg_b)
# Go off bus with all three channels.
ch_a.busOff()
ch_b.busOff()
ch_c.busOff()
# Lastly, close all channels.
ch_a.close()
ch_b.close()
ch_c.close()
# change_bitrate
from canlib import canlib, Frame
ch_a = canlib.openChannel(channel=0)
ch_b = canlib.openChannel(channel=1)
# Use getBusParams and print the result to see the preset parameters on both
# channels.
print(ch_a.getBusParams())
print(ch_b.getBusParams())
# After opening both channels we will call upon the setBusParams to change the
# bitrate of the message. From the list of predefined we will use BITRATE_100K
ch_a.setBusParams(canlib.Bitrate.BITRATE_100K)
ch_b.setBusParams(canlib.Bitrate.BITRATE_100K)
# Use getBusParams and print the result to see that the parameters changed on
# both channels.
print(ch_a.getBusParams())
print(ch_b.getBusParams())
ch_a.busOn()
ch_b.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
msg = ch_b.read(timeout=500)
print(msg)
ch_a.busOff()
ch_b.busOff()
ch_a.close()
ch_b.close()
> .\.venv\Scripts\activate
(pyproj)> py
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May 3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from canlib import canlib
>>> dat = canlib.ChannelData(0)
> .\.venv\Scripts\activate
(pyproj)> py
Python 3.9.5 (tags/v3.9.5:0a7dcbd, May 3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from canlib import canlib
>>> canlib.getNumberOfChannels()
4
>>> ch_a.write(frame)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\channel.py", line 718, in write
dll.canWrite(self.handle, frame.id, bytes(frame.data), frame.dlc, frame.flags)
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\dll.py", line 177, in _error_check
raise can_error(result)
canlib.canlib.exceptions.CanGeneralError: A hardware error was detected (-15)
要尝试使用已删除的通道读取报文,我们需要在删除通讯仪并运行读取代码之前再次运行设置代码。
>>> ch_a.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\channel.py", line 718, in write
dll.canWrite(self.handle, frame.id, bytes(frame.data), frame.dlc, frame.flags)
File "C:\Users\extac\Pyproj\.venv\lib\site-packages\canlib\canlib\dll.py", line 177, in _error_check
raise can_error(result)
canlib.canlib.exceptions.CanGeneralError: A hardware error was detected (-15)
#open__channel_by_name
from canlib import canlib, Frame
# The function we will use to open a channel using the custom channel name.
# The custom name will be sent in as an input.
def open_channel_by_name(cust_name):
# Firstly, using a for-loop will be used to go through every connected device.
num_channels = canlib.getNumberOfChannels()
for i in range(num_channels):
chd = canlib.ChannelData(i)
# For every device connected their custom name is compared to the input name.
# If the names are the same, the channel is opened and named ch.
if cust_name == chd.custom_name:
ch = canlib.openChannel(i)
break
# If we do not find a channel with the input name as a custom name, the
# following message is shown and the exception CanNotFound is raised.
else:
print(f"Channel with custom name {cust_name} not found”)
raise canlib.CanNotFound
# The opened channel named ch is returned by the function.
return ch
# We will now test the function by opening two channels using their custom
# name and sending a message between them. THe channels we will try to open is
# the first channel on a USBcan with the custom name USBone and the channel on
# a leaflight with the name My Leaf. The channels will be named ch_b and ch_a
# respectively.
ch_b = open_channel_by_name("My Leaf”)
ch_a = open_channel_by_name(“USBone")
ch_a.busOn()
ch_b.busOn()
frame = Frame(id_=123, data=[72, 69, 76, 76, 79, 33])
ch_a.write(frame)
msg = ch_b.read()
print(msg)
ch_a.close()
ch_b.close()
# After successfully sending a message we will see what happens when we try to
# open a channel with a custom name that does not exist.
ch_a = open_channel_by_name("USBoe")
为了找到正确的文档,首先我们需要展开“Using canlib”选项卡。下一步是了解使用方式和用途。目前,我们要发送一条报文,刚好有一个名为“Send and Receive”的选项卡,我们可以展开它。接下来,我们看到“Reading Messages”也是一个标题,那么点击它,直接转到读取报文。在“read”标题下阅读时,我们最终会看到一系列功能列表。其中一项功能如下:“If you want to wait until a message arrives (or a timeout occurs) and then read it, call read with a timeout(如果要等到报文到达(或发生超时)然后读取它,请调用带有超时的read)”。这看起来就是我们所需要的。要了解更多关于该函数的信息,我们可以单击标有“read”的链接直接转到“read”函数。现在我们可以看到“read”有一个名为“timeout”的参数,它是一个整数。该整数决定程序在返回超时错误之前等待报文传递的毫秒数。现在我们已经找到了我们要找的内容,可以将其输入到我们的代码中,例如channel.read(timeout = 500),以使程序等待500毫秒。