diff --git a/ODrive/Gemini.config b/ODrive/Gemini.config new file mode 100644 index 0000000..43a05bf --- /dev/null +++ b/ODrive/Gemini.config @@ -0,0 +1,128 @@ +# Torque control, pole pair and current tweak + +# 1. Reset configuration to a clean slate +odrv0.erase_configuration() + +# Cap total board draw at 27A to protect 30A regulatory fuse (3A safety buffer) +odrv0.config.dc_max_positive_current = 27.0 +# Max current allowed back into the battery pack during aggressive braking +odrv0.config.dc_max_negative_current = -20.0 + +# --- MOTOR CONFIGURATION (VEVOR 1800W / 2000W OPTIMIZED) --- +# Axis 0 +odrv0.axis0.motor.config.pole_pairs = 4 # Correct Vevor magnet count +odrv0.axis0.motor.config.current_lim = 30.0 # Max allowed phase current for torque +odrv0.axis0.motor.config.calibration_current = 10.0 +odrv0.axis0.motor.config.current_lim_margin = 12.0 # Isolates spikes from throwing a fault +odrv0.axis0.motor.config.requested_current_range = 45.0 # Gives shunt amps room to read +odrv0.axis0.motor.config.torque_constant = 0.0919 # Tidied precision (8.27 / 90 KV) +odrv0.axis0.motor.config.resistance_calib_max_voltage = 6.0 +odrv0.axis0.motor.config.current_control_bandwidth = 100.0 # Low bandwidth stops sensor noise/saturation +odrv0.axis0.config.I_bus_hard_max = 20.0 # Max battery draw allowed for this single axis + +# Axis 1 +odrv0.axis1.motor.config.pole_pairs = 4 +odrv0.axis1.motor.config.current_lim = 30.0 +odrv0.axis1.motor.config.calibration_current = 10.0 +odrv0.axis1.motor.config.current_lim_margin = 12.0 +odrv0.axis1.motor.config.requested_current_range = 45.0 +odrv0.axis1.motor.config.torque_constant = 0.0919 +odrv0.axis1.motor.config.resistance_calib_max_voltage = 6.0 +odrv0.axis1.motor.config.current_control_bandwidth = 100.0 +odrv0.axis1.config.I_bus_hard_max = 20.0 + +# --- ENCODER CONFIGURATION (HALL SENSORS) --- +# Axis 0 +odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL +odrv0.axis0.encoder.config.cpr = 24 # 4 Pole Pairs * 6 = 24 +odrv0.axis0.encoder.config.ignore_illegal_hall_state = True +odrv0.axis0.encoder.config.calib_scan_distance = 150.0 +odrv0.axis0.encoder.config.bandwidth = 100.0 + +# Axis 1 +odrv0.axis1.encoder.config.mode = ENCODER_MODE_HALL +odrv0.axis1.encoder.config.cpr = 24 +odrv0.axis1.encoder.config.ignore_illegal_hall_state = True +odrv0.axis1.encoder.config.calib_scan_distance = 150.0 +odrv0.axis1.encoder.config.bandwidth = 100.0 + +# --- CONTROLLER CONFIGURATION (TORQUE MODE & GAINS) --- +# Axis 0 +odrv0.axis0.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL +odrv0.axis0.controller.config.pos_gain = 50.0 +odrv0.axis0.controller.config.vel_gain = 0.1 +odrv0.axis0.controller.config.vel_integrator_gain = 0.2 +odrv0.axis0.controller.config.vel_limit = 85.0 # Hard RPM safety ceiling (~5200 RPM) +odrv0.axis0.controller.config.vel_ramp_rate = 30.0 + +# Axis 1 +odrv0.axis1.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL +odrv0.axis1.controller.config.pos_gain = 50.0 +odrv0.axis1.controller.config.vel_gain = 0.1 +odrv0.axis1.controller.config.vel_integrator_gain = 0.2 +odrv0.axis1.controller.config.vel_limit = 85.0 +odrv0.axis1.controller.config.vel_ramp_rate = 30.0 + +# Save and reboot +print("Saving configuration and rebooting... Reconnect your terminal in a moment.") +odrv0.save_configuration() +try: + odrv0.reboot() +except Exception: + pass + + +Phase 2: Live Calibration Setup + +Wait for the ODrive to reboot and reconnect. Keep the wheels off the ground. +Python + +print("Starting calibration sequence. Motors will beep and turn slowly...") +odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE +odrv0.axis1.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE + +# WAIT until the motors finish moving completely before continuing! + +Verify everything passed cleanly: +Python + +dump_errors(odrv0) +print(f"Axis 0 Ready: {odrv0.axis0.encoder.is_ready} | Axis 1 Ready: {odrv0.axis1.encoder.is_ready}") + +Phase 3: Lock and Commit (No More Calibrations) +Python + +# Save current calibration state as permanent baseline +odrv0.axis0.motor.config.pre_calibrated = True +odrv0.axis0.encoder.config.pre_calibrated = True +odrv0.axis1.motor.config.pre_calibrated = True +odrv0.axis1.encoder.config.pre_calibrated = True + +# Skip future startup calibrations and arm automatically on power-up +odrv0.axis0.config.startup_motor_calibration = False +odrv0.axis0.config.startup_encoder_offset_calibration = False +odrv0.axis0.config.startup_closed_loop_control = True + +odrv0.axis1.config.startup_motor_calibration = False +odrv0.axis1.config.startup_encoder_offset_calibration = False +odrv0.axis1.config.startup_closed_loop_control = True + +odrv0.save_configuration() +print("Calibration locked! System set to Motorcycle-Style Twist Torque Control.") + +Phase 4: Inputs and Controls Configuration +Twist-Grip Analog Torque Mapping (GPIO 3 & 4) +Python + +# Axis 0 Analog Input (GPIO 3) +odrv0.config.gpio3_analog_mapping.min = 0.0 # Twist grip at rest = 0.0 Nm (Coasting) +odrv0.config.gpio3_analog_mapping.max = 75.0 # Full twist = 75.0 Nm max acceleration torque +odrv0.config.gpio3_analog_mapping.endpoint = odrv0.axis0.controller._input_torque_property + +# Axis 1 Analog Input (GPIO 4) +odrv0.config.gpio4_analog_mapping.min = 0.0 +odrv0.config.gpio4_analog_mapping.max = 75.0 +odrv0.config.gpio4_analog_mapping.endpoint = odrv0.axis1.controller._input_torque_property + +odrv0.save_configuration() +print("Twist grip torque mapping complete! Good luck out on the track.")