The first tutorial does not require any programming. We will use the CANopen control tool to create CANopen master and slave processes that communicate over a virtual CAN bus. No CAN hardware is required; instead, we will use the virtual CAN interface provided by SocketCAN.
Note: Using SocketCAN means this tutorial only works on Linux.
Virtual CAN interface
Make sure the virtual CAN driver is loaded:
sudo modprobe vcan
and create a virtual CAN network interface with the name
sudo ip link add dev vcan0 type vcan sudo ip link set up vcan0
You can check that the interface was created by running
ip link show vcan0
This should output something like
3: vcan0: <NOARP,UP,LOWER_UP> mtu 72 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/can
To monitor the CAN traffic in this tutorial, run
in a terminal window and keep it open. You can also capture the traffic from
vcan0 with Wireshark.
A single device
Every CANopen device, including the mock master and slave in this tutorial, has an object dictionary. The layout and content of this object dictionary is described in an electronic data sheet (EDS) or device configuration file (DCF).
“EDS” and “DCF” tend to be used interchangeably. Technically speaking, an EDS describes a certain type of device, while a DCF describes an individual device, including unique values such as a serial number. But most tools and parsers do not make a distinction.
Open a terminal and create a virtual CANopen device with the default DCF for the CANopen control tool:
coctl vcan0 /etc/coctl.dcf
Note: If you installed Lely CANopen from source,
coctl.dcf might be in a
different directory, such as
Initialize the device (input is shown beginning with
>, output with
>  set network 1 # Set the default network-ID, so it can be omitted. <  OK >  set id 1 # Set the node-ID of this device to 1. <  OK >  init 0 # Initialize the device, and configure the CAN bus with >  # with a bit rate of 1000 kbit/s. < coctl: error: unable to set bitrate of vcan0 to 1000000 bit/s < coctl: NMT: entering reset application state < coctl: NMT: entering reset communication state < coctl: NMT: running as master < coctl: NMT: entering pre-operational state < coctl: NMT: entering operational state <  OK
vcan driver does not support changing the bitrate. This is an error you
can safely ignore.
The terminal running
candump shows two new lines:
vcan0 701  00 vcan0 000  82 00
The first line is the boot-up message from our device. Heartbeat and boot-up
messages always have CAN-ID
0x700+$NODEID and a single-byte payload with the
00 indicates the device just rebooted.
The second line is there because our device is configured as a CANopen master;
it sent the network management (NMT) command (CAN-ID
82) to all nodes (
00) the moment it went operational. If
other nodes where present, this command would be followed by their boot-up
Adding a slave
Download cmd-slave.dcf, open a terminal in the directory where you stored the file and run
coctl vcan0 ./cmd-slave.dcf
Initialize the slave with node-ID 2:
>  set network 1 <  OK >  set id 2 <  OK >  init 0 < coctl: error: unable to set bitrate of vcan0 to 1000000 bit/s < coctl: NMT: entering reset application state < coctl: NMT: entering reset communication state < coctl: NMT: running as slave < coctl: NMT: entering pre-operational state < coctl: NMT: entering operational state <  OK
candump shows a new line with the boot-up message:
vcan0 702  00
The boot-up message is detected by the master, which you can see by pressing
<Enter> in the terminal of the first device:
>  < 1 2 BOOT_UP < 1 2 USER BOOT A (The CANopen device is not listed in object 1F81.)
Neither the master or the slave are configured to produce heartbeat messages. From the master we can configure the heartbeat producer on the slave (node-ID 2) by using a service data object (SDO) request to write the number of milliseconds (as a 16-bit unsigned integer) to object 1017 sub-index 0 (Producer heartbeat time):
>  2 write 0x1017 0 u16 1000 <  OK
The SDO request shows up in the
candump output as two lines:
vcan0 602  2B 17 10 00 E8 03 00 00 vcan0 582  60 17 10 00 00 00 00 00
The first frame is the expedited SDO download (= write) request from the master. Because the value (0x03e8 = 1000) is smaller than 4 bytes, the entire request fits in a single frame. The second frame is the response from the slave, acknowledging that the value was written to the object dictionary.
From now on,
candump shows the following frame every second:
vcan0 702  05
05 means the slave is in the NMT state “operational”.
We can also read the value back from the master:
>  2 read 0x1017 0 u16 <  0x03e8
candump shows the request and reponse:
vcan0 602  40 17 10 00 00 00 00 00 vcan0 582  4B 17 10 00 E8 03 00 00
CANopen nodes are uniquely identified by a combination of four 32-bit numbers: the vendor-ID, product code, revision number and serial number. The identity values are stored in object 1018 sub-index 1-4, respectively:
>  2 r 0x1018 1 u32 <  0x00000360 >  2 r 0x1018 2 u32 <  0x00000000 >  2 r 0x1018 3 u32 <  0x00000000 >  2 r 0x1018 4 u32 <  0x00000000
The vendor-ID is 0x360 (registered by Lely Industries N.V.) and the product code, revision number and serial number are all 0.
If we don’t know the node-ID of a slave (or it is unconfigured), we can discover it by using the layer setting services (LSS).
The following (Lely-specific) command scans the network for nodes:
>  _lss_fastscan 0 0 0 0 0 0 0 0
The eight zeros are our initial guesses for the four identity values and the masks specifying which bits are already known (in this case none).
For every one of the 128 bits, the master sends a request (CAN-ID
if there is a node which matches the current (masked) value, first trying 0,
then 1. It waits for 100 ms for one or more nodes to reply (CAN-ID
most of the bits are zero for our slave, the scan takes a little over 13
The result is
<  0x00000360 0x00000000 0x00000000 0x00000000
which matches the values obtained earlier.
There also exists an
_lss_slowscan method for devices that don’t support the
LSS Fastscan service. It requires the user to provide the vendor-ID and product
code, and a range of revision numbers and serial numbers. It then uses a binary
search to narrow down those last two numbers.
Changing the node-ID
The node we just identified is now in the “configuration” state and will respond to LSS configuration requests. Any other node in the network will ignore those requests since it is still in the “waiting” state.
We can ask for the node-ID:
>  lss_get_node <  2
and even change it:
>  lss_set_node 3 >  OK
But this does not yet have any effect:
>  lss_get_node <  2
The new node-ID is still “pending”. First, switch the node back to the “waiting” state:
>  lss_switch_glob 0 <  OK
Further LSS configuration requests will now fail:
>  lss_get_node >  ERROR: 103 (Time-out)
Normally we would first use
lss_store to request the node to store the new
node-ID to non-volatile memory so it survives a reboot, but the virtual slave
created by the CANopen control tool does not support this.
To activate the new node-ID, we issue the NMT “reset communication” command to node 2:
>  2 reset comm <  OK < 1 3 BOOT_UP < 1 3 USER BOOT A (The CANopen device is not listed in object 1F81.)
and receive a boot-up message from node 3:
vcan0 000  82 02 vcan0 703  00
Note that the slave is no longer sending heartbeat messages. The “reset communication” command caused objects 1000..1FFF, which includes 1017 (Producer heartbeat time), to be reset to their default values.
Sending and receiving PDOs
During normal operation, real-time data transfer between nodes is performed by means of the process data object (PDO) service. The transmission of a PDO can be event-driven or synchronous. In the latter case, the master periodically sends a synchronization object (SYNC) to trigger the transmission, reception and processing of PDOs.
To start transmitting SYNC messages, write the period between messages (in µs) to object 1006 sub-index 0 (Communication cycle period) in the local object dictionary of the master:
>  1 w 0x1006 0 u32 1000000 <  OK
From now on, the following message shows up every second:
vcan0 080 
No PDOs are sent after the SYNC, because they have not been configured yet.
Go to the terminal running the CANopen control tool for the slave and configure a Transmit-PDO (TPDO) with
>  set tpdo 1 0x183 sync1 1 0x2007 0 u32 <  OK
This tells the slave to create the first TPDO (
1), with the default CAN-ID
0x180+$NODEID), that is sent on every SYNC (
sync1) and contains a single
1). The object mapped into the PDO is 0x2007 sub-index 0, which is a
32-bit unsigned integer (
Once the TPDO is configured, it is sent after every SYNC:
vcan0 080  vcan0 183  00 00 00 00
To see that it really contains the mapped object, change the value of object 2007 in the local object dictionary:
>  3 w 0x2007 0 u32 0x12345678 <  OK
Starting with the next SYNC, the new value appears in the payload of the CAN frame (in little-endian):
vcan0 080  vcan0 183  78 56 34 12
Although a PDO is now sent on every SYNC, it is not yet received, because no node has configured a corresponding Receive-PDO (RPDO).
Go back to the terminal running the CANopen control tool for the master and configure the first RPDO with
>  set rpdo 1 0x183 sync1 1 0x2007 0 u32 <  OK
The parameters are the same as for the TPDO on the slave. The CAN-ID and
transmission type must be equal, but the object mapping only has to be
compatible. However, in this case the master also happens to have an object in
the local object dictionary with index 2007, sub-index 0 and type
u32, so the
mapping is equal as well.
You can check that the master is now receiving the PDOs by pressing
>  < 1 pdo 1 1 0x12345678 < ...
and that it stores the value of the PDO in the local object dictionary:
>  1 r 0x2007 0 u32 < 1 pdo 1 1 0x12345678 < ... <  0x12345678
That concludes the command-line tutorial.