CAN Protocol
Note
This document describes the CAN Protocol. For examples of usage, check out our CAN Bus Guide.
Overview
The ODrive CANSimple protocol uses standard 11-bit message identifiers.
node_id: The node ID of the ODrive (
<axis>.config.can.node_id
). See Discovery & Addressing for details.cmd_id: The Command ID, identifying the message type. All available commands are listed in Messages.
Messages prefixed with
Set_
are messages that the host can send to the ODrive.Messages prefixed with
Get_
are messages that the ODrive can send to the host. These messages can be enabled as Cyclic Messages or requested explicitly by the master. To explicitly request a message, the master sends a message with the RTR bit set, and the ODrive responds with the same ID and corresponding payload. (A message with of RTR=0 and an empty payload can also be used, but is susceptible to collisions with the ODrive’s response.)All values are encoded in little endian (aka Intel format, aka least significant byte first).
Floats are encoded with the standard IEEE 754 Float format.
CMD ID |
Name |
Direction |
Signals |
---|---|---|---|
0x000 |
ODrive → Host |
Protocol_Version Hw_Version_Major Hw_Version_Minor Hw_Version_Variant Fw_Version_Major Fw_Version_Minor Fw_Version_Revision Fw_Version_Unreleased |
|
0x001 |
ODrive → Host |
Axis_Error Axis_State Procedure_Result Trajectory_Done_Flag |
|
0x002 |
Host → ODrive |
||
0x003 |
ODrive → Host |
Active_Errors Disarm_Reason |
|
0x004 |
Host → ODrive |
Opcode Endpoint_ID Reserved Value |
|
0x005 |
ODrive → Host |
Reserved0 Endpoint_ID Reserved1 Value |
|
0x006 |
Host → ODrive, ODrive → Host |
Node_ID Serial_Number |
|
0x007 |
Host → ODrive |
Axis_Requested_State |
|
0x009 |
ODrive → Host |
Pos_Estimate Vel_Estimate |
|
0x00b |
Host → ODrive |
Control_Mode Input_Mode |
|
0x00c |
Host → ODrive |
Input_Pos Vel_FF Torque_FF |
|
0x00d |
Host → ODrive |
Input_Vel Input_Torque_FF |
|
0x00e |
Host → ODrive |
Input_Torque |
|
0x00f |
Host → ODrive |
Velocity_Limit Current_Limit |
|
0x011 |
Host → ODrive |
Traj_Vel_Limit |
|
0x012 |
Host → ODrive |
Traj_Accel_Limit Traj_Decel_Limit |
|
0x013 |
Host → ODrive |
Traj_Inertia |
|
0x014 |
ODrive → Host |
Iq_Setpoint Iq_Measured |
|
0x015 |
ODrive → Host |
FET_Temperature Motor_Temperature |
|
0x016 |
Host → ODrive |
Action |
|
0x017 |
ODrive → Host |
Bus_Voltage Bus_Current |
|
0x018 |
Host → ODrive |
Identify |
|
0x019 |
Host → ODrive |
Position |
|
0x01a |
Host → ODrive |
Pos_Gain |
|
0x01b |
Host → ODrive |
Vel_Gain Vel_Integrator_Gain |
|
0x01c |
ODrive → Host |
Torque_Target Torque_Estimate |
|
0x01d |
ODrive → Host |
Electrical_Power Mechanical_Power |
|
0x01f |
Host → ODrive |
Cyclic Messages
The ODrive can be configured to send some messages periodically without a request
from the host. This is done by setting the desired send intervals in <odrv>.axis.config.can
. An interval of 0
disables the message.
If the ODrive is unaddressed (node_id = 0x3f), all cyclic messages are disabled regardless of their configured interval.
Message |
Configuration ( |
Default Interval |
---|---|---|
100 ms |
||
10 ms |
||
disabled |
||
disabled |
||
disabled |
||
disabled |
||
disabled |
Watchdog
The ODrive’s watchdog timer can be used as a safety feature to disable the motor when CAN communication is disrupted.
See axis.config.enable_watchdog
on how to enable the watchdog timer.
The watchdog is reset by every Set_Input_Pos, Set_Input_Vel and Set_Input_Torque message, as well as when entering CLOSED_LOOP_CONTROL
through Set_Axis_State.
DBC Files
DBC files are machine-readable database files that describe CAN message formats.
The CANSimple .dbc file for each firmware version can be downloaded here.
Several tools and libraries exist to ingest DBC files. For example you can use the free CANdb++ software from Vector to view the database.
Broadcast
⇒ New in Firmware 0.6.9
The node ID 0x3f
is a special broadcast address. When the host sends a
message with this ID, it is received by all ODrives on the bus.
If the broadcast message yields a response (typically Get_
messages with RTR=1), each ODrive responds with its own node_id
.
If an ODrive is configured with node_id = 0x3f
, it does not send out any cyclic messages or responses, except for the special message Address.
Discovery & Addressing
⇒ New in Firmware 0.6.9
By default, an unconfigured ODrive starts with node_id = 0x3f, which represents an unaddressed state. In this state the ODrive does not send any cyclic messages (heartbeats, feedback, …).
The node ID can be configured:
Over USB using
odrivetool
or in the GUI.Via CAN using automatic enumeration based on the Address (0x06) message. An interactive script for this is provided in Setting up the ODrive (CAN only) which should be sufficient for most commissioning scenarios.
Otherwise, a user application can implement its own procedure based on the use cases below.
Use cases:
Enumerate all ODrives on the bus:
Send
(node_id = 0x3f, cmd_id = 0x06, RTR=1)
.All ODrives that are already addressed (node_id != 0x3f) will respond immediately with their serial number and node_id.
All unaddressed ODrives (node_id == 0x3f) will respond after a small random delay, averaging 250 ms between each message.
Assign a new node ID (N) to an ODrive with unknown node ID and known serial number (SN):
Send
(node_id = 0x3f, cmd_id = 0x06, Node_ID = N, Serial_Number = SN)
.If the ODrive was at its default configuration, it will now start periodically sending Heartbeat and Get_Encoder_Estimates messages.
Assign a new node ID (new_N) to an ODrive with known node ID (old_N) and unknown serial number:
Send
(node_id = old_N, cmd_id = 0x06, Node_ID = new_N, Serial_Number = 0)
.
Furthermore, the Identify
field in Clear_Errors can be used to blink the status LED. This allows for setting up an interactive
procedure that lets the user associate newly discovered unconfigured ODrives with their location in a multi-axis robot.
Bus-off handling
“Bus-off” events are part of the CAN specification and are usually the result of a persistent fault condition on the CAN bus (e.g. short, disconnect or faulty bus node).
When the ODrive encounters a bus-off event, it tries to recover from it by
restarting its CAN interface. If the fault condition persists, the CAN interface
is restarted repeatedly. See also n_restarts
.
Interoperability with CANopen
ODrives can coexist with CANopen devices on the same bus if caution is taken with the node ID assignment.
The following table lists the valid combinations of node IDs for both CANopen and CANsimple.
CANOpen node IDs |
ODrive CANSimple node IDs |
---|---|
32 … 127 |
0x10, 0x18, 0x20, 0x28 |
64 … 127 |
0x10, 0x11, 0x18, 0x19, 0x20, 0x21, 0x28, 0x29 |
96 … 127 |
0x10, 0x11, 0x12, 0x18, 0x19, 0x1A, 0x20, 0x21, 0x22, 0x28, 0x29, 0x2A |
Messages
Get_Version
Command ID: 0x00
Direction: ODrive → Host
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Protocol_Version |
uint8 |
Always reported as 2 |
1 |
Hw_Version_Major |
uint8 |
|
2 |
Hw_Version_Minor |
uint8 |
|
3 |
Hw_Version_Variant |
uint8 |
|
4 |
Fw_Version_Major |
uint8 |
|
5 |
Fw_Version_Minor |
uint8 |
|
6 |
Fw_Version_Revision |
uint8 |
|
7 |
Fw_Version_Unreleased |
uint8 |
Heartbeat
Command ID: 0x01
Direction: ODrive → Host
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Axis_Error |
uint32 |
|
4 |
Axis_State |
uint8 |
|
5 |
Procedure_Result |
uint8 |
|
6 |
Trajectory_Done_Flag |
uint8 |
|
Estop
Command ID: 0x02
Direction: Host → ODrive
Empty Payload
Causes the axis to disarm with ESTOP_REQUESTED
.
Get_Error
Command ID: 0x03
Direction: ODrive → Host
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Active_Errors |
uint32 |
|
4 |
Disarm_Reason |
uint32 |
RxSdo
Command ID: 0x04
Direction: Host → ODrive
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Opcode |
uint8 |
0: read, 1: write |
1 |
Endpoint_ID |
uint16 |
Endpoint ID as found in |
3 |
Reserved |
uint8 |
|
4 |
Value |
uint32 |
Data type and length depend on endpoint ID |
Sent by the host to read or write from/to arbitrary parameters. See Arbitrary Parameter Access for details.
TxSdo
Command ID: 0x05
Direction: ODrive → Host
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Reserved0 |
uint8 |
|
1 |
Endpoint_ID |
uint16 |
Endpoint ID as found in |
3 |
Reserved1 |
uint8 |
|
4 |
Value |
uint32 |
Data type and length depend on endpoint ID |
Sent by the ODrive in response to an RxSdo with Opcode=READ. See Arbitrary Parameter Access for details.
Address
Command ID: 0x06
Direction: Host → ODrive, ODrive → Host
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Node_ID |
uint8 |
|
1 |
Serial_Number |
uint48 |
ODrive → Host: Serial number of the sending ODrive Host → ODrive: The serial number that shall be associated with the specified Node_ID |
Main section: Discovery & Addressing.
When an ODrive receives this message (subject to receive filters, that means node_id contained in the message ID must matches its own or be 0x3f), it takes the following action:
RTR=1 (or empty payload): Respond with own serial number and
node_id
.Matching Serial_Number: Take on the new Node_ID.
Mismatching Serial_Number but matching Node_ID: Go to unaddressed state (
node_id
= 0x3f).Mismatching Serial_Number and mismatching Node_ID: Ignore message.
Serial_Number == 0 is considered a wildcard that always matches.
Responses on this message are sent even if the ODrive is unaddressed (node_id = 0x3f). In this case, the response is sent after a random delay to avoid collisions.
Set_Axis_State
Command ID: 0x07
Direction: Host → ODrive
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Axis_Requested_State |
uint32 |
Get_Encoder_Estimates
Command ID: 0x09
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Pos_Estimate |
float32 |
rev |
depending on |
4 |
Vel_Estimate |
float32 |
rev/s |
This message is sent by the ODrive periodically by default. See also Cyclic Messages.
Set_Controller_Mode
Command ID: 0x0b
Direction: Host → ODrive
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Control_Mode |
uint32 |
|
4 |
Input_Mode |
uint32 |
Set_Input_Pos
Command ID: 0x0c
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Input_Pos |
float32 |
rev |
|
4 |
Vel_FF |
int16 |
0.001 rev/s (default) [1] |
|
6 |
Torque_FF |
int16 |
0.001 Nm (default) [2] |
Set_Input_Vel
Command ID: 0x0d
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Input_Vel |
float32 |
rev/s |
|
4 |
Input_Torque_FF |
float32 |
Nm |
Set_Input_Torque
Command ID: 0x0e
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Input_Torque |
float32 |
Nm |
Set_Limits
Command ID: 0x0f
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Velocity_Limit |
float32 |
rev/s |
|
4 |
Current_Limit |
float32 |
A |
Set_Traj_Vel_Limit
Command ID: 0x11
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Traj_Vel_Limit |
float32 |
rev/s |
Set_Traj_Accel_Limits
Command ID: 0x12
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Traj_Accel_Limit |
float32 |
rev/s^2 |
|
4 |
Traj_Decel_Limit |
float32 |
rev/s^2 |
Set_Traj_Inertia
Command ID: 0x13
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Traj_Inertia |
float32 |
Nm/(rev/s^2) |
Get_Iq
Command ID: 0x14
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Iq_Setpoint |
float32 |
A |
|
4 |
Iq_Measured |
float32 |
A |
Get_Temperature
Command ID: 0x15
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
FET_Temperature |
float32 |
deg C |
|
4 |
Motor_Temperature |
float32 |
deg C |
Reboot
Command ID: 0x16
Direction: Host → ODrive
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Action |
uint8 |
0: |
Reboots the ODrive according to Action. This requires the axis to be in IDLE
.
Get_Bus_Voltage_Current
Command ID: 0x17
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Bus_Voltage |
float32 |
V |
|
4 |
Bus_Current |
float32 |
A |
Clear_Errors
Command ID: 0x18
Direction: Host → ODrive
Start Byte |
Name |
Type |
Description |
---|---|---|---|
0 |
Identify |
uint8 |
Equivalent to calling clear_errors()
.
Set_Absolute_Position
Command ID: 0x19
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Position |
float32 |
rev |
See also Custom User Reference Frame.
Set_Pos_Gain
Command ID: 0x1a
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Pos_Gain |
float32 |
(rev/s) / rev |
Set_Vel_Gains
Command ID: 0x1b
Direction: Host → ODrive
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Vel_Gain |
float32 |
Nm / (rev/s) |
|
4 |
Vel_Integrator_Gain |
float32 |
Nm / rev |
Get_Torques
Command ID: 0x1c
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Torque_Target |
float32 |
Nm |
|
4 |
Torque_Estimate |
float32 |
Nm |
Get_Powers
Command ID: 0x1d
Direction: ODrive → Host
Start Byte |
Name |
Type |
Unit |
Description |
---|---|---|---|---|
0 |
Electrical_Power |
float32 |
W |
|
4 |
Mechanical_Power |
float32 |
W |
Enter_DFU_Mode
Command ID: 0x1f
Direction: Host → ODrive
Empty Payload
Puts the ODrive into DFU mode (see Firmware Update). Equivalent to calling enter_dfu_mode2()
.