Running Away Velocity

Hi everyone,

I’m trying to use the odrive to take velocity inputs from an Arduino with 4 buttons (one for each direction) and control a wheelchair with two hoverboard motors. My config is at the bottom.

The problem I’m having is that the velocity is running away. I try to set it to 2rev/s and it speeds up to ~6.7 rev/s. This problem makes me believe there is an issue with either the PID controller tune or the encoder.

For the encoder, I’m using the built-in hall sensors on the hoverboard motors and I believe this is working properly since when I check the velocity estimate it looks accurate (it tells me it’s about 6.7rev/s when it runs away which seems about right). My main concern is the PID tune. When using the typical values I see for hoverboard motors ( vel_gain = .930375, vel_integrater_gain = 4.651875, pos_gain = 1) and i use “odrive.SetVelocity(0, 2);” on the arduino, it slowly runs away to 6.7rev/s and won’t stop when set the input_vel to 0. If I use random values ( vel_gain = 30, vel_integrater_gain = 150, pos_gain = 1) and do the same as above the wheels will quickly jump to 6.7rev/s but slowly come to a stop when I set input_vel to 0, so this is the best I’ve gotten. I’ve tried to follow the tuning instructions here:Control | ODrive, but the motors won’t vibrate.

A lot of the PID controller is over my head and so if someone could check I’m not making an obvious mistake in my logic or config’s that would be great. Also, I don’t know if using velocity control is the best implementation. My final goal is to have 4 buttons for movement (forward, back, left, right) which will slowly accelerate to a max movement speed and by default the motors will stay parked and resist movement.

In [6]: odrv0.axis1.motor.config
Out[6]:
I_bus_hard_max: inf (float)
I_bus_hard_min: -inf (float)
I_leak_max: 0.10000000149011612 (float)
R_wL_FF_enable: False (bool)
acim_autoflux_attack_gain: 10.0 (float)
acim_autoflux_decay_gain: 1.0 (float)
acim_autoflux_enable: False (bool)
acim_autoflux_min_Id: 10.0 (float)
acim_gain_min_flux: 10.0 (float)
bEMF_FF_enable: False (bool)
calibration_current: 10.0 (float)
current_control_bandwidth: 100.0 (float)
current_lim: 10.0 (float)
current_lim_margin: 8.0 (float)
dc_calib_tau: 0.20000000298023224 (float)
inverter_temp_limit_lower: 100.0 (float)
inverter_temp_limit_upper: 120.0 (float)
motor_type: 0 (uint8)
phase_inductance: 0.00035902162198908627 (float)
phase_resistance: 0.1925504207611084 (float)
pole_pairs: 15 (int32)
pre_calibrated: True (bool)
requested_current_range: 25.0 (float)
resistance_calib_max_voltage: 4.0 (float)
torque_constant: 0.5168750286102295 (float)
torque_lim: inf (float)

In [7]: odrv0.axis1.encoder.config
Out[7]:
abs_spi_cs_gpio_pin: 1 (uint16)
bandwidth: 100.0 (float)
calib_range: 0.019999999552965164 (float)
calib_scan_distance: 150.0 (float)
calib_scan_omega: 12.566370964050293 (float)
cpr: 90 (int32)
direction: 1 (int32)
enable_phase_interpolation: True (bool)
find_idx_on_lockin_only: False (bool)
hall_polarity: 0 (uint8)
hall_polarity_calibrated: True (bool)
ignore_illegal_hall_state: True (bool)
index_offset: 0.0 (float)
mode: 1 (uint16)
phase_offset: 71 (int32)
phase_offset_float: 1.4609001874923706 (float)
pre_calibrated: True (bool)
sincos_gpio_pin_cos: 4 (uint16)
sincos_gpio_pin_sin: 3 (uint16)
use_index: False (bool)
use_index_offset: True (bool)

In [8]: odrv0.axis1.controller.config
Out[8]:
anticogging:
  anticogging_enabled: True (bool)
  calib_anticogging: False (bool)
  calib_pos_threshold: 1.0 (float)
  calib_vel_threshold: 1.0 (float)
  cogging_ratio: 1.0 (float)
  index: 0 (uint32)
  pre_calibrated: False (bool)
axis_to_mirror: 255 (uint8)
circular_setpoint_range: 1.0 (float)
circular_setpoints: False (bool)
control_mode: 2 (uint8)
electrical_power_bandwidth: 20.0 (float)
enable_current_mode_vel_limit: True (bool)
enable_gain_scheduling: False (bool)
enable_overspeed_error: True (bool)
enable_vel_limit: True (bool)
gain_scheduling_width: 10.0 (float)
homing_speed: 0.25 (float)
inertia: 0.0 (float)
input_filter_bandwidth: 2.0 (float)
input_mode: 2 (uint8)
load_encoder_axis: 0 (uint8)
mechanical_power_bandwidth: 20.0 (float)
mirror_ratio: 1.0 (float)
pos_gain: 1.0 (float)
spinout_electrical_power_threshold: 10.0 (float)
spinout_mechanical_power_threshold: -10.0 (float)
steps_per_circular_range: 1024 (int32)
torque_mirror_ratio: 0.0 (float)
torque_ramp_rate: 0.009999999776482582 (float)
vel_gain:  0.930375 (float)
vel_integrator_gain: 4.651875 (float)
vel_limit: 6.0 (float)
vel_limit_tolerance: 1.2000000476837158 (float)
vel_ramp_rate: 0.009999999776482582 (float)

It could be that the integral part of the PID is ‘winding up’ i.e. growing very large.
I notice your vel_integrator_gain is 4.6 which is huge by most standards (for me it is 0.05, iirc)
Try setting that to zero and just use proportional gain - it might be better for your application.

I have tried that and I get the same thing where the velocity slowly ramps up to the max speed.

I would try backing up and erasing your config. It’s possible that you have something configured e.g. anticogging, which could be causing odd behaviour.
odrivetool backup-config borked_config.json
odrv0.erase_configuration()

You can also try updating the firmware if you haven’t already.