odriverobotics / ODrive

High performance motor control
https://odriverobotics.com
MIT License
2.96k stars 1.52k forks source link

Encoder Index Search Fails on 0.5.3 #605

Closed Wetmelon closed 2 years ago

Wetmelon commented 3 years ago

Describe the bug Encoder Index Search fails on 0.5.3, but succeeds on 0.5.1.

See https://discourse.odriverobotics.com/t/problem-with-encoder-calibration-and-board-reset-after-firmware-odrivetool-update/7804/3

matevzsi commented 3 years ago

Bumping this issue as it is still present in 0.5.4.

Somehow correlated with odrv0.axis1.config.enable_step_dir being True.

image

samuelsadok commented 2 years ago

@matevzsi what's the complete (minimal) list of steps needed to reproduce this issue?

I tried the following:

odrv0.erase_configuration()
odrv0.axis1.encoder.config.use_index = True
odrv0.axis1.config.enable_step_dir = True
odrv0.axis1.min_endstop.config.gpio_num = 1
odrv0.axis1.min_endstop.config.enabled = True
odrv0.config.gpio1_mode = GPIO_MODE_DIGITAL_PULL_DOWN
odrv0.axis1.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis1.motor.config.pre_calibrated = True
odrv0.save_configuration()
odrv0.clear_errors()
odrv0.axis1.requested_state = AXIS_STATE_ENCODER_INDEX_SEARCH # interrupt manually with endstop press
odrv0.clear_errors()
odrv0.axis1.requested_state = AXIS_STATE_ENCODER_INDEX_SEARCH

However the second index search still works as expected.

matevzsi commented 2 years ago

I am using CUI encoders with index, connected to the M1 encoder header.

Video of the issue: https://photos.app.goo.gl/jcWELwLzaWPmLuQX6

# Start with a clean slate...
odrv0.erase_configuration()

# Enable brake resistor
odrv0.config.enable_brake_resistor = True

# General motor setup – motor 1 (belt motor)
odrv0.axis1.motor.config.current_lim = 40
odrv0.axis1.controller.config.vel_limit = 15
odrv0.axis1.motor.config.calibration_current = 20
odrv0.axis1.encoder.config.use_index = True
odrv0.axis1.encoder.config.cpr = 8192

odrv0.save_configuration()

# Calibrate…
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
# Wait to complete
odrv0.axis1.encoder.config.pre_calibrated = True
odrv0.axis1.motor.config.pre_calibrated = True

# Adjust the gains
odrv0.axis1.controller.config.pos_gain = 200.0
odrv0.axis1.controller.config.vel_integrator_gain = 1.5

# !!!! If the following two lines are left out, calibration works as expected !!!
odrv0.axis1.config.enable_step_dir = True
odrv0.axis1.config.step_dir_always_on = True

# Need to enable circular setpoints due to step/dir interface
odrv0.axis1.controller.config.circular_setpoints = True

# Save and reboot
odrv0.save_configuration()
odrv0.reboot()

# Calibrate…
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
# This one suceeds...

# ... but re-running the calibration fails
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
samuelsadok commented 2 years ago

Thanks, it seems that I was missing odrv0.axis1.config.step_dir_always_on = True. When I set this I can also see that index search on axis1 doesn't find the index anymore.

It boils down to a collision on the interrupt lines: The default step GPIO for axis 1 (GPIO7) maps to PA15 on the MCU and the index pin on axis 1 maps to PC15 on the MCU. Both PA15 and PC15 project onto the external interrupt line 15. It is invisible to software whether an external interrupt on line 15 came from PA15, PB15, PC15, etc. The firmware is implemented to allow only one subscriber per interrupt line, so the first one to subscribe wins.

Firmware handling of this needs to be improved, e.g. exiting index search if the interrupt line is already in use and changing the default GPIOs.

Here are some possible workarounds:

matevzsi commented 2 years ago

And as far as I can see it in the code, IO subscribers were introduced in 0.5.2, causing the issue since then...

We solved it by moving the step input to another GPIO pin. Other options are not really viable since we don't have the command line interface always available and the repeated homing/index search procedure may be required due to the setup (e.g. if it fails first time due to motor being too close to the hard limit).

Thank you for looking into the issue and suggesting the solutions.

samuelsadok commented 2 years ago

Ok I'm glad that the workaround works for you!

Note that step_dir_always_on and enable_step_dir are two separate settings. In most cases you can leave step_dir_always_on = False and still use step/dir input (it will just automatically be disabled during IDLE).

matevzsi commented 2 years ago

What is the application case for the step_dir_always_on? We had really rough time with 0.5.2 and 0.5.3 due to instability of the 0.5.2 (controllers randomly loosing the timing and spinning the motors out of control) and the amount of parameters that have changed since 0.5.1 - having both step_dir_always_on and 'enable_step_dir' set to True got us into somehow reliable waters and haven't diven deeper into the operation of those.

samuelsadok commented 2 years ago

step_dir_always_on was primarily added for testing so we can test step/dir input having a motor set up.

There might be some cases where it's useful for an end user. For example if the user's motion controller sends position changes while the ODrive is in IDLE and expects the ODrive's position setpoint to remain in sync with the motion controller's setpoint in absolute terms during that idle time.

Wetmelon commented 2 years ago

Given the workaround and fundamental hardware issue, I've added some information about this to the "troubleshooting" page on the docs. https://docs.odriverobotics.com/troubleshooting

tianrking commented 9 months ago

bug still here

samuelsadok commented 8 months ago

@tianrking As outlined in my earlier comment, this is a hardware issue and not something that can be easily fixed in firmware. Maybe you can use one of the workarounds proposed in my referenced comment.