Using sensorless control to find encoder index

Hi all,

I’m working on a project where I’d like to use multiple Odrives to control six motors for a mobile platform. I plan on using ‘velocity control’ mode, and have followed the motor and encoder calibration steps and saved those parameters, so that at this point the only start-up function that I have to call before moving on to velocity control is ‘AXIS_STATE_ENCODER_INDEX_SEARCH’, to find the encoder’s index pulse.

Since the motors are controlling the vehicle’s wheels, I’d rather avoid the case of having the wheels moving at start-up before being able to control the robot. So I’m trying to determine what the best way to avoid that would be (if it’s even possible). One thought I had was to incorporate the index search into the first commanded move. The idea is to have a ‘master’ control board that would handle the control logic, so that on the first move after start-up, it’d command the motors in sensorless mode, with as conservative of parameters as possible, and then switch back to normal (encoder-based) velocity control as soon as possible after the encoder index pulse is found. Would it be theoretically possible to achieve that smoothly? Is there a better way to get the same result?

I can’t actually find any info on how to get out of sensorless control after sending the odrv0.axis0.requested_state = AXIS_STATE_SENSORLESS_CONTROL command.

Also, kind of unrelated to the main topic of my question but I also wanted to ask whether the ideal PID gain parameters are the same for sensorless and encoder-based control? On this page, it gives some sample code for trying sensorless control with vel_gain of 0.01 and vel_integrator_gain = 0.05. Using those values works in sensorless (although the motor does vibrate, so I presume they could be tuned further). However, if I use those same values and try AXIS_STATE_CLOSED_LOOP_CONTROL instead, the motor goes crazy (they seem to be waaay too high).

Sensorless does a ramp-up before it even kicks in anyway. Just use absolute encoders to solve your problem instead.

With six wheels / motors, that adds a not-insignificant cost and complexity to the system; I’d rather get by without them if possible.

I actually did get it to work by starting with SENSORLESS_CONTROL, waiting for the index to be found, and then transitioning through IDLE state to CLOSED_LOOP_CONTROL as soon as it is. But then I was thinking, what’s actually the difference between doing it this way and running ENCODER_INDEX_SEARCH; that command must also be doing some kind of sensorless control to find the index, right? So I tested that as well - running ENCODER_INDEX_SEARCH on the first command move and then switching to CLOSED_LOOP_CONTROL as soon as it’s found. It does seem to be a little smoother than the SENSORLESS_CONTROL approach, and I think it’ll work out fine for my application.

I do still have a couple questions about ENCODER_INDEX_SEARCH:

  1. can the acceleration / velocity or any other parameters that it uses to turn the motor to look for the index be adjusted to make the search less ‘jerky’?
  2. does the index search still work if the motor meets some resistance? how is that treated? does it start out with a more conservative drive current and then ramp it up if it sees that the encoder value isn’t changing?

oh and one more question:

  1. I’ve seen it mentioned on other threads that the index search can be set to always go in the same direction, although they don’t say how to do it. Looking through the variables, I’ve seen ‘idx_search_unidirectional’, which is set to False by default. Is that the variable of interest? And if so, how is the direction determined? I’m specifically wondering about how to do it in my case, if I’d like it to match the direction of the commanded velocity.

ok I believe I may have found the parameters I’m looking for (doh - missed them right on the Encoder page):

  • <axis0>.config.calibration_lockin.vel
  • <axis0>.config.calibration_lockin.accel
  • <axis0>.config.calibration_lockin.ramp_distance

along with .motor.config.calibration_current for if the motor meets some resistance.