Coverage for /usr/lib/python3/dist-packages/gpiozero/output_devices.py: 20%
525 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
1# vim: set fileencoding=utf-8:
2#
3# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins
4#
5# Copyright (c) 2015-2021 Dave Jones <dave@waveform.org.uk>
6# Copyright (c) 2015-2020 Ben Nuttall <ben@bennuttall.com>
7# Copyright (c) 2019 tuftii <3215045+tuftii@users.noreply.github.com>
8# Copyright (c) 2019 tuftii <pi@raspberrypi>
9# Copyright (c) 2019 Yisrael Dov Lebow 🐻 <lebow@lebowtech.com>
10# Copyright (c) 2019 Kosovan Sofiia <sofiia.kosovan@gmail.com>
11# Copyright (c) 2016-2019 Andrew Scheller <github@loowis.durge.org>
12# Copyright (c) 2016 Ian Harcombe <ian.harcombe@gmail.com>
13#
14# SPDX-License-Identifier: BSD-3-Clause
16from __future__ import (
17 unicode_literals,
18 print_function,
19 absolute_import,
20 division,
21)
22str = type('')
24from threading import Lock
25from itertools import repeat, cycle, chain
26from colorzero import Color
27from collections import OrderedDict
28try:
29 from math import log2
30except ImportError:
31 from .compat import log2
32import warnings
34from .exc import (
35 OutputDeviceBadValue,
36 GPIOPinMissing,
37 PWMSoftwareFallback,
38 DeviceClosed,
39)
40from .devices import GPIODevice, Device, CompositeDevice
41from .mixins import SourceMixin
42from .threads import GPIOThread
43from .tones import Tone
44try:
45 from .pins.pigpio import PiGPIOFactory
46except ImportError:
47 PiGPIOFactory = None
49class OutputDevice(SourceMixin, GPIODevice):
50 """
51 Represents a generic GPIO output device.
53 This class extends :class:`GPIODevice` to add facilities common to GPIO
54 output devices: an :meth:`on` method to switch the device on, a
55 corresponding :meth:`off` method, and a :meth:`toggle` method.
57 :type pin: int or str
58 :param pin:
59 The GPIO pin that the device is connected to. See :ref:`pin-numbering`
60 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
61 will be raised.
63 :param bool active_high:
64 If :data:`True` (the default), the :meth:`on` method will set the GPIO
65 to HIGH. If :data:`False`, the :meth:`on` method will set the GPIO to
66 LOW (the :meth:`off` method always does the opposite).
68 :type initial_value: bool or None
69 :param initial_value:
70 If :data:`False` (the default), the device will be off initially. If
71 :data:`None`, the device will be left in whatever state the pin is
72 found in when configured for output (warning: this can be on). If
73 :data:`True`, the device will be switched on initially.
75 :type pin_factory: Factory or None
76 :param pin_factory:
77 See :doc:`api_pins` for more information (this is an advanced feature
78 which most users can ignore).
79 """
80 def __init__(
81 self, pin=None, active_high=True, initial_value=False,
82 pin_factory=None):
83 super(OutputDevice, self).__init__(pin, pin_factory=pin_factory)
84 self._lock = Lock()
85 self.active_high = active_high
86 if initial_value is None:
87 self.pin.function = 'output'
88 else:
89 self.pin.output_with_state(self._value_to_state(initial_value))
91 def _value_to_state(self, value):
92 return bool(self._active_state if value else self._inactive_state)
94 def _write(self, value):
95 try:
96 self.pin.state = self._value_to_state(value)
97 except AttributeError:
98 self._check_open()
99 raise
101 def on(self):
102 """
103 Turns the device on.
104 """
105 self._write(True)
107 def off(self):
108 """
109 Turns the device off.
110 """
111 self._write(False)
113 def toggle(self):
114 """
115 Reverse the state of the device. If it's on, turn it off; if it's off,
116 turn it on.
117 """
118 with self._lock:
119 if self.is_active:
120 self.off()
121 else:
122 self.on()
124 @property
125 def value(self):
126 """
127 Returns 1 if the device is currently active and 0 otherwise. Setting
128 this property changes the state of the device.
129 """
130 return super(OutputDevice, self).value
132 @value.setter
133 def value(self, value):
134 self._write(value)
136 @property
137 def active_high(self):
138 """
139 When :data:`True`, the :attr:`value` property is :data:`True` when the
140 device's :attr:`~GPIODevice.pin` is high. When :data:`False` the
141 :attr:`value` property is :data:`True` when the device's pin is low
142 (i.e. the value is inverted).
144 This property can be set after construction; be warned that changing it
145 will invert :attr:`value` (i.e. changing this property doesn't change
146 the device's pin state - it just changes how that state is
147 interpreted).
148 """
149 return self._active_state
151 @active_high.setter
152 def active_high(self, value):
153 self._active_state = True if value else False
154 self._inactive_state = False if value else True
156 def __repr__(self):
157 try:
158 return '<gpiozero.%s object on pin %r, active_high=%s, is_active=%s>' % (
159 self.__class__.__name__, self.pin, self.active_high, self.is_active)
160 except:
161 return super(OutputDevice, self).__repr__()
164class DigitalOutputDevice(OutputDevice):
165 """
166 Represents a generic output device with typical on/off behaviour.
168 This class extends :class:`OutputDevice` with a :meth:`blink` method which
169 uses an optional background thread to handle toggling the device state
170 without further interaction.
172 :type pin: int or str
173 :param pin:
174 The GPIO pin that the device is connected to. See :ref:`pin-numbering`
175 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
176 will be raised.
178 :param bool active_high:
179 If :data:`True` (the default), the :meth:`on` method will set the GPIO
180 to HIGH. If :data:`False`, the :meth:`on` method will set the GPIO to
181 LOW (the :meth:`off` method always does the opposite).
183 :type initial_value: bool or None
184 :param initial_value:
185 If :data:`False` (the default), the device will be off initially. If
186 :data:`None`, the device will be left in whatever state the pin is
187 found in when configured for output (warning: this can be on). If
188 :data:`True`, the device will be switched on initially.
190 :type pin_factory: Factory or None
191 :param pin_factory:
192 See :doc:`api_pins` for more information (this is an advanced feature
193 which most users can ignore).
194 """
195 def __init__(
196 self, pin=None, active_high=True, initial_value=False,
197 pin_factory=None):
198 self._blink_thread = None
199 self._controller = None
200 super(DigitalOutputDevice, self).__init__(
201 pin, active_high, initial_value, pin_factory=pin_factory
202 )
204 @property
205 def value(self):
206 return super(DigitalOutputDevice, self).value
208 @value.setter
209 def value(self, value):
210 self._stop_blink()
211 self._write(value)
213 def close(self):
214 self._stop_blink()
215 super(DigitalOutputDevice, self).close()
217 def on(self):
218 self._stop_blink()
219 self._write(True)
221 def off(self):
222 self._stop_blink()
223 self._write(False)
225 def blink(self, on_time=1, off_time=1, n=None, background=True):
226 """
227 Make the device turn on and off repeatedly.
229 :param float on_time:
230 Number of seconds on. Defaults to 1 second.
232 :param float off_time:
233 Number of seconds off. Defaults to 1 second.
235 :type n: int or None
236 :param n:
237 Number of times to blink; :data:`None` (the default) means forever.
239 :param bool background:
240 If :data:`True` (the default), start a background thread to
241 continue blinking and return immediately. If :data:`False`, only
242 return when the blink is finished (warning: the default value of
243 *n* will result in this method never returning).
244 """
245 self._stop_blink()
246 self._blink_thread = GPIOThread(
247 self._blink_device, (on_time, off_time, n)
248 )
249 self._blink_thread.start()
250 if not background:
251 self._blink_thread.join()
252 self._blink_thread = None
254 def _stop_blink(self):
255 if getattr(self, '_controller', None):
256 self._controller._stop_blink(self)
257 self._controller = None
258 if getattr(self, '_blink_thread', None):
259 self._blink_thread.stop()
260 self._blink_thread = None
262 def _blink_device(self, on_time, off_time, n):
263 iterable = repeat(0) if n is None else repeat(0, n)
264 for _ in iterable:
265 self._write(True)
266 if self._blink_thread.stopping.wait(on_time):
267 break
268 self._write(False)
269 if self._blink_thread.stopping.wait(off_time):
270 break
273class LED(DigitalOutputDevice):
274 """
275 Extends :class:`DigitalOutputDevice` and represents a light emitting diode
276 (LED).
278 Connect the cathode (short leg, flat side) of the LED to a ground pin;
279 connect the anode (longer leg) to a limiting resistor; connect the other
280 side of the limiting resistor to a GPIO pin (the limiting resistor can be
281 placed either side of the LED).
283 The following example will light the LED::
285 from gpiozero import LED
287 led = LED(17)
288 led.on()
290 :type pin: int or str
291 :param pin:
292 The GPIO pin which the LED is connected to. See :ref:`pin-numbering`
293 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
294 will be raised.
296 :param bool active_high:
297 If :data:`True` (the default), the LED will operate normally with the
298 circuit described above. If :data:`False` you should wire the cathode
299 to the GPIO pin, and the anode to a 3V3 pin (via a limiting resistor).
301 :type initial_value: bool or None
302 :param initial_value:
303 If :data:`False` (the default), the LED will be off initially. If
304 :data:`None`, the LED will be left in whatever state the pin is found
305 in when configured for output (warning: this can be on). If
306 :data:`True`, the LED will be switched on initially.
308 :type pin_factory: Factory or None
309 :param pin_factory:
310 See :doc:`api_pins` for more information (this is an advanced feature
311 which most users can ignore).
312 """
313 pass
315LED.is_lit = LED.is_active
318class Buzzer(DigitalOutputDevice):
319 """
320 Extends :class:`DigitalOutputDevice` and represents a digital buzzer
321 component.
323 .. note::
325 This interface is only capable of simple on/off commands, and is not
326 capable of playing a variety of tones (see :class:`TonalBuzzer`).
328 Connect the cathode (negative pin) of the buzzer to a ground pin; connect
329 the other side to any GPIO pin.
331 The following example will sound the buzzer::
333 from gpiozero import Buzzer
335 bz = Buzzer(3)
336 bz.on()
338 :type pin: int or str
339 :param pin:
340 The GPIO pin which the buzzer is connected to. See :ref:`pin-numbering`
341 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
342 will be raised.
344 :param bool active_high:
345 If :data:`True` (the default), the buzzer will operate normally with
346 the circuit described above. If :data:`False` you should wire the
347 cathode to the GPIO pin, and the anode to a 3V3 pin.
349 :type initial_value: bool or None
350 :param initial_value:
351 If :data:`False` (the default), the buzzer will be silent initially. If
352 :data:`None`, the buzzer will be left in whatever state the pin is
353 found in when configured for output (warning: this can be on). If
354 :data:`True`, the buzzer will be switched on initially.
356 :type pin_factory: Factory or None
357 :param pin_factory:
358 See :doc:`api_pins` for more information (this is an advanced feature
359 which most users can ignore).
360 """
361 pass
363Buzzer.beep = Buzzer.blink
366class PWMOutputDevice(OutputDevice):
367 """
368 Generic output device configured for pulse-width modulation (PWM).
370 :type pin: int or str
371 :param pin:
372 The GPIO pin that the device is connected to. See :ref:`pin-numbering`
373 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
374 will be raised.
376 :param bool active_high:
377 If :data:`True` (the default), the :meth:`on` method will set the GPIO
378 to HIGH. If :data:`False`, the :meth:`on` method will set the GPIO to
379 LOW (the :meth:`off` method always does the opposite).
381 :param float initial_value:
382 If 0 (the default), the device's duty cycle will be 0 initially.
383 Other values between 0 and 1 can be specified as an initial duty cycle.
384 Note that :data:`None` cannot be specified (unlike the parent class) as
385 there is no way to tell PWM not to alter the state of the pin.
387 :param int frequency:
388 The frequency (in Hz) of pulses emitted to drive the device. Defaults
389 to 100Hz.
391 :type pin_factory: Factory or None
392 :param pin_factory:
393 See :doc:`api_pins` for more information (this is an advanced feature
394 which most users can ignore).
395 """
396 def __init__(
397 self, pin=None, active_high=True, initial_value=0, frequency=100,
398 pin_factory=None):
399 self._blink_thread = None
400 self._controller = None
401 if not 0 <= initial_value <= 1:
402 raise OutputDeviceBadValue("initial_value must be between 0 and 1")
403 super(PWMOutputDevice, self).__init__(
404 pin, active_high, initial_value=None, pin_factory=pin_factory
405 )
406 try:
407 # XXX need a way of setting these together
408 self.pin.frequency = frequency
409 self.value = initial_value
410 except:
411 self.close()
412 raise
414 def close(self):
415 try:
416 self._stop_blink()
417 except AttributeError:
418 pass
419 try:
420 self.pin.frequency = None
421 except AttributeError:
422 # If the pin's already None, ignore the exception
423 pass
424 super(PWMOutputDevice, self).close()
426 def _state_to_value(self, state):
427 return float(state if self.active_high else 1 - state)
429 def _value_to_state(self, value):
430 return float(value if self.active_high else 1 - value)
432 def _write(self, value):
433 if not 0 <= value <= 1:
434 raise OutputDeviceBadValue("PWM value must be between 0 and 1")
435 super(PWMOutputDevice, self)._write(value)
437 @property
438 def value(self):
439 """
440 The duty cycle of the PWM device. 0.0 is off, 1.0 is fully on. Values
441 in between may be specified for varying levels of power in the device.
442 """
443 return super(PWMOutputDevice, self).value
445 @value.setter
446 def value(self, value):
447 self._stop_blink()
448 self._write(value)
450 def on(self):
451 self._stop_blink()
452 self._write(1)
454 def off(self):
455 self._stop_blink()
456 self._write(0)
458 def toggle(self):
459 """
460 Toggle the state of the device. If the device is currently off
461 (:attr:`value` is 0.0), this changes it to "fully" on (:attr:`value` is
462 1.0). If the device has a duty cycle (:attr:`value`) of 0.1, this will
463 toggle it to 0.9, and so on.
464 """
465 self._stop_blink()
466 self.value = 1 - self.value
468 @property
469 def is_active(self):
470 """
471 Returns :data:`True` if the device is currently active (:attr:`value`
472 is non-zero) and :data:`False` otherwise.
473 """
474 return self.value != 0
476 @property
477 def frequency(self):
478 """
479 The frequency of the pulses used with the PWM device, in Hz. The
480 default is 100Hz.
481 """
482 return self.pin.frequency
484 @frequency.setter
485 def frequency(self, value):
486 self.pin.frequency = value
488 def blink(
489 self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
490 n=None, background=True):
491 """
492 Make the device turn on and off repeatedly.
494 :param float on_time:
495 Number of seconds on. Defaults to 1 second.
497 :param float off_time:
498 Number of seconds off. Defaults to 1 second.
500 :param float fade_in_time:
501 Number of seconds to spend fading in. Defaults to 0.
503 :param float fade_out_time:
504 Number of seconds to spend fading out. Defaults to 0.
506 :type n: int or None
507 :param n:
508 Number of times to blink; :data:`None` (the default) means forever.
510 :param bool background:
511 If :data:`True` (the default), start a background thread to
512 continue blinking and return immediately. If :data:`False`, only
513 return when the blink is finished (warning: the default value of
514 *n* will result in this method never returning).
515 """
516 self._stop_blink()
517 self._blink_thread = GPIOThread(
518 self._blink_device,
519 (on_time, off_time, fade_in_time, fade_out_time, n)
520 )
521 self._blink_thread.start()
522 if not background:
523 self._blink_thread.join()
524 self._blink_thread = None
526 def pulse(self, fade_in_time=1, fade_out_time=1, n=None, background=True):
527 """
528 Make the device fade in and out repeatedly.
530 :param float fade_in_time:
531 Number of seconds to spend fading in. Defaults to 1.
533 :param float fade_out_time:
534 Number of seconds to spend fading out. Defaults to 1.
536 :type n: int or None
537 :param n:
538 Number of times to pulse; :data:`None` (the default) means forever.
540 :param bool background:
541 If :data:`True` (the default), start a background thread to
542 continue pulsing and return immediately. If :data:`False`, only
543 return when the pulse is finished (warning: the default value of
544 *n* will result in this method never returning).
545 """
546 on_time = off_time = 0
547 self.blink(
548 on_time, off_time, fade_in_time, fade_out_time, n, background
549 )
551 def _stop_blink(self):
552 if self._controller:
553 self._controller._stop_blink(self)
554 self._controller = None
555 if self._blink_thread:
556 self._blink_thread.stop()
557 self._blink_thread = None
559 def _blink_device(
560 self, on_time, off_time, fade_in_time, fade_out_time, n, fps=25):
561 sequence = []
562 if fade_in_time > 0:
563 sequence += [
564 (i * (1 / fps) / fade_in_time, 1 / fps)
565 for i in range(int(fps * fade_in_time))
566 ]
567 sequence.append((1, on_time))
568 if fade_out_time > 0:
569 sequence += [
570 (1 - (i * (1 / fps) / fade_out_time), 1 / fps)
571 for i in range(int(fps * fade_out_time))
572 ]
573 sequence.append((0, off_time))
574 sequence = (
575 cycle(sequence) if n is None else
576 chain.from_iterable(repeat(sequence, n))
577 )
578 for value, delay in sequence:
579 self._write(value)
580 if self._blink_thread.stopping.wait(delay):
581 break
584class TonalBuzzer(SourceMixin, CompositeDevice):
585 """
586 Extends :class:`CompositeDevice` and represents a tonal buzzer.
588 :type pin: int or str
589 :param pin:
590 The GPIO pin which the buzzer is connected to. See :ref:`pin-numbering`
591 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
592 will be raised.
594 :param float initial_value:
595 If :data:`None` (the default), the buzzer will be off initially. Values
596 between -1 and 1 can be specified as an initial value for the buzzer.
598 :type mid_tone: int or str
599 :param mid_tone:
600 The tone which is represented the device's middle value (0). The
601 default is "A4" (MIDI note 69).
603 :param int octaves:
604 The number of octaves to allow away from the base note. The default is
605 1, meaning a value of -1 goes one octave below the base note, and one
606 above, i.e. from A3 to A5 with the default base note of A4.
608 :type pin_factory: Factory or None
609 :param pin_factory:
610 See :doc:`api_pins` for more information (this is an advanced feature
611 which most users can ignore).
613 .. note::
615 Note that this class does not currently work with
616 :class:`~gpiozero.pins.pigpio.PiGPIOFactory`.
617 """
619 def __init__(self, pin=None, initial_value=None, mid_tone=Tone("A4"),
620 octaves=1, pin_factory=None):
621 self._mid_tone = None
622 super(TonalBuzzer, self).__init__(
623 pwm_device=PWMOutputDevice(
624 pin=pin, pin_factory=pin_factory
625 ), pin_factory=pin_factory)
626 try:
627 self._mid_tone = Tone(mid_tone)
628 if not (0 < octaves <= 9):
629 raise ValueError('octaves must be between 1 and 9')
630 self._octaves = octaves
631 try:
632 self.min_tone.note
633 except ValueError:
634 raise ValueError(
635 '%r is too low for %d octaves' %
636 (self._mid_tone, self._octaves))
637 try:
638 self.max_tone.note
639 except ValueError:
640 raise ValueError(
641 '%r is too high for %d octaves' %
642 (self._mid_tone, self._octaves))
643 self.value = initial_value
644 except:
645 self.close()
646 raise
648 def __repr__(self):
649 try:
650 self._check_open()
651 if self.value is None:
652 return '<gpiozero.TonalBuzzer object on pin %r, silent>' % (
653 self.pwm_device.pin,)
654 else:
655 return '<gpiozero.TonalBuzzer object on pin %r, playing %s>' % (
656 self.pwm_device.pin, self.tone.note)
657 except DeviceClosed:
658 return super(TonalBuzzer, self).__repr__()
660 def play(self, tone):
661 """
662 Play the given *tone*. This can either be an instance of
663 :class:`~gpiozero.tones.Tone` or can be anything that could be used to
664 construct an instance of :class:`~gpiozero.tones.Tone`.
666 For example::
668 >>> from gpiozero import TonalBuzzer
669 >>> from gpiozero.tones import Tone
670 >>> b = TonalBuzzer(17)
671 >>> b.play(Tone("A4"))
672 >>> b.play(Tone(220.0)) # Hz
673 >>> b.play(Tone(60)) # middle C in MIDI notation
674 >>> b.play("A4")
675 >>> b.play(220.0)
676 >>> b.play(60)
677 """
678 if tone is None:
679 self.value = None
680 else:
681 if not isinstance(tone, Tone):
682 tone = Tone(tone)
683 freq = tone.frequency
684 if self.min_tone.frequency <= tone <= self.max_tone.frequency:
685 self.pwm_device.pin.frequency = freq
686 self.pwm_device.value = 0.5
687 else:
688 raise ValueError("tone is out of the device's range")
690 def stop(self):
691 """
692 Turn the buzzer off. This is equivalent to setting :attr:`value` to
693 :data:`None`.
694 """
695 self.value = None
697 @property
698 def tone(self):
699 """
700 Returns the :class:`~gpiozero.tones.Tone` that the buzzer is currently
701 playing, or :data:`None` if the buzzer is silent. This property can
702 also be set to play the specified tone.
703 """
704 if self.pwm_device.pin.frequency is None:
705 return None
706 else:
707 return Tone.from_frequency(self.pwm_device.pin.frequency)
709 @tone.setter
710 def tone(self, value):
711 self.play(value)
713 @property
714 def value(self):
715 """
716 Represents the state of the buzzer as a value between -1 (representing
717 the minimum tone) and 1 (representing the maximum tone). This can also
718 be the special value :data:`None` indicating that the buzzer is
719 currently silent.
720 """
721 if self.pwm_device.pin.frequency is None:
722 return None
723 else:
724 # Can't have zero-division here; zero-frequency Tone cannot be
725 # generated and self.octaves cannot be zero either
726 return log2(
727 self.pwm_device.pin.frequency / self.mid_tone.frequency
728 ) / self.octaves
730 @value.setter
731 def value(self, value):
732 if value is None:
733 self.pwm_device.pin.frequency = None
734 elif -1 <= value <= 1:
735 freq = self.mid_tone.frequency * 2 ** (self.octaves * value)
736 self.pwm_device.pin.frequency = freq
737 self.pwm_device.value = 0.5
738 else:
739 raise OutputDeviceBadValue(
740 'TonalBuzzer value must be between -1 and 1, or None')
742 @property
743 def is_active(self):
744 """
745 Returns :data:`True` if the buzzer is currently playing, otherwise
746 :data:`False`.
747 """
748 return self.value is not None
750 @property
751 def octaves(self):
752 """
753 The number of octaves available (above and below mid_tone).
754 """
755 return self._octaves
757 @property
758 def min_tone(self):
759 """
760 The lowest tone that the buzzer can play, i.e. the tone played
761 when :attr:`value` is -1.
762 """
763 return self._mid_tone.down(12 * self.octaves)
765 @property
766 def mid_tone(self):
767 """
768 The middle tone available, i.e. the tone played when :attr:`value` is
769 0.
770 """
771 return self._mid_tone
773 @property
774 def max_tone(self):
775 """
776 The highest tone that the buzzer can play, i.e. the tone played when
777 :attr:`value` is 1.
778 """
779 return self._mid_tone.up(12 * self.octaves)
782class PWMLED(PWMOutputDevice):
783 """
784 Extends :class:`PWMOutputDevice` and represents a light emitting diode
785 (LED) with variable brightness.
787 A typical configuration of such a device is to connect a GPIO pin to the
788 anode (long leg) of the LED, and the cathode (short leg) to ground, with
789 an optional resistor to prevent the LED from burning out.
791 :type pin: int or str
792 :param pin:
793 The GPIO pin which the LED is connected to. See :ref:`pin-numbering`
794 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
795 will be raised.
797 :param bool active_high:
798 If :data:`True` (the default), the :meth:`on` method will set the GPIO
799 to HIGH. If :data:`False`, the :meth:`on` method will set the GPIO to
800 LOW (the :meth:`off` method always does the opposite).
802 :param float initial_value:
803 If ``0`` (the default), the LED will be off initially. Other values
804 between 0 and 1 can be specified as an initial brightness for the LED.
805 Note that :data:`None` cannot be specified (unlike the parent class) as
806 there is no way to tell PWM not to alter the state of the pin.
808 :param int frequency:
809 The frequency (in Hz) of pulses emitted to drive the LED. Defaults
810 to 100Hz.
812 :type pin_factory: Factory or None
813 :param pin_factory:
814 See :doc:`api_pins` for more information (this is an advanced feature
815 which most users can ignore).
816 """
817 pass
819PWMLED.is_lit = PWMLED.is_active
822class RGBLED(SourceMixin, Device):
823 """
824 Extends :class:`Device` and represents a full color LED component (composed
825 of red, green, and blue LEDs).
827 Connect the common cathode (longest leg) to a ground pin; connect each of
828 the other legs (representing the red, green, and blue anodes) to any GPIO
829 pins. You should use three limiting resistors (one per anode).
831 The following code will make the LED yellow::
833 from gpiozero import RGBLED
835 led = RGBLED(2, 3, 4)
836 led.color = (1, 1, 0)
838 The `colorzero`_ library is also supported::
840 from gpiozero import RGBLED
841 from colorzero import Color
843 led = RGBLED(2, 3, 4)
844 led.color = Color('yellow')
846 :type red: int or str
847 :param red:
848 The GPIO pin that controls the red component of the RGB LED. See
849 :ref:`pin-numbering` for valid pin numbers. If this is :data:`None` a
850 :exc:`GPIODeviceError` will be raised.
852 :type green: int or str
853 :param green:
854 The GPIO pin that controls the green component of the RGB LED.
856 :type blue: int or str
857 :param blue:
858 The GPIO pin that controls the blue component of the RGB LED.
860 :param bool active_high:
861 Set to :data:`True` (the default) for common cathode RGB LEDs. If you
862 are using a common anode RGB LED, set this to :data:`False`.
864 :type initial_value: ~colorzero.Color or tuple
865 :param initial_value:
866 The initial color for the RGB LED. Defaults to black ``(0, 0, 0)``.
868 :param bool pwm:
869 If :data:`True` (the default), construct :class:`PWMLED` instances for
870 each component of the RGBLED. If :data:`False`, construct regular
871 :class:`LED` instances, which prevents smooth color graduations.
873 :type pin_factory: Factory or None
874 :param pin_factory:
875 See :doc:`api_pins` for more information (this is an advanced feature
876 which most users can ignore).
878 .. _colorzero: https://colorzero.readthedocs.io/
879 """
880 def __init__(
881 self, red=None, green=None, blue=None, active_high=True,
882 initial_value=(0, 0, 0), pwm=True, pin_factory=None):
883 self._leds = ()
884 self._blink_thread = None
885 if not all(p is not None for p in [red, green, blue]):
886 raise GPIOPinMissing('red, green, and blue pins must be provided')
887 LEDClass = PWMLED if pwm else LED
888 super(RGBLED, self).__init__(pin_factory=pin_factory)
889 self._leds = tuple(
890 LEDClass(pin, active_high, pin_factory=pin_factory)
891 for pin in (red, green, blue)
892 )
893 self.value = initial_value
895 def close(self):
896 if getattr(self, '_leds', None):
897 self._stop_blink()
898 for led in self._leds:
899 led.close()
900 self._leds = ()
901 super(RGBLED, self).close()
903 @property
904 def closed(self):
905 return len(self._leds) == 0
907 @property
908 def value(self):
909 """
910 Represents the color of the LED as an RGB 3-tuple of ``(red, green,
911 blue)`` where each value is between 0 and 1 if *pwm* was :data:`True`
912 when the class was constructed (and only 0 or 1 if not).
914 For example, red would be ``(1, 0, 0)`` and yellow would be ``(1, 1,
915 0)``, while orange would be ``(1, 0.5, 0)``.
916 """
917 return tuple(led.value for led in self._leds)
919 @value.setter
920 def value(self, value):
921 for component in value:
922 if not 0 <= component <= 1:
923 raise OutputDeviceBadValue(
924 'each RGB color component must be between 0 and 1')
925 if isinstance(self._leds[0], LED):
926 if component not in (0, 1):
927 raise OutputDeviceBadValue(
928 'each RGB color component must be 0 or 1 with non-PWM '
929 'RGBLEDs')
930 self._stop_blink()
931 for led, v in zip(self._leds, value):
932 led.value = v
934 @property
935 def is_active(self):
936 """
937 Returns :data:`True` if the LED is currently active (not black) and
938 :data:`False` otherwise.
939 """
940 return self.value != (0, 0, 0)
942 is_lit = is_active
944 @property
945 def color(self):
946 """
947 Represents the color of the LED as a :class:`~colorzero.Color` object.
948 """
949 return Color(*self.value)
951 @color.setter
952 def color(self, value):
953 self.value = value
955 @property
956 def red(self):
957 """
958 Represents the red element of the LED as a :class:`~colorzero.Red`
959 object.
960 """
961 return self.color.red
963 @red.setter
964 def red(self, value):
965 self._stop_blink()
966 r, g, b = self.value
967 self.value = value, g, b
969 @property
970 def green(self):
971 """
972 Represents the green element of the LED as a :class:`~colorzero.Green`
973 object.
974 """
975 return self.color.green
977 @green.setter
978 def green(self, value):
979 self._stop_blink()
980 r, g, b = self.value
981 self.value = r, value, b
983 @property
984 def blue(self):
985 """
986 Represents the blue element of the LED as a :class:`~colorzero.Blue`
987 object.
988 """
989 return self.color.blue
991 @blue.setter
992 def blue(self, value):
993 self._stop_blink()
994 r, g, b = self.value
995 self.value = r, g, value
997 def on(self):
998 """
999 Turn the LED on. This equivalent to setting the LED color to white
1000 ``(1, 1, 1)``.
1001 """
1002 self.value = (1, 1, 1)
1004 def off(self):
1005 """
1006 Turn the LED off. This is equivalent to setting the LED color to black
1007 ``(0, 0, 0)``.
1008 """
1009 self.value = (0, 0, 0)
1011 def toggle(self):
1012 """
1013 Toggle the state of the device. If the device is currently off
1014 (:attr:`value` is ``(0, 0, 0)``), this changes it to "fully" on
1015 (:attr:`value` is ``(1, 1, 1)``). If the device has a specific color,
1016 this method inverts the color.
1017 """
1018 r, g, b = self.value
1019 self.value = (1 - r, 1 - g, 1 - b)
1021 def blink(
1022 self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
1023 on_color=(1, 1, 1), off_color=(0, 0, 0), n=None, background=True):
1024 """
1025 Make the device turn on and off repeatedly.
1027 :param float on_time:
1028 Number of seconds on. Defaults to 1 second.
1030 :param float off_time:
1031 Number of seconds off. Defaults to 1 second.
1033 :param float fade_in_time:
1034 Number of seconds to spend fading in. Defaults to 0. Must be 0 if
1035 *pwm* was :data:`False` when the class was constructed
1036 (:exc:`ValueError` will be raised if not).
1038 :param float fade_out_time:
1039 Number of seconds to spend fading out. Defaults to 0. Must be 0 if
1040 *pwm* was :data:`False` when the class was constructed
1041 (:exc:`ValueError` will be raised if not).
1043 :type on_color: ~colorzero.Color or tuple
1044 :param on_color:
1045 The color to use when the LED is "on". Defaults to white.
1047 :type off_color: ~colorzero.Color or tuple
1048 :param off_color:
1049 The color to use when the LED is "off". Defaults to black.
1051 :type n: int or None
1052 :param n:
1053 Number of times to blink; :data:`None` (the default) means forever.
1055 :param bool background:
1056 If :data:`True` (the default), start a background thread to
1057 continue blinking and return immediately. If :data:`False`, only
1058 return when the blink is finished (warning: the default value of
1059 *n* will result in this method never returning).
1060 """
1061 if isinstance(self._leds[0], LED):
1062 if fade_in_time:
1063 raise ValueError('fade_in_time must be 0 with non-PWM RGBLEDs')
1064 if fade_out_time:
1065 raise ValueError('fade_out_time must be 0 with non-PWM RGBLEDs')
1066 self._stop_blink()
1067 self._blink_thread = GPIOThread(
1068 self._blink_device,
1069 (
1070 on_time, off_time, fade_in_time, fade_out_time,
1071 on_color, off_color, n
1072 )
1073 )
1074 self._blink_thread.start()
1075 if not background:
1076 self._blink_thread.join()
1077 self._blink_thread = None
1079 def pulse(
1080 self, fade_in_time=1, fade_out_time=1,
1081 on_color=(1, 1, 1), off_color=(0, 0, 0), n=None, background=True):
1082 """
1083 Make the device fade in and out repeatedly.
1085 :param float fade_in_time:
1086 Number of seconds to spend fading in. Defaults to 1.
1088 :param float fade_out_time:
1089 Number of seconds to spend fading out. Defaults to 1.
1091 :type on_color: ~colorzero.Color or tuple
1092 :param on_color:
1093 The color to use when the LED is "on". Defaults to white.
1095 :type off_color: ~colorzero.Color or tuple
1096 :param off_color:
1097 The color to use when the LED is "off". Defaults to black.
1099 :type n: int or None
1100 :param n:
1101 Number of times to pulse; :data:`None` (the default) means forever.
1103 :param bool background:
1104 If :data:`True` (the default), start a background thread to
1105 continue pulsing and return immediately. If :data:`False`, only
1106 return when the pulse is finished (warning: the default value of
1107 *n* will result in this method never returning).
1108 """
1109 on_time = off_time = 0
1110 self.blink(
1111 on_time, off_time, fade_in_time, fade_out_time,
1112 on_color, off_color, n, background
1113 )
1115 def _stop_blink(self, led=None):
1116 # If this is called with a single led, we stop all blinking anyway
1117 if self._blink_thread:
1118 self._blink_thread.stop()
1119 self._blink_thread = None
1121 def _blink_device(
1122 self, on_time, off_time, fade_in_time, fade_out_time, on_color,
1123 off_color, n, fps=25):
1124 # Define a simple lambda to perform linear interpolation between
1125 # off_color and on_color
1126 lerp = lambda t, fade_in: tuple(
1127 (1 - t) * off + t * on
1128 if fade_in else
1129 (1 - t) * on + t * off
1130 for off, on in zip(off_color, on_color)
1131 )
1132 sequence = []
1133 if fade_in_time > 0:
1134 sequence += [
1135 (lerp(i * (1 / fps) / fade_in_time, True), 1 / fps)
1136 for i in range(int(fps * fade_in_time))
1137 ]
1138 sequence.append((on_color, on_time))
1139 if fade_out_time > 0:
1140 sequence += [
1141 (lerp(i * (1 / fps) / fade_out_time, False), 1 / fps)
1142 for i in range(int(fps * fade_out_time))
1143 ]
1144 sequence.append((off_color, off_time))
1145 sequence = (
1146 cycle(sequence) if n is None else
1147 chain.from_iterable(repeat(sequence, n))
1148 )
1149 for l in self._leds:
1150 l._controller = self
1151 for value, delay in sequence:
1152 for l, v in zip(self._leds, value):
1153 l._write(v)
1154 if self._blink_thread.stopping.wait(delay):
1155 break
1158class Motor(SourceMixin, CompositeDevice):
1159 """
1160 Extends :class:`CompositeDevice` and represents a generic motor
1161 connected to a bi-directional motor driver circuit (i.e. an `H-bridge`_).
1163 Attach an `H-bridge`_ motor controller to your Pi; connect a power source
1164 (e.g. a battery pack or the 5V pin) to the controller; connect the outputs
1165 of the controller board to the two terminals of the motor; connect the
1166 inputs of the controller board to two GPIO pins.
1168 .. _H-bridge: https://en.wikipedia.org/wiki/H_bridge
1170 The following code will make the motor turn "forwards"::
1172 from gpiozero import Motor
1174 motor = Motor(17, 18)
1175 motor.forward()
1177 :type forward: int or str
1178 :param forward:
1179 The GPIO pin that the forward input of the motor driver chip is
1180 connected to. See :ref:`pin-numbering` for valid pin numbers. If this
1181 is :data:`None` a :exc:`GPIODeviceError` will be raised.
1183 :type backward: int or str
1184 :param backward:
1185 The GPIO pin that the backward input of the motor driver chip is
1186 connected to. See :ref:`pin-numbering` for valid pin numbers. If this
1187 is :data:`None` a :exc:`GPIODeviceError` will be raised.
1189 :type enable: int or str or None
1190 :param enable:
1191 The GPIO pin that enables the motor. Required for *some* motor
1192 controller boards. See :ref:`pin-numbering` for valid pin numbers.
1194 :param bool pwm:
1195 If :data:`True` (the default), construct :class:`PWMOutputDevice`
1196 instances for the motor controller pins, allowing both direction and
1197 variable speed control. If :data:`False`, construct
1198 :class:`DigitalOutputDevice` instances, allowing only direction
1199 control.
1201 :type pin_factory: Factory or None
1202 :param pin_factory:
1203 See :doc:`api_pins` for more information (this is an advanced feature
1204 which most users can ignore).
1205 """
1206 def __init__(self, forward=None, backward=None, enable=None, pwm=True,
1207 pin_factory=None):
1208 if not all(p is not None for p in [forward, backward]):
1209 raise GPIOPinMissing(
1210 'forward and backward pins must be provided'
1211 )
1212 PinClass = PWMOutputDevice if pwm else DigitalOutputDevice
1213 devices = OrderedDict((
1214 ('forward_device', PinClass(forward, pin_factory=pin_factory)),
1215 ('backward_device', PinClass(backward, pin_factory=pin_factory)),
1216 ))
1217 if enable is not None:
1218 devices['enable_device'] = DigitalOutputDevice(
1219 enable,
1220 initial_value=True,
1221 pin_factory=pin_factory
1222 )
1223 super(Motor, self).__init__(_order=devices.keys(), **devices)
1225 @property
1226 def value(self):
1227 """
1228 Represents the speed of the motor as a floating point value between -1
1229 (full speed backward) and 1 (full speed forward), with 0 representing
1230 stopped.
1231 """
1232 return self.forward_device.value - self.backward_device.value
1234 @value.setter
1235 def value(self, value):
1236 if not -1 <= value <= 1:
1237 raise OutputDeviceBadValue("Motor value must be between -1 and 1")
1238 if value > 0:
1239 try:
1240 self.forward(value)
1241 except ValueError as e:
1242 raise OutputDeviceBadValue(e)
1243 elif value < 0:
1244 try:
1245 self.backward(-value)
1246 except ValueError as e:
1247 raise OutputDeviceBadValue(e)
1248 else:
1249 self.stop()
1251 @property
1252 def is_active(self):
1253 """
1254 Returns :data:`True` if the motor is currently running and
1255 :data:`False` otherwise.
1256 """
1257 return self.value != 0
1259 def forward(self, speed=1):
1260 """
1261 Drive the motor forwards.
1263 :param float speed:
1264 The speed at which the motor should turn. Can be any value between
1265 0 (stopped) and the default 1 (maximum speed) if *pwm* was
1266 :data:`True` when the class was constructed (and only 0 or 1 if
1267 not).
1268 """
1269 if not 0 <= speed <= 1:
1270 raise ValueError('forward speed must be between 0 and 1')
1271 if isinstance(self.forward_device, DigitalOutputDevice):
1272 if speed not in (0, 1):
1273 raise ValueError(
1274 'forward speed must be 0 or 1 with non-PWM Motors')
1275 self.backward_device.off()
1276 self.forward_device.value = speed
1278 def backward(self, speed=1):
1279 """
1280 Drive the motor backwards.
1282 :param float speed:
1283 The speed at which the motor should turn. Can be any value between
1284 0 (stopped) and the default 1 (maximum speed) if *pwm* was
1285 :data:`True` when the class was constructed (and only 0 or 1 if
1286 not).
1287 """
1288 if not 0 <= speed <= 1:
1289 raise ValueError('backward speed must be between 0 and 1')
1290 if isinstance(self.backward_device, DigitalOutputDevice):
1291 if speed not in (0, 1):
1292 raise ValueError(
1293 'backward speed must be 0 or 1 with non-PWM Motors')
1294 self.forward_device.off()
1295 self.backward_device.value = speed
1297 def reverse(self):
1298 """
1299 Reverse the current direction of the motor. If the motor is currently
1300 idle this does nothing. Otherwise, the motor's direction will be
1301 reversed at the current speed.
1302 """
1303 self.value = -self.value
1305 def stop(self):
1306 """
1307 Stop the motor.
1308 """
1309 self.forward_device.off()
1310 self.backward_device.off()
1313class PhaseEnableMotor(SourceMixin, CompositeDevice):
1314 """
1315 Extends :class:`CompositeDevice` and represents a generic motor connected
1316 to a Phase/Enable motor driver circuit; the phase of the driver controls
1317 whether the motor turns forwards or backwards, while enable controls the
1318 speed with PWM.
1320 The following code will make the motor turn "forwards"::
1322 from gpiozero import PhaseEnableMotor
1323 motor = PhaseEnableMotor(12, 5)
1324 motor.forward()
1326 :type phase: int or str
1327 :param phase:
1328 The GPIO pin that the phase (direction) input of the motor driver chip
1329 is connected to. See :ref:`pin-numbering` for valid pin numbers. If
1330 this is :data:`None` a :exc:`GPIODeviceError` will be raised.
1332 :type enable: int or str
1333 :param enable:
1334 The GPIO pin that the enable (speed) input of the motor driver chip
1335 is connected to. See :ref:`pin-numbering` for valid pin numbers. If
1336 this is :data:`None` a :exc:`GPIODeviceError` will be raised.
1338 :param bool pwm:
1339 If :data:`True` (the default), construct :class:`PWMOutputDevice`
1340 instances for the motor controller pins, allowing both direction and
1341 variable speed control. If :data:`False`, construct
1342 :class:`DigitalOutputDevice` instances, allowing only direction
1343 control.
1345 :type pin_factory: Factory or None
1346 :param pin_factory:
1347 See :doc:`api_pins` for more information (this is an advanced feature
1348 which most users can ignore).
1349 """
1350 def __init__(self, phase=None, enable=None, pwm=True, pin_factory=None):
1351 if not all([phase, enable]):
1352 raise GPIOPinMissing('phase and enable pins must be provided')
1353 PinClass = PWMOutputDevice if pwm else DigitalOutputDevice
1354 super(PhaseEnableMotor, self).__init__(
1355 phase_device=DigitalOutputDevice(phase, pin_factory=pin_factory),
1356 enable_device=PinClass(enable, pin_factory=pin_factory),
1357 _order=('phase_device', 'enable_device'),
1358 pin_factory=pin_factory
1359 )
1361 @property
1362 def value(self):
1363 """
1364 Represents the speed of the motor as a floating point value between -1
1365 (full speed backward) and 1 (full speed forward).
1366 """
1367 return (
1368 -self.enable_device.value
1369 if self.phase_device.is_active else
1370 self.enable_device.value
1371 )
1373 @value.setter
1374 def value(self, value):
1375 if not -1 <= value <= 1:
1376 raise OutputDeviceBadValue("Motor value must be between -1 and 1")
1377 if value > 0:
1378 self.forward(value)
1379 elif value < 0:
1380 self.backward(-value)
1381 else:
1382 self.stop()
1384 @property
1385 def is_active(self):
1386 """
1387 Returns :data:`True` if the motor is currently running and
1388 :data:`False` otherwise.
1389 """
1390 return self.value != 0
1392 def forward(self, speed=1):
1393 """
1394 Drive the motor forwards.
1396 :param float speed:
1397 The speed at which the motor should turn. Can be any value between
1398 0 (stopped) and the default 1 (maximum speed).
1399 """
1400 if isinstance(self.enable_device, DigitalOutputDevice):
1401 if speed not in (0, 1):
1402 raise ValueError(
1403 'forward speed must be 0 or 1 with non-PWM Motors')
1404 self.enable_device.off()
1405 self.phase_device.off()
1406 self.enable_device.value = speed
1408 def backward(self, speed=1):
1409 """
1410 Drive the motor backwards.
1412 :param float speed:
1413 The speed at which the motor should turn. Can be any value between
1414 0 (stopped) and the default 1 (maximum speed).
1415 """
1416 if isinstance(self.enable_device, DigitalOutputDevice):
1417 if speed not in (0, 1):
1418 raise ValueError(
1419 'backward speed must be 0 or 1 with non-PWM Motors')
1420 self.enable_device.off()
1421 self.phase_device.on()
1422 self.enable_device.value = speed
1424 def reverse(self):
1425 """
1426 Reverse the current direction of the motor. If the motor is currently
1427 idle this does nothing. Otherwise, the motor's direction will be
1428 reversed at the current speed.
1429 """
1430 self.value = -self.value
1432 def stop(self):
1433 """
1434 Stop the motor.
1435 """
1436 self.enable_device.off()
1439class Servo(SourceMixin, CompositeDevice):
1440 """
1441 Extends :class:`CompositeDevice` and represents a PWM-controlled servo
1442 motor connected to a GPIO pin.
1444 Connect a power source (e.g. a battery pack or the 5V pin) to the power
1445 cable of the servo (this is typically colored red); connect the ground
1446 cable of the servo (typically colored black or brown) to the negative of
1447 your battery pack, or a GND pin; connect the final cable (typically colored
1448 white or orange) to the GPIO pin you wish to use for controlling the servo.
1450 The following code will make the servo move between its minimum, maximum,
1451 and mid-point positions with a pause between each::
1453 from gpiozero import Servo
1454 from time import sleep
1456 servo = Servo(17)
1458 while True:
1459 servo.min()
1460 sleep(1)
1461 servo.mid()
1462 sleep(1)
1463 servo.max()
1464 sleep(1)
1466 You can also use the :attr:`value` property to move the servo to a
1467 particular position, on a scale from -1 (min) to 1 (max) where 0 is the
1468 mid-point::
1470 from gpiozero import Servo
1472 servo = Servo(17)
1474 servo.value = 0.5
1476 .. note::
1478 To reduce servo jitter, use the pigpio pin driver rather than the default
1479 RPi.GPIO driver (pigpio uses DMA sampling for much more precise edge
1480 timing). See :ref:`changing-pin-factory` for further information.
1482 :type pin: int or str
1483 :param pin:
1484 The GPIO pin that the servo is connected to. See :ref:`pin-numbering`
1485 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
1486 will be raised.
1488 :param float initial_value:
1489 If ``0`` (the default), the device's mid-point will be set initially.
1490 Other values between -1 and +1 can be specified as an initial position.
1491 :data:`None` means to start the servo un-controlled (see
1492 :attr:`value`).
1494 :param float min_pulse_width:
1495 The pulse width corresponding to the servo's minimum position. This
1496 defaults to 1ms.
1498 :param float max_pulse_width:
1499 The pulse width corresponding to the servo's maximum position. This
1500 defaults to 2ms.
1502 :param float frame_width:
1503 The length of time between servo control pulses measured in seconds.
1504 This defaults to 20ms which is a common value for servos.
1506 :type pin_factory: Factory or None
1507 :param pin_factory:
1508 See :doc:`api_pins` for more information (this is an advanced feature
1509 which most users can ignore).
1510 """
1511 def __init__(
1512 self, pin=None, initial_value=0.0,
1513 min_pulse_width=1/1000, max_pulse_width=2/1000,
1514 frame_width=20/1000, pin_factory=None):
1515 if min_pulse_width >= max_pulse_width:
1516 raise ValueError('min_pulse_width must be less than max_pulse_width')
1517 if max_pulse_width >= frame_width:
1518 raise ValueError('max_pulse_width must be less than frame_width')
1519 self._frame_width = frame_width
1520 self._min_dc = min_pulse_width / frame_width
1521 self._dc_range = (max_pulse_width - min_pulse_width) / frame_width
1522 self._min_value = -1
1523 self._value_range = 2
1524 super(Servo, self).__init__(
1525 pwm_device=PWMOutputDevice(
1526 pin, frequency=int(1 / frame_width), pin_factory=pin_factory
1527 ),
1528 pin_factory=pin_factory
1529 )
1531 if PiGPIOFactory is None or not isinstance(self.pin_factory, PiGPIOFactory):
1532 warnings.warn(PWMSoftwareFallback(
1533 'To reduce servo jitter, use the pigpio pin factory.'
1534 'See https://gpiozero.readthedocs.io/en/stable/api_output.html#servo for more info'
1535 ))
1537 try:
1538 self.value = initial_value
1539 except:
1540 self.close()
1541 raise
1543 @property
1544 def frame_width(self):
1545 """
1546 The time between control pulses, measured in seconds.
1547 """
1548 return self._frame_width
1550 @property
1551 def min_pulse_width(self):
1552 """
1553 The control pulse width corresponding to the servo's minimum position,
1554 measured in seconds.
1555 """
1556 return self._min_dc * self.frame_width
1558 @property
1559 def max_pulse_width(self):
1560 """
1561 The control pulse width corresponding to the servo's maximum position,
1562 measured in seconds.
1563 """
1564 return (self._dc_range * self.frame_width) + self.min_pulse_width
1566 @property
1567 def pulse_width(self):
1568 """
1569 Returns the current pulse width controlling the servo.
1570 """
1571 if self.pwm_device.pin.frequency is None:
1572 return None
1573 else:
1574 return self.pwm_device.pin.state * self.frame_width
1576 @pulse_width.setter
1577 def pulse_width(self, value):
1578 self.pwm_device.pin.state = value / self.frame_width
1580 def min(self):
1581 """
1582 Set the servo to its minimum position.
1583 """
1584 self.value = -1
1586 def mid(self):
1587 """
1588 Set the servo to its mid-point position.
1589 """
1590 self.value = 0
1592 def max(self):
1593 """
1594 Set the servo to its maximum position.
1595 """
1596 self.value = 1
1598 def detach(self):
1599 """
1600 Temporarily disable control of the servo. This is equivalent to
1601 setting :attr:`value` to :data:`None`.
1602 """
1603 self.value = None
1605 def _get_value(self):
1606 if self.pwm_device.pin.frequency is None:
1607 return None
1608 else:
1609 return (
1610 ((self.pwm_device.pin.state - self._min_dc) / self._dc_range) *
1611 self._value_range + self._min_value)
1613 @property
1614 def value(self):
1615 """
1616 Represents the position of the servo as a value between -1 (the minimum
1617 position) and +1 (the maximum position). This can also be the special
1618 value :data:`None` indicating that the servo is currently
1619 "uncontrolled", i.e. that no control signal is being sent. Typically
1620 this means the servo's position remains unchanged, but that it can be
1621 moved by hand.
1622 """
1623 result = self._get_value()
1624 if result is None:
1625 return result
1626 else:
1627 # NOTE: This round() only exists to ensure we don't confuse people
1628 # by returning 2.220446049250313e-16 as the default initial value
1629 # instead of 0. The reason _get_value and _set_value are split
1630 # out is for descendents that require the un-rounded values for
1631 # accuracy
1632 return round(result, 14)
1634 @value.setter
1635 def value(self, value):
1636 if value is None:
1637 self.pwm_device.pin.frequency = None
1638 elif -1 <= value <= 1:
1639 self.pwm_device.pin.frequency = int(1 / self.frame_width)
1640 self.pwm_device.pin.state = (
1641 self._min_dc + self._dc_range *
1642 ((value - self._min_value) / self._value_range)
1643 )
1644 else:
1645 raise OutputDeviceBadValue(
1646 "Servo value must be between -1 and 1, or None")
1648 @property
1649 def is_active(self):
1650 return self.value is not None
1653class AngularServo(Servo):
1654 """
1655 Extends :class:`Servo` and represents a rotational PWM-controlled servo
1656 motor which can be set to particular angles (assuming valid minimum and
1657 maximum angles are provided to the constructor).
1659 Connect a power source (e.g. a battery pack or the 5V pin) to the power
1660 cable of the servo (this is typically colored red); connect the ground
1661 cable of the servo (typically colored black or brown) to the negative of
1662 your battery pack, or a GND pin; connect the final cable (typically colored
1663 white or orange) to the GPIO pin you wish to use for controlling the servo.
1665 Next, calibrate the angles that the servo can rotate to. In an interactive
1666 Python session, construct a :class:`Servo` instance. The servo should move
1667 to its mid-point by default. Set the servo to its minimum value, and
1668 measure the angle from the mid-point. Set the servo to its maximum value,
1669 and again measure the angle::
1671 >>> from gpiozero import Servo
1672 >>> s = Servo(17)
1673 >>> s.min() # measure the angle
1674 >>> s.max() # measure the angle
1676 You should now be able to construct an :class:`AngularServo` instance
1677 with the correct bounds::
1679 >>> from gpiozero import AngularServo
1680 >>> s = AngularServo(17, min_angle=-42, max_angle=44)
1681 >>> s.angle = 0.0
1682 >>> s.angle
1683 0.0
1684 >>> s.angle = 15
1685 >>> s.angle
1686 15.0
1688 .. note::
1690 You can set *min_angle* greater than *max_angle* if you wish to reverse
1691 the sense of the angles (e.g. ``min_angle=45, max_angle=-45``). This
1692 can be useful with servos that rotate in the opposite direction to your
1693 expectations of minimum and maximum.
1695 :type pin: int or str
1696 :param pin:
1697 The GPIO pin that the servo is connected to. See :ref:`pin-numbering`
1698 for valid pin numbers. If this is :data:`None` a :exc:`GPIODeviceError`
1699 will be raised.
1701 :param float initial_angle:
1702 Sets the servo's initial angle to the specified value. The default is
1703 0. The value specified must be between *min_angle* and *max_angle*
1704 inclusive. :data:`None` means to start the servo un-controlled (see
1705 :attr:`value`).
1707 :param float min_angle:
1708 Sets the minimum angle that the servo can rotate to. This defaults to
1709 -90, but should be set to whatever you measure from your servo during
1710 calibration.
1712 :param float max_angle:
1713 Sets the maximum angle that the servo can rotate to. This defaults to
1714 90, but should be set to whatever you measure from your servo during
1715 calibration.
1717 :param float min_pulse_width:
1718 The pulse width corresponding to the servo's minimum position. This
1719 defaults to 1ms.
1721 :param float max_pulse_width:
1722 The pulse width corresponding to the servo's maximum position. This
1723 defaults to 2ms.
1725 :param float frame_width:
1726 The length of time between servo control pulses measured in seconds.
1727 This defaults to 20ms which is a common value for servos.
1729 :type pin_factory: Factory or None
1730 :param pin_factory:
1731 See :doc:`api_pins` for more information (this is an advanced feature
1732 which most users can ignore).
1733 """
1734 def __init__(
1735 self, pin=None, initial_angle=0.0,
1736 min_angle=-90, max_angle=90,
1737 min_pulse_width=1/1000, max_pulse_width=2/1000,
1738 frame_width=20/1000, pin_factory=None):
1739 self._min_angle = min_angle
1740 self._angular_range = max_angle - min_angle
1741 if initial_angle is None:
1742 initial_value = None
1743 elif ((min_angle <= initial_angle <= max_angle) or
1744 (max_angle <= initial_angle <= min_angle)):
1745 initial_value = 2 * ((initial_angle - min_angle) / self._angular_range) - 1
1746 else:
1747 raise OutputDeviceBadValue(
1748 "AngularServo angle must be between %s and %s, or None" %
1749 (min_angle, max_angle))
1750 super(AngularServo, self).__init__(
1751 pin, initial_value, min_pulse_width, max_pulse_width, frame_width,
1752 pin_factory=pin_factory
1753 )
1755 @property
1756 def min_angle(self):
1757 """
1758 The minimum angle that the servo will rotate to when :meth:`min` is
1759 called.
1760 """
1761 return self._min_angle
1763 @property
1764 def max_angle(self):
1765 """
1766 The maximum angle that the servo will rotate to when :meth:`max` is
1767 called.
1768 """
1769 return self._min_angle + self._angular_range
1771 @property
1772 def angle(self):
1773 """
1774 The position of the servo as an angle measured in degrees. This will
1775 only be accurate if :attr:`min_angle` and :attr:`max_angle` have been
1776 set appropriately in the constructor.
1778 This can also be the special value :data:`None` indicating that the
1779 servo is currently "uncontrolled", i.e. that no control signal is being
1780 sent. Typically this means the servo's position remains unchanged, but
1781 that it can be moved by hand.
1782 """
1783 result = self._get_value()
1784 if result is None:
1785 return None
1786 else:
1787 # NOTE: Why round(n, 12) here instead of 14? Angle ranges can be
1788 # much larger than -1..1 so we need a little more rounding to
1789 # smooth off the rough corners!
1790 return round(
1791 self._angular_range *
1792 ((result - self._min_value) / self._value_range) +
1793 self._min_angle, 12)
1795 @angle.setter
1796 def angle(self, angle):
1797 if angle is None:
1798 self.value = None
1799 elif ((self.min_angle <= angle <= self.max_angle) or
1800 (self.max_angle <= angle <= self.min_angle)):
1801 self.value = (
1802 self._value_range *
1803 ((angle - self._min_angle) / self._angular_range) +
1804 self._min_value)
1805 else:
1806 raise OutputDeviceBadValue(
1807 "AngularServo angle must be between %s and %s, or None" %
1808 (self.min_angle, self.max_angle))