AS5047D affected by external magnet?

Hi All

I have two blocks of neodymium magnets underneath my robot and AS5047D set up a few millimetres above it, facing a wheel.

My parameters are as follows. My robot uses a turnigy motor, 2:1 gear reduction:

odrv0.axis0.motor.config.current_lim=30
odrv0.axis0.controller.config.vel_limit=50000
odrv0.axis0.motor.config.calibration_current=10
odrv0.axis0.motor.config.pole_pairs=12
odrv0.axis0.encoder.config.cpr=2000
odrv0.axis0.motor.config.resistance_calib_max_voltage=3
odrv0.axis0.encoder.config.calib_range =0.4
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (12 * 1050)    
odrv0.axis0.motor.config.current_control_bandwidth=500
---------------------------------------------------------------------------------------------
odrv0.axis0.controller.config.vel_gain=.001
odrv0.axis0.controller.config.vel_integrator_gain=.5

Full calibration works fine but I found myself gradually increasing the calib_range.
When I tried odrv0.axis0.controller.set_vel_setpoint(3000,0) the motor turns then stopped. If left for a while, the motor gets hot. I’m using version 0.4 firmware. I have tuned my motor and it seems pretty stable. Could the two neodymium magnets be the cause of the said behaviour?

Yes, it is very possible that AS5047D could be affected by a large Neodymium magnet immediately below it, since this sensor is trying to use the field from a diametrically polarised disc magnet to precisely measure the motor angle. It is supposed to be robust to weak fields e.g. from the motor coils, but strong or moving fields could saturate the sensor or otherwise interfere with the measurement.
Please try increasing the separation between the AS5047D chip and this unrelated magnet. :stuck_out_tongue:

IIRC, magnetic flux density falls off as somewhere between the square and the cube in relation to distance. You shouldn’t need a lot of extra distance. If you can place a sheet of steel between the external magnet and the sensor, that should help a lot.

That said, encoder.config.calib_range=0.4 is much higher than the default, I think. Can you get it to calibrate at 0.05? If not, you may have the wrong pole pairs or encoder resolution. Have you tried encoder.config.cpr=2048 instead of 2000?

Whether it’s 2048 or 2000, the calibration works unreliably. Increasing the calib_range makes the calibration works more often. Honestly, I can’t have calib_range too big. Correct me if I’m wrong but I suppose the calibration function relies on the calib_range value which allowed the calibration routine to work…with large enough calib_range value.
But when it comes to odrv0.axis0.controller.set_vel_setpoint(3000,0), it is more precise and thus fails to carry out its function?

Edit:
The error I had was ERROR_CPR_OUT_OF_RANGE. Even after I removed the magnet, I still get the same error…

Edit2:
Does having calib_range >0.05 affect the outcome of odrv0.axis0.controller.set_vel_setpoint(3000,0)?

Yes, it can (sort of).

Calib_range adjusts the minimum tolerance needed to pass calibration, that’s all it does. Normally, the CPR and polepairs should match up easily within 5%, which is why the default is 0.05.
If you find that you have to increase calib_range, then it means your encoder CPR does not match your pole pairs, and that means you WILL get issues like what you are describing, because the ODrive then cannot use the encoder to commutate the motor. Polepairs and CPR need to be set exactly - even if CPR is out even by one count, you will get a commutation failure whereby after turning a short way, the motor will be unable to produce torque.

Essentially, a commutation failure is where the ODrive energises the wrong coils, so they don’t produce the right force on the magnets. If there is even a tiny error between CPR and polepairs, then the ODrive will think it has gone round 20 poles, but in fact it has moved 19.99 poles or 20.01 poles, in 100 turns it will be out by a whole pole, and cannot produce torque anymore.

It sounds to me like your polepairs is wrong.

Thanks for the explanation and you’re spot on. I double-checked and the pole pairs are actually 7. The encoder is mounted at the wheel with 32 teeth gear while the motor mounted with 16 teeth gear. So that’s 2:1 gear reduction.

The following parameter should both work, right?

odrv0.axis0.motor.config.pole_pairs=14
odrv0.axis0.encoder.config.cpr=2000

or

odrv0.axis0.motor.config.pole_pairs=7
odrv0.axis0.encoder.config.cpr=1000

The initial calibration worked. Subsequent calibration also worked. However, when I rotate the motor by hand, reboot, then ran the calibration again, I got the cpr out of range error. Changing the cpr value to 1024 or 2048 for each case made no difference either. This is weird…

1 Like

Hmm.
Your encoder and motor are separated by a gear reduction? That’s never a good idea for control.

What is the lowest value of value of calib_range where the calibration works?

Can you connect your AS5047D in absolute SPI mode? (normally CPR is fixed at 16384 in this mode)

I managed to bring the calib_range back to 0.05 but the calibration failed later as the way Ii described above. I saw your post https://discourse.odriverobotics.com/t/encoder-on-gearbox-shaft/5710. Really appreciate your help!

If the motor and encoder are separated by gearing, then there’s not much that can be done even if you have the correct CPR and pole_pairs…
As I said in the other thread, backlash and compliance in the gearbox will cause big problems. Is there any way that you can mount your encoder directly to the motor?

What is your application?

The gears are actually connected through a belt. Not sure how taut it should be. Perhaps I need to try a new encoder just in case.

It is possible to redesign the robot to have the encoder encode the motor instead of the wheel. The robot basically carries a magnet.

Edit:

Can you confirm that if the belt is taut enough and the encoder is functioning, the following parameters should work?

odrv0.axis0.motor.config.pole_pairs=14
odrv0.axis0.encoder.config.cpr=2000

or

odrv0.axis0.motor.config.pole_pairs=7
odrv0.axis0.encoder.config.cpr=1000

The problem with a belt is that it stretches, no matter how taut it is.
Having any kind of compliant mechanism will always present a difficult problem: If you put the encoder on the motor, then you can get control instability at the load due to the compliance. If you put the encoder on the load, then you may no longer be able to drive the motor properly as in this case.

Do this. Or even better, have both encoders, one on the motor and the other on the load. You can use the motor encoder for commutation, and the load encoder for positioning.