Startup procedure for sensorless with Odrive 3.5?

Hey all,

I just received my 3.5 and I’m trying to figure out how to use it in sensorless mode. I’m using the Python ODriveTool for now.

This is the reported FW version info:

fw_version_major = 0
fw_version_minor = 4
fw_version_revision = 1
fw_version_unreleased = 1

Here’s the configuration steps that I settled upon:

# The included 50W brake resistor
odrv0.config.brake_resistance = 2.0

# Counted by running current through two leads of the motor and counting
# cogging positions. Motor is a Tacon 96M936 2250kV inrunner.
odrv0.axis0.motor.config.pole_pairs = 2

# Start the motor calibration process
odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION

# Seems to allows skipping of motor calibration after saving config
odrv0.axis0.motor.config.pre_calibrated = True

# Configure blind spin-up to sensorless estimator takeover
# Values same as default for now
odrv0.axis0.config.spin_up_current = 10.0
odrv0.axis0.config.spin_up_acceleration = 1000.0
odrv0.axis0.config.spin_up_target_vel = 1000.0

odrv0.save_configuration()

After configuration, the startup sequence that I’ve been trying:

odrv0.axis0.controller.set_vel_setpoint(1000, 0.2)
odrv0.axis0.requested_state = AXIS_STATE_SENSORLESS_CONTROL

After requesting the state, the motor usually spins up a bit and then stops with no errors.

Occasionally, it will spin up, hesitate, then rapidly accelerate before stopping with the axis0 error 0x31, which looks like the following:

ERROR_INVALID_STATE
ERROR_BRAKE_RESISTOR_DISARMED
ERROR_MOTOR_DISARMED

Very occasionally, it will spin up and then slowly oscillate around the target velocity.

I tried changing the controller’s “current_feed_forward” value by increments of 0.1; decreases seem to make the immediate stop behavior more likely and increases seem to make the rapid accel then error behavior more likely.

I’ve also tried increasing the spin up target to 2000 or 3000, or trying current control instead. I’ve gotten the same behavior with those.

I’m guessing after this that I’m missing some tuning parameters. What should I look for, and what’s the best way to tune them?

Also, a couple more questions:

First, when something goes wrong and I try to reset the error codes, I have tried

odrv0.axis0.error = 0
odrv0.axis0.motor.error = 0
etc

and this gets rid of most of them. But odrv0.axis0.error usually stays stuck on ERROR_INVALID_STATE, and the only way I’ve found to start over is to reboot. What’s the proper way to reset errors?

Second, is there a way to have ODriveTool print all currently-existing errors in human-readable format? Scanning through the states by hand and then comparing error codes to the firmware is really slow.

Edit: Third, how do you figure out the target speed for spin-up? It’s based on the lowest back-EMF voltage that the board can sense, right?

Thanks!

1 Like

I found out that I still need to tune the “vel_gain” parameter, and I got a stable spin with this motor with the following:

odrv0.axis0.controller.set_vel_setpoint(1125, 0.8)
odrv0.axis0.controller.config.vel_gain = 0.25
odrv0.axis0.controller.config.vel_integrator_gain = 0

But changing speeds with the same vel_gain often resulted in heavy vibration. Tuning vel_gain to stop the vibration at that speed made it run badly at other speeds.

I tried messing around with the current_feed_forward and vel_gain, and got it running nicely at all speeds, but then had no success stopping and starting it by requesting states.

Later I tried the following:

odrv0.axis0.controller.set_vel_setpoint(2000, 1.0)
odrv0.axis0.controller.config.vel_gain = 0.25

It refused to keep spinning after spin up (switching from idle to sensorless state), but when I called set_vel_setpoint() with the same parameters the motor started up instantly from a dead stop, without following the spin-up sequence. This was pretty consistent.

A couple more comments/questions:

When changing speeds, the motor will sometimes skip to a different harmonic of the set speed, if that’s the right word, and then run smoothly. For example, setting to 400 rad/s and then loading it down would make it skip down to what looked more like 4 rad/s. In this state the ODrive current draw was double what it was for 400 or 800 rad/s.

In the sensorless mode intro post (Sensorless mode), there’s a pm_flux_linkage variable mentioned, but it doesn’t seem to be exposed to ODriveTool anymore. Is that still something that needs to be set?

In controller.hpp, there’s CTRL_MODE_VOLTAGE_CONTROL but I can’t see a property or function for setting it. Is there still a way to use it? If it makes the motor respond like a brushed motor with voltage control, it seems like it would be nice for testing.

Apologies for the delay in responding to your issue. We recently did a very large refactoring of the codebase, and we only had time to test on a single kind of motor before releasing firmware v0.4.0. We indeed forgot something:

Yes exactly that. We forgot to expose this variable, and setting this is critical to the correct operation of the sensorless mode.
How comfortable would you be to modify the firmware code to add this? If you can do it, you should be able to get it working. If not, I will do it for next release, but that will take a few weeks.

Also, I expect that once you supply the correct PM flux linkage you shouldn’t need to play with the current feed-forward, you can just leave it at 0.

The way you mentioned to write 0 to the errors is the correct way to reset it, so this is a bug. Can you please make an issue in github about this? We’ll look into it.

Thanks for the feedback, can you please also make a feature request “issue” in github for this too?

Yes kind of. The noise floor is determined by the current sense noise, so the noise floor is in Amps. The value depends on the current sense gain settings, but is on the order of 1/500 of single-side full scale. So if they are set up for +/-75A, the noise is about 150mA RMS. You can convert this to a minimum back-emf voltage via the resistance of the motor. Say you have a 50 milliohm motor, then 150mA is equivalent to 7.5 millivolts. But you don’t want your vector to be out more than say 5 degrees electrical, so you can do 7.5 millivolt / sin(5 deg) = 86 millivolt. Multiply this by your kv to get minimum RPM, and then add a safety factor of like 2x.

Thanks for the detailed reply, madcowswe.

I see the place in the firmware where pm_flux_linkage access needs to be added with Fibre. I just have to find the time to set up the build environment.

I’ll add the two issues when I have time, too.

Thanks!

1 Like

Can you explain and write formula for calculate torque feed-forward, when use VELOCITY_CONTROL and send velocity command with torque_FF?