A Controller Area Network, or CAN for short is a common message based protocol used in cars and other vehicles. If you are trying to interface with a car/truck/bulldozer, there is a good chance that you will be reading data its CAN bus, and sending it commands via its CAN bus. It is also used in industrial/robotic applications such as motor control (Elmo, Copley, etc..). While there is no standard way of wiring a CAN bus there are two wires/signals you will always see (should be a twisted cable pair), and another two that you will often see. The first two are CAN+ (or CAN_H) and CAN- (or CAN_L) which are used for sending the CAN data. The next two wires are for power and ground that can be used by the attached devices. Many implementation will just have the ground wire and not the power wire. One reason CAN is popular is for its excellent noise immunity, from using the + and – differential pair. You can typically wire all of your CAN devices in series creating a large bus of devices. The first and last device must terminate the CAN bus by putting a 120ohm resistor between the CAN+ and CAN- lines. Some signs of improper termination are lots of CAN errors on the bus, especially at higher data rates. Some devices are designed to be at the end of a bus or the only item on a bus and will not need external termination (since they have built-in termination resistors).
Tip: Reminder if you measure a working CAN bus you will see 60 ohms and not 120. Remember 2 resistors in parallel!
CAN is a data link level protocol (remember the OSI model??), on top of it can sit higher level protocols for defining how data actually gets sent. A common higher level protocol is called CANopen. CANopen builds up from the data link layer where CAN ends, all the way up to the application layer. It defines addressing schemes and some basic packet types that can be used. In order to define how the basic packet types work there are standard profiles that can be used. The profiles that we are typically interested in were standardized by the CAN in Automation group (CiA). Some of the common CiA standards that we use are:
DS 301 – Basic communication profile for motor controllers
DS 302 – Framework for programmable devices.
DS 305 – Layer setting services, for configuring CAN node parameters such as baud rate and ID to new devices.
DSP 402 – For setting device profiles
Most of this post is about CiA DS 301.
Typically (in robotics) each CAN network will have one “master” node which is typically a computer or micro-controller that requests information or listens for alerts/emergencies from all of the CAN devices on the network.
Each CANopen device will have an internal state machine and an object dictionary (OD). The state machine has states defined such as initialization, operational, and stopped. The object dictionary is a list of the commands that can be sent to the device. Each “object” can be thought of as an index into a large configuration array (not technically true, but is good for understanding the object dictionary). Each object can also have sub-objects (think of a multi-dimensional array).
CANopen is little endian (ie. starts with the LSB). So for example if you have the number 0x1234ABCD, it would be put into a CANopen message as CD AB 34 12. I know it gets confusing (at least for me).
There are several different types of messages defined within CANopen. Each one is a communication object (COB).
|Network Management (NMT)||0b0000||NMT messages are used to control the state of the CAN bus and can be used to start, stop, and reset things. NMT messages are typically broadcast to all devices on the network.|
|Synchronization Object (SYNC)||0b0001||Produces a signal so multiple sensors can start doing something (such as publish data) at the same time.|
|Timestamp Object (TIME)||0b0010||Publishes the time. Typically with a 1us resolution. A timestamp usually refers to the SYNC message that was just published.|
|Emergency Object (EMCY)||0b0001||Emergency messages are a way of sending out a message that has a higher priority than other messages. As the name says, they are used for emergency and error conditions. EMCY messages are the only messages a device may send out without someone requesting it or configuring it to be sent out.|
|Service Data Object (SDO)||TSDO-0b1011
|SDO messages come in 2 varieties; transmit (TSDO) and receive (RSDO). TSDO’s are sent from the device (ie motor driver) and RSDO’s are received by the device. SDO’s are used to configure the values from the OD. SDO’s can be used to configure the PDO’s and create PDO mappings (see below) and have a lower priority then PDO messages.|
|Process Data Object (PDO)||TPDO-0b0011,0101,0111,1001
|PDO messages come in 2 varieties; transmit (TPDO) and receive (RPDO). TPDO’s are sent from the device (ie motor driver) and RPDO’s are received by the device. Each device will typically have multiple PDO’s (often 4). Using an SDO you can configure PDO mappings. A PDO mapping defines what each PDO will be used for. An example could be every time a sync pulse is received by an RPDO (or limit, or encoder, etc..) a data value should be sent out using a TPDO.|
Once you know which message type you need to send out, it is time to assemble the full CANopen message. The CANopen message has several parts as shown below.
|Length:||11 bits||1 bit||4 bits||0-8 bytes(based on length field)|
* Often not used for anything. It could be used if a device needs to request data from a master.
** for SDO messages it must be a length of 8. The data field gets padded with 0’s accordingly.
Each CAN device has a unique ID from 1-127 (there is an extended addressing mode that allows for more devices but it is rarely used). The ID of 0 is reserved as a broadcast address to all nodes in the CANopen network. To form the COB-ID field we need to combine the COB (from the message type table above) with the ID of the nodes. To do that we combine the 4 bit COB with the 7 bit ID to form the full 11 bit field. For example if an EMCY (0b0001) message was being sent out from node 2 (0b0000010) the full COB-ID would be 0b00010000010 (or 0x82).
On some processors if you are implementing CANOpen control on a CAN network you will need to create “mailboxes” (part of configuring the CAN bus) for each COB-ID. So if your CAN implementation has 20 “mailboxes” you can send and receive up to 20 different COB-ID’s (each of a given length). For example with a TI Hercules processor you need to you the HALCOGEN tool to configure mailboxes. In each mailbox you specify the COB-ID, length of packet and a mask (you generally wont touch the mask). Then in your software when you want to send that message you just specify the mailbox to use (and CAN device if you have multiple) and the array of data you wish to send.
As mentioned before CANopen is little endian. So if you have the following in your data field
Bytes 0-1: 0x1234
Bytes 2-3: 0x5678
Bytes 4-8: 0x9abcdef0
The CAN message data would be (in hex): (byte 0) 34 12 78 56 f0 de bc 9a (byte 8)
Some random notes:
– Always listen to a response from a device
– Do not send the next command until you receive said response.
– When figuring out your maximum rate remember to include the responses. For example if your bus rate is 500Hz, you can send out 250 messages per second. This can be important if you are getting back data from multiple devices at high rate.
– Respect the inhibit time. This is the maximum time that you can transmit the same data onto the CAN bus. This is to prevent the bus from becoming flooded with messages.
Most of my CAN experience comes from working with Elmo motor controllers, so I will be using examples from Elmo using their OD.
Setting a TPDO to send data based on a digital IO line changing value
// NMT Reset
0x000 0x81 0x00
usleep(1000) // Allow some time to change state after NMT message
// Start all devices on the network
0x000 0x01 0x00
usleep(100) // Allow some time to change state after NMT message
//DeviceID = 1
// Stop TPDO4
0x601 0x22 0x03 0x1a 0x00 0x00 0x00 0x00 0x00
// Set TPDO3 trigger 254
0x601 0x22 0x03 0x18 0x02 0xFE 0x00 0x00 0x00
// Set digital input event
0x601 0x22 0x20 0x2f 0x04 0x80 0x00 0x00 0x00
// Set input mask
0x601 0x22 0x23 0x2f 0x00 0x0f 0x03 0x00 0x00
// Map 0x6064 = PX
0x601 0x22 0x03 0x1a 0x01 0x20 0x00 0x64 0x60
// Enable mapping
0x601 0x22 0x03 0x1a 0x00 0x01 0x00 0x00 0x00
Using the Binary Interpreter
One of the easiest ways to send commands to an Elmo motor controller is with the binary interpreter. This lets you take any of the standard commands (such as AC, to set the acceleration , or BG to begin motion) and put them into a CANopen message using DS 301 and PDO’s. By default PDO2 is used for the binary interpreter.
To set your acceleration using the AC command we need to get the ASCII codes for A & C; so A=0x41 and C=0x43. Next we need to convert the acceleration we want to hex; so 150,000 is 0x0249F0. So the data fielf of the RPDO2 (with data length of 8) sent to the device would be 0x41 0x43 0x0 0x0 0xF0 0x49 0x02 0x0. The response would come from TPDO2 and have the same values in the data field to confirm the response.
A BG command to begin motion could be sent only using a data length of 4 if desired since there are no options needed. So with B=0x42 and G=0x47 the data field would be 0x42 047 0x0 0x0.
If you need to connect you computer to a CAN bus and you do not have a CAN interface, there are several USB to CAN interfaces available. The three that I have used are listed below. I have used the top two with Linux, and the bottom one in Windows (it might work in Linux, I just have not tried it). It is useful to have two of interfaces so that you can use one for sending commands, and the other one for snooping the network when debugging a problem.
Main image based on http://commons.wikimedia.org/wiki/File:CAN-Bus_Elektrische_Zweidrahtleitung.svg