I need to develop a code for ODRIVE board to control a hoverboard motor to run slower but on a max torque to simulate a motor gear, the main ideal is to automatically apply torque when needed if the load increase for some reason.

I need to develop a code for ODRIVE board to control a hoverboard motor to run slower but on a max torque to simulate a motor gear, the main ideal is to automatically apply torque when needed if the load increase for some reason.

############################################################################################
import odrive
from odrive.enums import *

# Connect to the ODrive
odrv = odrive.find_any()

# Set current and velocity limits
odrv.axis0.motor.config.current_lim = 20.0 # Set maximum current limit
odrv.axis0.controller.config.vel_limit = 10.0 # Set lower velocity limit

# Enable the motor
odrv.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

# Monitor load and adjust current if needed
while True:
    # Read the current load
    load = odrv.axis0.motor.current_control.Iq_measured

    # If load exceeds a threshold, increase current
    if load > 30.0:
        odrv.axis0.controller.current_setpoint = 10.0 # Set a higher current
    else:
        odrv.axis0.controller.current_setpoint = 0.0 # Set back to 0 if load is normal

    # Add some delay to avoid high CPU usage
    time.sleep(0.1)
############################################################################################




############################################################################################
import odrive
from odrive.enums import *

# Connect to the ODrive
odrv = odrive.find_any()

# Calibrate motor and encoder
odrv.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
while odrv.axis0.current_state != AXIS_STATE_IDLE or odrv.axis1.current_state != AXIS_STATE_IDLE:
    time.sleep(0.1)

# Set motor parameters
odrv.axis0.motor.config.current_lim = 20.0  # Max current limit for motor 1
odrv.axis1.motor.config.current_lim = 20.0  # Max current limit for motor 2

# Set controller parameters
odrv.axis0.controller.config.vel_limit = 10.0  # Max velocity for motor 1
odrv.axis1.controller.config.vel_limit = 10.0  # Max velocity for motor 2

# Set gains for current control
odrv.axis0.controller.config.pos_gain = 0.01
odrv.axis0.controller.config.vel_gain = 0.02
odrv.axis0.controller.config.vel_integrator_gain = 0.1

odrv.axis1.controller.config.pos_gain = 0.01
odrv.axis1.controller.config.vel_gain = 0.02
odrv.axis1.controller.config.vel_integrator_gain = 0.1

# Set control mode to velocity control
odrv.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL
odrv.axis1.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL

# Set requested state to closed loop control
odrv.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

# Function to monitor and adjust torque based on load
def adjust_torque():
    while True:
        # Monitor load (current) for both motors
        load_motor1 = odrv.axis0.motor.current_control.Iq_measured
        load_motor2 = odrv.axis1.motor.current_control.Iq_measured

        # Adjust current (torque) based on load
        if load_motor1 > 30.0:
            odrv.axis0.controller.current_setpoint = 10.0  # Set a higher current for motor 1
        else:
            odrv.axis0.controller.current_setpoint = 0.0  # Set back to 0 if load is normal

        if load_motor2 > 30.0:
            odrv.axis1.controller.current_setpoint = 10.0  # Set a higher current for motor 2
        else:
            odrv.axis1.controller.current_setpoint = 0.0  # Set back to 0 if load is normal

        # Add some delay to avoid high CPU usage
        time.sleep(0.1)

# Start the torque adjustment loop in a separate thread
import threading
adjust_torque_thread = threading.Thread(target=adjust_torque)
adjust_torque_thread.start()
############################################################################################

Hi! This seems conceptually sane - note that velocity limited torque control mode and torque limited velocity control mode are mathematically equivalent - I think in this situation it might be best to run in torque limited velocity control mode, just for reasoning and configuration, but as I said it’s equivalent.

All that being said - if you set the current setpoint to 0, the motor will just stop, and the Iq will never increase past the load current.

Though are you just trying to turn the hoverboard wheel at a constant slow velocity with high torque? You can just use velocity control mode for that. Maybe you could say exactly what behavior you want, and what issue or questions you have, and we could help from there?

You should probably also update the firmware - it looks like you’re running something super super super old.

Thank you for you reply.

YES, I am just trying to turn the hoverboard wheel at a constant slow velocity with high torque if needed.

I need some help to config the ODRIVE to do that, do you know any one how can help?

You can check out the hoverboard guide here:

Hoverboard motor and remote control setup guide — ODrive Documentation 0.5.6 documentation - obviously you don’t care about the PWM input section

Note that the hall sensors on hoverboard wheels are so low resolution it’s quite difficult to achieve smooth motion at low velocities. I may recommend checking out the Botwheels - when paired with an ODrive S1, you can use the additional high-resolution encoder in the botwheels to allow for extremely smooth movement at low speeds.

Thank you, I saw that before, but it has not torque at low speeds, how to config the ODrive high torque if needed. Do I need to use external board like and Arduino to do that?

You need to tune your vel_gain and vel_integrator_gain - this can be done empirically, by increasing them and then decreasing if there’s instability.

