Motor Windup in Sensorless Velocity Mode

I am attenpting to drive a 20-A motor in sensorless velocity control mode. In order to get the motors to output the torque I need for my system, I had to set the current_setpoint parameter to 100 which keeps the motor from stalling. However, in doing so, after exiting the ramp-up state the motor will spin up, exceeding the target velocity before slowing down again.

I have adjusted the motor current and velocity PI parameters:
Current_I: No change, motor stalls at lower load
Current_P:No change
Veloc_P: Increasing this parameter would reduce the amount of windup, however the motor does not run properly if this value exceeds .15 (It vibrates, makes a loud noise, and heats up)
Veloc_I: Increasing this value reduced the amount of time it takes for the motor to reach its target speed after the windup. I increased by a factor of 10 from .1->1

Here is my setup code:
odrv0.axis0.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (POLEPAIRS * MOTORKV) #Constants defined above

odrv0.axis0.controller.vel_ramp_target = 500
odrv0.axis0.controller.vel_ramp_enable = True
odrv0.axis0.config.startup_motor_calibration = True

odrv0.axis0.config.spin_up_acceleration = 1000
odrv0.axis0.config.ramp_up_time = .1
odrv0.axis0.controller.current_setpoint = 20
odrv0.axis0.config.spin_up_target_vel = 200
odrv0.axis0.config.spin_up_current = 20
odrv0.axis0.motor.config.current_lim = 27

odrv0.axis0.motor.current_control.p_gain = .015 #.015
odrv0.axis0.motor.current_control.i_gain = 102 #102
odrv0.axis0.controller.config.vel_gain = 0.1 #0.1
odrv0.axis0.controller.config.vel_integrator_gain = 1 #0.1 

odrv0.axis0.requested_state = AXIS_STATE_IDLE
odrv0.axis0.requested_state = AXIS_STATE_SENSORLESS_CONTROL

Is there another tuning parameter I may be missing? I need the current setpoint to be high, else the motor will stall at too low a load, but the windup is its own control issue.

What type of load is it? Is it mostly mass or is there a lot of friction/drag also? It seems you want to spool it up very quickly is that the case?

The motors are for a drivetrain. I want the motors to ramp up from rest to a set velocity while being able to carry the load of the vehicle. I have three ODrive 3.5s operating six NeuMotor 1907 3Ys to move a 50 KG vehicle.
When I do not set the value "“controller.current_setpoint” the drives stall out before moving the system. When I set the value of “controller.current_setpoint” to 100* the motor has enough torque to move the system, but when going from the ramp-up state to the open-loop-velocity state the motor will jump from its spin_up_target_vel to a speed past the vel_ramp_target before resolving to the vel_ramp_target. This puts a lot of strain on the gearboxes and is non-ideal for short-distance control of the vehicle, so I’m trying to eliminate that overshoot.

*(This is done in a library I wrote for the TM4C129 launchpad in Energia which comunicates serially to the drives)

Thank you for your quick reply.

What is <odrv>.<axis>.config.lockin.current set to? You should set it to 20A and then current_setpoint to 0. If that doesn’t work, then you can either:

  1. Increase lockin current until you have enough that it doesn’t stall
  2. Reduce the lockin acceleration

I have not set ..config.lockin.current, so it would be set to its default value. I am out of the shop for the week and wont be able to test until Saturday, but I’ll certainly give this a try.

Can you explain what the lockin parameters do?

There is no parameter ..config.lockin

That is in the new (as of now unreleased) firmware version.
You probably have it as odrv0.axis0.config.spin_up_current.

I had the spin_up_current and current_setpoint both set to 20.

when I set spin_up_current to 20 and current_setpoint to 0, the motor would spin up just fine and not overshoot, but would not have enough torque to move under a load. It would spin up, but then immediately stall.

Adjusting the spin_up_current only changes the motor acceleration in the spin_up state. Once it exits that state, the motor overshoots.

I believe the issue is caused by the current_setpoint parameter engaging immediately following the spinup. I have tried to adjust the motor.current_control PI parameters and saw no difference in operation. I wrote a current rampup function in my external controller to slowly ramp up the current_setpoint after the drive is enabled to mitigate the overshoot while allowing full current to be quickly delivered to the drive. That seems to work alright but there is still a bit of overshoot, and setting the current setpoint lower would mean the drive initially has less torque. That may be the best I can get using sensorless control though.

I would suggest not changing the current_control.p/i_gain, instead you should set the motor.config.current_control_bandwidth, it will update the current control gains for you.

Here is my recommendation, start by leaving:

motor.config.current_control_bandwidth = 100

You can try to turn it up a little bit later if you need faster response.

Then play with

controller.config.vel_gain
controller.config.vel_integrator_gain

I would suggest to leave current_setpoint at 0, since otherwise you may get issues at steady-state.

If all that still stalls it out, you can try this feature branch, where I have added an inertia term to the ramped velocity mode (see here). You set it at controller.config.inertia with units of A/(counts/s^2). You can set that value to the amps you seem to need to accelerate, divided by your vel_ramp_rate.

Even with the bandwidth set higher the motor does not get enough power. Adjusting the vel_gain parameters has no effect on the output torque on the motors. They still stall at low speeds, and at vel_gain>.2 the motors will make a noise, move slowly and not function properly.

Adjusting the current setpoint (to about 100) does allow the motor to output more torque, with the side effect of the velocity overshoot mentioned here and occasionally I will get a motor error 0x0400 “ERROR_CURRENT_SENSE_SATURATION” when driving at higher loads or when I set the current_setpoint to greater than 200. The motor stalls out at 16.4AVbus. I have also tried changing the “requested_current_range” parameter to no avail.

I have driven these motors on a TI F28027f platform and received much better performance. The motor would go to a much higher load before stalling out, and when it did stop, I wouldn’t have to go back into an idle state to get the motor to start up again, it would spin back up as soon as the load is removed. The motors were able to draw up to 23A using this platform, which the ODrives should be more than capable of providing.

The only parameters I am setting on the ODrive are:

odrv0.axis0.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (POLEPAIRS * MOTORKV)
odrv0.axis0.controller.config.vel_gain = 0.1 #0.1
odrv0.axis0.controller.config.vel_integrator_gain = 0.1 #0.1 
odrv0.axis0.requested_state = AXIS_STATE_IDLE
odrv0.axis0.requested_state = AXIS_STATE_SENSORLESS_CONTROL
odrv0.axis0.controller.vel_ramp_target = 500
odrv0.axis0.controller.vel_ramp_enable = True
odrv0.axis0.config.startup_motor_calibration = True
odrv0.axis0.config.spin_up_acceleration = 1000
odrv0.axis0.config.ramp_up_time = .1
odrv0.axis0.config.spin_up_target_vel = 200
odrv0.axis0.config.spin_up_current = 20
odrv0.axis0.motor.config.current_lim = 27
odrv0.axis0.motor.config.requested_current_range = 200
odrv0.axis0.motor.current_control.p_gain = .015 #.015
odrv0.axis0.motor.current_control.i_gain = 102 #102

I have another program running on a TM4C129 launchpad that takes in a speed command over ethernet, and will command the ODrive to change odrv0.axis1.controller.vel_ramp_target.

The main issue is that the motor will stall at low loads, forcing me to go to set the motor to idle, then back into sensorless.
Is there a parameter I am missing that will allow the ODrive to maintain its velocity against loads around 60in*oz

The specs for the motor can be found here:


I’m using the 1907/3Y

I am also getting motor error 0x0040.