ODrive Documentation

High performance motor control

View the Project on GitHub madcowswe/ODrive

Help improve these docs: submit edits using the link in the top right.

If you need help, please search or ask the ODrive Community.

Parameters & Commands

We will use the <odrv> as a placeholder for any ODrive object. Every ODrive controller is an ODrive object. In odrivetool this is usually odrv0. Furthermore we use <axis> as a placeholder for any axis, which is an attribute of an ODrive object (for example odrv0.axis0). An axis represents where the motors are connected. (axis0 for M0 or axis1 for M1)

Table of contents

Per-Axis commands

For the most part, both axes on the ODrive can be controlled independently.

State Machine

The current state of an axis is indicated by <axis>.current_state. The user can request a new state by assigning a new value to <axis>.requested_state. The default state after startup is AXIS_STATE_IDLE.

  1. AXIS_STATE_IDLE Disable motor PWM and do nothing.
  2. AXIS_STATE_STARTUP_SEQUENCE Run the startup procedure.
  3. AXIS_STATE_FULL_CALIBRATION_SEQUENCE Run motor calibration and then encoder offset calibration (or encoder index search if <axis>.encoder.config.use_index is True).
  4. AXIS_STATE_MOTOR_CALIBRATION Measure phase resistance and phase inductance of the motor.
    • To store the results set <axis>.motor.config.pre_calibrated to True and save the configuration. After that you don’t have to run the motor calibration on the next start up.
    • This modifies the variables <axis>.motor.config.phase_resistance and <axis>.motor.config.phase_inductance.
  5. AXIS_STATE_SENSORLESS_CONTROL Run sensorless control.
  6. AXIS_STATE_ENCODER_INDEX_SEARCH Turn the motor in one direction until the encoder index is traversed. This state can only be entered if <axis>.encoder.config.use_index is True.
  7. AXIS_STATE_ENCODER_OFFSET_CALIBRATION Turn the motor in one direction for a few seconds and then back to measure the offset between the encoder position and the electrical phase.
    • Can only be entered if the motor is calibrated (<axis>.motor.is_calibrated).
    • A successful encoder calibration will make the <axis>.encoder.is_ready go to true.
  8. AXIS_STATE_CLOSED_LOOP_CONTROL Run closed loop control.
    • The action depends on the control mode.
    • Can only be entered if the motor is calibrated (<axis>.motor.is_calibrated) and the encoder is ready (<axis>.encoder.is_ready).

Startup Procedure

By default the ODrive takes no action at startup and goes to idle immediately. In order to change what startup procedures are used, set the startup procedures you want to True. The ODrive will sequence all enabled startup actions selected in the order shown below.

See state machine for a description of each state.

Control Mode

The default control mode is position control. If you want a different mode, you can change <axis>.controller.config.control_mode. Possible values are:

Control Commands

System monitoring commands

Encoder position and velocity

Motor current and torque estimation

Using the motor current and the known KV of your motor you can estimate the motors torque using the following relationship: Torque [N.m] = 8.27 * Current [A] / KV.

General system commands

Saving the configuration

All variables that are part of a [...].config object can be saved to non-volatile memory on the ODrive so they persist after you remove power. The relevant commands are:


Setting up sensorless

The ODrive can run without encoder/hall feedback, but there is a minimum speed, usually around a few hunderd RPM. However the units of this mode is different from when using an encoder. Velocities are not measured in counts/s, instead it is electrical rad/s. This also applies to the gains. For example, vel_gain is in units of A / (rad/s) instead of A / (count/s).

To give an example, suppose you have a motor with 7 pole pairs, and you want to spin it at 3000 RPM. Then you would set the vel_setpoint to 3000 * 2*pi/60 * 7 = 2199 rad/s electrical.

Below are some suggested starting parameters that you can use. Note that you must set the pm_flux_linkage correctly for sensorless mode to work.

odrv0.axis0.controller.config.vel_gain = 0.01
odrv0.axis0.controller.config.vel_integrator_gain = 0.05
odrv0.axis0.controller.config.control_mode = 2
odrv0.axis0.controller.vel_setpoint = 400
odrv0.axis0.motor.config.direction = 1
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (<pole pairs> * <motor kv>)

To start the motor:

<axis>.requested_state = AXIS_STATE_SENSORLESS_CONTROL