Python-can库的使用(3)——API库之Bus

🙆‍♂️我是纯良思安,爱技术、爱分享,更爱生活🙆‍♂️

💖喜欢的朋友可以关注一下,下次更新不迷路💖


目录

前言

Bus

Transmitting

Receiving

Filtering

Bus API


前言

介绍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–如果无法确定通道

🎈如果文章对您有帮助,您可以“点赞、收藏、关注”,这也是我创作动力的源泉🎈
💘感谢支持💘

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值