Source code for drivers.motor

from pyb import Pin, Timer, ADC
import gc


[docs] class Motor: """ Simple motor driver wrapper for a Romi-style motor driver. Responsibilities: - configure a PWM channel for the motor - control the direction pin - control the sleep (enable) pin - provide a simple set_effort(value) interface where value is in -100..100 (percent). Positive values select one direction, negative values select the other direction. Notes: - `pwm`/`slp`/`dir` arguments may be either Pin instances or arguments that the pyb.Pin constructor accepts """ def __init__(self, pwm, tim, channel, slp, dir, battAdc): """ Initialize motor control. Parameters pwm -- pin identifier / pyb.Pin for PWM output (passed to Timer.channel) tim -- pyb.Timer instance used for PWM channel -- integer channel number for the timer (1..4 typically) slp -- pin identifier / pyb.Pin for sleep (enable) pin dir -- pin identifier / pyb.Pin for direction pin batt_adc -- pin identifier / pyb.Pin for battery ADC """ # Create/configure the timer channel for PWM (starts at 0% duty). # This mirrors the original usage of tim.channel(..., pulse_width_percent=0). self.pwm = tim.channel(channel, pin=pwm, mode=Timer.PWM, pulse_width_percent=0) # Configure direction and sleep pins as push-pull outputs. # Note: original code used Pin(slp, Pin.OUT_PP) etc., so we preserve that. self.sleep = Pin(slp, Pin.OUT_PP) self.dir = Pin(dir, Pin.OUT_PP) # Configure battery ADC pin for battery droop compensation self._battAdc = ADC(Pin(battAdc)) # Start disabled and with zero effort to match original behavior. self.disable() self.set_effort(0)
[docs] def enable(self): """Enable the motor driver by setting the SLEEP pin high.""" self.sleep.high()
[docs] def disable(self): """ Disable the motor driver by setting the SLEEP pin low. The original implementation also set effort to zero when disabling; we preserve that behavior by calling set_effort(0) first. """ # Reset PWM to zero effort before disabling (preserves original behavior). self.set_effort(0) self.sleep.low()
[docs] def set_effort(self, value): """ Set motor effort. `value` is interpreted as percent in the range -100..100 (as in the original code). Positive selects one direction, negative the opposite. The method writes the direction pin and then sets PWM duty to the absolute magnitude of `value` (via pulse_width_percent). The effort is capped such that 100% effort corresponds to 6.5V by measuring battery voltage and applying a scale factor to the effort requested IMPORTANT: behavior unchanged from original code — there is no extra validation/clamping here. """ # Choose direction pin state: # - original code sets dir.low() when value > 0, else dir.high() if value > 0: self.dir.low() else: self.dir.high() # --- Clip effort to valid range (-100 to 100) --- if value > 100: value = 100 elif value < -100: value = -100 # --- Scale value to account for battery droop adcVoltage = self._battAdc.read() / 4096 * 3.3 # Scale for 4.7k and 10k voltage divider. # (Slightly tweaked to account for actual VDD) battVoltage = adcVoltage / 0.305 # Calculate scaling factor effortScale = 6.5 / battVoltage # Apply scaling factor to battery voltage value *= effortScale # Apply absolute percent duty to PWM channel. self.pwm.pulse_width_percent(abs(value))
gc.collect()