canopen-rpi
canopen-rpi copied to clipboard
CANopen nodes and services implemented in Python 3 for a Rasbperry Pi
About
This repository contains a Python module used for instantiating CANopen nodes in Linux, especially for a Raspberry Pi. The socketcanopen module contains classes to instantiate a CANopen node application. This module now requires the can module, replacing the original socketcan module. Each node must be initialized with at least one can.BusABC instance, a node-ID (integer, 1 to 127), and a socketcanopen.ObjectDictionary instance.
Node Applications
Example node applications are provided:
canopen-node-sdo.pyis the simplest implentation of a node that supports SDO communication.canopen-node-sdo-normal.pyhas object dictionary entries with values greater than 4 bytes to demonstrate normal (non-expedited) SDO.canopen-node-eds.pyimports the CANopen object dictionary from an EDS file (node.eds).canopen-node-pdo.pyadds synchronous PDO support.canopen-master.pyis a complex example of a CANopen Master that involves using GPIOs and how to interact with changes to the object dictionary.
systemd .service unit files and instructions for starting the node applications at boot are also provided.
Protocol Adaptors
Example protocol adaptors are provided: Note that these are very crude and do not provide buffering.
- CANopen-to-HTTP (
canopen-http.py, implementation of CiA 309-5) - CAN-to-WebSocket (
websocketcan-server.py, uses SocketCAN message structure;websocketcan.jsandwebsocketcanopen.jsprovide wrappers to JavaScript's WebSocket, which can be used to decode messages in client browser)
Raspberry Pi Setup
Install and Configure Raspbian
-
Install the latest version of Raspbian.
-
(Optional) Because of a driver issue, you may need to add
dtoverlay=mmcto/boot/config.txtfor the Raspberry Pi to boot. -
(Optional) Run
sudo raspi-configand adjust internationalization options. -
(Optional) Prevent flash memory corruption:
-
Change
/etc/fstabto:proc /proc proc defaults 0 0 /dev/mmcblk0p1 /boot vfat ro,noatime 0 2 /dev/mmcblk0p2 / ext4 defaults,noatime 0 1 none /var/log tmpfs size=1M,noatime 0 0 -
Disable swap memory:
sudo dphys-swapfile swapoff sudo dphys-swapfile uninstall sudo update-rc.d dphys-swapfile remove -
Reboot:
sudo reboot
-
Add CAN Support
-
Connect MCP2515 circuit(s) to the Raspberry Pi
SPI0bus. Interrupt GPIOs are defined in step 4. -
If necessary, enable writable boot partition:
sudo mount -o remount,rw /dev/mmcblk0p1 /boot -
Run
sudo raspi-config- Interfacing Options
- SPI: Enable/Disable automatic loading (Yes)
- Interfacing Options
-
Configure SPI Module: Change
/boot/config.txtto:dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=24 dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25Note: It appears the order of the mcp2515-can* overlay determines which SPI CE is used (first listing gets spi0.1/CE1, second listing get spi0.0/CE0), even though the documentation says otherwise. See https://github.com/raspberrypi/linux/issues/1490 for more info.
Note: The
oscillatorandinterruptparameters may be different for your application. -
Reboot to enable the MCP2515 drivers.
-
Setup CAN interfaces
- Manual
sudo ip link set can0 up type can bitrate 1000000 sudo ip link set can1 up type can bitrate 1000000- Automatic (start at boot-up)
- Copy can_if to
/home/pi/(or change location incan_if.service - Modify
can_iflineCAN_IF=""toCAN_IF="can0@1000000,2000 can1@1000000,2000"(may vary per application) - Set
can_ifto be globally executable (chmod +x can_if) - Copy
can_if.serviceto/etc/systemd/system/ sudo systemctl daemon-reloadsudo systemctl enable can_if.servicesudo rebootorsudo systemctl start can_if.service
- Copy can_if to
-
(Optional) Install
can-utilsfor debuggingsudo apt install can-utils
Library Usage
Installation
git clone https://github.com/bggardner/canopen-rpi.gitcd canopen-rpipip3 install -e .
Examples
Many examples are provided. The simplest code is when using an EDS file:
#!/usr/bin/env python3
import can
import signal
import socketcanopen
can_bus = can.Bus("vcan0", bustype="socketcan")
node_id = 0x02
canopen_od = socketcanopen.ObjectDictionary.from_eds(os.path.dirname(os.path.abspath(__file__)) + '/node.eds', node_id)
node = socketcanopen.Node(can_bus, node_idd, canopen_od)
signal.pause() # Run forever
Example: Configure as CANopen Master with CAN-to-HTTP Adapter on Boot
-
Setup CANopen Master
- Copy canopen-master.py to
/home/pi/ - Copy canopen-master.service to
/etc/systemd/service/and configure withsystemctllikecan_if.serviceabove
- Copy canopen-master.py to
-
Setup CAN-to-WebSocket Adapter
- Copy websocketcan-server.py to
/home/pi/ - Copy websocketcan-server.service to
/etc/systemd/service/and configure withsystemctllikecan_if.serviceabove
- Copy websocketcan-server.py to