CANopen

CANopen is a specific protocol built on top of CAN bus, widely used to coordinate simple field devices - drives, I/O modules, sensors - that share a single bus. The CANopen specification defines an Object Dictionary (OD), and this driver honors that structure through index and sub-index addressing of fields. It does not ship an Electronic Data Sheet (EDS) parser, leaving that to applications that wish to utilize one.
Supported Operations
Name Value Description
CANopen SDO
read / write
SDO are request/response conversations. Both read and write path is supported.
CANopen PDO
write
PDO messages are broadcasted to the bus and have to be mapped at application layer.
subscribe
- Receiving PDO messages requires construction of valid subscription.
- It is possible to subscribe to CANopen NMT and HEARTBEAT messages.
Connection String
The connection string layout is canopen:<transport-code>://<transport-address>.
canopen:can-socketcan://can0canopen:can-virtualcan://test
The interface and the bus name can also be given as options - can-socketcan.interface-name and can-virtualcan.bus-name - for callers that assemble a connection string out of options alone. The address segment wins if both name one.
Connection String Options
Name
Type
Default Value
Required
Description
Name
CANopen
Code
canopen
Maven Dependency
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-canopen</artifactId>
<version>1.0.0</version>
</dependency>Default Transport
can-socketcan
Supported Transports
can-socketcancan-virtualcan
Config options:
node-id
INT
CAN node identifier. Depending on used CAN version it might be 11 or 29 bit unsigned int.
request-timeout-ms
INT
1000
Time after which dispatched BUS operation (ie. SDO request) will be marked as failed.
Transport config options:
can-socketcan
can-socketcan.interface-name
STRING
Linux CAN interface name (e.g., "can0", "vcan0"). Alternative to naming the interface in the address segment of the connection string, which takes precedence.
can-socketcan.reuse-interface
BOOLEAN
false
Share CAN socket across multiple transport instances on the same interface
can-socketcan.read-timeout-ms
INT
1000
Read timeout in milliseconds for blocking reads on the CAN socket
can-socketcan.filter-ids
STRING
Comma-separated list of accepted CAN IDs (decimal or 0x hex). Empty means accept all.
can-socketcan.filter-range-start
INT
-1
Start of accepted CAN ID range (inclusive). -1 means no range filtering.
can-socketcan.filter-range-end
INT
-1
End of accepted CAN ID range (inclusive). -1 means no range filtering.
can-virtualcan
can-virtualcan.bus-name
STRING
default
Name of the virtual CAN bus. Instances on the same bus exchange frames in-memory.
can-virtualcan.filter-ids
STRING
Comma-separated list of accepted CAN IDs (decimal or 0x hex). Empty means accept all.
can-virtualcan.filter-range-start
INT
-1
Start of accepted CAN ID range (inclusive). -1 means no range filtering.
can-virtualcan.filter-range-end
INT
-1
End of accepted CAN ID range (inclusive). -1 means no range filtering.
Tag Addresses
Addressing is implemented in Java. See the protocol support matrix for what each implementation does.
General Format
CANopen specification defines several groups of addresses dedicated to certain kind of operations. Critical services and message exchanges related with them have lower identifiers making them wining eventual bus access.
SDO addresses request/response reads and writes against a single Object Dictionary entry: SDO:nodeId:index/subindex:type[arraySize]. Both expedited and segmented transfer modes are supported, chosen automatically based on payload length; block transfer is not supported. All numeric values - nodeId, index, subindex - can be specified using hexadecimal notation (ie. 0xA). An optional /answerNodeId after the node ID lets the response be expected from a different node than the request was sent to.
PDO addresses identify one of the four transmit or receive PDO channels of a node: TRANSMIT_PDO_1:nodeId:type[arraySize] through RECEIVE_PDO_4:nodeId:type[arraySize]. PDO is an asynchronous broadcast, so receiving it requires a subscription; a subscriber is notified with the value mapped to the type given in the address.
NMT addresses target the Network Management service, which is broadcast using CAN node ID 0 and carries the highest priority on the bus. The syntax is NMT or NMT:nodeId; omitting the node ID (or using 0) is a wildcard that subscribes to state updates for all bus participants. A subscription receives a structure with two fields, node (USINT) and state (USINT). Writable values indicate the requested NMT state and are supplied as USINT: 0x01 START, 0x02 STOP, 0x80 PRE_OPERATIONAL, 0x81 RESET_NODE, 0x82 RESET_COMMUNICATION. The NMTStateRequest enumeration can be used on the application side instead of the plain numbers.
Heartbeat addresses subscribe to the lowest-priority service on the bus, which still indicates a node’s operating state (booted, operational). The syntax is HEARTBEAT or HEARTBEAT:nodeId; as with NMT, omitting the node ID (or using 0) subscribes to all bus participants. A subscription receives the same two-field structure as NMT: node (USINT) and state (USINT).
Data Types
CANopen defines its own set of data types, which this driver maps onto PLC4X types as follows:
| CANopen Type | Length (in bits) | PLC4X Type |
|---|---|---|
| BOOLEAN | 1 | BOOL |
| UNSIGNED8 | 8 | USINT |
| UNSIGNED16 | 16 | UINT |
| UNSIGNED24 | 24 | UDINT |
| UNSIGNED32 | 32 | UDINT |
| UNSIGNED40 | 40 | ULINT |
| UNSIGNED48 | 48 | ULINT |
| UNSIGNED56 | 56 | ULINT |
| UNSIGNED64 | 64 | ULINT |
| INTEGER8 | 8 | SINT |
| INTEGER16 | 16 | INT |
| INTEGER24 | 24 | DINT |
| INTEGER32 | 32 | DINT |
| INTEGER40 | 40 | LINT |
| INTEGER48 | 48 | LINT |
| INTEGER56 | 56 | LINT |
| INTEGER64 | 64 | LINT |
| REAL32 | 32 | REAL |
| REAL64 | 64 | LREAL |
| RECORD | 8 * size | BYTE |
| OCTET_STRING | 8 * size | STRING (UTF-8) |
| VISIBLE_STRING | 8 * size | STRING (UTF-8) |
| TIME_OF_DAY | unsupported | |
| TIME_DIFFERENCE | unsupported | |
| UNICODE_STRING | 8 * size | STRING (UTF-8) |
All string types are decoded using UTF-8 encoding regardless of their kind (octet, visible, unicode). In case a device returns text using a different encoding, it is recommended to use the RECORD type and construct the text manually above PLC4X.
The size of variable-length structures is automatically assumed to be the full length of the SDO answer. When writing, the length of the field can be omitted; for example write(SDO:1:2/3:RECORD, payload) will try to write the whole payload to the specified address. The same applies to responses sent by devices, as the requester often does not know the full length of the reply payload beforehand.
Examples
SDO:20:0x10/0xAA:RECORD- read/write the object at index0x10, sub-index0xAAon node 20 as aRECORD.SDO:20/22:0x10/0xAA:RECORD- same object, but the response is expected from node 22 instead of node 20.SDO:20:0x30/40:BOOLEAN- object at index0x30, sub-index40(decimal) on node 20, as aBOOLEAN.RECEIVE_PDO_2:20:RECORD- the second receive PDO of node 20, mapped as aRECORD.NMT:20- subscribe to or write NMT state changes of node 20.NMT- subscribe to NMT state changes of every node on the bus (wildcard).HEARTBEAT- subscribe to heartbeat messages of every node on the bus (wildcard).
Protocol Details
CAN, despite (or due) to its popularity has ambiguous meaning. There are multiple articles and sources which attempts to give introduction, yet very few of them is consistent between each other.
There are two dominant formats of frames - CAN 2.0A and 2.0B:
- CAN 2.0A uses 11 bit identifier and up to 8 bytes of data.
- CAN 2.0B uses 29 bit identifier and up to 8 bytes of data.
To make things worse with introduction of CAN FD amount of combinations increased even more. Double check frame format as this integration supports CANopen and does not support CANopen FD nor CAN 2.0B.
Further reading on CAN flavors: https://en.wikipedia.org/wiki/CAN_bus
Default transport used with this protocol is socketcan. Currently, only 2.0A format (up to 8 bytes of data) is supported.
Implemented driver supports currently socketcan transport. Change of transport requires code modifications and injection of new "transport" type which will encode CANopen payloads to specific frame format.
Socketcan seems to be most widespread way to access CAN bus. It also masks different hardware variants which might come with their own drivers.
评论
登录后参与评论
KnowForge