Skip to content

Commit

Permalink
New firmware support (#190)
Browse files Browse the repository at this point in the history
* New firmware

* Changes for new PID

* Remove bias test, as no longer exists

* Update pwm params

* Test down to 10ms interval

* Lower speed to improve positioning accuracy
  • Loading branch information
chrisruk authored Mar 31, 2023
1 parent 9c1dbb9 commit 1ac33cf
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 29 deletions.
Binary file modified buildhat/data/firmware.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion buildhat/data/signature.bin
Original file line number Diff line number Diff line change
@@ -1 +1 @@
�kt�Cr�>_iۼ*����c=Y옢3#��lw!H�w�F�Z2y���4���9��d鱾o
Q#�E]��]-.T~�駶�e[yE�V}A5�L��}���A�$I!�u�9Nzw`��l�@eK��;�{E�
2 changes: 1 addition & 1 deletion buildhat/data/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1670596313
1674818421
77 changes: 63 additions & 14 deletions buildhat/motors.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def __init__(self, port):
self._default_speed = 20
self._currentspeed = 0
self.plimit(0.7)
self.bias(0.3)

def set_default_speed(self, default_speed):
"""Set the default speed of the motor
Expand Down Expand Up @@ -79,10 +78,10 @@ def bias(self, bias):
:param bias: Value 0 to 1
:raises MotorError: Occurs if invalid bias value passed
"""
if not (bias >= 0 and bias <= 1):
raise MotorError("bias should be 0 to 1")
self._write(f"port {self.port} ; bias {bias}\r")
.. deprecated:: 0.6.0
""" # noqa: RST303
raise MotorError("Bias no longer available")


class MotorRunmode(Enum):
Expand Down Expand Up @@ -118,14 +117,22 @@ def __init__(self, port):
self._combi = "1 0 2 0 3 0"
self._noapos = False
self.plimit(0.7)
self.bias(0.3)
self.pwmparams(0.65, 0.01)
self._rpm = False
self._release = True
self._bqueue = deque(maxlen=5)
self._cvqueue = Condition()
self.when_rotated = None
self._oldpos = None
self._runmode = MotorRunmode.NONE

def set_speed_unit_rpm(self, rpm=False):
"""Set whether to use RPM for speed units or not
:param rpm: Boolean to determine whether to use RPM for units
"""
self._rpm = rpm

def set_default_speed(self, default_speed):
"""Set the default speed of the motor
Expand Down Expand Up @@ -200,11 +207,13 @@ def _run_positional_ramp(self, pos, newpos, speed):
:param newpos: New motor postion in decimal rotations (from preset position)
:param speed: -100 to 100
"""
# Collapse speed range to -5 to 5
speed *= 0.05
if self._rpm:
speed = self._speed_process(speed)
else:
speed *= 0.05 # Collapse speed range to -5 to 5
dur = abs((newpos - pos) / speed)
cmd = (f"port {self.port}; select 0 ; selrate {self._interval}; "
f"pid {self.port} 0 1 s4 0.0027777778 0 5 0 .1 3; "
f"pid {self.port} 0 1 s4 0.0027777778 0 5 0 .1 3 0.01; "
f"set ramp {pos} {newpos} {dur} 0\r")
ftr = Future()
self._hat.rampftr[self.port].append(ftr)
Expand Down Expand Up @@ -258,9 +267,14 @@ def run_to_position(self, degrees, speed=None, blocking=True, direction="shortes
self._run_to_position(degrees, speed, direction)

def _run_for_seconds(self, seconds, speed):
speed = self._speed_process(speed)
self._runmode = MotorRunmode.SECONDS
if self._rpm:
pid = f"pid_diff {self.port} 0 5 s2 0.0027777778 1 0 2.5 0 .4 0.01; "
else:
pid = f"pid {self.port} 0 0 s1 1 0 0.003 0.01 0 100 0.01;"
cmd = (f"port {self.port} ; select 0 ; selrate {self._interval}; "
f"pid {self.port} 0 0 s1 1 0 0.003 0.01 0 100; "
f"{pid}"
f"set pulse {speed} 0.0 {seconds} 0\r")
ftr = Future()
self._hat.pulseftr[self.port].append(ftr)
Expand Down Expand Up @@ -309,10 +323,15 @@ def start(self, speed=None):
else:
if not (speed >= -100 and speed <= 100):
raise MotorError("Invalid Speed")
speed = self._speed_process(speed)
cmd = f"port {self.port} ; set {speed}\r"
if self._runmode == MotorRunmode.NONE:
if self._rpm:
pid = f"pid_diff {self.port} 0 5 s2 0.0027777778 1 0 2.5 0 .4 0.01; "
else:
pid = f"pid {self.port} 0 0 s1 1 0 0.003 0.01 0 100 0.01; "
cmd = (f"port {self.port} ; select 0 ; selrate {self._interval}; "
f"pid {self.port} 0 0 s1 1 0 0.003 0.01 0 100; "
f"{pid}"
f"set {speed}\r")
self._runmode = MotorRunmode.FREE
self._currentspeed = speed
Expand Down Expand Up @@ -401,10 +420,23 @@ def bias(self, bias):
:param bias: Value 0 to 1
:raises MotorError: Occurs if invalid bias value passed
.. deprecated:: 0.6.0
""" # noqa: RST303
raise MotorError("Bias no longer available")

def pwmparams(self, pwmthresh, minpwm):
"""PWM thresholds
:param pwmthresh: Value 0 to 1, threshold below, will switch from fast to slow, PWM
:param minpwm: Value 0 to 1, threshold below which it switches off the drive altogether
:raises MotorError: Occurs if invalid values are passed
"""
if not (bias >= 0 and bias <= 1):
raise MotorError("bias should be 0 to 1")
self._write(f"port {self.port} ; bias {bias}\r")
if not (pwmthresh >= 0 and pwmthresh <= 1):
raise MotorError("pwmthresh should be 0 to 1")
if not (minpwm >= 0 and minpwm <= 1):
raise MotorError("minpwm should be 0 to 1")
self._write(f"port {self.port} ; pwmparams {pwmthresh} {minpwm}\r")

def pwm(self, pwmv):
"""PWM motor
Expand Down Expand Up @@ -453,6 +485,13 @@ def _wait_for_nonblocking(self):
"""Wait for nonblocking commands to finish"""
Device._instance.motorqueue[self.port].join()

def _speed_process(self, speed):
"""Lower speed value"""
if self._rpm:
return speed / 60
else:
return speed


class MotorPair:
"""Pair of motors
Expand All @@ -473,6 +512,7 @@ def __init__(self, leftport, rightport):
self._rightmotor = Motor(rightport)
self.default_speed = 20
self._release = True
self._rpm = False

def set_default_speed(self, default_speed):
"""Set the default speed of the motor
Expand All @@ -481,6 +521,15 @@ def set_default_speed(self, default_speed):
"""
self.default_speed = default_speed

def set_speed_unit_rpm(self, rpm=False):
"""Set whether to use RPM for speed units or not
:param rpm: Boolean to determine whether to use RPM for units
"""
self._rpm = rpm
self._leftmotor.set_speed_unit_rpm(rpm)
self._rightmotor.set_speed_unit_rpm(rpm)

def run_for_rotations(self, rotations, speedl=None, speedr=None):
"""Run pair of motors for N rotations
Expand Down
17 changes: 4 additions & 13 deletions test/motors.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def test_rotations(self):
def test_nonblocking(self):
"""Test motor nonblocking mode"""
m = Motor('A')
m.set_default_speed(10)
last = 0
for delay in [1, 0]:
for _ in range(3):
Expand All @@ -44,7 +45,9 @@ def test_nonblocking(self):
def test_nonblocking_multiple(self):
"""Test motor nonblocking mode"""
m1 = Motor('A')
m1.set_default_speed(10)
m2 = Motor('B')
m2.set_default_speed(10)
last = 0
for delay in [1, 0]:
for _ in range(3):
Expand Down Expand Up @@ -118,13 +121,6 @@ def test_plimit(self):
self.assertRaises(MotorError, m.plimit, -1)
self.assertRaises(MotorError, m.plimit, 2)

def test_bias(self):
"""Test setting motor bias"""
m = Motor('A')
m.bias(0.5)
self.assertRaises(MotorError, m.bias, -1)
self.assertRaises(MotorError, m.bias, 2)

def test_pwm(self):
"""Test PWMing motor"""
m = Motor('A')
Expand Down Expand Up @@ -157,11 +153,6 @@ def handle_motor(speed, pos, apos):
m.run_for_seconds(5)
self.assertGreater(handle_motor.evt, 0.8 * ((1 / ((m.interval) * 1e-3)) * 5))

handle_motor.evt = 0
m.interval = 5
m.run_for_seconds(5)
self.assertGreater(handle_motor.evt, 0.8 * ((1 / ((m.interval) * 1e-3)) * 5))

def test_none_callback(self):
"""Test setting empty callback"""
m = Motor('A')
Expand Down Expand Up @@ -234,7 +225,7 @@ def test_dual_interval(self):
"""Test dual motor interval"""
m1 = Motor('A')
m2 = Motor('B')
for interval in [10, 5]:
for interval in [20, 10]:
m1.interval = interval
m2.interval = interval
count = 1000
Expand Down

0 comments on commit 1ac33cf

Please sign in to comment.