Firmware v0.5.2 Release Candidate Feedback Thread

The Release Candidate for Firmware v0.5.2 is ready! You can find binaries here, and check the instructions “How to flash a custom firmware” here. You can also check out this release on GitHub. This thread is for feedback and discussion about the firmware.

Please let us know in the poll below even if everything works.

Binaries here.

Install the odrivetool release candidate version by running pip install odrive==0.5.2.dev0

Documentation here

A complete list of changes is in the changelog.

Release Candidate 2


  • Spinout error is no longer sticky and doesn’t trigger on static torque loads due to I^2*R electrical power
  • Step and direction mode resets position when entering closed loop just like input_pos does
  • CAN baud rate setting works

Release Candidate 1



  • Dual RC PWM no longer causes DEADLINE_MISSED errors


  • Added phase balance check to motor calibration and MOTOR_ERROR_UNBALANCED_PHASES to error enums
  • Added polarity and phase offset calibration for hall effect encoders
  • Mechanical brake support
  • Added periodic sending of encoder position on CAN
  • Support for UART1 on GPIO3 and GPIO4. UART0 (on GPIO1/2) and UART1 can currently not be enabled at the same time.
  • Thermistors now have a 2nd order lowpass filter applied to reduce noise
  • 2-norm current clamping is used for AC induction motors
  • Added spinout detection to detect incorrect encoder offset and ENCODER_ERROR_INCORRECT_OFFSET to error enums.
  • Added AARCH64 support to libfibre
  • Tuning input mode added to provide sinusoidal position, velocity, or torque stimulus. See INPUT_MODE_TUNING and the controller class for details.
  • Added torque mirroring to INPUT_MODE_MIRROR


  • Step/dir performance improved! Dual axis step rates up to 250kHz have been tested
  • Apply_config is called for encoders after a successful direction find
  • Full calibration sequence now includes hall polarity calibration if a hall effect encoder is used
  • Modified encoder offset calibration to work correctly when calib_scan_distance is not a multiple of 4pi
  • Moved thermistors from being a top level object to belonging to Motor objects. Also changed errors: thermistor errors rolled into motor errors
  • Use DMA for DRV8301 setup
  • Make NVM configuration code more dynamic so that the layout doesn’t have to be known at compile time.
  • GPIO initialization logic was changed. GPIOs now need to be explicitly set to the mode corresponding to the feature that they are used by. See <odrv>.config.gpioX_mode.
  • Previously, if two components used the same interrupt pin (e.g. step input for axis0 and axis1) then the one that was configured later would override the other one. Now this is no longer the case (the old component remains the owner of the pin).
  • New control loop architecture:
    1. TIM8 update interrupt handler (CNT = 0) runs at a high priority and invokes the system level function sample_cb() to sample all timing critical inputs (currently only encoder state).
    2. TIM8 update interrupt handler (CNT = 0) raises an NVIC flag to kick off a lower priority interrupt.
    3. The control loop interrupt handler checks if all ADC measurements are ready and informs both motor objects about the current measurements.
    4. The control loop interrupt handler invokes the system level function control_loop_cb() which updates all components (encoders, estimators, torque controllers, etc). The data paths between the components are configured by the Axis threads based on the requested state. This replaces the previous architecture where the components were updated inside the Axis threads in Axis::run_control_loop().
    5. Meanwhile the TIM1 and TIM8 updates for CNT = 3500 will have fired. The control loop interrupt handler thus reads the new ADC measurements and informs both motor objects that a DC calibration event has happened.
    6. Finally, the control loop interrupt invokes pwm_update_cb on both motors to make them update their PWM timing registers.
  • Components that need low level control over PWM timings are implemented by inheriting from the PhaseControlLaw interface. Three components currently inherit this interface: FieldOrientedController, ResistanceMeasurementControlLaw and InductanceMeasurementControlLaw.
  • The FOC algorithm is now found in foc.cpp and and is presumably capable of running at a different frequency than the main control tasks (not relevant for ODrive v3).
  • ACIM estimator was consolidated into a separate component <odrv>.acim_estimator.
  • The Automatic Output Enable (AOE) flag of TIM1/TIM8 is used to achieve glitch-free motor arming.
  • Sensorless mode was merged into closed loop control mode. Use <axis>.enable_sensorless_mode to disable the use of an encoder.
  • More informative profiling instrumentation was added.
  • A system-level error property was introduced.
  • Added torque_mirror_ratio and use it to feed-forward controller_.torque_output in INPUT_MODE_MIRROR
  • Accumulate integer steps in step/dir to avoid float precision errors
  • Circular setpoint mode must be enabled when the step/dir interface is used.

