Source code for pyrolab.drivers.arduino.arduino

# Copyright © PyroLab Project Contributors
# Licensed under the terms of the GNU GPLv3+ License
# (see pyrolab/__init__.py for details)

"""
Arduino Driver
==============

Driver for Arduino that is running firmata code.

Arduino should be running example code found under standard `Arduino Firmata
examples`_, or similar code if the device memory is not large enough. See:

* SimpleDigitalFirmata
* StandardFirmata

.. _Arduino Firmata examples: https://github.com/firmata/arduino

Code also available in the PyroLab repository under ``/extras/arduino``.

.. admonition:: Dependencies
   :class: note

   pyfirmata
"""

import logging

from pyfirmata import (
    ANALOG,
    INPUT,
    OUTPUT,
    PWM,
    SERVO,
    Arduino,
    ArduinoDue,
    ArduinoMega,
    ArduinoNano,
    util,
)

from pyrolab.drivers.arduino import Arduino as PyroArduino
from pyrolab.api import expose


log = logging.getLogger(__name__)


[docs] @expose class BaseArduinoDriver(PyroArduino): """ A base class providing pin read/write access for common Arduino boards. """
[docs] def connect(self, port: str, board: str = "uno") -> None: """ Initialize a connection with the arduino. If the arduino is already connected to another process this will also kill that program. Parameters ---------- port : str Computer serial port to which the arduino is connected board : str, optional | The type of the arduino that is being used: | ``uno``: `Arduino Uno <https://store.arduino.cc/products/arduino-uno-rev3>`_ | ``mega``: `Arduino Mega <https://store.arduino.cc/products/arduino-mega-2560-rev3>`_ | ``due``: `Arduino Due <https://store.arduino.cc/products/arduino-due>`_ | ``nano``: `Arduino Nano <https://store.arduino.cc/products/arduino-nano>`_ Raises ------ ValueError If the board type is not supported. """ if hasattr(self, "board"): log.debug("Already connected") return True self.port = port if board == "uno": self.board = Arduino(self.port) elif board == "mega": self.board = ArduinoMega(self.port) elif board == "due": self.board = ArduinoDue(self.port) elif board == "nano": self.board = ArduinoNano(self.port) else: raise ValueError(f"Unknown board '{board}'") try: self.it = util.Iterator(self.board) self.it.start() except Exception as e: self.close() raise e
[docs] def digital_write(self, pin: int, value: int) -> None: """ Tell the arduino to turn a pin digitally to the inputted value. Parameters ---------- pin : int Integer that represents the digital out pin number on an arduino value : int | The value of the digital pin to be set | 0: LOW | 1: HIGH """ self.board.digital[pin].mode = OUTPUT pin = self.board.digital[pin].write(value)
[docs] def pwm_write(self, pin: int, value: float) -> None: """ Tell the arduino to produce a pwm signal on a pin. Parameters ---------- pin : int Integer that represents the digital out pin number on an arduino value : float The duty cycle of the pwm to be set (0 - 1.0) """ self.board.digital[pin].mode = PWM self.board.digital[pin].write(value)
[docs] def servo_write(self, pin: int, value: int) -> None: """ Tell the arduino to configure a pin to drive a servo to the inputed angle. Parameters ---------- pin : int Integer that represents the digital out pin number on an arduino value : int The angle in degrees to move the servo to """ self.board.digital[pin].mode = SERVO self.board.digital[pin].write(value)
[docs] def digital_read(self, pin: int) -> int: """ Tell the arduino to read a value from a digital pin. Parameters ---------- pin : int Integer that represents the digital in pin number on an arduino Returns ------- int The value read by the digital pin, 0 (LOW) or 1 (HIGH) """ self.board.digital[pin].mode = INPUT return self.board.digital[pin].read()
[docs] def analog_read(self, pin: int) -> float: """ Tell the arduino to read a value from an analog pin. Parameters ---------- pin : int Integer that represents the analog in pin number on an arduino Returns ------- float The value read by the analog pin (0 - 1.0) """ # self.board.iterate() self.board.analog[pin].mode = INPUT self.board.analog[pin].enable_reporting() while True: value = self.board.analog[pin].read() if value is not None: break return value
[docs] def close(self) -> None: """ Close the connection with the arduino. """ self.board.exit() del self.board