We use a BLDC motor (a wheel from HOVER-1 hoverboard)
We do not use ODrivetool.
calibration_current = 10.0
Se the entire Python script attached. Also attaching pictures.
Please note that we bought two S1s and the other one works perfectly.
Here is the output of the script:
bis@ubuntu:~/Documents/Robot/ODrive$ python3 01_config_and_calibrate.py
- Searching for ODrive…
- Connected: 144157578035
Applying configuration…
Saving configuration (device will reboot)…
- Searching for ODrive…
- Connected: 144157578035
Running motor calibration…
Saving motor calibration…
- Searching for ODrive…
- Connected: 144157578035
Running Hall polarity calibration…
Running Hall phase calibration…
Saving the configuration…
- Searching for ODrive…
- Connected: 144157578035
- Searching for ODrive…
- Connected: 144157578035
Closed loop…
— Diagnostics —
axis0
active_errors: no error
disarm_reason: no error
procedure_result: ProcedureResult.NOT_CALIBRATED
last_drv_fault: none
internal issues: none
disarm_reason: 0
vbus: 36.620853424072266
Here is the script:
import time
from odrive.enums import AxisState, EncoderId, MotorType, ControlMode, InputMode
from odrv_common import connect, safe_save, diag
odrv = connect()
print(“Applying configuration…”)
---------- Motor ----------
odrv.axis0.config.motor.motor_type = MotorType.HIGH_CURRENT
odrv.axis0.config.motor.pole_pairs = 15 # 30 poles → 15 PP
odrv.axis0.config.motor.torque_constant = 8.27 / 15.0 # ≈0.551 Nm/A
odrv.axis0.config.motor.current_soft_max = 20.0 # replaces current_lim
odrv.axis0.config.motor.calibration_current = 10.0
---------- Hall encoder ----------
odrv.hall_encoder0.config.enabled = True # top-level object
try:
odrv.hall_encoder0.config.cpr = 6 * 15
except AttributeError:
pass # some versions derive this automatically
Attach Hall encoder to axis (both commutation & load)
odrv.axis0.config.commutation_encoder = EncoderId.HALL_ENCODER0
odrv.axis0.config.load_encoder = EncoderId.HALL_ENCODER0
odrv.axis0.config.encoder_bandwidth = 100
---------- Controller ----------
odrv.axis0.controller.config.control_mode = ControlMode.VELOCITY_CONTROL
odrv.axis0.controller.config.input_mode = InputMode.VEL_RAMP
odrv.axis0.controller.config.vel_limit = 10
---------- Bus protection (36 V pack) ----------
odrv.config.dc_bus_overvoltage_trip_level = 43.5
print(“Saving configuration (device will reboot)…”)
safe_save(odrv)
---------- Reconnect after reboot ----------
odrv = connect()
---------- Calibrate & test ----------
— Motor calibration (one-time per motor/wiring) —
print(“Running motor calibration…”)
odrv.axis0.requested_state = AxisState.MOTOR_CALIBRATION
while odrv.axis0.current_state != AxisState.IDLE:
time.sleep(0.05)
Verify calibration stuck (new flag replaces ‘pre_calibrated’)
try:
print(“motor R/L valid:”,
odrv.axis0.config.motor.phase_resistance_inductance_valid)
except AttributeError:
pass
print(“Saving motor calibration…”)
safe_save(odrv)
Reconnect after save
odrv = connect()
— Run Hall calibrations (one-time per configuration) —
print(“Running Hall polarity calibration…”)
odrv.axis0.requested_state = AxisState.ENCODER_HALL_POLARITY_CALIBRATION
while odrv.axis0.current_state != AxisState.IDLE:
time.sleep(0.05)
print(“Running Hall phase calibration…”)
odrv.axis0.requested_state = AxisState.ENCODER_HALL_PHASE_CALIBRATION
while odrv.axis0.current_state != AxisState.IDLE:
time.sleep(0.05)
Mark pre-calibrated if the field exists, then SAVE so the map persists
for attr in (“pre_calibrated”, “is_pre_calibrated”):
if hasattr(odrv.hall_encoder0.config, attr):
setattr(odrv.hall_encoder0.config, attr, True)
print(“Saving the configuration…”)
safe_save(odrv)
---------- End safely in IDLE; no auto-run on boot ----------
odrv = connect()
odrv.axis0.requested_state = AxisState.IDLE
odrv.axis0.config.startup_motor_calibration = False
odrv.axis0.config.startup_encoder_index_search = False
odrv.axis0.config.startup_encoder_offset_calibration = False
odrv.axis0.config.startup_closed_loop_control = False
safe_save(odrv)
Final quick closed-loop poke (like your original), then cancel
odrv = connect()
print(“Closed loop…”)
odrv.axis0.requested_state = AxisState.CLOSED_LOOP_CONTROL
odrv.axis0.controller.input_vel = 1.2 # gentle start
t0 = time.time()
while time.time() - t0 < 6.0:
if odrv.axis0.current_state == AxisState.IDLE:
break
time.sleep(0.05)
Stop & idle
odrv.axis0.controller.input_vel = 0.0
time.sleep(0.3)
odrv.axis0.requested_state = AxisState.IDLE
diag(odrv)