Hello everyone,
I’m using an ODrive Micro x4 with a T-motor RI50, powering it off a 24V power supply. We’re trying to get homing working with a custom end-stop (hall sensor) and use the onboard encoder for position control, and having trouble getting it working.
We are currently using a Python script to drive the ODrive via USB, and we want to execute a test with flow of operations like this:
- Clear config
- Upload motor and homing config (see below)
- Run calibration
- Move between points using position control -20 +20
- Enter homing sequence to set position relative to an end stop (not fully implemented as I can’t get past step 4)
The issue is after the FULL_CALIBRATION_SEQUENCE completes successfully (no errors), requesting closed loop control fails with a procedure result of NOT_CALIBRATED. So we are unable to successfully complete step 4 above.
axis0
active_errors: no error
disarm_reason: no error
procedure_result: ProcedureResult.NOT_CALIBRATED
last_drv_fault: none
internal issues: none
Where I’m confused is that I dump errors after calibration and before requesting closed loop control and it says no errors and the calibration was successful.
axis0
active_errors: no error
disarm_reason: no error
procedure_result: ProcedureResult.SUCCESS
last_drv_fault: none
internal issues: none
Is there some aspect of calibration which were are not doing properly? Or some other reason you could get a NOT_CALIBRATED
result immediately after successful calibration?
I’ve included code snippets and configuration details below.
Thanks,
Finn
Python code:
def calibrate_motor(odrv0):
logger.info("calibrating")
odrv0.axis0.requested_state = AxisState.FULL_CALIBRATION_SEQUENCE # may be offset calibration and not full sequence
sleep(0.1)
while odrv0.axis0.current_state != AxisState.IDLE:
sleep(0.2)
logger.debug("current state: %s", repr(AxisState(odrv0.axis0.current_state)))
# dump_errors(odrv0)
dump_errors(odrv0)
sleep(5.0)
logger.info("successfully calibrated")
def test_movement(odrv0):
logger.info("entering testing range")
dump_errors(odrv0)
odrv0.axis0.controller.config.control_mode = ControlMode.POSITION_CONTROL
odrv0.axis0.requested_state = AxisState.CLOSED_LOOP_CONTROL
sleep(0.1)
logger.debug("current state: %s", repr(AxisState(odrv0.axis0.current_state)))
if odrv0.axis0.current_state != AxisState.CLOSED_LOOP_CONTROL:
dump_errors(odrv0) # <-- dies here
exit(1)
while True:
odrv0.axis0.controller.input_pos = 20
for _ in range(5):
logger.info(f"State: {odrv0.get_gpio_states()}")
sleep(1)
odrv0.axis0.controller.input_pos = -20
for _ in range(5):
logger.info(f"State: {odrv0.get_gpio_states()}")
sleep(1)
logger.info(f"pos_estimate: {odrv0.axis0.pos_estimate}")
dump_errors(odrv0)
def main():
odrv0 = odrive.find_any(timeout=5)
configure_odrive(odrv0)
calibrate_motor(odrv0)
test_movement(odrv0) # fails due to not_calibrated
Motor configuration:
odrv0.config.dc_bus_overvoltage_trip_level = 28
odrv0.config.dc_max_positive_current = 5
odrv0.config.dc_max_negative_current = -1
odrv0.axis0.config.motor.motor_type = MotorType.HIGH_CURRENT
odrv0.axis0.config.motor.pole_pairs = 7
odrv0.axis0.config.motor.torque_constant = 8.27 / 96
odrv0.axis0.config.motor.calibration_current = 3
odrv0.axis0.config.motor.resistance_calib_max_voltage = 3
odrv0.axis0.config.calibration_lockin.current = 3
odrv0.axis0.config.motor.current_soft_max = 10
odrv0.axis0.config.motor.current_hard_max = 12
# odrv0.axis0.controller.config.vel_limit = 10
odrv0.axis0.config.load_encoder = EncoderId.ONBOARD_ENCODER0
odrv0.axis0.config.commutation_encoder = EncoderId.ONBOARD_ENCODER0
odrv0.axis0.controller.config.pos_gain = 10
odrv0.axis0.controller.config.vel_gain = 0.04
odrv0.axis0.controller.config.vel_integrator_gain = 0.2
odrv0.axis0.controller.config.vel_limit = 30
odrv0.axis0.controller.config.vel_limit_tolerance = 1.2
odrv0.axis0.controller.config.vel_ramp_rate = 30
odrv0.axis0.controller.config.input_filter_bandwidth = 20
odrv0.axis0.controller.config.homing_speed = 0.75
Homing configuration - some duplication here, but I don’t think it would affect the calibration:
odrv0.config.gpio5_mode = GpioMode.DIGITAL
odrv0.axis0.min_endstop.config.enabled = False
odrv0.axis0.min_endstop.config.gpio_num = 5
odrv0.axis0.min_endstop.config.offset = -5
odrv0.axis0.min_endstop.config.debounce_ms = 500
odrv0.axis0.min_endstop.config.is_active_high = False # end stop is active-low
odrv0.axis0.config.motor.motor_type = MotorType.HIGH_CURRENT
odrv0.axis0.config.motor.pole_pairs = 7
odrv0.axis0.config.motor.calibration_current = 3
odrv0.axis0.config.motor.current_hard_max = 10
odrv0.axis0.config.startup_homing = False # Set to true once working