mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2025-10-29 17:50:37 +00:00
Add a pwm option to the RGBLED and Motor constructors
...along with the other necessary changes required, to allow them to optionally be used with non-PWM-capable pins
This commit is contained in:
@@ -28,7 +28,7 @@ PWMLED
|
||||
RGBLED
|
||||
======
|
||||
|
||||
.. autoclass:: RGBLED(red, green, blue, active_high=True, initial_value=(0, 0, 0))
|
||||
.. autoclass:: RGBLED(red, green, blue, active_high=True, initial_value=(0, 0, 0), pwm=True)
|
||||
:members: on, off, toggle, blink, pulse, red, green, blue, is_lit, color
|
||||
|
||||
Buzzer
|
||||
@@ -40,7 +40,7 @@ Buzzer
|
||||
Motor
|
||||
=====
|
||||
|
||||
.. autoclass:: Motor(forward, backward)
|
||||
.. autoclass:: Motor(forward, backward, pwm=True)
|
||||
:members: forward, backward, stop
|
||||
|
||||
Base Classes
|
||||
|
||||
@@ -5,6 +5,7 @@ digraph classes {
|
||||
node [shape=rect, style=filled, color="#298029", fontname=Sans, fontcolor="#ffffff", fontsize=10];
|
||||
edge [arrowhead=onormal, style=dashed];
|
||||
|
||||
RGBLED->LED;
|
||||
RGBLED->PWMLED;
|
||||
LEDBoard->LED;
|
||||
LEDBoard->PWMLED;
|
||||
@@ -16,5 +17,6 @@ digraph classes {
|
||||
TrafficLightsBuzzer->Button;
|
||||
|
||||
Robot->Motor;
|
||||
Motor->DigitalOutputDevice;
|
||||
Motor->PWMOutputDevice;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 30 KiB |
@@ -4,120 +4,135 @@
|
||||
<!-- Generated by graphviz version 2.36.0 (20140111.2315)
|
||||
-->
|
||||
<!-- Title: classes Pages: 1 -->
|
||||
<svg width="563pt" height="188pt"
|
||||
viewBox="0.00 0.00 563.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="575pt" height="188pt"
|
||||
viewBox="0.00 0.00 575.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
|
||||
<title>classes</title>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-184 559,-184 559,4 -4,4"/>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-184 571,-184 571,4 -4,4"/>
|
||||
<!-- RGBLED -->
|
||||
<g id="node1" class="node"><title>RGBLED</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="55.5,-180 0.5,-180 0.5,-144 55.5,-144 55.5,-180"/>
|
||||
<text text-anchor="middle" x="28" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">RGBLED</text>
|
||||
</g>
|
||||
<!-- LED -->
|
||||
<g id="node2" class="node"><title>LED</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="78,-108 24,-108 24,-72 78,-72 78,-108"/>
|
||||
<text text-anchor="middle" x="51" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">LED</text>
|
||||
</g>
|
||||
<!-- RGBLED->LED -->
|
||||
<g id="edge1" class="edge"><title>RGBLED->LED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M33.6854,-143.697C36.2478,-135.898 39.3329,-126.509 42.1847,-117.829"/>
|
||||
<polygon fill="none" stroke="black" points="45.5835,-118.697 45.38,-108.104 38.9333,-116.512 45.5835,-118.697"/>
|
||||
</g>
|
||||
<!-- PWMLED -->
|
||||
<g id="node2" class="node"><title>PWMLED</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="143.5,-108 86.5,-108 86.5,-72 143.5,-72 143.5,-108"/>
|
||||
<text text-anchor="middle" x="115" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text>
|
||||
<g id="node3" class="node"><title>PWMLED</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="153.5,-108 96.5,-108 96.5,-72 153.5,-72 153.5,-108"/>
|
||||
<text text-anchor="middle" x="125" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text>
|
||||
</g>
|
||||
<!-- RGBLED->PWMLED -->
|
||||
<g id="edge1" class="edge"><title>RGBLED->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M49.5056,-143.697C60.4625,-134.881 73.9459,-124.032 85.8249,-114.474"/>
|
||||
<polygon fill="none" stroke="black" points="88.1446,-117.1 93.7418,-108.104 83.7565,-111.646 88.1446,-117.1"/>
|
||||
<g id="edge2" class="edge"><title>RGBLED->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M51.9775,-143.697C64.3113,-134.796 79.5164,-123.823 92.853,-114.199"/>
|
||||
<polygon fill="none" stroke="black" points="95.2374,-116.794 101.298,-108.104 91.1411,-111.118 95.2374,-116.794"/>
|
||||
</g>
|
||||
<!-- LEDBoard -->
|
||||
<g id="node3" class="node"><title>LEDBoard</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="238,-180 174,-180 174,-144 238,-144 238,-180"/>
|
||||
<text text-anchor="middle" x="206" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBoard</text>
|
||||
</g>
|
||||
<!-- LEDBoard->PWMLED -->
|
||||
<g id="edge3" class="edge"><title>LEDBoard->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M183.506,-143.697C172.045,-134.881 157.942,-124.032 145.516,-114.474"/>
|
||||
<polygon fill="none" stroke="black" points="147.296,-111.427 137.236,-108.104 143.028,-116.976 147.296,-111.427"/>
|
||||
</g>
|
||||
<!-- LED -->
|
||||
<g id="node4" class="node"><title>LED</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="224,-108 170,-108 170,-72 224,-72 224,-108"/>
|
||||
<text text-anchor="middle" x="197" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">LED</text>
|
||||
<g id="node4" class="node"><title>LEDBoard</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="138,-180 74,-180 74,-144 138,-144 138,-180"/>
|
||||
<text text-anchor="middle" x="106" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBoard</text>
|
||||
</g>
|
||||
<!-- LEDBoard->LED -->
|
||||
<g id="edge2" class="edge"><title>LEDBoard->LED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M203.775,-143.697C202.783,-135.983 201.592,-126.712 200.486,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="203.946,-117.576 199.199,-108.104 197.003,-118.469 203.946,-117.576"/>
|
||||
<g id="edge3" class="edge"><title>LEDBoard->LED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M92.4045,-143.697C85.8773,-135.389 77.932,-125.277 70.7534,-116.141"/>
|
||||
<polygon fill="none" stroke="black" points="73.3695,-113.805 64.4391,-108.104 67.8653,-118.13 73.3695,-113.805"/>
|
||||
</g>
|
||||
<!-- LEDBoard->PWMLED -->
|
||||
<g id="edge4" class="edge"><title>LEDBoard->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M110.697,-143.697C112.813,-135.898 115.362,-126.509 117.718,-117.829"/>
|
||||
<polygon fill="none" stroke="black" points="121.116,-118.672 120.357,-108.104 114.36,-116.838 121.116,-118.672"/>
|
||||
</g>
|
||||
<!-- LEDBarGraph -->
|
||||
<g id="node5" class="node"><title>LEDBarGraph</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="155.25,-180 74.75,-180 74.75,-144 155.25,-144 155.25,-180"/>
|
||||
<text text-anchor="middle" x="115" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBarGraph</text>
|
||||
</g>
|
||||
<!-- LEDBarGraph->PWMLED -->
|
||||
<g id="edge5" class="edge"><title>LEDBarGraph->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M115,-143.697C115,-135.983 115,-126.712 115,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="118.5,-118.104 115,-108.104 111.5,-118.104 118.5,-118.104"/>
|
||||
<polygon fill="#298029" stroke="#298029" points="237.25,-180 156.75,-180 156.75,-144 237.25,-144 237.25,-180"/>
|
||||
<text text-anchor="middle" x="197" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBarGraph</text>
|
||||
</g>
|
||||
<!-- LEDBarGraph->LED -->
|
||||
<g id="edge4" class="edge"><title>LEDBarGraph->LED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M135.27,-143.697C145.498,-134.965 158.061,-124.24 169.178,-114.75"/>
|
||||
<polygon fill="none" stroke="black" points="171.63,-117.259 176.963,-108.104 167.085,-111.935 171.63,-117.259"/>
|
||||
<g id="edge5" class="edge"><title>LEDBarGraph->LED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M161.284,-143.876C138.829,-133.11 109.939,-119.258 87.3611,-108.433"/>
|
||||
<polygon fill="none" stroke="black" points="88.639,-105.165 78.1086,-103.997 85.6126,-111.477 88.639,-105.165"/>
|
||||
</g>
|
||||
<!-- LEDBarGraph->PWMLED -->
|
||||
<g id="edge6" class="edge"><title>LEDBarGraph->PWMLED</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M179.202,-143.697C170.396,-135.135 159.618,-124.656 149.999,-115.304"/>
|
||||
<polygon fill="none" stroke="black" points="152.203,-112.566 142.593,-108.104 147.323,-117.585 152.203,-112.566"/>
|
||||
</g>
|
||||
<!-- TrafficLightsBuzzer -->
|
||||
<g id="node6" class="node"><title>TrafficLightsBuzzer</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="411.25,-180 306.75,-180 306.75,-144 411.25,-144 411.25,-180"/>
|
||||
<text text-anchor="middle" x="359" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLightsBuzzer</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="360.25,-180 255.75,-180 255.75,-144 360.25,-144 360.25,-180"/>
|
||||
<text text-anchor="middle" x="308" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLightsBuzzer</text>
|
||||
</g>
|
||||
<!-- TrafficLights -->
|
||||
<g id="node7" class="node"><title>TrafficLights</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="314,-108 242,-108 242,-72 314,-72 314,-108"/>
|
||||
<text text-anchor="middle" x="278" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLights</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="263,-108 191,-108 191,-72 263,-72 263,-108"/>
|
||||
<text text-anchor="middle" x="227" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLights</text>
|
||||
</g>
|
||||
<!-- TrafficLightsBuzzer->TrafficLights -->
|
||||
<g id="edge6" class="edge"><title>TrafficLightsBuzzer->TrafficLights</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M338.978,-143.697C328.874,-134.965 316.464,-124.24 305.482,-114.75"/>
|
||||
<polygon fill="none" stroke="black" points="307.647,-111.995 297.792,-108.104 303.07,-117.291 307.647,-111.995"/>
|
||||
<g id="edge7" class="edge"><title>TrafficLightsBuzzer->TrafficLights</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M287.978,-143.697C277.874,-134.965 265.464,-124.24 254.482,-114.75"/>
|
||||
<polygon fill="none" stroke="black" points="256.647,-111.995 246.792,-108.104 252.07,-117.291 256.647,-111.995"/>
|
||||
</g>
|
||||
<!-- Buzzer -->
|
||||
<g id="node8" class="node"><title>Buzzer</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="386,-108 332,-108 332,-72 386,-72 386,-108"/>
|
||||
<text text-anchor="middle" x="359" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Buzzer</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="335,-108 281,-108 281,-72 335,-72 335,-108"/>
|
||||
<text text-anchor="middle" x="308" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Buzzer</text>
|
||||
</g>
|
||||
<!-- TrafficLightsBuzzer->Buzzer -->
|
||||
<g id="edge7" class="edge"><title>TrafficLightsBuzzer->Buzzer</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M359,-143.697C359,-135.983 359,-126.712 359,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="362.5,-118.104 359,-108.104 355.5,-118.104 362.5,-118.104"/>
|
||||
<g id="edge8" class="edge"><title>TrafficLightsBuzzer->Buzzer</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M308,-143.697C308,-135.983 308,-126.712 308,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="311.5,-118.104 308,-108.104 304.5,-118.104 311.5,-118.104"/>
|
||||
</g>
|
||||
<!-- Button -->
|
||||
<g id="node9" class="node"><title>Button</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="458,-108 404,-108 404,-72 458,-72 458,-108"/>
|
||||
<text text-anchor="middle" x="431" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="407,-108 353,-108 353,-72 407,-72 407,-108"/>
|
||||
<text text-anchor="middle" x="380" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text>
|
||||
</g>
|
||||
<!-- TrafficLightsBuzzer->Button -->
|
||||
<g id="edge8" class="edge"><title>TrafficLightsBuzzer->Button</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M376.798,-143.697C385.604,-135.135 396.382,-124.656 406.001,-115.304"/>
|
||||
<polygon fill="none" stroke="black" points="408.677,-117.585 413.407,-108.104 403.797,-112.566 408.677,-117.585"/>
|
||||
<g id="edge9" class="edge"><title>TrafficLightsBuzzer->Button</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M325.798,-143.697C334.604,-135.135 345.382,-124.656 355.001,-115.304"/>
|
||||
<polygon fill="none" stroke="black" points="357.677,-117.585 362.407,-108.104 352.797,-112.566 357.677,-117.585"/>
|
||||
</g>
|
||||
<!-- Robot -->
|
||||
<g id="node10" class="node"><title>Robot</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="530,-180 476,-180 476,-144 530,-144 530,-180"/>
|
||||
<text text-anchor="middle" x="503" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">Robot</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="479,-180 425,-180 425,-144 479,-144 479,-180"/>
|
||||
<text text-anchor="middle" x="452" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">Robot</text>
|
||||
</g>
|
||||
<!-- Motor -->
|
||||
<g id="node11" class="node"><title>Motor</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="530,-108 476,-108 476,-72 530,-72 530,-108"/>
|
||||
<text text-anchor="middle" x="503" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text>
|
||||
<polygon fill="#298029" stroke="#298029" points="479,-108 425,-108 425,-72 479,-72 479,-108"/>
|
||||
<text text-anchor="middle" x="452" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text>
|
||||
</g>
|
||||
<!-- Robot->Motor -->
|
||||
<g id="edge9" class="edge"><title>Robot->Motor</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M503,-143.697C503,-135.983 503,-126.712 503,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="506.5,-118.104 503,-108.104 499.5,-118.104 506.5,-118.104"/>
|
||||
<g id="edge10" class="edge"><title>Robot->Motor</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M452,-143.697C452,-135.983 452,-126.712 452,-118.112"/>
|
||||
<polygon fill="none" stroke="black" points="455.5,-118.104 452,-108.104 448.5,-118.104 455.5,-118.104"/>
|
||||
</g>
|
||||
<!-- DigitalOutputDevice -->
|
||||
<g id="node12" class="node"><title>DigitalOutputDevice</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="444.5,-36 333.5,-36 333.5,-0 444.5,-0 444.5,-36"/>
|
||||
<text text-anchor="middle" x="389" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">DigitalOutputDevice</text>
|
||||
</g>
|
||||
<!-- Motor->DigitalOutputDevice -->
|
||||
<g id="edge11" class="edge"><title>Motor->DigitalOutputDevice</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M436.427,-71.6966C428.798,-63.2198 419.477,-52.8636 411.124,-43.5826"/>
|
||||
<polygon fill="none" stroke="black" points="413.685,-41.1959 404.394,-36.1043 408.482,-45.8787 413.685,-41.1959"/>
|
||||
</g>
|
||||
<!-- PWMOutputDevice -->
|
||||
<g id="node12" class="node"><title>PWMOutputDevice</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="555,-36 451,-36 451,-0 555,-0 555,-36"/>
|
||||
<text text-anchor="middle" x="503" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMOutputDevice</text>
|
||||
<g id="node13" class="node"><title>PWMOutputDevice</title>
|
||||
<polygon fill="#298029" stroke="#298029" points="567,-36 463,-36 463,-0 567,-0 567,-36"/>
|
||||
<text text-anchor="middle" x="515" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMOutputDevice</text>
|
||||
</g>
|
||||
<!-- Motor->PWMOutputDevice -->
|
||||
<g id="edge10" class="edge"><title>Motor->PWMOutputDevice</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M503,-71.6966C503,-63.9827 503,-54.7125 503,-46.1124"/>
|
||||
<polygon fill="none" stroke="black" points="506.5,-46.1043 503,-36.1043 499.5,-46.1044 506.5,-46.1043"/>
|
||||
<g id="edge12" class="edge"><title>Motor->PWMOutputDevice</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M467.573,-71.6966C475.202,-63.2198 484.523,-52.8636 492.876,-43.5826"/>
|
||||
<polygon fill="none" stroke="black" points="495.518,-45.8787 499.606,-36.1043 490.315,-41.1959 495.518,-45.8787"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.4 KiB |
@@ -555,16 +555,22 @@ class RGBLED(SourceMixin, Device):
|
||||
|
||||
:param bool initial_value:
|
||||
The initial color for the LED. Defaults to black ``(0, 0, 0)``.
|
||||
|
||||
:param bool pwm:
|
||||
If ``True`` (the default), construct :class:`PWMLED` instances for
|
||||
each component of the RGBLED. If ``False``, construct regular
|
||||
:class:`LED` instances, which prevents smooth color graduations.
|
||||
"""
|
||||
def __init__(
|
||||
self, red=None, green=None, blue=None, active_high=True,
|
||||
initial_value=(0, 0, 0)):
|
||||
initial_value=(0, 0, 0), pwm=True):
|
||||
self._leds = ()
|
||||
self._blink_thread = None
|
||||
if not all([red, green, blue]):
|
||||
raise GPIOPinMissing('red, green, and blue pins must be provided')
|
||||
LEDClass = PWMLED if pwm else LED
|
||||
super(RGBLED, self).__init__()
|
||||
self._leds = tuple(PWMLED(pin, active_high) for pin in (red, green, blue))
|
||||
self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue))
|
||||
self.value = initial_value
|
||||
|
||||
red = _led_property(0)
|
||||
@@ -587,7 +593,8 @@ class RGBLED(SourceMixin, Device):
|
||||
def value(self):
|
||||
"""
|
||||
Represents the color of the LED as an RGB 3-tuple of ``(red, green,
|
||||
blue)`` where each value is between 0 and 1.
|
||||
blue)`` where each value is between 0 and 1 if ``pwm`` was ``True``
|
||||
when the class was constructed (and only 0 or 1 if not).
|
||||
|
||||
For example, purple would be ``(1, 0, 1)`` and yellow would be ``(1, 1,
|
||||
0)``, while orange would be ``(1, 0.5, 0)``.
|
||||
@@ -596,6 +603,12 @@ class RGBLED(SourceMixin, Device):
|
||||
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
for component in value:
|
||||
if not 0 <= component <= 1:
|
||||
raise OutputDeviceBadValue('each RGB color component must be between 0 and 1')
|
||||
if isinstance(self._leds[0], LED):
|
||||
if component not in (0, 1):
|
||||
raise OutputDeviceBadValue('each RGB color component must be 0 or 1 with non-PWM RGBLEDs')
|
||||
self._stop_blink()
|
||||
self.red, self.green, self.blue = value
|
||||
|
||||
@@ -647,10 +660,14 @@ class RGBLED(SourceMixin, Device):
|
||||
Number of seconds off. Defaults to 1 second.
|
||||
|
||||
:param float fade_in_time:
|
||||
Number of seconds to spend fading in. Defaults to 0.
|
||||
Number of seconds to spend fading in. Defaults to 0. Must be 0 if
|
||||
``pwm`` was ``False`` when the class was constructed
|
||||
(:exc:`ValueError` will be raised if not).
|
||||
|
||||
:param float fade_out_time:
|
||||
Number of seconds to spend fading out. Defaults to 0.
|
||||
Number of seconds to spend fading out. Defaults to 0. Must be 0 if
|
||||
``pwm`` was ``False`` when the class was constructed
|
||||
(:exc:`ValueError` will be raised if not).
|
||||
|
||||
:param tuple on_color:
|
||||
The color to use when the LED is "on". Defaults to white.
|
||||
@@ -667,6 +684,11 @@ class RGBLED(SourceMixin, Device):
|
||||
blink is finished (warning: the default value of *n* will result in
|
||||
this method never returning).
|
||||
"""
|
||||
if isinstance(self._leds[0], LED):
|
||||
if fade_in_time:
|
||||
raise ValueError('fade_in_time must be 0 with non-PWM RGBLEDs')
|
||||
if fade_out_time:
|
||||
raise ValueError('fade_out_time must be 0 with non-PWM RGBLEDs')
|
||||
self._stop_blink()
|
||||
self._blink_thread = GPIOThread(
|
||||
target=self._blink_device,
|
||||
@@ -782,22 +804,31 @@ class Motor(SourceMixin, CompositeDevice):
|
||||
:param int backward:
|
||||
The GPIO pin that the backward input of the motor driver chip is
|
||||
connected to.
|
||||
|
||||
:param bool pwm:
|
||||
If ``True`` (the default), construct :class:`PWMOutputDevice`
|
||||
instances for the motor controller pins, allowing both direction and
|
||||
variable speed control. If ``False``, construct
|
||||
:class:`DigitalOutputDevice` instances, allowing only direction
|
||||
control.
|
||||
"""
|
||||
def __init__(self, forward=None, backward=None):
|
||||
def __init__(self, forward=None, backward=None, pwm=True):
|
||||
if not all([forward, backward]):
|
||||
raise GPIOPinMissing(
|
||||
'forward and backward pins must be provided'
|
||||
)
|
||||
PinClass = PWMOutputDevice if pwm else DigitalOutputDevice
|
||||
super(Motor, self).__init__(
|
||||
forward_device=PWMOutputDevice(forward),
|
||||
backward_device=PWMOutputDevice(backward),
|
||||
forward_device=PinClass(forward),
|
||||
backward_device=PinClass(backward),
|
||||
_order=('forward_device', 'backward_device'))
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""
|
||||
Represents the speed of the motor as a floating point value between -1
|
||||
(full speed backward) and 1 (full speed forward).
|
||||
(full speed backward) and 1 (full speed forward), with 0 representing
|
||||
stopped.
|
||||
"""
|
||||
return self.forward_device.value - self.backward_device.value
|
||||
|
||||
@@ -806,9 +837,15 @@ class Motor(SourceMixin, CompositeDevice):
|
||||
if not -1 <= value <= 1:
|
||||
raise OutputDeviceBadValue("Motor value must be between -1 and 1")
|
||||
if value > 0:
|
||||
self.forward(value)
|
||||
try:
|
||||
self.forward(value)
|
||||
except ValueError as e:
|
||||
raise OutputDeviceBadValue(e)
|
||||
elif value < 0:
|
||||
self.backward(-value)
|
||||
try:
|
||||
self.backward(-value)
|
||||
except ValueError as e:
|
||||
raise OutputDeviceBadValue(e)
|
||||
else:
|
||||
self.stop()
|
||||
|
||||
@@ -826,8 +863,14 @@ class Motor(SourceMixin, CompositeDevice):
|
||||
|
||||
:param float speed:
|
||||
The speed at which the motor should turn. Can be any value between
|
||||
0 (stopped) and the default 1 (maximum speed).
|
||||
0 (stopped) and the default 1 (maximum speed) if ``pwm`` was
|
||||
``True`` when the class was constructed (and only 0 or 1 if not).
|
||||
"""
|
||||
if not 0 <= speed <= 1:
|
||||
raise ValueError('forward speed must be between 0 and 1')
|
||||
if isinstance(self.forward_device, DigitalOutputDevice):
|
||||
if speed not in (0, 1):
|
||||
raise ValueError('forward speed must be 0 or 1 with non-PWM Motors')
|
||||
self.backward_device.off()
|
||||
self.forward_device.value = speed
|
||||
|
||||
@@ -837,8 +880,14 @@ class Motor(SourceMixin, CompositeDevice):
|
||||
|
||||
:param float speed:
|
||||
The speed at which the motor should turn. Can be any value between
|
||||
0 (stopped) and the default 1 (maximum speed).
|
||||
0 (stopped) and the default 1 (maximum speed) if ``pwm`` was
|
||||
``True`` when the class was constructed (and only 0 or 1 if not).
|
||||
"""
|
||||
if not 0 <= speed <= 1:
|
||||
raise ValueError('backward speed must be between 0 and 1')
|
||||
if isinstance(self.backward_device, DigitalOutputDevice):
|
||||
if speed not in (0, 1):
|
||||
raise ValueError('backward speed must be 0 or 1 with non-PWM Motors')
|
||||
self.forward_device.off()
|
||||
self.backward_device.value = speed
|
||||
|
||||
|
||||
@@ -378,67 +378,6 @@ def test_output_pwm_pulse_foreground():
|
||||
(0.04, 0),
|
||||
])
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_output_pwm_pulse_background():
|
||||
pin = MockPWMPin(2)
|
||||
with PWMOutputDevice(pin) as device:
|
||||
device.pulse(0.2, 0.2, n=2)
|
||||
device._blink_thread.join()
|
||||
pin.assert_states_and_times([
|
||||
(0.0, 0),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.8),
|
||||
(0.04, 1),
|
||||
(0.04, 0.8),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.8),
|
||||
(0.04, 1),
|
||||
(0.04, 0.8),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0),
|
||||
])
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_output_pwm_pulse_foreground():
|
||||
pin = MockPWMPin(2)
|
||||
with PWMOutputDevice(pin) as device:
|
||||
device.pulse(0.2, 0.2, n=2, background=False)
|
||||
pin.assert_states_and_times([
|
||||
(0.0, 0),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.8),
|
||||
(0.04, 1),
|
||||
(0.04, 0.8),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.8),
|
||||
(0.04, 1),
|
||||
(0.04, 0.8),
|
||||
(0.04, 0.6),
|
||||
(0.04, 0.4),
|
||||
(0.04, 0.2),
|
||||
(0.04, 0),
|
||||
])
|
||||
|
||||
def test_output_pwm_blink_interrupt():
|
||||
pin = MockPWMPin(2)
|
||||
with PWMOutputDevice(pin) as device:
|
||||
@@ -461,9 +400,47 @@ def test_rgbled_initial_value():
|
||||
assert isclose(g.state, 0.2)
|
||||
assert isclose(b.state, 0.0)
|
||||
|
||||
def test_rgbled_initial_value_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False, initial_value=(0, 1, 1)) as device:
|
||||
assert r.state == 0
|
||||
assert g.state == 1
|
||||
assert b.state == 1
|
||||
|
||||
def test_rgbled_initial_bad_value():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with pytest.raises(ValueError):
|
||||
RGBLED(r, g, b, initial_value=(0.1, 0.2, 1.2))
|
||||
|
||||
def test_rgbled_initial_bad_value_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with pytest.raises(ValueError):
|
||||
RGBLED(r, g, b, pwm=False, initial_value=(0.1, 0.2, 0))
|
||||
|
||||
def test_rgbled_value():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b) as device:
|
||||
assert isinstance(device._leds[0], PWMLED)
|
||||
assert isinstance(device._leds[1], PWMLED)
|
||||
assert isinstance(device._leds[2], PWMLED)
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
device.on()
|
||||
assert device.is_active
|
||||
assert device.value == (1, 1, 1)
|
||||
device.off()
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
device.value = (0.5, 0.5, 0.5)
|
||||
assert device.is_active
|
||||
assert device.value == (0.5, 0.5, 0.5)
|
||||
|
||||
def test_rgbled_value_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
assert isinstance(device._leds[0], LED)
|
||||
assert isinstance(device._leds[1], LED)
|
||||
assert isinstance(device._leds[2], LED)
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
device.on()
|
||||
@@ -473,6 +450,33 @@ def test_rgbled_value():
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
|
||||
def test_rgbled_bad_value():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (2, 0, 0)
|
||||
with RGBLED(r, g, b) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (0, -1, 0)
|
||||
|
||||
def test_rgbled_bad_value_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (2, 0, 0)
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (0, -1, 0)
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (0.5, 0, 0)
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (0, 0.5, 0)
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = (0, 0, 0.5)
|
||||
|
||||
def test_rgbled_toggle():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b) as device:
|
||||
@@ -485,6 +489,18 @@ def test_rgbled_toggle():
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
|
||||
def test_rgbled_toggle_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
device.toggle()
|
||||
assert device.is_active
|
||||
assert device.value == (1, 1, 1)
|
||||
device.toggle()
|
||||
assert not device.is_active
|
||||
assert device.value == (0, 0, 0)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_blink_background():
|
||||
@@ -506,6 +522,27 @@ def test_rgbled_blink_background():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_blink_background_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
start = time()
|
||||
device.blink(0.1, 0.1, n=2)
|
||||
assert isclose(time() - start, 0, abs_tol=0.05)
|
||||
device._blink_thread.join()
|
||||
assert isclose(time() - start, 0.4, abs_tol=0.05)
|
||||
expected = [
|
||||
(0.0, 0),
|
||||
(0.0, 1),
|
||||
(0.1, 0),
|
||||
(0.1, 1),
|
||||
(0.1, 0)
|
||||
]
|
||||
r.assert_states_and_times(expected)
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_blink_foreground():
|
||||
@@ -525,6 +562,25 @@ def test_rgbled_blink_foreground():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_blink_foreground_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
start = time()
|
||||
device.blink(0.1, 0.1, n=2, background=False)
|
||||
assert isclose(time() - start, 0.4, abs_tol=0.05)
|
||||
expected = [
|
||||
(0.0, 0),
|
||||
(0.0, 1),
|
||||
(0.1, 0),
|
||||
(0.1, 1),
|
||||
(0.1, 0)
|
||||
]
|
||||
r.assert_states_and_times(expected)
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_fade_background():
|
||||
@@ -562,6 +618,12 @@ def test_rgbled_fade_background():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
def test_rgbled_fade_background_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.blink(0, 0, 0.2, 0.2, n=2)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_fade_foreground():
|
||||
@@ -597,6 +659,12 @@ def test_rgbled_fade_foreground():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
def test_rgbled_fade_foreground_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.blink(0, 0, 0.2, 0.2, n=2, background=False)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_pulse_background():
|
||||
@@ -634,6 +702,12 @@ def test_rgbled_pulse_background():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
def test_rgbled_pulse_background_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.pulse(0.2, 0.2, n=2)
|
||||
|
||||
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
|
||||
reason='timing is too random on pypy')
|
||||
def test_rgbled_pulse_foreground():
|
||||
@@ -669,6 +743,12 @@ def test_rgbled_pulse_foreground():
|
||||
g.assert_states_and_times(expected)
|
||||
b.assert_states_and_times(expected)
|
||||
|
||||
def test_rgbled_pulse_foreground_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.pulse(0.2, 0.2, n=2, background=False)
|
||||
|
||||
def test_rgbled_blink_interrupt():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b) as device:
|
||||
@@ -679,6 +759,16 @@ def test_rgbled_blink_interrupt():
|
||||
g.assert_states([0, 1, 0])
|
||||
b.assert_states([0, 1, 0])
|
||||
|
||||
def test_rgbled_blink_interrupt_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
device.blink(1, 0.1)
|
||||
sleep(0.2)
|
||||
device.off() # should interrupt while on
|
||||
r.assert_states([0, 1, 0])
|
||||
g.assert_states([0, 1, 0])
|
||||
b.assert_states([0, 1, 0])
|
||||
|
||||
def test_rgbled_close():
|
||||
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b) as device:
|
||||
@@ -688,6 +778,15 @@ def test_rgbled_close():
|
||||
device.close()
|
||||
assert device.closed
|
||||
|
||||
def test_rgbled_close_nonpwm():
|
||||
r, g, b = (MockPin(i) for i in (1, 2, 3))
|
||||
with RGBLED(r, g, b, pwm=False) as device:
|
||||
assert not device.closed
|
||||
device.close()
|
||||
assert device.closed
|
||||
device.close()
|
||||
assert device.closed
|
||||
|
||||
def test_motor_missing_pins():
|
||||
with pytest.raises(ValueError):
|
||||
Motor()
|
||||
@@ -697,7 +796,18 @@ def test_motor_pins():
|
||||
b = MockPWMPin(2)
|
||||
with Motor(f, b) as device:
|
||||
assert device.forward_device.pin is f
|
||||
assert isinstance(device.forward_device, PWMOutputDevice)
|
||||
assert device.backward_device.pin is b
|
||||
assert isinstance(device.backward_device, PWMOutputDevice)
|
||||
|
||||
def test_motor_pins_nonpwm():
|
||||
f = MockPin(1)
|
||||
b = MockPin(2)
|
||||
with Motor(f, b, pwm=False) as device:
|
||||
assert device.forward_device.pin is f
|
||||
assert isinstance(device.forward_device, DigitalOutputDevice)
|
||||
assert device.backward_device.pin is b
|
||||
assert isinstance(device.backward_device, DigitalOutputDevice)
|
||||
|
||||
def test_motor_close():
|
||||
f = MockPWMPin(1)
|
||||
@@ -710,6 +820,15 @@ def test_motor_close():
|
||||
device.close()
|
||||
assert device.closed
|
||||
|
||||
def test_motor_close_nonpwm():
|
||||
f = MockPin(1)
|
||||
b = MockPin(2)
|
||||
with Motor(f, b, pwm=False) as device:
|
||||
device.close()
|
||||
assert device.closed
|
||||
assert device.forward_device.pin is None
|
||||
assert device.backward_device.pin is None
|
||||
|
||||
def test_motor_value():
|
||||
f = MockPWMPin(1)
|
||||
b = MockPWMPin(2)
|
||||
@@ -726,6 +845,27 @@ def test_motor_value():
|
||||
assert device.is_active
|
||||
assert device.value == 0.5
|
||||
assert b.state == 0 and f.state == 0.5
|
||||
device.value = -0.5
|
||||
assert device.is_active
|
||||
assert device.value == -0.5
|
||||
assert b.state == 0.5 and f.state == 0
|
||||
device.value = 0
|
||||
assert not device.is_active
|
||||
assert not device.value
|
||||
assert b.state == 0 and f.state == 0
|
||||
|
||||
def test_motor_value_nonpwm():
|
||||
f = MockPin(1)
|
||||
b = MockPin(2)
|
||||
with Motor(f, b, pwm=False) as device:
|
||||
device.value = -1
|
||||
assert device.is_active
|
||||
assert device.value == -1
|
||||
assert b.state == 1 and f.state == 0
|
||||
device.value = 1
|
||||
assert device.is_active
|
||||
assert device.value == 1
|
||||
assert b.state == 0 and f.state == 1
|
||||
device.value = 0
|
||||
assert not device.is_active
|
||||
assert not device.value
|
||||
@@ -735,9 +875,24 @@ def test_motor_bad_value():
|
||||
f = MockPWMPin(1)
|
||||
b = MockPWMPin(2)
|
||||
with Motor(f, b) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = -2
|
||||
with pytest.raises(ValueError):
|
||||
device.value = 2
|
||||
|
||||
def test_motor_bad_value_nonpwm():
|
||||
f = MockPin(1)
|
||||
b = MockPin(2)
|
||||
with Motor(f, b, pwm=False) as device:
|
||||
with pytest.raises(ValueError):
|
||||
device.value = -2
|
||||
with pytest.raises(ValueError):
|
||||
device.value = 2
|
||||
with pytest.raises(ValueError):
|
||||
device.value = 0.5
|
||||
with pytest.raises(ValueError):
|
||||
device.value = -0.5
|
||||
|
||||
def test_motor_reverse():
|
||||
f = MockPWMPin(1)
|
||||
b = MockPWMPin(2)
|
||||
@@ -748,4 +903,20 @@ def test_motor_reverse():
|
||||
device.reverse()
|
||||
assert device.value == -1
|
||||
assert b.state == 1 and f.state == 0
|
||||
device.backward(0.5)
|
||||
assert device.value == -0.5
|
||||
assert b.state == 0.5 and f.state == 0
|
||||
device.reverse()
|
||||
assert device.value == 0.5
|
||||
assert b.state == 0 and f.state == 0.5
|
||||
|
||||
def test_motor_reverse_nonpwm():
|
||||
f = MockPin(1)
|
||||
b = MockPin(2)
|
||||
with Motor(f, b, pwm=False) as device:
|
||||
device.forward()
|
||||
assert device.value == 1
|
||||
assert b.state == 0 and f.state == 1
|
||||
device.reverse()
|
||||
assert device.value == -1
|
||||
assert b.state == 1 and f.state == 0
|
||||
|
||||
Reference in New Issue
Block a user