Motor velocity actively limited for unknown reason

I have an iPower GM5208-12 motor connected to an ODrive S1, with an AS5048A encoder. There is a plastic disk connected to the motor that I want to spin at a constant velocity, so practically no load on the motor.

The problem I encounter is that the ODrive seems to actively limit the velocity for a reason I do not understand. I expect it to be able to spin at k_v * v_dc * 0.78. The motor is rated at 24 rpm/V, so with 24 V it should reach 450 rpm, and at 30 V up to 560 rpm. However, the velocity saturates at around 420 rpm at 25 V and doesn’t increase further with increasing supply voltage. Setting the target velocity to 15 rps and slowly increasing the voltage from 20 V to 30 V yields the following behavior:

On an oscilloscope connected between two motor phases at the ODrive terminals I can observe that at 25 V, the motor voltage does indeed reach the maximum 78 % duty cycle during the sine wave peaks. However, at 30 V, the duty cycle only goes up to around 66 %. The effective voltage is 25 V * 78 % = 19.5 V and 30 V * 66 % = 19.8 V, so this matches the observed behavior.

The ODrive is configured with the following values (I believe these are all the relevant parameters):

# Power supply
print('Configuring power supply')
odrv0.config.dc_bus_overvoltage_trip_level = 31
odrv0.config.dc_bus_undervoltage_trip_level = 10.5
odrv0.config.dc_max_positive_current = 2
odrv0.config.dc_max_negative_current = -0.01
odrv0.config.brake_resistor0.resistance = 2
odrv0.config.brake_resistor0.enable = True
odrv0.clear_errors()

# Motor parameters
print('Configuring motor parameters')
odrv0.axis0.config.motor.motor_type = MotorType.PMSM_VOLTAGE_CONTROL # For a gimbal motor with high phase resistance
odrv0.axis0.config.motor.pole_pairs = 7
odrv0.axis0.config.motor.phase_resistance = 7.6
odrv0.axis0.config.motor.phase_resistance_valid = True
motor_kv = 24 # rpm/V
odrv0.axis0.config.motor.torque_constant = 8.27 / motor_kv
odrv0.axis0.config.motor.current_soft_max = 1.5
odrv0.axis0.config.motor.current_hard_max = 3
odrv0.axis0.config.motor.calibration_current = 0.5
odrv0.axis0.config.motor.resistance_calib_max_voltage = 4
odrv0.axis0.config.calibration_lockin.current = 0.5
# run_state(odrv0.axis0, AxisState.MOTOR_CALIBRATION) # apparently not necessary for MotorType.PMSM_VOLTAGE_CONTROL
odrv0.axis0.motor.motor_thermistor.config.enabled = False
#odrv0.save_configuration()

# Control mode
print('Configuring control mode')
odrv0.axis0.controller.config.control_mode = ControlMode.VELOCITY_CONTROL
odrv0.axis0.controller.config.input_mode = InputMode.VEL_RAMP
odrv0.axis0.controller.config.vel_limit = 15
odrv0.axis0.controller.config.vel_limit_tolerance = 1.3333333333333333
odrv0.axis0.config.torque_soft_min = -math.inf
odrv0.axis0.config.torque_soft_max = math.inf
odrv0.axis0.trap_traj.config.accel_limit = 10
odrv0.axis0.controller.config.vel_ramp_rate = 10

Does anyone have an idea if there are further configuration parameters or hardware limitations that can limit motor velocity?

Here is a scope capture of the phase-to-phase voltage at 30 V, where the duty cycle only reaches 66 %:

Hi! If you’re running in PMSM_VOLTAGE_CONTROL, then this is normal – that’s only really applicable for low-speed control, it won’t compensate for things like motor inductance (which is what prevents the higher speed control in this case). I’d recommend running in PMSM_CURRENT_CONTROL. You may have to manually set the phase inductance, since it’s higher than the typical acceptable range for the S1; I measured a GM5208-12 on my LCR meter, and got a number of 5mH. Try setting:

odrv0.axis0.config.motor.motor_type = MotorType.PMSM_CURRENT_CONTROL 
odrv0.axis0.config.motor.phase_inductance = 5e-3
odrv0.axis0.config.motor.phase_inductance_valid = True
odrv0.axis0.config.motor.phase_resistance = 7.6
odrv0.axis0.config.motor.phase_resistance_valid = True
odrv0.axis0.config.motor.current_control_bandwidth = 50
odrv0.save_configuration()

If you need to specifically run in voltage control mode, you can set axis0.config.motor.bEMF_FF_enable to True; note that this will require an accurate torque_constant. Measuring on my desk, I’m seeing a KV of more along the lines of ~40 RPM/V (thus Kt of more like 0.206 Nm/A). You can tune this by putting the motor in torque mode with a zero torque setpoint, then moving it by hand – if you feel a “drag” then the torque constant is too low, if you feel the motor trying to accelerate as you move it, the torque constant is too high.

Thank you very much, that did indeed increase the maximum speed to around 500 rpm at 30 V. In what instances would I need to run in voltage control mode? I couldn’t really notice a difference with bEMF_FF_enable set to True or False in my quick test.

One issue I have in this mode is that at zero/slow speed, the motor moves quite a bit back and forth in a seemingly random way. I assume this is is because of limited resolution of the current measurement, am I correct? Is there any way to mitigate that?

Re KV: I determined the value of 24 rpm/V myself by spinning the motor with an electric screwdriver and observing the open-circuit phase-to-phase voltage on an oscilloscope. I got an amplitude of 5.9 V at 138 rpm, so 23.4 rpm/V. This also matches the manufacturer spec for an unloaded motor of 456-504 rpm at 20 V. How did you determine the KV?