Odrive UART communication failure[Fixed But ...]

Hello ODrive Community,

I have been struggling for a long time with a persistent “UART communication failure” on my oDrive v3.6 board running firmware version 0.5.6. The issue would occur intermittently, and the only temporary solution was to perform a hard reset of the board.

After extensive troubleshooting, I decided to modify the firmware. The UART communication failures have completely disappeared since I implemented the change below.

Here is the code I modified in :

interface_uart.cpp :  
osThreadDef(uart_server_thread_def, uart_server_thread, osPriorityNormal, 0, stack_size_uart_thread / sizeof(StackType_t) /* the ascii protocol needs considerable stack space */);
Change to ->
osThreadDef(uart_server_thread_def, uart_server_thread, osPriorityRealtime, 0, stack_size_uart_thread / sizeof(StackType_t) /* the ascii protocol needs considerable stack space */);
............................................................
board.cpp :
std::array<Axis, AXIS_COUNT> axes{{
    {
        0, // axis_num
        1, // step_gpio_pin
        2, // dir_gpio_pin
        (osPriority)(osPriorityHigh + (osPriority)1), // thread_priority
        encoders[0], // encoder
        sensorless_estimators[0], // sensorless_estimator
        controllers[0], // controller
        motors[0], // motor
        trap[0], // trap
        endstops[0], endstops[1], // min_endstop, max_endstop
        mechanical_brakes[0], // mechanical brake
    },
    {
        1, // axis_num
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5
        7, // step_gpio_pin
        8, // dir_gpio_pin
#else
        3, // step_gpio_pin
        4, // dir_gpio_pin
#endif
        osPriorityHigh, // thread_priority
        encoders[1], // encoder
        sensorless_estimators[1], // sensorless_estimator
        controllers[1], // controller
        motors[1], // motor
        trap[1], // trap
        endstops[2], endstops[3], // min_endstop, max_endstop
        mechanical_brakes[1], // mechanical brake
    },
}};
Change to ->
std::array<Axis, AXIS_COUNT> axes{{
    {
        0, // axis_num
        1, // step_gpio_pin
        2, // dir_gpio_pin
        osPriorityHigh, // thread_priority
        encoders[0], // encoder
        sensorless_estimators[0], // sensorless_estimator
        controllers[0], // controller
        motors[0], // motor
        trap[0], // trap
        endstops[0], endstops[1], // min_endstop, max_endstop
        mechanical_brakes[0], // mechanical brake
    },
    {
        1, // axis_num
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5
        7, // step_gpio_pin
        8, // dir_gpio_pin
#else
        3, // step_gpio_pin
        4, // dir_gpio_pin
#endif
        osPriorityHigh, // thread_priority
        encoders[1], // encoder
        sensorless_estimators[1], // sensorless_estimator
        controllers[1], // controller
        motors[1], // motor
        trap[1], // trap
        endstops[2], endstops[3], // min_endstop, max_endstop
        mechanical_brakes[1], // mechanical brake
    },
}};

This change has proven to be a stable fix for the communication issue. However, I am not entirely certain about the potential side effects.

My question for the experts here is: **Could this modification negatively impact the motor’s performance or behavior in any way?

Hi!

Yes, I think this could have some side effects regarding motor performance, however it’s very difficult to tell.

What’s the actual symptom of the UART/communications failure? Is it dropped messages? Or just a longer reply time? I can only see increasing the thread priority as helping with faster response time / higher incoming message processing bandwidth. But UART is frankly not a good choice if you need fast communication, that’s what CAN is for.

Thank you for your replies. Let me provide some more specific details about my setup and the failure mode, which might help with the analysis.

My Communication Workflow:

My standard process for communicating with the oDrive is as follows:

  1. ​I send a command to the oDrive.
  2. ​I wait for a fixed 30 ms delay.
  3. ​I then read the response data back from the oDrive for use in my application.

Specifics of the “UART Communication Failure”:

To be more precise, the failure isn’t data corruption; it’s that the oDrive’s response (TX) line completely stops sending any data.

​What’s very strange is that the communication still works perfectly in one direction (from my controller to the oDrive). For example, even after the failure has occurred:

  • ​If I send a command to request AXIS_STATE_CLOSED_LOOP_CONTROL (state 8), the motor engages correctly.
  • ​If I send a command to request AXIS_STATE_IDLE (state 1), the motor disengages as expected.

​However, any command that requires the oDrive to send data back (like requesting the current state or other feedback) receives no response at all.

​This one-way communication failure is the exact state that I could only recover from with a hard reset, prior to oDrive firmware modification.

​I hope this additional information provides more clarity. Thank you again for your help!

The axes array is initialised with the following thread priorities:
Axis 0: osPriorityHigh + 1 (which is likely osPriorityRealtime)
Axis 1: osPriorityHigh
UART thread: osPriorityNormal

In my opinion, sometimes the two high-priority motor control threads are consuming all the CPU time, preventing the normal-priority UART thread from ever running. When the UART thread can’t run, it can’t process transmit-complete events, and the entire communication pipeline stalls.