Can't Control D6374-150Kv

Hi ODrive community!
Big fan here- recently purchased a board (56V Configuration), Motor (D6374-150Kv), and Encoder (AMT102) from the shop.

The motor and encoder are all mounted up. Powered by a 1550mAh LiPo pack @ 45V (6s2p).

We’re able to connect to ODrive without issue, communicate and change values as needed.

Calibration runs seemingly fine (motor makes a complete revolution in each direction) using

odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE

However, trying to set a position or velocity does nothing. Using for example;

odrv0.axis0.controller.input_pos = 10

or similarly for velocity

Attached you can see I’m using the live plotter to to show the set value for velocity (in turns/s) and the estimated value. It’s clear that the value is set, and I can change the value and it does update, but no movement from the motor. We’ve manually spun the motor to confirm that the encoder does work. Have also watched the readout during calibration.

Please help! Trying to get this motor turning today- have an entire cycloidal reduction unit built and ready to test.

Thanks!

Have you run odrv0.axis0.requested_state=AXIS_STATE_CLOSED_LOOP_CONTROL? Otherwise the odrive won’t try to do anything.

Thanks for the reply! I have run that command prior to anything else. Just tried again to confirm, but unfortunately no dice.

Update; moved the motor and encoder to Axis 1, and now it works… mostly.

When running it in position mode, if I hand it a position that is significantly far from current position, I get this sort of ‘error’ printed in cmd window before it converges with the set values. Running the closed loop control command gets it back and re running the same position command returns the same issue. (also I can’t get it to run in velocity mode?)

Any ideas? Here’s the readout from the cmd window;



Unhandled exception in event loop:
  File "c:\python38\lib\asyncio\proactor_events.py", line 768, in _loop_self_reading
    f.result()  # may raise
  File "c:\python38\lib\asyncio\windows_events.py", line 808, in _poll
    value = callback(transferred, key, ov)
  File "c:\python38\lib\asyncio\windows_events.py", line 457, in finish_recv
    raise ConnectionResetError(*exc.args)

Exception [WinError 995] The I/O operation has been aborted because of either a thread exit or an application request
Press ENTER to continue...

Thanks!!

What do you get with dump_errors(odrv0)? This feels like noise gremlins.

Thanks for the reply!

I’ve done a lot of work since the last post, but since you asked me to check errors I came up on something interesting.

I have a rough script made for running the motor and fooling around with the tuning parameters. I have it tuned and setup so that providing it with step inputs of 1 turn, it runs fine without issues. When I give it a larger step, it intermittently fails (motor stops turning, lose connection to odrive)

Here is the output on the plot of the position, as well as the error report. I’ll also attach my code.

Thanks guys!

# ChargeValet_ODrive_simple
# Config. and basic control
#
# Nathan Hollett
# 04-02-22
#
# To run; (copy and paste into cmd)
# cd Desktop\T8\Capstone 
# (specific to Nathan's laptop)
# python ChargeValet_ODrive_simple.py

# Importing
import sys
import time
# For ODrive control
import odrive
from odrive.enums import *
# For position and velocity readout
import matplotlib
from odrive.utils import start_liveplotter

# Opening plotter- set position and real position
start_liveplotter(lambda:[odrv0.axis1.encoder.pos_estimate, odrv0.axis1.controller.pos_setpoint])

# Connecting to ODrive
print ("Connecting to ODrive...")
odrv0 = odrive.find_any()

# Setting limits
odrv0.axis0.motor.config.calibration_current = 15 # [A] - should be half of max curr lim
odrv0.axis1.motor.config.current_lim = 55 # [A]
odrv0.axis0.controller.config.vel_limit = 1501 / 60 # [RPM]

# Encoder setup
#odrv0.inc_encoder0.config.cpr = 8192
#odrv0.inc_encoder0.config.enabled = True
#odrv0.axis1.config.load_encoder = EncoderId.INC_ENCODER1
#odrv0.axis1.config.commutation_encoder = EncoderId.INC_ENCODER1
#odrv0.save_configuration()
# [wait for ODrive to reboot]
#odrv0.axis1.requested_state = AxisState.ENCODER_OFFSET_CALIBRATION
# [wait for motor to stop]

# Calibration sequence
print ("An audible beep should follow if connection was successful")
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE

# Wait 15s
time.sleep(15)

# Enabling closed loop position control
print ("Enabling closed loop position control")
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

# Wait 1s
time.sleep(1)

# Tuning block of code below;
# Following; https://docs.odriverobotics.com/v/latest/control.html#tuning
# Tuning parameters- edit this, following guide online
# Found sig vib at vel_gain = 0.4, setting to 0.2 in tuning procedure
tuned_vel_gain = 0.2
# Measure, in s, the settilng time of the step response (worked at 1.2)
# settling_time = 1.2
# Trying to tune for now (temp) and measuring in ms
settling_time = 500 / 1000
# Bandwith is the frequency of the response
bandwidth = 1 / settling_time
# 30 seems like a good value, with 1200ms settling time
odrv0.axis1.controller.config.pos_gain = 75
odrv0.axis1.controller.config.vel_gain = tuned_vel_gain
# Velocity integrator is a function of bandwith and vel gain, comment out and set to 0 for tuning
#odrv0.axis1.controller.config.vel_integrator_gain = 0
odrv0.axis1.controller.config.vel_integrator_gain = 0.5 * bandwidth * tuned_vel_gain

# Moving motor to test tuning
# Setting input position to current position, "zeroing" axis
zero_pos = odrv0.axis1.encoder.pos_estimate
odrv0.axis1.controller.input_pos = zero_pos
print ("Testing for tuning")
# Defining step input
step_test = 5
odrv0.axis1.controller.input_pos = zero_pos + step_test
time.sleep(4)
odrv0.axis1.controller.input_pos = zero_pos
time.sleep(5)

# Saving the configuration
print("Saving tuning parameters, ODrive will reboot")
odrv0.save_configuration()
# Wait 20s
time.sleep(20)
print("Configuration has been saved. Reconnecting to ODrive...")
odrv0 = odrive.find_any()
# Calibration sequence
time.sleep(2)
print ("An audible beep should follow if connection was successful")
odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE

print ("Ctrl+C to end the script")
# Keeping script open for a bit
time.sleep(100)