It’s not perfect but try to take a look through this and copy or modify as needed, if a command is ‘missing’ its because I am using the default still, in another thread I posted all the parameters with default values
‘’‘’‘’
VSTA001.py written by Zachary The’ on October 6th, 2022 for HORC Lab VST 2.0
Contact at +1 (302) 753-3570 or thezach@udel.edu
For odrive info visit Getting Started — ODrive Documentation 0.5.5 documentation
Using ODrive v3.6-56V
To install/update odrivetool run … in command window
pip install --upgrade odrive
Running ODrive control utility v0.6.3
To install missing modules run … or … in command window
conda install -c conda-forge
pip install
Ro resolve USB issues visit https://zadig.akeo.ie/
Run application, Options > List All Devices, ODrive 3.6 Native Interface (Interface 2), libusb-win32 (v.1.2.6.0), Install Driver
To update odrive firmware run … in command window, use Zadig utility to set STM32 BOOTLOADER to libusb-win32
odrivetool dfu
Running v0.5.5.0
odrv0 → ODrive 316D335C3030 (patient left)
odrv1 → ODrive 3359365B3539 (patient right)
axis0 → VSM
axis1 → Belt
‘’’
import os
import sys
import time
from cmath import pi
from logging import exception
import odrive
def save_odrive(odrv, odrv_ID):
print("Saving ODrive")
odrv.axis0.requested_state = 1
odrv.axis1.requested_state = 1
try:
odrv.save_configuration()
countdown(5)
except Exception:
countdown(5)
print()
odrv = odrive.find_any(serial_number=odrv_ID)
odrv.axis0.requested_state = 1
odrv.axis1.requested_state = 1
return odrv
def countdown(t):
for i in range(t):
# write = sys.stdout.write
# write('\b \b')
if (t - i) > 1:
print(f"Please wait {t - i} seconds \t", end="\r")
else:
print("Please wait 1 second \t", end="\r")
time.sleep(1)
print(" ", end="\r")
def autoanticog(odrv, odrv_ID):
odrv.axis0.requested_state = 8
odrv.axis0.controller.config.anticogging.pre_calibrated = False # {False}
odrv.axis0.controller.config.control_mode = 2 # velocity control {3}
odrv.axis0.controller.config.input_mode = 1 # passthrough {1}
odrv.axis0.controller.config.pos_gain = 10*20 # {20}
odrv.axis0.controller.config.vel_integrator_gain = 10*0.3333 # {0.3333}
odrv.axis0.controller.start_anticogging_calibration()
t = time.time()
i = odrv.axis0.encoder.pos_estimate_counts
while odrv.axis0.controller.config.anticogging.calib_anticogging:
dt = time.time() - t
rem = 1 - abs(odrv.axis0.encoder.pos_estimate_counts - i) / 8192
est = dt / rem
print(f"Expected run time of {est:.1f} seconds (run time of {dt:.1f} seconds, {100 * rem:.1f}% complete", end="\r")
print(" ", end="\r")
odrv.axis0.controller.config.anticogging.pre_calibrated = True # {False}
odrv.axis1.controller.config.control_mode = 3 # position control {3}
odrv.axis0.controller.config.input_mode = 5 # trapazoidal {1}
odrv.axis0.controller.config.pos_gain = 20 # {20}
odrv.axis0.controller.config.vel_integrator_gain = 0.3333 # {0.3333}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
return odrv
def autocal_VSM(odrv, odrv_ID):
# Continue/cancel autodetection
str_in = input(
"Remove platform and center VSM prior to calibration\nPress ENTER to continue or X to cancel\n")
if str_in in ["x", "X"]:
print()
return
# look into anticogging
# look into autotuning
# Update parameters
odrv.axis0.controller.config.input_mode = 5 # trapazoidal {1}
odrv.axis0.controller.config.pos_gain = 20 # {20}
odrv.axis0.controller.config.vel_gain = 0.1667 # {0.1667}
odrv.axis0.controller.config.vel_integrator_gain = 0.3333 # {0.3333}
odrv.axis0.controller.config.vel_limit = 114 # {2}
odrv.axis0.encoder.config.pre_calibrated = False # {False}
odrv.axis0.encoder.config.use_index = True # {False}
odrv.axis0.motor.config.calibration_current = 20 # {10}
odrv.axis0.motor.config.current_lim = 65 # {10}
odrv.axis0.motor.config.current_lim_margin = 52 # {8}
odrv.axis0.motor.config.pre_calibrated = False # {False}
odrv.axis0.motor.config.requested_current_range = 130 # {60}
odrv.axis0.motor.config.torque_constant = 8.27/190 # {0.04}
odrv.axis0.trap_traj.config.accel_limit = 114 # {0.5}
odrv.axis0.trap_traj.config.decel_limit = 114 # {0.5}
odrv.axis0.trap_traj.config.vel_limit = 114 # {2}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
# Calibrate VSM motor
print("Calibrating VSM")
odrv.axis0.requested_state = 3 # full calibration sequence
countdown(20)
print()
# Error exit case
if odrv.axis0.error:
print("ERROR")
sys.exit()
# Update additional parameters
odrv.axis0.config.startup_closed_loop_control = True # {False}
odrv.axis0.config.startup_encoder_index_search = True # {False}
odrv.axis0.encoder.config.pre_calibrated = True # {False}
odrv.axis0.motor.config.pre_calibrated = True # {False}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
str_in = input("Press ENTER to skip or Y to start VSM anticogging\n")
if str_in in ["y", "Y"]:
print()
odrv = autoanticog(odrv, odrv_ID)
return
return odrv
'''
# odrv0.axis0 data
# odrv0.axis0.controller.electrical_power
# odrv0.axis0.controller.error
# odrv0.axis0.controler.mechanical_power
# odrv0.axis0.current_state
# odrv0.axis0.encoder.count_in_cpr # raw counts bound
# odrv0.axis0.encoder.error
# odrv0.axis0.encoder.index_found
# odrv0.axis0.encoder.is_ready
# odrv0.axis0.encoder.pos_circular # circular turns
# odrv0.axis0.encoder.pos_cpr_counts # circular counts
# odrv0.axis0.encoder.pos_estimate # linear turns
# odrv0.axis0.encoder.pos_estimate_counts # linear counts
# odrv0.axis0.encoder.shadow_count # raw counts
# odrv0.axis0.encoder.vel_estimate # turns/sec
# odrv0.axis0.encoder.vel_estimate_counts # counts/sec
# odrv0.axis0.error
# odrv0.axis0.is_homed
# odrv0.axis0.motor.I_bus
# odrv0.axis0.motor.error
# odrv0.axis0.motor.fet_thermistor.temperature
# odrv0.axis0 fix
# odrv0.axis0.encoder.config.pre_calibrated = False
# odrv0.axis0 input
# odrv0.axis0.controller.input_pos
# odrv0.axis0.controller.start_anticogging_calibration
# odrv0.axis0.requested_state
'''
def autocal_belt(odrv, odrv_ID):
# Continue/cancel autodetection
str_in = input(
"Remove roller gear prior to calibration\nPress ENTER to continue or X to cancel\n")
if str_in in ["x", "X"]:
print()
return
# Update parameters
odrv.axis1.controller.config.control_mode = 2 # velocity control {3}
odrv.axis1.controller.config.input_mode = 2 # velocity ramp {3}
odrv.axis1.controller.config.vel_gain = 0.1667 # {0.1667}
odrv.axis1.controller.config.vel_integrator_gain = 0.3333 # {0.3333}
odrv.axis1.controller.config.vel_limit = 114 # {2}
odrv.axis1.controller.config.vel_ramp_rate = 5 # {1}
odrv.axis1.encoder.config.pre_calibrated = False # {False}
odrv.axis1.encoder.config.use_index = True # {False}
odrv.axis1.motor.config.calibration_current = 20 # {10}
odrv.axis1.motor.config.current_lim = 100 # {10}
odrv.axis1.motor.config.current_lim_margin = 80 # {8}
odrv.axis1.motor.config.pre_calibrated = False # {False}
odrv.axis1.motor.config.requested_current_range = 200 # {60}
odrv.axis1.motor.config.torque_constant = 8.27/190 # {0.04}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
# Calibrate velt motor
print("Calibrating Belt motor")
odrv.axis1.requested_state = 3 # full calibration sequence
countdown(20)
print()
# Error exit case
if odrv.axis0.error:
print("ERROR")
sys.exit()
# Update additional parameters
odrv.axis1.config.startup_closed_loop_control = True # {False}
odrv.axis1.config.startup_encoder_index_search = True # {False}
odrv.axis1.encoder.config.pre_calibrated = True # {False}
odrv.axis1.motor.config.pre_calibrated = True # {False}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
return odrv
def autocal(odrv, odrv_ID):
# Find ODrive
odrv.axis0.requested_state = 1
odrv.axis1.requested_state = 1
# Print Info
print("Running Variable Stiffness Treadmill Autocalibrater v001")
print(f"ODrive {odrv_ID} with hardware v{odrv.hw_version_major}.{odrv.hw_version_minor}-{odrv.hw_version_variant}V running firmware v{odrv.fw_version_major}.{odrv.fw_version_minor}.{odrv.fw_version_revision}.{odrv.fw_version_unreleased}")
print(f"Pulling {odrv.ibus}A at {odrv.vbus_voltage}V\n")
# Clear/erase ODrive
str_in = input("Press ENTER to clear errors or E to erase configuration\n")
if str_in in ["e", "E"]:
print()
print("Erasing ODrive")
try:
odrv.erase_configuration()
countdown(5)
except Exception:
countdown(5)
odrv = odrive.find_any(serial_number=odrv_ID)
print()
else:
odrv.clear_errors()
# Update parameters
odrv.config.dc_max_positive_current = 20 # {inf}
odrv.config.enable_brake_resistor = True # {False}
# Save ODrive
odrv = save_odrive(odrv, odrv_ID)
# Autocalibrate VSM
str_in = input(
"Press ENTER to skip or Y to start VSM motor autocalibration\n")
if str_in in ["y", "Y"]:
print()
odrv = autocal_VSM(odrv, odrv_ID)
# Autocalibrate belt
str_in = input(
"Press ENTER to skip or Y to start belt motor autocalibration\n")
if str_in in ["y", "Y"]:
print()
odrv = autocal_belt(odrv, odrv_ID)
odrv.axis0.requested_state = 8
odrv.axis1.requested_state = 8
'''
# odrv0 data
# odrv0.error
# odrv0.ibus
# odrv0.system_stats.uptime
# odrv0.vbus_voltage
'''
def main():
# Clear terminal
os.system('cls')
# ODrive ID numbers
odrv0_ID = '316D335C3030'
odrv1_ID = '3359365B3539'
# Find ODrives
odrv0 = odrive.find_any(serial_number=odrv0_ID)
# odrv1 = odrive.find_any(serial_number=odrv1_ID)
# Autocalibration sequence
odrv0 = autocal(odrv0, odrv0_ID)
# odrv1 = autocal(odrv1, odrv1_ID)
main()
‘’’