Motor stalled without any resistance

Hi,

I’m encountering a strange behaviour on an O-drive S1 (running FW 0.6.8) where the motor is commanded to move to a new position, but sometimes doesn’t move at all. Since there is a large position error, the controller sends full current (up to the soft current limit) to the motor, but the motor nevertheless doesn’t rotate.

This is not a binding or friction issue since the motor will easily conduct the motion (well under the current limit), but then spontaneously “lock up” a moment later. No error is reported – the motor simply remains stationary. To be clear, the motor is also not trying to hold position either. When this situation occurs, it is able to be rotated by hand but just feels like a constant DC current is being pushed through the coils.

Also, the problem appears more frequently when the system is tuned more aggressively. If the position/velocity gains are reduced substantially the problem occurs much less frequently.

Some notes about the setup:

  • The motor is an 8 pole pair BLDC motor
  • Commutation is handled by hall effect sensors in the motor
  • Velocity and position are sensed by an AS5047 magnetic encoder put on the load (not the motor shaft). This load does not have a fixed ratio with the motor, but varies between 100:1 and 180:1; i.e. it is not a fixed ratio gearbox, but instead drives a mechanism that has a somewhat variable “reduction ratio”. That said, the effective reduction ratio is always positive (rotating the motor CW will always rotate the load CW)
  • There is almost no backlash in the mechanism

I suspect putting an encoder on the motor shaft itself will help, but unfortunately that would be a bit invasive at this point in the project. Are there any other things I can look at to see what the controller is “thinking” in these circumstances?

Hi there,

Can you post your configuration? Does this issue still happen if you use the motor’s hall effect sensors as both the commutation and load encoder? Have you run both hall polarity and phase calibration, with the motor under no load?

This may also be a regression that was fixed in a more recent firmware version, I’d strongly suggest updating to 0.6.10

Upgrading to 0.6.10 only mildly solves the problem. With 0.6.10, the drive will still “stall” randomly, but will recover after about 10-20 seconds after the target position is changed. By contrast, with 0.6.8, the motor stays stalled indefinitely until the drive is rebooted.

All calibration has done been with a (purely friction) load. I’ll try disconnecting the motor from the mechanisms for the calibrations you mentioned.

I was able to temporarily place an encoder on the motor and use it for commutation and load (this is not a practical change to the hardware, though) and did not see any problems surface, but I didn’t test too extensively so I can’t say for sure.

The config is pasted below:

