🙆♂️我是纯良思安,爱技术、爱分享,更爱生活🙆♂️
💖喜欢的朋友可以关注一下,下次更新不迷路💖
目录
前言
介绍python-can库的常用API库之Bus
Bus
BusABC为物理和虚拟CAN Bus提供一个包装器。
通过调用具有特定接口的Bus()函数来创建特定于接口的实例,例如:
vector_bus = can.Bus(interface='vector', ...)
Transmitting
将单个消息写入总线是通过调用send()方法同时传递一个Message实例来完成的。
"""
This example shows how sending a single message works.
"""
import can
from can.interface import Bus
from Config.VN1630A_Config import *
def send_one( id, can_data_list):
"""Sends a single message."""
bus = Bus()
with bus:
msg = can.Message(
arbitration_id=id, data=can_data_list, is_extended_id=False,is_fd=True
)
try:
bus.send(msg)
print(f"Message sent on {bus.channel_info}")
except can.CanError:
print("Message NOT sent")
if __name__ == "__main__":
send_data_list = [0x03, 0x22, 0xF1, 0x30, 0x00,0x00,0x00,0x00]
send_one(0x735,send_data_list)
如果想要周期发送可以通过Broadcast Manager(允许用户设置周期报文。例如在给定的时间段发送特定的报文)
下面的例子展示了在socketcan中使用broadcast manager:
#!/usr/bin/env python
"""
This example exercises the periodic sending capabilities.
Expects a vcan0 interface:
python3 -m examples.cyclic
"""
import logging
import time
import can
logging.basicConfig(level=logging.INFO)
def simple_periodic_send(bus):
"""
Sends a message every 20ms with no explicit timeout
Sleeps for 2 seconds then stops the task.
"""
print("Starting to send a message every 200ms for 2s")
msg = can.Message(
arbitration_id=0x123, data=[1, 2, 3, 4, 5, 6], is_extended_id=False
)
task = bus.send_periodic(msg, 0.20)
assert isinstance(task, can.CyclicSendTaskABC)
time.sleep(2)
task.stop()
print("stopped cyclic send")
def limited_periodic_send(bus):
"""Send using LimitedDurationCyclicSendTaskABC."""
print("Starting to send a message every 200ms for 1s")
msg = can.Message(
arbitration_id=0x12345678, data=[0, 0, 0, 0, 0, 0], is_extended_id=True
)
task = bus.send_periodic(msg, 0.20, 1, store_task=False)
if not isinstance(task, can.LimitedDurationCyclicSendTaskABC):
print("This interface doesn't seem to support LimitedDurationCyclicSendTaskABC")
task.stop()
return
time.sleep(2)
print("Cyclic send should have stopped as duration expired")
# Note the (finished) task will still be tracked by the Bus
# unless we pass `store_task=False` to bus.send_periodic
# alternatively calling stop removes the task from the bus
# task.stop()
def test_periodic_send_with_modifying_data(bus):
"""Send using ModifiableCyclicTaskABC."""
print("Starting to send a message every 200ms. Initial data is four consecutive 1s")
msg = can.Message(arbitration_id=0x0CF02200, data=[1, 1, 1, 1])
task = bus.send_periodic(msg, 0.20)
if not isinstance(task, can.ModifiableCyclicTaskABC):
print("This interface doesn't seem to support modification")
task.stop()
return
time.sleep(2)
print("Changing data of running task to begin with 99")
msg.data[0] = 0x99
task.modify_data(msg)
time.sleep(2)
task.stop()
print("stopped cyclic send")
print("Changing data of stopped task to single ff byte")
msg.data = bytearray([0xFF])
msg.dlc = 1
task.modify_data(msg)
time.sleep(1)
print("starting again")
task.start()
time.sleep(1)
task.stop()
print("done")
# Will have to consider how to expose items like this. The socketcan
# interfaces will continue to support it... but the top level api won't.
# def test_dual_rate_periodic_send():
# """Send a message 10 times at 1ms intervals, then continue to send every 500ms"""
# msg = can.Message(arbitration_id=0x123, data=[0, 1, 2, 3, 4, 5])
# print("Creating cyclic task to send message 10 times at 1ms, then every 500ms")
# task = can.interface.MultiRateCyclicSendTask('vcan0', msg, 10, 0.001, 0.50)
# time.sleep(2)
#
# print("Changing data[0] = 0x42")
# msg.data[0] = 0x42
# task.modify_data(msg)
# time.sleep(2)
#
# task.stop()
# print("stopped cyclic send")
#
# time.sleep(2)
#
# task.start()
# print("starting again")
# time.sleep(2)
# task.stop()
# print("done")
def main():
"""Test different cyclic sending tasks."""
reset_msg = can.Message(
arbitration_id=0x00, data=[0, 0, 0, 0, 0, 0], is_extended_id=False
)
# this uses the default configuration (for example from environment variables, or a
# config file) see https://python-can.readthedocs.io/en/stable/configuration.html
with can.Bus() as bus:
bus.send(reset_msg)
simple_periodic_send(bus)
bus.send(reset_msg)
limited_periodic_send(bus)
test_periodic_send_with_modifying_data(bus)
# print("Carrying out multirate cyclic test for {} interface".format(interface))
# can.rc['interface'] = interface
# test_dual_rate_periodic_send()
time.sleep(2)
if __name__ == "__main__":
main()
Receiving
从总线读取是通过调用recv()方法或直接在总线上迭代来实现的,例如通过VN1630A实现报文的接收:
1、编写配置文件VN1630A_Config.py:
import can
can.rc['interface'] = 'vector'
can.rc['bustype'] = 'vector'
can.rc['channel'] = '0'
can.rc['app_name'] = 'Python_can'
#波特率配置,启用CANFD
can.rc['fd'] = True # 默认ABaudr 500000, DBaudr 500000
can.rc['bitrate'] = 500000
can.rc['data_bitrate'] = 2000000
#Arbitration 采样点设置 80%, prescaler 4
can.rc['sjw_abr'] = 8
can.rc['tseg1_abr'] = 31
can.rc['tseg2_abr'] = 8
#Data Phase 采样点设置 70%, prescaler 4
can.rc['sjw_dbr'] = 3
can.rc['tseg1_dbr'] = 6
can.rc['tseg2_dbr'] = 3
2、编写receive_all.py:
from can.bus import BusState
from Config.VN1630A_Config import *
def receive_all():
"""接收所有总线报文."""
with can.Bus() as bus:
try:
bus.state = BusState.PASSIVE
except NotImplementedError:
pass
try:
while True:
msg = bus.recv(1)
if msg is not None:
print(msg)
except KeyboardInterrupt:
pass
if __name__ == "__main__":
bus = can.Bus()
# msg = bus.recv(1)
# print(msg)
receive_all()
Filtering
可以为每条总线设置消息过滤。在接口支持它的地方,这是在硬件或内核层中执行的,而不是在Python中。将返回与至少一个筛选器匹配的所有消息。
下面是两个过滤器的示例,一个通过11位ID 0x451,另一个通过29位ID 0xA0000:
filters = [
{"can_id": 0x451, "can_mask": 0x7FF, "extended": False},
{"can_id": 0xA0000, "can_mask": 0x1FFFFFFF, "extended": True},
]
bus = can.interface.Bus(channel="can0", interface="socketcan", can_filters=filters)
Bus API
can.Bus(channel=None, interface=None, config_context=None, ignore_config=False, **kwargs)
参数:
- channel(str|int|None)–通道标识。所需的类型依赖于后端。设置为“无”可使其从默认配置中自动解析。
- interface(str|None)–有关支持的接口列表,可以查看上一篇配置文章Python-can库的使用(2)——配置。设置为“无”可使其从默认配置中自动解析。
- config_context(str|None)–传递给配置源的额外“context”。这可用于在配置文件中选择“默认”以外的节。
- ignore_config(bool)–如果为True,则只有给定的参数将用于总线实例化。现有配置源将被忽略。
- kwargs(Any)–接口特定的关键字参数。
RAISES:
- CanInterfaceNotImplementedError–如果接口无法识别或无法加载
- CanInitializationError–如果总线无法实例化
- ValueError–如果无法确定通道
🎈如果文章对您有帮助,您可以“点赞、收藏、关注”,这也是我创作动力的源泉🎈
💘感谢支持💘