Small (<1 deg), quick movements with high frequency (100hz) updates

I have a project I am working on that uses a mirror on a gimbal to track moving objects, and everything seems to be implemented fine, except that I am having problems updating the position of the mirror reliably and quickly enough.

I chose these motors because I wanted to have plenty of speed and smooth control.

My setup:
2 X D5065 motors with w/ am102 encoders. (8192)
4:1 reduction in rotation

So in my program I have implemented just about everything I need to.
My problems occur when I try to input position values to the odrive that are very small changes but at 60-100hz. The motors tend to be sluggish and then overshoot, and back and forth. It kind of looks to me like cogging, but it’s at a very small scale, much less than the size of a pole for sure.

I have tried to adjust the gain values but then I either start getting oscillations, vibrations, or a sluggish response for very small changes (0.0002 revolutions, say) I have confirmed this with the plotter, sorry I don’t have an output.

So… at this point I am wondering if I would have been better off getting stepper motors or something. There isn’t much inertia in the system. The system doesn’t really need to make longer distance position jumps.

So is there a way to smooth out these tiny movements, with updates coming in via python+usb at 100+hz? Am I missing something in the docs?

I’ve attached a video of the what I mean as well as a photo of the setup. You can see in the video that the mirror tends to stick and then overshoot, but it is also quite slow to respond.

In the photo, the belts aren’t connected to the sprockets

Photo: https://drive.google.com/file/d/1N_uY59d91iE2nNe9R825AN4vOm5IW_hr/view?usp=sharing

Video: https://drive.google.com/file/d/1xpIjIFO-6RXNgVmD9VIvBpLq060tqfAj/view?usp=sharing

Video: https://drive.google.com/file/d/1th0xE69BTMpBf6stpF5XN8gYPgl7AhH5/view?usp=sharing

On second thought, it possibly could be cogging issue or a tuning issue.

  1. Is there a reliable way to run an anti-cogging calibration. I tried to follow along with various pieces of instructions around the internet, and I have read a few times that it’s not fully implemented properly.

  2. What is the rate I can send instructions over USB? Is there some way I can streamline this? All I really need during operation is to send position data and recieve encoder data.

About 4kHz, give or take. There’s actually a test script in the tools folder you can try.

Try the INPUT_MODE_POS_FILTER - it implements a 2nd order filter of a given bandwidth to try to smooth out commands.

Looks like you need higher gains too.

Try the gain scheduling!

You can also try increasing the current controllr bandwith to 2000 [1/s] and increasing the encoder estimator bandwidth to 2000 [1/s].

2 Likes

@Wetmelon when trying to run the anticogging routine listed in his blog, I get an AXIS_INVALID_STATE when I try to set the axis back into position mode before running the anticogging command. Presumably this is because being calibrated is a pre-requesit for position mode. Calibrating it after rebooting it (instead of before, as in this code) avoids this error, but when I run the anticogging then it just sits and hums.

Are there different gains I should try or something? It doesn’t seem to like being told it’s pre-calibrated.

#Proper Tuning
odrv0.axis0.controller.config.vel_gain=0.32/2 #[Nm/(turn/s)]
odrv0.axis0.controller.config.vel_integrator_gain  = (0.5 * 10 * 0.32/2 ) #[Nm/((turn/s) * s)]
odrv0.axis0.controller.config.pos_gain=15  #[(turn/s) / turn]

#Run the calibration
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE


#At this point you can test with the following commands to see how the motor performs, it should be stuttery
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL
odrv0.axis0.controller.input_vel = 0.2

#Save the config and reboot
odrv0.save_configuration()
odrv0.reboot()


# Anticogging Setup
# https://github.com/odriverobotics/ODrive/blob/ebd237673a483dec87b0d372dd09dfbf0bc7dd64/docs/anticogging.md


#tell the odrive we are pr-calibrated so we don't need to recalibrate every time
odrv0.axis0.encoder.config.pre_calibrated = True
odrv0.axis0.encoder.config.use_index = True
odrv0.axis0.motor.config.pre_calibrated = True

#NOTE: THE FOLLOWING COMMANDS MIGHT MAKE YOUR MOTOR SPIN WILDLY FOR A SECOND IF YOU HAVE MOVED IT SINCE TURNING IT ON
#Put the controller in position control mode
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_POSITION_CONTROL #<< THROWS ERROR
odrv0.axis0.controller.config.input_mode = INPUT_MODE_PASSTHROUGH
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

#Temporarily increase the gain so that the calibration happens quickly
odrv0.axis0.controller.config.pos_gain = 200.0
odrv0.axis0.controller.config.vel_integrator_gain  = (0.5 * 10 * 0.32/2 )*10

#THIS IS THE MAGIC - Start the calibration
odrv0.axis0.controller.start_anticogging_calibration()

#Put the gain back to what it was before
odrv0.axis0.controller.config.vel_integrator_gain  = (0.5 * 10 * 0.32/2 )
odrv0.axis0.controller.config.pos_gain=15

# Wait until odrv0.axis0.controller.config.anticogging.calib_anticogging == False
# you can type 
#     odrv0.axis0.controller.config.anticogging.calib_anticogging
# and just up arrow and enter till it turns false

#Now tell the ODrive we are pre-calibrated for anti-cogging so we don't need to do it every time we power on
odrv0.axis0.controller.config.anticogging.pre_calibrated = True

#Save the new config and reboot
odrv0.save_configuration()
odrv0.reboot()

Yeah that’s correct. Anticogging calibration requires a well-tuned position controller with near-zero vibration and near-zero steady-state error (which can sometimes be hard to achieve)

When running the anticogging calibration, it will wait for velocity and position-error to both be near-zero before it proceeds to the next calibration position. If you have any noise on your encoder, or any limit-cycle oscillation in your position controller, it will get stuck.

I’d probably use a high-precision low-speed no-load tuning strategy specifically for anticogging calibration (obviously, be sure to remove the load) and use a different tuning for normal operation.
Probably, i’d go for relatively low pos_gain, vel_gain and current_control_bandwidth, and relatively high vel_integrator_gain. That should give good positioning accuracy, but only at low speed.

If you are unable to improve your controller tuning, as a workaround you can increase anticogging.config.pos_tolerance and vel_tolerance (the exact names may differ from my memory)

That will allow the calibration to proceed, but the higher you set these numbers, the worse the calibration will be.

1 Like