{
“axis0.commutation_mapper.config.approx_init_pos”: 0.0,
“axis0.commutation_mapper.config.approx_init_pos_valid”: false,
“axis0.commutation_mapper.config.circular_output_range”: 1.0,
“axis0.commutation_mapper.config.circular”: true,
“axis0.commutation_mapper.config.index_gpio”: 10,
“axis0.commutation_mapper.config.index_offset”: 0.0,
“axis0.commutation_mapper.config.index_offset_valid”: false,
“axis0.commutation_mapper.config.index_search_always_on”: false,
“axis0.commutation_mapper.config.offset”: 0.0,
“axis0.commutation_mapper.config.offset_valid”: true,
“axis0.commutation_mapper.config.scale”: 1.0,
“axis0.commutation_mapper.config.use_endstop”: false,
“axis0.commutation_mapper.config.use_index_gpio”: false,
“axis0.config.I_bus_hard_max”: Infinity,
“axis0.config.I_bus_hard_min”: -Infinity,
“axis0.config.calib_range”: 0.019999999552965164,
“axis0.config.calib_scan_distance”: 8.0,
“axis0.config.calib_scan_vel”: 2.0,
“axis0.config.commutation_encoder”: 8,
“axis0.config.dir_gpio_pin”: 5,
“axis0.config.enable_error_gpio”: false,
“axis0.config.enable_step_dir”: false,
“axis0.config.enable_watchdog”: false,
“axis0.config.encoder_bandwidth”: 100.0,
“axis0.config.error_gpio_pin”: 6,
“axis0.config.index_search_at_target_vel_only”: false,
“axis0.config.load_encoder”: 5,
“axis0.config.startup_closed_loop_control”: false,
“axis0.config.startup_encoder_index_search”: false,
“axis0.config.startup_encoder_offset_calibration”: false,
“axis0.config.startup_homing”: false,
“axis0.config.startup_max_wait_for_ready”: 3.0,
“axis0.config.startup_motor_calibration”: false,
“axis0.config.step_dir_always_on”: false,
“axis0.config.step_gpio_pin”: 8,
“axis0.config.torque_soft_max”: 0.12999999523162842,
“axis0.config.torque_soft_min”: -0.12999999523162842,
“axis0.config.watchdog_timeout”: 0.0,
“axis0.config.anticogging.calib_bidirectional”: true,
“axis0.config.anticogging.calib_coarse_integrator_gain”: 10.0,
“axis0.config.anticogging.calib_coarse_tuning_duration”: 60.0,
“axis0.config.anticogging.calib_end_vel”: 0.15000000596046448,
“axis0.config.anticogging.calib_fine_dist_scale”: 1.0,
“axis0.config.anticogging.calib_fine_tuning_duration”: 120.0,
“axis0.config.anticogging.calib_start_vel”: 1.0,
“axis0.config.anticogging.enabled”: false,
“axis0.config.anticogging.max_torque”: 0.15000000596046448,
“axis0.config.calibration_lockin.accel”: 3.183098793029785,
“axis0.config.calibration_lockin.current”: 2.0,
“axis0.config.calibration_lockin.ramp_distance”: 0.5,
“axis0.config.calibration_lockin.ramp_time”: 0.4000000059604645,
“axis0.config.calibration_lockin.vel”: 6.36619758605957,
“axis0.config.can.bus_voltage_msg_rate_ms”: 500,
“axis0.config.can.encoder_msg_rate_ms”: 5,
“axis0.config.can.error_msg_rate_ms”: 500,
“axis0.config.can.heartbeat_msg_rate_ms”: 100,
“axis0.config.can.iq_msg_rate_ms”: 20,
“axis0.config.can.is_extended”: false,
“axis0.config.can.node_id”: 0,
“axis0.config.can.temperature_msg_rate_ms”: 500,
“axis0.config.can.torques_msg_rate_ms”: 0,
“axis0.config.can.version_msg_rate_ms”: 0,
“axis0.config.general_lockin.accel”: 20.0,
“axis0.config.general_lockin.current”: 10.0,
“axis0.config.general_lockin.finish_distance”: 100.0,
“axis0.config.general_lockin.finish_on_distance”: false,
“axis0.config.general_lockin.finish_on_vel”: false,
“axis0.config.general_lockin.initial_pos”: 0.0,
“axis0.config.general_lockin.ramp_distance”: 3.1415927410125732,
“axis0.config.general_lockin.ramp_time”: 0.4000000059604645,
“axis0.config.general_lockin.vel”: 40.0,
“axis0.config.motor.acim_autoflux_attack_gain”: 10.0,
“axis0.config.motor.acim_autoflux_decay_gain”: 1.0,
“axis0.config.motor.acim_autoflux_enable”: false,
“axis0.config.motor.acim_autoflux_min_Id”: 10.0,
“axis0.config.motor.acim_gain_min_flux”: 10.0,
“axis0.config.motor.acim_nominal_slip_vel”: 2.3399999141693115,
“axis0.config.motor.bEMF_FF_enable”: false,
“axis0.config.motor.calibration_current”: 2.0,
“axis0.config.motor.current_control_bandwidth”: 1000.0,
“axis0.config.motor.current_hard_max”: 20.0,
“axis0.config.motor.current_slew_rate_limit”: 10000.0,
“axis0.config.motor.current_soft_max”: 1.0,
“axis0.config.motor.direction”: 1.0,
“axis0.config.motor.ff_pm_flux_linkage”: 0.0,
“axis0.config.motor.ff_pm_flux_linkage_valid”: false,
“axis0.config.motor.fw_enable”: false,
“axis0.config.motor.fw_fb_bandwidth”: 500.0,
“axis0.config.motor.fw_mod_setpoint”: 0.6103333234786987,
“axis0.config.motor.motor_model_l_d”: 0.0,
“axis0.config.motor.motor_model_l_dq_valid”: false,
“axis0.config.motor.motor_model_l_q”: 0.0,
“axis0.config.motor.motor_type”: 0,
“axis0.config.motor.phase_inductance”: 0.00012565572978928685,
“axis0.config.motor.phase_inductance_valid”: true,
“axis0.config.motor.phase_resistance”: 0.31849393248558044,
“axis0.config.motor.phase_resistance_valid”: true,
“axis0.config.motor.pole_pairs”: 8,
“axis0.config.motor.resistance_calib_max_voltage”: 4.0,
“axis0.config.motor.sensorless_observer_gain”: 1000.0,
“axis0.config.motor.sensorless_pll_bandwidth”: 1000.0,
“axis0.config.motor.sensorless_pm_flux_linkage”: 0.0,
“axis0.config.motor.sensorless_pm_flux_linkage_valid”: false,
“axis0.config.motor.torque_constant”: 0.03659291937947273,
“axis0.config.motor.wL_FF_enable”: false,
“axis0.config.sensorless_ramp.accel”: 31.83098793029785,
“axis0.config.sensorless_ramp.current”: 10.0,
“axis0.config.sensorless_ramp.finish_distance”: 15.915493965148926,
“axis0.config.sensorless_ramp.finish_on_distance”: false,
“axis0.config.sensorless_ramp.finish_on_vel”: true,
“axis0.config.sensorless_ramp.initial_pos”: 0.0,
“axis0.config.sensorless_ramp.ramp_distance”: 0.5,
“axis0.config.sensorless_ramp.ramp_time”: 0.4000000059604645,
“axis0.config.sensorless_ramp.vel”: 63.6619758605957,
“axis0.controller.config.absolute_setpoints”: false,
“axis0.controller.config.circular_setpoint_range”: 1.0,
“axis0.controller.config.circular_setpoints”: false,
“axis0.controller.config.commutation_vel_scale”: 1.0,
“axis0.controller.config.control_mode”: 3,
“axis0.controller.config.enable_gain_scheduling”: false,
“axis0.controller.config.enable_overspeed_error”: true,
“axis0.controller.config.enable_torque_mode_vel_limit”: true,
“axis0.controller.config.enable_vel_limit”: true,
“axis0.controller.config.gain_scheduling_width”: 0.0010000000474974513,
“axis0.controller.config.homing_speed”: 0.25,
“axis0.controller.config.inertia”: 0.0,
“axis0.controller.config.input_filter_bandwidth”: 20.0,
“axis0.controller.config.input_mode”: 1,
“axis0.controller.config.pos_gain”: 20.0,
“axis0.controller.config.spinout_electrical_power_bandwidth”: 20.0,
“axis0.controller.config.spinout_electrical_power_threshold”: 10.0,
“axis0.controller.config.spinout_mechanical_power_bandwidth”: 20.0,
“axis0.controller.config.spinout_mechanical_power_threshold”: -10.0,
“axis0.controller.config.steps_per_circular_range”: 1024,
“axis0.controller.config.torque_ramp_rate”: 0.009999999776482582,
“axis0.controller.config.use_commutation_vel”: false,
“axis0.controller.config.vel_gain”: 2.0,
“axis0.controller.config.vel_integrator_gain”: 1.0,
“axis0.controller.config.vel_integrator_limit”: Infinity,
“axis0.controller.config.vel_limit”: 2.0,
“axis0.controller.config.vel_limit_tolerance”: 1.875,
“axis0.controller.config.vel_ramp_rate”: 4.0,
“axis0.interpolator.config.dynamic”: true,
“axis0.max_endstop.config.debounce_ms”: 50,
“axis0.max_endstop.config.enabled”: false,
“axis0.max_endstop.config.gpio_num”: 0,
“axis0.max_endstop.config.is_active_high”: false,
“axis0.max_endstop.config.offset”: 0.0,
“axis0.mechanical_brake.config.gpio_num”: 0,
“axis0.mechanical_brake.config.is_active_low”: true,
“axis0.min_endstop.config.debounce_ms”: 50,
“axis0.min_endstop.config.enabled”: false,
“axis0.min_endstop.config.gpio_num”: 0,
“axis0.min_endstop.config.is_active_high”: false,
“axis0.min_endstop.config.offset”: 0.0,
“axis0.motor.motor_thermistor.config.beta”: 0.0,
“axis0.motor.motor_thermistor.config.enabled”: false,
“axis0.motor.motor_thermistor.config.gpio_pin”: 4,
“axis0.motor.motor_thermistor.config.r_ref”: 0.0,
“axis0.motor.motor_thermistor.config.t_ref”: 25.0,
“axis0.motor.motor_thermistor.config.temp_limit_lower”: 100.0,
“axis0.motor.motor_thermistor.config.temp_limit_upper”: 120.0,
“axis0.pos_vel_mapper.config.approx_init_pos”: 0.0,
“axis0.pos_vel_mapper.config.approx_init_pos_valid”: false,
“axis0.pos_vel_mapper.config.circular_output_range”: 1.0,
“axis0.pos_vel_mapper.config.circular”: false,
“axis0.pos_vel_mapper.config.index_gpio”: 10,
“axis0.pos_vel_mapper.config.index_offset”: 0.0,
“axis0.pos_vel_mapper.config.index_offset_valid”: false,
“axis0.pos_vel_mapper.config.index_search_always_on”: false,
“axis0.pos_vel_mapper.config.offset”: 0.0,
“axis0.pos_vel_mapper.config.offset_valid”: false,
“axis0.pos_vel_mapper.config.scale”: 1.0,
“axis0.pos_vel_mapper.config.use_endstop”: false,
“axis0.pos_vel_mapper.config.use_index_gpio”: false,
“axis0.trap_traj.config.accel_limit”: 4.0,
“axis0.trap_traj.config.decel_limit”: 0.5,
“axis0.trap_traj.config.vel_limit”: 2.0,
“can.config.baud_rate”: 1000000,
“can.config.protocol”: 1,
“config.dc_bus_overvoltage_trip_level”: 30.0,
“config.dc_bus_undervoltage_trip_level”: 18.0,
“config.dc_max_negative_current”: -9.5,
“config.dc_max_positive_current”: 9.5,
“config.enable_can_a”: true,
“config.enable_uart_a”: false,
“config.gpio0_mode”: 17,
“config.gpio10_mode”: 17,
“config.gpio11_mode”: 17,
“config.gpio12_mode”: 17,
“config.gpio1_mode”: 17,
“config.gpio2_mode”: 17,
“config.gpio3_mode”: 17,
“config.gpio4_mode”: 17,
“config.gpio5_mode”: 17,
“config.gpio6_mode”: 17,
“config.gpio7_mode”: 17,
“config.gpio8_mode”: 17,
“config.gpio9_mode”: 17,
“config.max_regen_current”: 0.0,
“config.uart0_protocol”: 3,
“config.uart_a_baudrate”: 115200,
“config.usb_cdc_protocol”: 3,
“config.brake_resistor0.dc_bus_voltage_feedback_ramp_end”: 30.0,
“config.brake_resistor0.dc_bus_voltage_feedback_ramp_start”: 26.0,
“config.brake_resistor0.enable_dc_bus_voltage_feedback”: true,
“config.brake_resistor0.enable”: true,
“config.brake_resistor0.resistance”: 2.0,
“config.gpio11_analog_mapping.endpoint”: null,
“config.gpio11_analog_mapping.max”: 0.0,
“config.gpio11_analog_mapping.min”: 0.0,
“config.gpio1_analog_mapping.endpoint”: null,
“config.gpio1_analog_mapping.max”: 0.0,
“config.gpio1_analog_mapping.min”: 0.0,
“config.gpio8_pwm_mapping.endpoint”: null,
“config.gpio8_pwm_mapping.max”: 0.0,
“config.gpio8_pwm_mapping.min”: 0.0,
“config.inverter0.current_hard_max”: 96.0,
“config.inverter0.current_soft_max”: 80.0,
“config.inverter0.drv_config”: 9029553697166464,
“config.inverter0.shunt_conductance”: 1999.9998779296875,
“config.inverter0.temp_limit_lower”: 83.95999908447266,
“config.inverter0.temp_limit_upper”: 103.11000061035156,
“hall_encoder0.config.enabled”: true,
“hall_encoder0.config.hall_polarity_calibrated”: true,
“hall_encoder0.config.hall_polarity”: 0,
“hall_encoder0.config.ignore_illegal_hall_state”: false,
“inc_encoder0.config.cpr”: 8192,
“inc_encoder0.config.enabled”: false,
“rs485_encoder_group0.config.mode”: 0,
“spi_encoder0.config.baudrate”: 1687500,
“spi_encoder0.config.biss_c_bits”: 18,
“spi_encoder0.config.delay”: 0.0,
“spi_encoder0.config.max_error_rate”: 0.004999999888241291,
“spi_encoder0.config.mode”: 2,
“spi_encoder0.config.ncs_gpio”: 12,
“spi_encoder1.config.baudrate”: 1687500,
“spi_encoder1.config.biss_c_bits”: 18,
“spi_encoder1.config.delay”: 0.0,
“spi_encoder1.config.max_error_rate”: 0.004999999888241291,
“spi_encoder1.config.mode”: 0,
“spi_encoder1.config.ncs_gpio”: 12
}

A calibration problem would match the description well. When the angle, with which the ODrive applies current, is off by around plus or minus 90° electrical (90°/pole_pairs mechanical), then the motor will feel like “freely coasting” even though the ODrive applies a significant current.

Given that the ODrive calibrates each hall sensor edge individually, the amount of bias can change as you turn the motor.

Suggestions:

  • Run calibration without load, ideally remove any gearbox from the motor to get the cleanest possible test data.

  • To simplify the problem, run in torque mode only. This way we don’t have to worry about the effect of higher level components.

  • Look at these variables in the liveplotter or GUI:

    axis0.motor.foc.phase # the electrical angle at which the current is applied
    axis0.motor.foc.Id_measured # should be around zero
    axis0.motor.foc.Iq_measured # should be your non-zero torque-generating current
    

    If I understand correctly, you can make it work well when you use an encoder different from hall effect encoder for commutation. You can use this working configuration to see how the plotted variables behave compared to the non-working configuration. Especially phase should be the same when you move the motor to the same physical location. (since this is electrical phase, it can be quite sensitive)