Home Can Bus Communication using Python
Post
Cancel

Can Bus Communication using Python

Introduction

This article is an installation and use case guide for communicating with can devices using python. For this article I am focussing on using the PCAN-USB usb-to-can hardware, but follow the link to see if your hardware is supported - python-can interfaces.

Install free commercial tools and drivers

We will first install the peak can drivers and a free software to view the can messages PCAN-View. Next install candb++ which lets you open, view and create dbc files.

Desktop View

Python Libraries Installation

The first library is python-can. The python-can library provides Controller Area Network support for Python, providing common abstractions to different hardware devices, and a suite of utilities for sending and receiving messages on a CAN bus. It can use pywin32 extension to run faster using windowsAPI.

To install perform the following from inside your development venv:

1
2
3
pip install python-can
pip install python-can[pcan]
python -m pip install --upgrade pywin32

Then you have to run the post-install script for pywin32 from OUTSIDE of the venv AND with admin rights. Open a command window as administrator and execute the following

1
2
3

python [venv root folder path]\Scripts\pywin32_postinstall.py -install

The other important library to install specially using DBC files (CAN database file) is to install cantools library. Run this from within your venv.

1
pip install cantools

You are all set !

How to communicate via can

Below is a simple script from the documentation on how to send a simple packet using pcan and configure bus for a specific bitrate 12.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import can

with can.interface.Bus(interface='pcan', bitrate=250000) as bus:
    msg = can.Message(
        arbitration_id=0xC0FFEE,
        data=[0, 25, 0, 1, 3, 1, 4, 1],
        is_extended_id=True
    )
    try:
        bus.send(msg)
        print(f"Message sent on {bus.channel_info}")
    except can.CanError:
        print("Message NOT sent")


However, this is quite difficult as you have to set all the individual bytes in a packet manually. A better option is to use the cantools package. Here is an example from the cantools docs where ExampleMessage has an address of 0x1f0 and within the 8 bytes Temperature and AverageRadius are data as shown in the screenshot of the candb++ tool.

Desktop View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import can
import cantools
from pprint import pprint

db = cantools.database.load_file('tests/files/dbc/motohawk.dbc')
pprint(db.messages)
example_message = db.get_message_by_name('ExampleMessage')
pprint(example_message.signals)

can_bus = can.interface.Bus(interface='pcan', bitrate=250000)
data = example_message.encode({'Temperature': 250.1, 'AverageRadius': 3.2, 'Enable': 1})
message = can.Message(arbitration_id=example_message.frame_id, data=data)
can_bus.send(message)

The pprint output is shown below

1
2
3
4
5
6
7

[message('ExampleMessage', 0x1f0, False, 8, 'Example message used as template in MotoHawk models.')]


[signal('Enable', 7, 1, 'big_endian', False, 1.0, 0, 0.0, 0.0, '-', False, None, {0: 'Disabled', 1: 'Enabled'}, None),
 signal('AverageRadius', 6, 6, 'big_endian', False, 0.1, 0, 0.0, 5.0, 'm', False, None, None, ''),
 signal('Temperature', 0, 12, 'big_endian', True, 0.01, 250, 229.53, 270.47, 'degK', False, None, None, None)]

Important Gotcha for Displaying encoded Data

The data encoded by cantools when printed is shown as a series of hex bytes except if the data can be displayed as a valid ascii character3. This can sometimes create confusion that perhaps the data didn’t get encoded correctly.

1
2
3
4
5
6
>>data
b' \x00\x00\x00\x00\x00\x00\x00'

>>data.hex()
'2000000000000000'

In the above example, 0x20 has an equivalent ascii character of space 4 and therefore displayed with a space. The best way to prevent confusion is to use .hex() method to display the hex values.

References

This post is licensed under CC BY 4.0 by the author.

Oscilloscope Passive Probes

VPN in WSL2