Do you know any one that can make a simple configuration on the on the ODrive? I need some professional Help?

There’s a fundamental conflict between high torque and precision with hoverboard wheels, as the hall sensors are so low resolution. Is there the possibility of adding an additional external encoder? You could consider using an ODrive S1 and the Botwheels.

I don’t need any precision I just need power, the idea is to put that in a wagon, sometimes there is a lot of loads sometimes just a few.

In that case, you should be able to increase the vel_gain and/or vel_integrator_gain. What’s the exact issue here, does the hoverboard wheel not have enough torque for the wagon?

I was using a different controller, the problem with that is I had to increase the speed in order to increase the power, as soon as the load decreases the Wagon speed up pretty quickly, in order to be safe I need to make sure the speed will not exceed a certain amount, that’s why I want to use the ODrive, because this way I could control the speed and maybe maintain the same torque, the load is usually created by the difficult terrain or inclination.

In this case, you could use ODrive in velocity control mode. With correctly configured parameters and tuned gains, it should accomplish what you’re looking to do.

Thank you very much for your help, I will try that today. I will try to attach a RC remote control as well.

Did not work here my configuration:

odrv0.axis0.motor.config.current_lim = 10
odrv0.axis1.motor.config.current_lim = 10
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis1.motor.config.calibration_current = 5
odrv0.config.brake_resistance
odrv0.config.dc_max_negative_current
odrv0.axis0.motor.config.pole_pairs = 15
odrv0.axis1.motor.config.pole_pairs = 15
odrv0.axis0.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT
odrv0.axis1.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT
odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis1.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.motor.config.requested_current_range = 25
odrv0.axis1.motor.config.requested_current_range = 25
odrv0.save_configuration()

odrv0.axis0.motor.config.current_control_bandwidth = 100
odrv0.axis1.motor.config.current_control_bandwidth = 100
odrv0.axis0.motor.config.torque_constant = 1
odrv0.axis1.motor.config.torque_constant = 1
odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis1.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90
odrv0.axis1.encoder.config.cpr = 90
odrv0.axis0.encoder.config.calib_scan_distance = 150
odrv0.axis1.encoder.config.calib_scan_distance = 150

odrv0.axis0.encoder.config.bandwidth = 100
odrv0.axis1.encoder.config.bandwidth = 100
odrv0.axis0.controller.config.pos_gain = 1
odrv0.axis1.controller.config.pos_gain = 1

odrv0.axis0.controller.config.vel_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis1.controller.config.vel_gain = 0.1 * odrv0.axis1.motor.config.torque_constant * odrv0.axis1.encoder.config.cpr

odrv0.axis0.controller.config.vel_integrator_gain = 0.5 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis1.controller.config.vel_integrator_gain = 0.5 * odrv0.axis1.motor.config.torque_constant * odrv0.axis1.encoder.config.cpr

odrv0.axis0.controller.config.vel_limit = 10
odrv0.axis1.controller.config.vel_limit = 10
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL
odrv0.axis1.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL

odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis1.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis0.motor
odrv0.axis1.motor

odrv0.axis0.motor.config.pre_calibrated = True
odrv0.axis1.motor.config.pre_calibrated = True

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION
odrv0.axis1.requested_state = AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION

odrv0.axis0.encoder
odrv0.axis1.encoder

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis1.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION

odrv0.axis0.encoder.config.pre_calibrated = True
odrv0.axis1.encoder.config.pre_calibrated = True

odrv0.save_configuration()
odrv0.reboot()

============================================================

enable the closed loop control state

odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

this sets the initial velocity

odrv0.axis0.controller.input_vel = 4
odrv0.axis1.controller.input_vel = 4

What didn’t work? You need to give more details than that, or I can’t help. What does dump_errors(odrv0) give in ODrivetool?

when I activated the motive AXIS_STATE_CLOSED_LOOP_CONTROL the motors spins a little bit and then stop right after that than the motor stopped, I tried to apply velocity to it (odrv0.axis0.controller.input_vel = 4) but it doesn’t work at all. That was not happening on the old configuration lower vel_gain and vel_integrator_gain

odrv0.axis0.controller.config.vel_gain = 0.02 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_integrator_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr

But if i used

odrv0.axis0.controller.config.vel_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_integrator_gain = 0.5 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr

It does not work.

Can you run dump_errors(odrv0)?

Here it is:

In [2]: dump_errors(odrv0)
system: not found
axis0
axis: Error(s):
AxisError.CONTROLLER_FAILED
motor: Error(s):
MotorError.CONTROL_DEADLINE_MISSED
DRV fault: not found
sensorless_estimator: no error
encoder: no error
controller: Error(s):
ControllerError.OVERSPEED
axis1
axis: Error(s):
AxisError.CONTROLLER_FAILED
motor: Error(s):
MotorError.CONTROL_DEADLINE_MISSED
DRV fault: not found
sensorless_estimator: no error
encoder: no error
controller: Error(s):
ControllerError.OVERSPEED

Looks like there’s an OVERSPEED error. Could you increase your velocity limit, or velocity limit margin?