diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fff3aa9..1dad804 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: source actions-ci/install.sh - name: Pip install pylint, black, & Sphinx run: | - pip install --force-reinstall pylint==1.9.2 black==19.10b0 Sphinx sphinx-rtd-theme + pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme - name: Library version run: git describe --dirty --always --tags - name: PyLint diff --git a/.pylintrc b/.pylintrc index cd65e95..d8f0ee8 100644 --- a/.pylintrc +++ b/.pylintrc @@ -119,7 +119,8 @@ spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO +# notes=FIXME,XXX,TODO +notes=FIXME,XXX [TYPECHECK] diff --git a/adafruit_motor/motor.py b/adafruit_motor/motor.py index 69d1a48..31d0b24 100644 --- a/adafruit_motor/motor.py +++ b/adafruit_motor/motor.py @@ -40,6 +40,7 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Motor.git" + 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". @@ -48,6 +49,7 @@ class DCMotor: when high and the other is low. :param ~pulseio.PWMOut negative_pwm: The motor input that causes the motor to spin backwards when high and the other is low.""" + def __init__(self, positive_pwm, negative_pwm): self._positive = positive_pwm self._negative = negative_pwm @@ -70,10 +72,10 @@ def throttle(self, value): self._positive.duty_cycle = 0 self._negative.duty_cycle = 0 elif value == 0: - self._positive.duty_cycle = 0xffff - self._negative.duty_cycle = 0xffff + self._positive.duty_cycle = 0xFFFF + self._negative.duty_cycle = 0xFFFF else: - duty_cycle = int(0xffff * abs(value)) + duty_cycle = int(0xFFFF * abs(value)) if value < 0: self._positive.duty_cycle = 0 self._negative.duty_cycle = duty_cycle diff --git a/adafruit_motor/servo.py b/adafruit_motor/servo.py index da760a2..80ef829 100644 --- a/adafruit_motor/servo.py +++ b/adafruit_motor/servo.py @@ -34,20 +34,21 @@ # We disable the too few public methods check because this is a private base class for the two types # of servos. -class _BaseServo: # pylint: disable-msg=too-few-public-methods +class _BaseServo: # pylint: disable-msg=too-few-public-methods """Shared base class that handles pulse output based on a value between 0 and 1.0 :param ~pulseio.PWMOut pwm_out: PWM output object. :param int min_pulse: The minimum pulse length of the servo in microseconds. :param int max_pulse: The maximum pulse length of the servo in microseconds.""" + def __init__(self, pwm_out, *, min_pulse=750, max_pulse=2250): self._pwm_out = pwm_out self.set_pulse_width_range(min_pulse, max_pulse) def set_pulse_width_range(self, min_pulse=750, max_pulse=2250): """Change min and max pulse widths.""" - self._min_duty = int((min_pulse * self._pwm_out.frequency) / 1000000 * 0xffff) - max_duty = (max_pulse * self._pwm_out.frequency) / 1000000 * 0xffff + self._min_duty = int((min_pulse * self._pwm_out.frequency) / 1000000 * 0xFFFF) + max_duty = (max_pulse * self._pwm_out.frequency) / 1000000 * 0xFFFF self._duty_range = int(max_duty - self._min_duty) @property @@ -56,20 +57,21 @@ def fraction(self): For conventional servos, corresponds to the servo position as a fraction of the actuation range. Is None when servo is diabled (pulsewidth of 0ms). """ - if self._pwm_out.duty_cycle == 0: # Special case for disabled servos + if self._pwm_out.duty_cycle == 0: # Special case for disabled servos return None return (self._pwm_out.duty_cycle - self._min_duty) / self._duty_range @fraction.setter def fraction(self, value): if value is None: - self._pwm_out.duty_cycle = 0 # disable the motor + self._pwm_out.duty_cycle = 0 # disable the motor return if not 0.0 <= value <= 1.0: raise ValueError("Must be 0.0 to 1.0") duty_cycle = self._min_duty + int(value * self._duty_range) self._pwm_out.duty_cycle = duty_cycle + class Servo(_BaseServo): """Control the position of a servo. @@ -99,6 +101,7 @@ class Servo(_BaseServo): the servo mechanism may hit the end stops, buzz, and draw extra current as it stalls. Test carefully to find the safe minimum and maximum. """ + def __init__(self, pwm_out, *, actuation_range=180, min_pulse=750, max_pulse=2250): super().__init__(pwm_out, min_pulse=min_pulse, max_pulse=max_pulse) self.actuation_range = actuation_range @@ -115,18 +118,20 @@ def angle(self): @angle.setter def angle(self, new_angle): - if new_angle is None: # disable the servo by sending 0 signal + if new_angle is None: # disable the servo by sending 0 signal self.fraction = None return if new_angle < 0 or new_angle > self.actuation_range: raise ValueError("Angle out of range") self.fraction = new_angle / self.actuation_range + class ContinuousServo(_BaseServo): """Control a continuous rotation servo. :param int min_pulse: The minimum pulse width of the servo in microseconds. :param int max_pulse: The maximum pulse width of the servo in microseconds.""" + @property def throttle(self): """How much power is being delivered to the motor. Values range from ``-1.0`` (full diff --git a/adafruit_motor/stepper.py b/adafruit_motor/stepper.py index ffa78bc..5873cec 100644 --- a/adafruit_motor/stepper.py +++ b/adafruit_motor/stepper.py @@ -57,6 +57,7 @@ """Step a fraction of a step by partially activating two neighboring coils. Step size is determined by ``microsteps`` constructor argument.""" + class StepperMotor: """A bipolar stepper motor or four coil unipolar motor. @@ -70,10 +71,11 @@ class StepperMotor: the fourth coil (unipolar) or second input to second coil (bipolar). :param int microsteps: Number of microsteps between full steps. Must be at least 2 and even. """ + def __init__(self, ain1, ain2, bin1, bin2, *, microsteps=16): self._coil = (ain2, bin1, ain1, bin2) - # set a safe pwm freq for each output + # set a safe pwm freq for each output for i in range(4): if self._coil[i].frequency < 1500: self._coil[i].frequency = 2000 @@ -84,8 +86,10 @@ def __init__(self, ain1, ain2, bin1, bin2, *, microsteps=16): if microsteps % 2 == 1: raise ValueError("Microsteps must be even") self._microsteps = microsteps - self._curve = [int(round(0xffff * math.sin(math.pi / (2 * microsteps) * i))) - for i in range(microsteps + 1)] + self._curve = [ + int(round(0xFFFF * math.sin(math.pi / (2 * microsteps) * i))) + for i in range(microsteps + 1) + ] self._update_coils() def _update_coils(self, *, microstepping=False): @@ -98,10 +102,12 @@ def _update_coils(self, *, microstepping=False): # This ensures DOUBLE steps use full torque. Without it, we'd use partial torque from the # microstepping curve (0xb504). - if not microstepping and (duty_cycles[leading_coil] == duty_cycles[trailing_coil] and - duty_cycles[leading_coil] > 0): - duty_cycles[leading_coil] = 0xffff - duty_cycles[trailing_coil] = 0xffff + if not microstepping and ( + duty_cycles[leading_coil] == duty_cycles[trailing_coil] + and duty_cycles[leading_coil] > 0 + ): + duty_cycles[leading_coil] = 0xFFFF + duty_cycles[trailing_coil] = 0xFFFF # Energize coils as appropriate: for i in range(4): @@ -145,8 +151,9 @@ def onestep(self, *, direction=FORWARD, style=SINGLE): step_size = half_step current_interleave = self._current_microstep // half_step - if ((style == SINGLE and current_interleave % 2 == 1) or - (style == DOUBLE and current_interleave % 2 == 0)): + if (style == SINGLE and current_interleave % 2 == 1) or ( + style == DOUBLE and current_interleave % 2 == 0 + ): step_size = half_step elif style in (SINGLE, DOUBLE): step_size = full_step diff --git a/docs/conf.py b/docs/conf.py index 121c2aa..707edb4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,8 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) + +sys.path.insert(0, os.path.abspath("..")) # -- General configuration ------------------------------------------------ @@ -10,9 +11,9 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", ] # Uncomment the below if you use native CircuitPython modules such as @@ -20,29 +21,32 @@ # autodoc module docs will fail to generate with a warning. # autodoc_mock_imports = ["micropython"] -intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3.4", None), + "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), +} # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Adafruit motor Library' -copyright = u'2017 Scott Shawcroft' -author = u'Scott Shawcroft' +project = u"Adafruit motor Library" +copyright = u"2017 Scott Shawcroft" +author = u"Scott Shawcroft" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = u"1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = u"1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -54,7 +58,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -66,7 +70,7 @@ add_function_parentheses = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -77,12 +81,13 @@ # Avoid an `= None` on instance attributes with their own doc strings. # Workaround from here: https://github.com/sphinx-doc/sphinx/issues/2044#issuecomment-285888160 # -from sphinx.ext.autodoc import ( - ClassLevelDocumenter, InstanceAttributeDocumenter) +from sphinx.ext.autodoc import ClassLevelDocumenter, InstanceAttributeDocumenter + def iad_add_directive_header(self, sig): ClassLevelDocumenter.add_directive_header(self, sig) + InstanceAttributeDocumenter.add_directive_header = iad_add_directive_header # -- Options for HTML output ---------------------------------------------- @@ -90,59 +95,62 @@ def iad_add_directive_header(self, sig): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] except: - html_theme = 'default' - html_theme_path = ['.'] + html_theme = "default" + html_theme_path = ["."] else: - html_theme_path = ['.'] + html_theme_path = ["."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # -html_favicon = '_static/favicon.ico' +html_favicon = "_static/favicon.ico" # Output file base name for HTML help builder. -htmlhelp_basename = 'AdafruitMotorLibrarydoc' +htmlhelp_basename = "AdafruitMotorLibrarydoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AdafruitmotorLibrary.tex', u'Adafruitmotor Library Documentation', - author, 'manual'), + ( + master_doc, + "AdafruitmotorLibrary.tex", + u"Adafruitmotor Library Documentation", + author, + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -150,8 +158,13 @@ def iad_add_directive_header(self, sig): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'Adafruitmotorlibrary', u'Adafruit motor Library Documentation', - [author], 1) + ( + master_doc, + "Adafruitmotorlibrary", + u"Adafruit motor Library Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -160,7 +173,13 @@ def iad_add_directive_header(self, sig): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AdafruitmotorLibrary', u'Adafruit motor Library Documentation', - author, 'AdafruitmotorLibrary', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "AdafruitmotorLibrary", + u"Adafruit motor Library Documentation", + author, + "AdafruitmotorLibrary", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/examples/motor_pca9685_dc_motor.py b/examples/motor_pca9685_dc_motor.py index 01e629f..c5c18d2 100644 --- a/examples/motor_pca9685_dc_motor.py +++ b/examples/motor_pca9685_dc_motor.py @@ -27,7 +27,7 @@ # cases. A capacitor can be used to help prevent this. The demo uses motor 4 because it worked ok # in testing without a capacitor. # See here for more info: https://learn.adafruit.com/adafruit-motor-shield-v2-for-arduino/faq#faq-13 -pca.channels[7].duty_cycle = 0xffff +pca.channels[7].duty_cycle = 0xFFFF motor4 = motor.DCMotor(pca.channels[5], pca.channels[6]) print("Forwards slow") diff --git a/examples/motor_pca9685_stepper_motor.py b/examples/motor_pca9685_stepper_motor.py index 39020af..824ce61 100644 --- a/examples/motor_pca9685_stepper_motor.py +++ b/examples/motor_pca9685_stepper_motor.py @@ -23,10 +23,11 @@ # Motor 3 is channels 3 and 4 with 2 held high. # Motor 4 is channels 5 and 6 with 7 held high. -pca.channels[7].duty_cycle = 0xffff -pca.channels[2].duty_cycle = 0xffff -stepper_motor = stepper.StepperMotor(pca.channels[4], pca.channels[3], # Motor 3 - pca.channels[5], pca.channels[6]) # Motor 4 +pca.channels[7].duty_cycle = 0xFFFF +pca.channels[2].duty_cycle = 0xFFFF +stepper_motor = stepper.StepperMotor( + pca.channels[4], pca.channels[3], pca.channels[5], pca.channels[6] +) for i in range(100): stepper_motor.onestep() diff --git a/setup.py b/setup.py index c84fe4f..5c9e73a 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ # Always prefer setuptools over distutils from setuptools import setup, find_packages + # To use a consistent encoding from codecs import open from os import path @@ -14,47 +15,38 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, "README.rst"), encoding="utf-8") as f: long_description = f.read() setup( - name='adafruit-circuitpython-motor', - + name="adafruit-circuitpython-motor", use_scm_version=True, - setup_requires=['setuptools_scm'], - - description='CircuitPython helper library provides higher level objects to control motors and servos.', + setup_requires=["setuptools_scm"], + description="CircuitPython helper library provides higher level objects to control motors and servos.", long_description=long_description, - long_description_content_type='text/x-rst', - + long_description_content_type="text/x-rst", # The project's main homepage. - url='https://github.com/adafruit/Adafruit_CircuitPython_Motor', - + url="https://github.com/adafruit/Adafruit_CircuitPython_Motor", # Author details - author='Adafruit Industries', - author_email='circuitpython@adafruit.com', - - install_requires=['Adafruit-Blinka'], - + author="Adafruit Industries", + author_email="circuitpython@adafruit.com", + install_requires=["Adafruit-Blinka"], # Choose your license - license='MIT', - + license="MIT", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Topic :: System :: Hardware', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ], - # What does your project relate to? - keywords='adafruit servo stepper motor hardware micropython circuitpython', - + keywords="adafruit servo stepper motor hardware micropython circuitpython", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). - packages=['adafruit_motor'], -) \ No newline at end of file + packages=["adafruit_motor"], +) diff --git a/tests/test_stepper.py b/tests/test_stepper.py index 3f939b6..e262ab2 100644 --- a/tests/test_stepper.py +++ b/tests/test_stepper.py @@ -3,12 +3,13 @@ from unittest.mock import MagicMock # Fix up the path to include our neighboring module. -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -micropython = MagicMock() # pylint: disable-msg=invalid-name +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +micropython = MagicMock() # pylint: disable-msg=invalid-name micropython.const = lambda x: x sys.modules["micropython"] = micropython -from adafruit_motor import stepper # pylint: disable-msg=wrong-import-position +from adafruit_motor import stepper # pylint: disable-msg=wrong-import-position + class Coil: def __init__(self): @@ -24,20 +25,22 @@ def duty_cycle(self): @duty_cycle.setter def duty_cycle(self, value): - assert 0 <= value <= 0xffff + assert 0 <= value <= 0xFFFF self._duty_cycle = value + def test_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]) # Always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) - for i in range(1, 7): # Test 6 steps so we wrap around + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) + for i in range(1, 7): # Test 6 steps so we wrap around motor.onestep() for j in range(4): - assert coil[j].duty_cycle == (0xffff if i % 4 == j else 0) + assert coil[j].duty_cycle == (0xFFFF if i % 4 == j else 0) + def test_double_coil(): coil = (Coil(), Coil(), Coil(), Coil()) @@ -45,11 +48,14 @@ def test_double_coil(): motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) # Despite double stepping we always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) - for i in range(6): # Test 6 steps so we wrap around + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) + for i in range(6): # Test 6 steps so we wrap around motor.onestep(style=stepper.DOUBLE) for j in range(4): - assert coil[j].duty_cycle == (0xffff if i % 4 == j or (i + 1) % 4 == j else 0) + assert coil[j].duty_cycle == ( + 0xFFFF if i % 4 == j or (i + 1) % 4 == j else 0 + ) + def test_interleave_steps(): coil = (Coil(), Coil(), Coil(), Coil()) @@ -57,25 +63,26 @@ def test_interleave_steps(): motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3]) # We always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) - for i in range(15): # Test 15 half steps so we wrap around + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) + for i in range(15): # Test 15 half steps so we wrap around motor.onestep(style=stepper.INTERLEAVE) for j in range(4): expected_value = 0 # Even half steps should be DOUBLE coil active steps. if i % 2 == 0: - if j == i // 2 % 4 or j == (i // 2 + 1) %4: - expected_value = 0xffff + if j == i // 2 % 4 or j == (i // 2 + 1) % 4: + expected_value = 0xFFFF # Odd half steps should be SINGLE coil active steps elif j == (i // 2 + 1) % 4: - expected_value = 0xffff + expected_value = 0xFFFF assert coil[j].duty_cycle == expected_value motor.onestep(direction=stepper.BACKWARD, style=stepper.INTERLEAVE) assert coil[0].duty_cycle == 0 assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xffff + assert coil[3].duty_cycle == 0xFFFF + def test_microstep_steps(): coil = (Coil(), Coil(), Coil(), Coil()) @@ -83,73 +90,75 @@ def test_microstep_steps(): motor = stepper.StepperMotor(coil[2], coil[0], coil[1], coil[3], microsteps=2) # We always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) motor.onestep(style=stepper.MICROSTEP) - assert coil[0].duty_cycle == 0xb504 - assert coil[1].duty_cycle == 0xb504 + assert coil[0].duty_cycle == 0xB504 + assert coil[1].duty_cycle == 0xB504 assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0 motor.onestep(style=stepper.MICROSTEP) assert coil[0].duty_cycle == 0x0 - assert coil[1].duty_cycle == 0xffff + assert coil[1].duty_cycle == 0xFFFF assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0 motor.onestep(style=stepper.MICROSTEP) assert coil[0].duty_cycle == 0 - assert coil[1].duty_cycle == 0xb504 - assert coil[2].duty_cycle == 0xb504 + assert coil[1].duty_cycle == 0xB504 + assert coil[2].duty_cycle == 0xB504 assert coil[3].duty_cycle == 0 motor.onestep(direction=stepper.BACKWARD, style=stepper.MICROSTEP) assert coil[0].duty_cycle == 0x0 - assert coil[1].duty_cycle == 0xffff + assert coil[1].duty_cycle == 0xFFFF assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0 + def test_double_to_single(): 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]) # We always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) motor.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE) - assert coil[0].duty_cycle == 0xffff + assert coil[0].duty_cycle == 0xFFFF assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xffff + assert coil[3].duty_cycle == 0xFFFF motor.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE) assert coil[0].duty_cycle == 0 assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xffff + assert coil[3].duty_cycle == 0xFFFF motor.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE) - assert coil[0].duty_cycle == 0xffff + assert coil[0].duty_cycle == 0xFFFF assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xffff + assert coil[3].duty_cycle == 0xFFFF motor.onestep(direction=stepper.FORWARD, style=stepper.SINGLE) - assert coil[0].duty_cycle == 0xffff + assert coil[0].duty_cycle == 0xFFFF assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0 + def test_microstep_to_single(): 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]) # We always start with a single step. for j in range(4): - assert coil[j].duty_cycle == (0xffff if j == 0 else 0) + assert coil[j].duty_cycle == (0xFFFF if j == 0 else 0) motor.onestep(direction=stepper.BACKWARD, style=stepper.MICROSTEP) - assert coil[0].duty_cycle == 0xfec3 + assert coil[0].duty_cycle == 0xFEC3 assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0x1918 @@ -158,16 +167,16 @@ def test_microstep_to_single(): assert coil[0].duty_cycle == 0 assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xffff + assert coil[3].duty_cycle == 0xFFFF motor.onestep(direction=stepper.FORWARD, style=stepper.MICROSTEP) assert coil[0].duty_cycle == 0x1918 assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 - assert coil[3].duty_cycle == 0xfec3 + assert coil[3].duty_cycle == 0xFEC3 motor.onestep(direction=stepper.FORWARD, style=stepper.SINGLE) - assert coil[0].duty_cycle == 0xffff + assert coil[0].duty_cycle == 0xFFFF assert coil[1].duty_cycle == 0 assert coil[2].duty_cycle == 0 assert coil[3].duty_cycle == 0