Quick feedback

  • Calibrate motor works
  • Closed loop control works
  • CAN works
  • Incremental encoder works
  • Absolute encoder works
  • Step/dir input works
  • RC PWM input works
  • USB and Python works
  • USB and ASCII protocol works
  • UART and ASCII protocol works

0 voters

If you have any issues, please report it below.


CAN does NOT work for me. I did post a couple of times on the discord support channel, but nobody could give me any suggestions.
I have tried two ODrives, and three FW versions. On both fw-v0.5.2rc1 and devel, I get the following issue:
I cannot set the CAN baud rate, and even if I set my Pi to 250k, still the ODrive doesn’t seem to be transmitting or receiving anything.

On fw-0.5.1 it works.

In [10]: odrv0.erase_configuration()
Oh no odrv0 disappeared

                                    Reconnected to ODrive 205639994D4D as odrv0
In [11]: odrv0.can.config.baud_rate
Out[11]: 250000

In [12]: odrv0.can.config.baud_rate=500000

In [13]: odrv0.can.config.baud_rate
Out[13]: 250000

In [14]: odrv0.can.config.baud_rate=100000

In [15]: odrv0.can.config.baud_rate
Out[15]: 250000

Did you do odrv0.config.enable_can_a = True with save & reboot first?

it was already enabled, and is enabled by default, so the erase_configuration above would have done exactly that.
I did try disabling it and then changing baud rate, but that doesn’t work either

1 Like

I noticed that in the board.cpp (somewhere around line 350)

if (odrv.config_.enable_can_a) {
    // The CAN initialization will (and must) init its own GPIOs before the
    // GPIO modes are initialized. Therefore we ensure that the later GPIO
    // mode initialization won't override the CAN mode.
    if (odrv.config_.gpio_modes[15] != ODriveIntf::GPIO_MODE_CAN_A || odrv.config_.gpio_modes[16] != ODriveIntf::GPIO_MODE_CAN_A) {
        odrv.misconfigured_ = true;
    } else {

The last else statement has been removed in v0.5.2.
Could this possibly be the problem?

USB and python not work for me. I tried both [fw-v0.5.2 Release Candidate 1] and devel. The usb device just not show up in Zadig for both two interfaces. But [fw-v0.5.1] is fine. Any suggestions?


I found the CAN issue - this was the callback for setting baud_rate over fibre, line 29 odrive_can.hpp:

void set_baud_rate(uint32_t value) { parent->set_baud_rate(baud_rate); }

Instead of set_baud_rate(baud_rate), it should have been set_baud_rate(value). It’s now fixed on the latest push to the fw-v0.5.2rc1 branch. I intend to publish the binaries tomorrow after running it through the test suite.

Also, the spinout detection now correctly handles static torque loads and the error is no longer sticky.


I’ve heard of this problem for one other person, but I haven’t been able to replicate it. What operating system and which ODrive version are you using?

Does the ODrive show up in Device Manager (if you are using windows)?


I’m using v3.6-56V. The OS version is Windows 10 20H2 19042.964. And there is no new device can be found in the device manager. I doubt it might be a problem related to boot up sequence.

Hi everyone, I tried updating the device firmware from my laptop with Python 3.9 installed. It threw the error that it could not find gcd within fractions. A quick Google search told me that gcd in fractions is now deprecated and moved to math. And it was apparently removed in 3.9.

I don’t recall the position where the error occurred but I suppose a Python update will show already.

If this is old news to you that’s fine. If this is the wrong place to mention this, please redirect me.

i vaguely remember seeing that issue a long time ago.

Try running the odrivetool from the github repo, i.e.
git clone
cd ODrive
tools/odrivetool dfu

1 Like

I still have problem with CAN on fw-0.5.1.I can set baud_rate and CAN ID, and I download CAN program into STM32F407 to control ODrive . I use channel 1 of one controller to control the amount of current.(I have set CONTROL_MODE_VELOCITY_CONTROL on oDrive. Is this the problem?)When I pushed the joystick, it just didn’t respond.

Please try to keep this thread on-topic, about fw-v0.5.2rc1 specifically.
StenfenSer, see my PM.

An encoder error 0x200 on AXIS_STATE_ENCODER_OFFSET_CALIBRATION with ENCODER_MODE_HALL is not working on v0.5.2.

In [11]: odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
In [12]: odrv0.axis0.motor.config.pre_calibrated = True
In [13]: odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
In [14]: odrv0.axis0.requested_state
Out[14]: 0
In [15]: odrv0.axis0.encoder
error = 0x0200 (int)


I had the error on a MacBook that I grabbed from a colleague. My Ubuntu doesn’t ship with Python3.9 and I’d rather stick to the repo version. If I ever run into that problem again, however, I will get back to this.

Anyways, thanks for the reply