From e4fb8426d0d42368a33844003061389f7fb3ca23 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Tue, 9 Mar 2021 16:11:16 -0800 Subject: [PATCH 01/10] Update motor.py Add recirculation current decay mode to throttle control; add decay mode setter/getter; default to fast decay (coasting mode) to preserve performance of legacy applications --- adafruit_motor/motor.py | 58 +++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index 503baeb..f2c8c9f 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -20,14 +20,27 @@ * Author(s): Scott Shawcroft """ -__version__ = "0.0.0-auto.0" +__version__ = "3.2.7" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Motor.git" +from micropython import const + +FAST_DECAY = const(0) # Recirculation current fast decay mode (coasting) +SLOW_DECAY = const(1) # Recirculation current slow decay mode (braking) class DCMotor: """DC motor driver. ``positive_pwm`` and ``negative_pwm`` can be swapped if the motor runs in the opposite direction from what was expected for "forwards". + Motor controller recirculation current decay mode is selectable and defaults to + ``motor.FAST_DECAY`` (coasting). ``motor.SLOW_DECAY`` is recommended to improve spin + threshold, speed-to-throttle linearity, and PWM frequency sensitivity. + + Decay mode settings only effect the operational performance of controller chips such + as the DRV8833, DRV8871, and TB6612. Although either decay mode setting is compatible + with discrete h-bridge controller circuitry such as the L9110H and L293D, operational + performance will not be altered. + :param ~pwmio.PWMOut positive_pwm: The motor input that causes the motor to spin forwards when high and the other is low. :param ~pwmio.PWMOut negative_pwm: The motor input that causes the motor to spin backwards @@ -37,11 +50,12 @@ def __init__(self, positive_pwm, negative_pwm): self._positive = positive_pwm self._negative = negative_pwm self._throttle = None + self._decay_mode = FAST_DECAY @property def throttle(self): """Motor speed, ranging from -1.0 (full speed reverse) to 1.0 (full speed forward), - or ``None``. + or ``None`` (controller off). If ``None``, both PWMs are turned full off. If ``0.0``, both PWMs are turned full on. """ return self._throttle @@ -49,22 +63,44 @@ def throttle(self): @throttle.setter def throttle(self, value): if value is not None and (value > 1.0 or value < -1.0): - raise ValueError("Throttle must be None or between -1.0 and 1.0") + raise ValueError("Throttle must be None or between -1.0 and +1.0") self._throttle = value - if value is None: + if value is None: # Turn off motor controller (high-Z) self._positive.duty_cycle = 0 self._negative.duty_cycle = 0 - elif value == 0: + elif value == 0: # Brake motor (low-Z) self._positive.duty_cycle = 0xFFFF self._negative.duty_cycle = 0xFFFF else: duty_cycle = int(0xFFFF * abs(value)) - if value < 0: - self._positive.duty_cycle = 0 - self._negative.duty_cycle = duty_cycle - else: - self._positive.duty_cycle = duty_cycle - self._negative.duty_cycle = 0 + if self._decay_mode == SLOW_DECAY: # Slow Decay (Braking) Mode + if value < 0: + self._positive.duty_cycle = 0xffff - duty_cycle + self._negative.duty_cycle = 0xffff + else: + self._positive.duty_cycle = 0xffff + self._negative.duty_cycle = 0xffff - duty_cycle + else: # Default Fast Decay (Coasting) Mode + if value < 0: + self._positive.duty_cycle = 0 + self._negative.duty_cycle = duty_cycle + else: + self._positive.duty_cycle = duty_cycle + self._negative.duty_cycle = 0 + + @property + def decay_mode(self): + """Motor controller recirculation current decay mode. A value of ``motor.FAST_DECAY`` + sets the motor controller to the default fast recirculation current decay mode + (coasting); ``motor.SLOW_DECAY`` sets slow decay (braking) mode.""" + return self._decay_mode + + @decay_mode.setter + def decay_mode(self, mode=FAST_DECAY): + if mode in (FAST_DECAY, SLOW_DECAY): + self._decay_mode = mode + else: + raise ValueError("Decay mode value must be either motor.FAST_DECAY or motor.SLOW_DECAY") def __enter__(self): return self From 3436e302201e7646b7cfcbef15b23b1ba4bbb139 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Tue, 9 Mar 2021 17:09:00 -0800 Subject: [PATCH 02/10] passed black --- adafruit_motor/motor.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index f2c8c9f..93ff008 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -28,6 +28,7 @@ FAST_DECAY = const(0) # Recirculation current fast decay mode (coasting) SLOW_DECAY = const(1) # Recirculation current slow decay mode (braking) + class DCMotor: """DC motor driver. ``positive_pwm`` and ``negative_pwm`` can be swapped if the motor runs in the opposite direction from what was expected for "forwards". @@ -75,11 +76,11 @@ def throttle(self, value): duty_cycle = int(0xFFFF * abs(value)) if self._decay_mode == SLOW_DECAY: # Slow Decay (Braking) Mode if value < 0: - self._positive.duty_cycle = 0xffff - duty_cycle - self._negative.duty_cycle = 0xffff + self._positive.duty_cycle = 0xFFFF - duty_cycle + self._negative.duty_cycle = 0xFFFF else: - self._positive.duty_cycle = 0xffff - self._negative.duty_cycle = 0xffff - duty_cycle + self._positive.duty_cycle = 0xFFFF + self._negative.duty_cycle = 0xFFFF - duty_cycle else: # Default Fast Decay (Coasting) Mode if value < 0: self._positive.duty_cycle = 0 @@ -100,7 +101,9 @@ def decay_mode(self, mode=FAST_DECAY): if mode in (FAST_DECAY, SLOW_DECAY): self._decay_mode = mode else: - raise ValueError("Decay mode value must be either motor.FAST_DECAY or motor.SLOW_DECAY") + raise ValueError( + "Decay mode value must be either motor.FAST_DECAY or motor.SLOW_DECAY" + ) def __enter__(self): return self From 9df0164e8f92811257998ae74e2a86d1fcee5db2 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 15:33:08 -0700 Subject: [PATCH 03/10] update motor.py and pca9685 example --- adafruit_motor/motor.py | 8 ++++---- examples/motor_pca9685_dc_motor.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index 93ff008..ecbca28 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries +# SPDX-FileCopyrightText: 2021 Scott Shawcroft for Adafruit Industries # # SPDX-License-Identifier: MIT @@ -38,9 +38,9 @@ class DCMotor: threshold, speed-to-throttle linearity, and PWM frequency sensitivity. Decay mode settings only effect the operational performance of controller chips such - as the DRV8833, DRV8871, and TB6612. Although either decay mode setting is compatible - with discrete h-bridge controller circuitry such as the L9110H and L293D, operational - performance will not be altered. + as the DRV8833, DRV8871, and TB6612. Either decay mode setting is compatible + with discrete h-bridge controller circuitry such as the L9110H and L293D; operational + performance is not altered. :param ~pwmio.PWMOut positive_pwm: The motor input that causes the motor to spin forwards when high and the other is low. diff --git a/examples/motor_pca9685_dc_motor.py b/examples/motor_pca9685_dc_motor.py index cec9aa9..27f5f5a 100644 --- a/examples/motor_pca9685_dc_motor.py +++ b/examples/motor_pca9685_dc_motor.py @@ -32,6 +32,7 @@ # See here for more info: https://learn.adafruit.com/adafruit-motor-shield-v2-for-arduino/faq#faq-13 pca.channels[7].duty_cycle = 0xFFFF motor4 = motor.DCMotor(pca.channels[5], pca.channels[6]) +motor4.decay_mode = motor.SLOW_DECAY # Set motor to active braking mode to improve performance print("Forwards slow") motor4.throttle = 0.5 From de07607e2aabd39e7cb3b4a978fd30df153becc4 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 16:31:06 -0700 Subject: [PATCH 04/10] black passed --- examples/motor_pca9685_dc_motor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/motor_pca9685_dc_motor.py b/examples/motor_pca9685_dc_motor.py index 27f5f5a..17e34bb 100644 --- a/examples/motor_pca9685_dc_motor.py +++ b/examples/motor_pca9685_dc_motor.py @@ -32,7 +32,9 @@ # See here for more info: https://learn.adafruit.com/adafruit-motor-shield-v2-for-arduino/faq#faq-13 pca.channels[7].duty_cycle = 0xFFFF motor4 = motor.DCMotor(pca.channels[5], pca.channels[6]) -motor4.decay_mode = motor.SLOW_DECAY # Set motor to active braking mode to improve performance +motor4.decay_mode = ( + motor.SLOW_DECAY +) # Set motor to active braking mode to improve performance print("Forwards slow") motor4.throttle = 0.5 From 163d7ca4ded4fd9550ade19c8cd4da61e9b96281 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 21:29:57 -0700 Subject: [PATCH 05/10] Update test_stepper.py --- tests/test_stepper.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_stepper.py b/tests/test_stepper.py index 24673cf..2668fc3 100644 --- a/tests/test_stepper.py +++ b/tests/test_stepper.py @@ -2,6 +2,18 @@ # # SPDX-License-Identifier: Unlicense +""" +`test_stepper` +==================================================== + +Tests stepper functionality. + +* Author(s): ladyada +""" + +__version__ = "1.0.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Motor.git" + import os import sys from unittest.mock import MagicMock @@ -16,6 +28,8 @@ class Coil: + """Class Coil""" + def __init__(self): self._duty_cycle = 0 From abee3d32002c3674f14864a1e298ccd0591c5ee5 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 21:35:54 -0700 Subject: [PATCH 06/10] Update test_stepper.py --- tests/test_stepper.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_stepper.py b/tests/test_stepper.py index 2668fc3..b03d201 100644 --- a/tests/test_stepper.py +++ b/tests/test_stepper.py @@ -35,10 +35,12 @@ def __init__(self): @property def frequency(self): + """Default frequency setting""" return 1500 @property def duty_cycle(self): + """16-bit duty cycle value""" return self._duty_cycle @duty_cycle.setter @@ -48,6 +50,7 @@ def duty_cycle(self, value): def test_single_coil(): + """Tests single coil""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) @@ -61,6 +64,7 @@ def test_single_coil(): def test_double_coil(): + """Tests double coil""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) @@ -76,6 +80,7 @@ def test_double_coil(): def test_interleave_steps(): + """Tests interleave steps""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) @@ -103,6 +108,7 @@ def test_interleave_steps(): def test_microstep_steps(): + """Tests microsteps""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3], microsteps=2) @@ -135,6 +141,7 @@ def test_microstep_steps(): def test_double_to_single(): + """Tests double to single movement""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) @@ -168,6 +175,7 @@ def test_double_to_single(): def test_microstep_to_single(): + """Tests microsteps to single movement""" coil = (Coil(), Coil(), Coil(), Coil()) # We undo the coil order so our tests make more sense. motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) From 588fa433e5bd0fe3bcef7438b287c5f03653ed13 Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 21:42:46 -0700 Subject: [PATCH 07/10] Update test_stepper.py --- tests/test_stepper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_stepper.py b/tests/test_stepper.py index b03d201..9c45dc5 100644 --- a/tests/test_stepper.py +++ b/tests/test_stepper.py @@ -26,6 +26,7 @@ from adafruit_motor import stepper # pylint: disable-msg=wrong-import-position +#pylint: disable=consider-using-in class Coil: """Class Coil""" From 045ad7d80f0a8bc6256b5cffdf543d5512673dfb Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Sun, 14 Mar 2021 21:45:45 -0700 Subject: [PATCH 08/10] Update test_stepper.py --- tests/test_stepper.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_stepper.py b/tests/test_stepper.py index 9c45dc5..73c312a 100644 --- a/tests/test_stepper.py +++ b/tests/test_stepper.py @@ -26,7 +26,8 @@ from adafruit_motor import stepper # pylint: disable-msg=wrong-import-position -#pylint: disable=consider-using-in +# pylint: disable=consider-using-in + class Coil: """Class Coil""" From dde3a8a73096c02147890299423ff4bdbc1cfcaf Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Mon, 15 Mar 2021 16:32:04 -0700 Subject: [PATCH 09/10] update version number to "auto" --- adafruit_motor/motor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index ecbca28..ed65201 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -20,7 +20,7 @@ * Author(s): Scott Shawcroft """ -__version__ = "3.2.7" +__version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Motor.git" from micropython import const From 413c3c32d0dec620b89874dbf4ee6b3e77ccd28f Mon Sep 17 00:00:00 2001 From: Cedar Grove Maker Studios Date: Tue, 16 Mar 2021 19:17:01 -0700 Subject: [PATCH 10/10] drop const and improve docs: motor.py Co-authored-by: Scott Shawcroft --- adafruit_motor/motor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index ed65201..61f6253 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -23,10 +23,11 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Motor.git" -from micropython import const +FAST_DECAY = 0 +"""Recirculation current fast decay mode (coasting)""" -FAST_DECAY = const(0) # Recirculation current fast decay mode (coasting) -SLOW_DECAY = const(1) # Recirculation current slow decay mode (braking) +SLOW_DECAY = 1 +"""Recirculation current slow decay mode (braking)""" class DCMotor: