python-can
python-can provides a consistent Python API for sending, receiving, filtering and logging CAN and CAN FD frames on Windows and Linux.
Supported Interfaces
Common backends include:
socketcanfor Linux SocketCAN interfaces such ascan0pcanfor PCAN devices and compatible CANmeleon applications on Windows- Other vendor backends listed in the python-can interface documentation
Prepare the Environment
Linux SocketCAN
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
ip -details link show can0For CAN FD:
sudo ip link set can0 down
sudo ip link set can0 type can bitrate 1000000 dbitrate 5000000 fd on
sudo ip link set can0 upWindows
Install the device driver or the required CANmeleon protocol application before opening the adapter from Python.
Install python-can
python -m pip install python-canQuick Start
import can
# Windows PCAN-compatible interface
bus = can.Bus(interface="pcan", channel="PCAN_USBBUS1", bitrate=500000)
# For Linux, use:
# bus = can.Bus(interface="socketcan", channel="can0")
message = can.Message(
arbitration_id=0x123,
data=[0x11, 0x22, 0x33, 0x44],
is_extended_id=False,
)
bus.send(message)
received = bus.recv(timeout=2.0)
print(received)
bus.shutdown()Create a Bus Object
import can
def open_socketcan(channel="can0"):
return can.Bus(interface="socketcan", channel=channel)
def open_pcan(channel="PCAN_USBBUS1", bitrate=500000):
return can.Bus(
interface="pcan",
channel=channel,
bitrate=bitrate,
)The exact arguments depend on the selected backend. SocketCAN timing is normally configured with the Linux ip command before Python opens the interface.
CAN Messages
import can
# Standard 11-bit ID
standard = can.Message(
arbitration_id=0x123,
data=[1, 2, 3, 4],
is_extended_id=False,
)
# Extended 29-bit ID
extended = can.Message(
arbitration_id=0x18FF50E5,
data=[0x10, 0x20],
is_extended_id=True,
)
# Remote frame
remote = can.Message(
arbitration_id=0x321,
is_remote_frame=True,
dlc=8,
is_extended_id=False,
)Send CAN and CAN FD Frames
def send_classical(bus):
msg = can.Message(
arbitration_id=0x123,
data=[0x11, 0x22, 0x33, 0x44],
is_extended_id=False,
)
bus.send(msg, timeout=1.0)
def send_can_fd(bus):
msg = can.Message(
arbitration_id=0x456,
data=bytes(range(32)),
is_fd=True,
bitrate_switch=True,
is_extended_id=False,
)
bus.send(msg, timeout=1.0)The interface must be opened in CAN FD mode before sending FD frames. On SocketCAN, configure fd on; vendor backends may require an fd=True option or a timing string.
Periodic Transmission
import time
import can
msg = can.Message(
arbitration_id=0x100,
data=[0, 1, 2, 3, 4, 5, 6, 7],
is_extended_id=False,
)
task = bus.send_periodic(msg, period=0.1)
time.sleep(5)
task.stop()Receive Frames
Blocking Receive
while True:
msg = bus.recv(timeout=1.0)
if msg is not None:
print(f"{msg.timestamp:.6f} {msg.channel} {msg.arbitration_id:X} {msg.data.hex()}")Asynchronous Notification
import can
class Printer(can.Listener):
def on_message_received(self, msg):
print(msg)
listener = Printer()
notifier = can.Notifier(bus, [listener])
# Stop before closing the application:
# notifier.stop()
# bus.shutdown()Filters
filters = [
{"can_id": 0x123, "can_mask": 0x7FF, "extended": False},
{"can_id": 0x456, "can_mask": 0x7FF, "extended": False},
]
bus.set_filters(filters)Filters reduce unwanted traffic. Whether filtering is performed in hardware, the driver or Python depends on the backend.
Logging and Playback
import can
logger = can.Logger("capture.asc")
notifier = can.Notifier(bus, [logger])
# ... collect frames ...
notifier.stop()
logger.stop()python-can supports several log formats. Select the filename extension appropriate for the intended reader or playback workflow.
Troubleshooting
- Interface not found: verify the driver and channel name. On Linux, run
ip link show. - Permission denied: run with appropriate CAN-device permissions; avoid using elevated privileges as a permanent application design.
- No received frames: check CAN_H / CAN_L, ground, bit rate, sample point and termination.
- Bus-Off: stop transmission, correct the physical or timing problem, then reset the interface.
- CAN FD send fails: confirm that both the interface and target network use CAN FD and matching ISO / Non-ISO and data-phase timing.
Enable library diagnostics when needed:
import logging
logging.basicConfig(level=logging.DEBUG)