Hello, I am trying to run the motor using AS5047P encoder in position mode. I am connecting an encoder with SPI protocol pins (MOSI, MISO and so on). When I connect CS pin to GPIO 1 pin, the motor calibrated successfully and the encoder calibration gave the ‘EncoderError.CPR_POLEPAIRS_MISMATCH’ error, but when I connected CS pin to other ones, it gave ‘EncoderError.ABS_SPI_COM_FAIL’ error.
What can be a problem? How to fix CPR_POLEPAIRS_MISMATCH error?
Motor: Sunnysky X6215S 340KV
pole pairs = 14
We tried to set cpr to 16384 and 4000. Also tried to increase the odrv0.axis0.encoder.config.calib_scan_distance and odrv0.axis0.motor.config.calibration_current.
Also I tried to run shadow_count and now it outputs values in small ranges. (ex: 19557, 19716 and so on). But when i tried it earlier it gave values in larger range. Is it okay?
What should we do to run motor with position input?
import odrive
import time
import math
from odrive.enums import *
odrv0 = odrive.find_any()
print(str(odrv0.vbus_voltage))
print("Erasing pre-exsisting configuration...")
try:
odrv0.erase_configuration()
except Exception:
pass
odrv0 = odrive.find_any()
odrv0.config.brake_resistance = 2.0
odrv0.config.dc_max_positive_current = 20
odrv0.config.dc_max_negative_current = -1
odrv0.config.max_regen_current = 0
odrv0.config.dc_bus_undervoltage_trip_level = 8.0
odrv0.config.dc_bus_overvoltage_trip_level = 26
try:
odrv0.save_configuration()
except:
print('Config 1 pass!')
odrv0 = odrive.find_any()
odrv0.axis0.motor.config.motor_type = odrive.utils.MotorType.HIGH_CURRENT
odrv0.axis0.controller.config.pos_gain = 20
odrv0.axis0.controller.config.vel_gain = 0.02
odrv0.axis0.controller.config.vel_integrator_gain = 0.01
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_POSITION_CONTROL
odrv0.axis0.controller.config.vel_limit = odrv0.axis0.config.sensorless_ramp.vel / (2 * math.pi * 14)
odrv0.axis0.motor.config.current_lim = 68
odrv0.axis0.motor.config.pole_pairs = 14
odrv0.axis0.motor.config.calibration_current = 20
odrv0.axis0.motor.config.resistance_calib_max_voltage = 2
odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / (14 * 340)
odrv0.axis0.encoder.config.calib_scan_distance = 300
odrv0.axis0.encoder.config.calib_range = 0.05
# odrv0.axis0.requested_state = odrive.utils.AxisState.MOTOR_CALIBRATION
odrv0.axis0.encoder.config.abs_spi_cs_gpio_pin = 1 # or which ever GPIO pin you choose
odrv0.axis0.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis0.encoder.config.cpr = 4000
try:
odrv0.save_configuration()
except:
print('Config 2 pass!')
odrv0 = odrive.find_any()
# odrv0.reboot()
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
time.sleep(10)
print(str(odrive.utils.dump_errors(odrv0)))
try:
odrv0.save_configuration()
except:
print('Config 3 pass!')
odrv0 = odrive.find_any()
print('Config saved')
Looks like GPIO1 is correct – the polepairs error means the encoder’s at least reading data.
CPR should be 16384 on that encoder.
You can ignore shadow count – all that matters is that it increments/deincrements as the motor turns.
This may be an issue with the magnet and encoder mounting – can you show how your encoder magnet is mounted on the motor shaft? What’s the distance between the magnet and the AS5047P sensor?
Also can it the problem with power supply? Our odrive v3.6 56V and we are giving 24V
currently there are several magnets stacked togather,
1mm
d
No, the 24Vo is definitely not your issue.
How is this magnet held onto the motor shaft? Is it just attached from the magnetism? Or is there a machined pocket and/or glue holding it?
Yes, it is just attached from the magnetism
Okay, that’s definitely the issue. Magnetic encoders need extremely precise magnet mounting, the magnet must be securely fixed +/- 0.5mm to the center of the motor shaft, and the magnetic encoder must be aligned to +/- 0.5mm on the xy over the magnet. I would recommend making a machined cutout or a 3D printed piece, and using glue to fix everything in place. Additionally, because the magnet is so small, you must ensure there are no magnetically permeable materials like steel or iron surrounding the magnet – so any magnet holder pieces must be made out of a material like plastic or aluminum, that will not affect or distort the magnetic field.
Also I find out if I connect the CS pin to 3.3v the motor error is solved. Also other pins except 1 and 2 GPIO pins is not giving more than 2v. As I understood CS pin should be high to say that encoder is not working, and should be low when encoder is working
Additionally, it doesn’t seem the magnetic encoder is actually centered over the magnet, that’s another source of issues:
You won’t be able to get your system to work until you fix these issues, unfortunately.
Might be either damage to the ODrive or a configuration issue. I’d keep using the GPIO1 that you showed works for communication, then go fix the encoder mounting issues.
The odrive is completely new, what kind of configuration can affect that?
Ah, probably just a configuration issue then, may have to configure the other GPIOs with the appropriate mode: ODrive Reference — ODrive Documentation 0.5.6 documentation
I wouldn’t worry about it, fix your mechanical setup first and use GPIO1 and we can revisit this if there’s still issues.
We put the magnet in the center, but still there is an error “encoderError.CPR_POLEPAIRS_MISMATCH”,
we put the cpr to 16384, what can be also problem?
Can the metal bolt shown in the picture be a problem?
Thank you very much for answers. This is valuable for me.
Hello again, we also trying to connect this encoder with AB connection and calibrate the motor with encoder. AB connection seems to work because when we check ‘shadow_count’ it gives values. But still with this connection we get an ‘EncoderError.CPR_POLEPAIRS_MISMATCH’ error. We tried to put cpr to 4000, 4096, 16000 and 16384. It is not working. I am not sure what is the problem. We put the magnet to the center and there are no metal things around except the bolts like in the picture I send earlier?
Thank you for your help!
Is the motor moving with zero load on it? What do you have set for axis0.config.calibration_lockin.current?
I don’t think the metal bolt is the issue, but note I previously showed that your magnetic encoder is mounted off center, have you redesigned the 3D printed mount?
Hello, the motor moves when I try to calibrate the encoder by setting "odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION"
.
Yesterday, using an AB connection, I attempted to calibrate the encoder with cpr=2000
while holding the encoder by hand. It seemed to work since I did not receive the cpr_pole_pair_mismatch
error. During calibration, the motor rotates in one direction, then the other, and finally stops with a short “beep” sound—unlike the long “beep” that occurs after motor calibration. Is it okay that this encoder works with AB connection? Also after the encoder calibration I am running the odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
which gives another errors like
MotorError. UNKNOWN_TORQUE
MotorError. UNKNOWN_VOLTAGE_COMMAND
ControllerError. OVERSPEED
I did not set any value for 'axis0.config.calibration_lockin.current'
, and there will be a new holder for the encoder. Also motor moving without the any load.
Thank you for your answer.
Hello again, now I am connecting the encoder with AB connection, and we make new holder for a encoder which should hold it exactly at the center. Now it should not be a problem. However, I tried to calibrate the encoder with cpr=2000, first time the motor rotates in one direction, then the other, and finally stops with a short “beep” sound—again unlike the long “beep” that occurs after motor calibration. But then I tried to calibrate the encoder again from the start with erasing all configurations, it is giving the error cpr_pole_pair_mismatch. I do not understand it.
Also I checked the value of odrv0.axis0.config.calibration_lockin.current, it is 10
Thank you
My code by the way:
import odrive
import time
import math
from odrive.enums import *
odrv0 = odrive.find_any()
print(str(odrv0.vbus_voltage))
print("Erasing pre-exsisting configuration...")
try:
odrv0.erase_configuration()
except Exception:
pass
odrv0 = odrive.find_any()
time.sleep(5)
odrv0.config.enable_brake_resistor = True
odrv0.config.brake_resistance = 2.0
odrv0.config.dc_max_positive_current = 20
odrv0.config.dc_max_negative_current = -1
odrv0.config.max_regen_current = 0
odrv0.config.dc_bus_undervoltage_trip_level = 8.0
odrv0.config.dc_bus_overvoltage_trip_level = 26
#motor config
odrv0.axis0.motor.config.motor_type = odrive.utils.MotorType.HIGH_CURRENT
odrv0.axis0.motor.config.current_lim = 68
odrv0.axis0.motor.config.pole_pairs = 14
odrv0.axis0.motor.config.calibration_current = 10
odrv0.axis0.motor.config.resistance_calib_max_voltage = 5
odrv0.axis0.motor.config.requested_current_range = 73
odrv0.axis0.motor.config.torque_constant = 8.27 / 340
odrv0.axis0.motor.config.current_control_bandwidth = 2000
#controller config
odrv0.axis0.controller.config.pos_gain = 30
odrv0.axis0.controller.config.vel_gain = 0.02
odrv0.axis0.controller.config.vel_integrator_gain = 0.2
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_POSITION_CONTROL
odrv0.axis0.controller.config.input_mode = INPUT_MODE_TRAP_TRAJ
odrv0.axis0.trap_traj.config.vel_limit = 5
odrv0.axis0.trap_traj.config.accel_limit = 5
odrv0.axis0.trap_traj.config.decel_limit = 5
odrv0.axis0.requested_state = AXIS_STATE_IDLE
try:
odrv0.save_configuration()
except:
pass
odrv0 = odrive.find_any()
odrv0.axis0.requested_state = odrive.utils.AxisState.MOTOR_CALIBRATION
time.sleep(10)
print(str(odrive.utils.dump_errors(odrv0)))
print('Motor Calibrated')
odrv0.axis0.encoder.config.mode = ENCODER_MODE_INCREMENTAL
odrv0.axis0.encoder.config.cpr = 2000
odrv0.axis0.encoder.config.calib_scan_distance = 100
odrv0.axis0.encoder.config.calib_range = 0.05
odrv0.axis0.encoder.config.bandwidth = 1000
odrv0.axis0.encoder.config.use_index = False
odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
time.sleep(10)
print(str(odrive.utils.dump_errors(odrv0)))
print('Encoder Calibrated')
So you definitely need an actual rigid mounting for the magnetic encoder, I think the CPR=2000 working before was just a fluke, evidenced by the overspeed error (which can be caused when the encoder mounting is very bad). That encoder should have a CPR of 4096 by default.
Set odrv0.axis0.config.calibration_lockin.current to the maximum continuous current of your motor.
Also, don’t change the calib_scan_distance or calib_range for now, keep those at the default.
Now I am connecting pin A to A, B to B, 3.3v to 3.3v and GND to GND. I also put the valueodrv0.axis0.config.calibration_lockin.current to 73 A. I did not change the values of calib_scan_distance or calib_range. But there is still the cpr_pole_pair_mismatch error
Okay, 73A is very high and there’s no way that your motor can take 73A continuous. I’d try 20A.
What did you set the CPR value to? And can you take a video of the calibration sequence and upload it somewhere?
I am setting it to 4096 or 4000. I am setting odrv0.axis0.config.calibration_lockin.current to 20.
video: video link