Package micromelon

Python module for connecting to and interacting with the Micromelon Rover
and simulated rovers in the Micromelon Robot Simulator.

Submodules can be accessed with either lower-case or upper case notation.

Expand source code
"""
Python module for connecting to and interacting with the Micromelon Rover
and simulated rovers in the Micromelon Robot Simulator.

Submodules can be accessed with either lower-case or upper case notation.
"""

from ._robot_comms import RoverController
from . import battery as Battery
from . import colour as Colour
from . import i2c as I2C
from . import imu as IMU
from . import ir as IR
from . import leds as LEDs
from . import motors as Motors
from . import robot as Robot
from . import servos as Servos
from . import sounds as Sounds
from . import ultrasonic as Ultrasonic
from .helper_math import _math as Math
from ._utils import delay

CS = Colour.CS
COLOURS = Colour.COLOURS
NOTES = Sounds.NOTES
TUNES = Sounds.TUNES

__all__ = [
    "RoverController",
    "Motors",
    "Ultrasonic",
    "IMU",
    "IR",
    "Battery",
    "Math",
    "Robot",
    "Sounds",
    "NOTES",
    "TUNES",
    "LEDs",
    "Colour",
    "CS",
    "COLOURS",
    "Servos",
    "I2C",
    "delay",
]

Sub-modules

micromelon.battery

Functions to read the state of the robot's internal battery

micromelon.colour

Collection of functions for manipulating colour representations.
Includes functions for reading from the robot's colour sensors.

micromelon.helper_math

Collection of helpful maths functions and aliases

micromelon.i2c

Functions for communicating with I2C devices connected to the expansion header
If the rover controller is in uart operation then these functions are …

micromelon.imu

Collection of functions to read information from the robot's Inertial Measurement Unit (IMU)
The robot's IMU has an accelerometer and gyroscope

micromelon.ir

Functions for reading from the robot's IR time of flight distance sensors.
These sensors read the distance in cm to the nearest object on each side of …

micromelon.leds

Functions for controlling the RGB LEDs on the corners of the robot
Top and bottom LEDs are coupled so you can only control 4
Bottom LEDs mirror …

micromelon.motors

Collection of functions to control the movement of the robot

micromelon.robot

Collection of functions to set and get robot attributes and use the onboard screen …

micromelon.servos

Collection of functions for controlling servo motors connected to
the three pin headers on the back of the robot.

micromelon.sounds

Functions to control the onboard buzzer to play tunes or specific frequencies.
Also helpful definitions for musical notes to their frequency and …

micromelon.ultrasonic

Functions to read from the robot's ultrasonic sensor.

Functions

def delay(seconds) ‑> None

Alias to Python time.sleep(seconds)

Args

seconds : number
see Python time.sleep documentation

Returns

None

Expand source code
def delay(seconds) -> None:
    """
    Alias to Python time.sleep(seconds)

    Args:
        seconds (number): see Python time.sleep documentation

    Returns:
        None
    """
    sleep(seconds)

Classes

class COLOURS (value, names=None, *, module=None, qualname=None, type=None, start=1)

A collection of predefined colour names mapped to an RGB array

Expand source code
class COLOURS(Enum):
    """
    A collection of predefined colour names mapped to an RGB array
    """

    WHITE = [255, 255, 255]
    GREY = [128, 128, 128]
    BLACK = [0, 0, 0]
    LAVENDER = [220, 190, 255]
    MAGENTA = [240, 50, 230]
    PURPLE = [163, 53, 232]
    CYAN = [70, 240, 240]
    BLUE = [0, 128, 255]
    NAVY = [0, 0, 128]
    MINT = [170, 255, 195]
    GREEN = [0, 255, 0]
    TEAL = [0, 128, 128]
    LIME = [210, 245, 60]
    YELLOW = [255, 255, 0]
    OLIVE = [128, 128, 0]
    APRICOT = [255, 215, 180]
    ORANGE = [255, 128, 0]
    BROWN = [170, 110, 40]
    PINK = [250, 190, 212]
    RED = [255, 0, 34]
    MAROON = [128, 0, 0]

Ancestors

  • enum.Enum

Class variables

var APRICOT
var BLACK
var BLUE
var BROWN
var CYAN
var GREEN
var GREY
var LAVENDER
var LIME
var MAGENTA
var MAROON
var MINT
var NAVY
var OLIVE
var ORANGE
var PINK
var PURPLE
var RED
var TEAL
var WHITE
var YELLOW
class CS (value, names=None, *, module=None, qualname=None, type=None, start=1)

A collection of attributes that can be read from the colour sensor
Values correspond to attribute position in the sensor read array

CS.HUE = 0
CS.RED = 1
CS.GREEN = 2
CS.BLUE = 3
CS.BRIGHT = 4
CS.ALL = 5

Expand source code
class CS(Enum):
    """
    A collection of attributes that can be read from the colour sensor
    Values correspond to attribute position in the sensor read array

    CS.HUE = 0
    CS.RED = 1
    CS.GREEN = 2
    CS.BLUE = 3
    CS.BRIGHT = 4
    CS.ALL = 5
    """

    HUE = 0
    RED = 1
    GREEN = 2
    BLUE = 3
    BRIGHT = 4
    ALL = 5

Ancestors

  • enum.Enum

Class variables

var ALL
var BLUE
var BRIGHT
var GREEN
var HUE
var RED
class NOTES (value, names=None, *, module=None, qualname=None, type=None, start=1)

A collection of standard musical note frequencies
As '#' is not valid in a variable name 's' is used instead
Example: F sharp in the 6th octave would be NOTES.Fs6
B flat in the 4th octave would be NOTES.Bb4

Ancestors

  • enum.Enum

Class variables

var A0
var A1
var A2
var A3
var A4
var A5
var A6
var A7
var A8
var AsBb0
var AsBb1
var AsBb2
var AsBb3
var AsBb4
var AsBb5
var AsBb6
var AsBb7
var AsBb8
var B0
var B1
var B2
var B3
var B4
var B5
var B6
var B7
var B8
var C0
var C1
var C2
var C3
var C4
var C5
var C6
var C7
var C8
var CsDb0
var CsDb1
var CsDb2
var CsDb3
var CsDb4
var CsDb5
var CsDb6
var CsDb7
var CsDb8
var D0
var D1
var D2
var D3
var D4
var D5
var D6
var D7
var D8
var DsEb0
var DsEb1
var DsEb2
var DsEb3
var DsEb4
var DsEb5
var DsEb6
var DsEb7
var DsEb8
var E0
var E1
var E2
var E3
var E4
var E5
var E6
var E7
var E8
var F0
var F1
var F2
var F3
var F4
var F5
var F6
var F7
var F8
var FsGb0
var FsGb1
var FsGb2
var FsGb3
var FsGb4
var FsGb5
var FsGb6
var FsGb7
var FsGb8
var G0
var G1
var G2
var G3
var G4
var G5
var G6
var G7
var G8
var GsAb0
var GsAb1
var GsAb2
var GsAb3
var GsAb4
var GsAb5
var GsAb6
var GsAb7
var GsAb8
class RoverController (defaultTimeout=3.0)

Manages connection and packet level communication with the robot
Is a singleton - get a reference to the instance with constructor

standard usage
rc = RoverController()

Then connect using one of the three methods below
rc.connectSerial('COM port name')
rc.connectIP(address, port)
rc.connectBLE(botID)

Expand source code
class RoverController(metaclass=Singleton):
    """
    Manages connection and packet level communication with the robot
    Is a singleton - get a reference to the instance with constructor

    standard usage
    rc = RoverController()

    Then connect using one of the three methods below
    rc.connectSerial('COM port name')
    rc.connectIP(address, port)
    rc.connectBLE(botID)
    """

    def __init__(self, defaultTimeout=3.0) -> None:
        signal.signal(signal.SIGINT, _sigint_handler)
        self._roverSimInfo = 0
        self._roverCharge = None
        self._roverErrorMask = None
        self._defaultCommunicationTimeout = defaultTimeout
        self._robotCommunicator = RobotCommunicatorThread()
        self._robotCommunicator.start()

    def setDefaultCommunicationTimeout(self, newDefaultTimeout: float) -> None:
        """
        This default timeout (in seconds) is used as a fallback for any communication
        that happens with the robot.
        Can be overridden for individual function calls.
        Set a longer timeout if you expect slow communcation.

        Args:
          newDefaultTimeout (float): time in seconds to timeout on a communication command

        Returns:
          None
        """
        self._defaultCommunicationTimeout = newDefaultTimeout

    def isConnected(self) -> bool:
        return self._robotCommunicator.isConnected()

    def connectedRobotIsSimulated(self) -> bool:
        return self.isConnected() and self._roverSimInfo != 0

    def startRover(self, overrideSensorSpamMode: bool = None) -> None:
        """
        Start sequence depending on robot mode:
          Serial UART: Set rover to Expansion mode to respond to packets from UART on header
          Serial TCP: Write the running state for program start
          Bluetooth: Write the running state for program start and start sensor spam iff not overridden to False

        Args:
          overrideSensorSpamMode (bool):
            - Defaults to None
            - Sensor Spam mode will be activated by default for a Bluetooth connection to improve sensor read speeds
            - It is not activated by default for serial and TCP connections

        Returns:
          None
        """
        if (
            self._robotCommunicator.isInBluetoothMode()
            and overrideSensorSpamMode is None
        ) or overrideSensorSpamMode:
            self._robotCommunicator.startSensorSpam()
        if not self._robotCommunicator.isInSerialMode():
            self.writeAttribute(OPTYPE.BUTTON_PRESS, [RUNNING_STATES.RUNNING.value])

    def _postConnectionSetup(self) -> None:
        """
        Check whether the connected robot is simulated
        Read battery percentage and sensor error mask

        Returns:
          None
        """
        self._roverSimInfo = None
        self._roverCharge = None
        self._roverErrorMask = None
        try:
            self._roverSimInfo = self.readAttribute(OPTYPE.SIMULATOR_INFO)[0]
            logger.debug("Rover siminfo: " + str(self._roverSimInfo))
        except Exception as e:
            # couldn't read simulator info - assume not simulated
            logger.info("Rover siminfo read failed")
            logger.info(e)
            self._roverSimInfo = 0

        try:
            self._roverCharge = self.readAttribute(OPTYPE.STATE_OF_CHARGE)[0]
            logger.info("Rover battery at " + str(self._roverCharge) + "%")
            self._roverErrorMask = bytesToIntArray(
                self.readAttribute(OPTYPE.SENSOR_ERRORS), 2, False
            )[0]
            if self._roverErrorMask == 0:
                logger.info("No sensor errors detected")
            else:
                logger.warning("Sensor errors detected")
                logger.warning("Error mask: " + str(self._roverErrorMask))
        except Exception as e:
            logger.error("Failed to read battery and error mask")
            logger.error(e)

    def connectSerial(self, port="/dev/ttyS0"):
        """
        Connects to the desired port and attempts to set the rover to UART mode
        The default port is the miniUART on a Raspberry Pi (primary UART on Zero W, 3, and 4)
          Other Raspberry Pi models have "/dev/ttyAMA0" as primary UART
          Note: You will need to disable serial console on the UART you choose to use for it to function correctly

        Args:
          port (string): Name of serial COM port

        Returns:
          None
        """
        self._robotCommunicator.connectSerial(port)
        self.setRoverToUART(True)
        self._postConnectionSetup()

    def connectIP(self, address="127.0.0.1", port=9000):
        """
        Connects over TCP to the address and port provided.
        To connect to a simulated robot choose the port to match the BotID shown in the robot
          controls on the top left of the simulator window.

        Args:
          address (string): IP address - defaults to IPv4 loopback (127.0.0.1)
          port (int): TCP port number - defaults to 9000

        Returns:
          None
        """
        self._robotCommunicator.connectIP(address, port)
        self._postConnectionSetup()

    def connectBLE(self, botID):
        """
        Connects over Bluetooth LE to a robot displaying the given ID on its screen.

        Args:
          botID (int): Robot ID number (shown on robot screen)

        Returns:
          None
        """
        self._robotCommunicator.connectBLE(botID)
        self._postConnectionSetup()

    def disconnect(self) -> None:
        self._robotCommunicator.disconnect()

    def getTransmitAverageMS(self) -> int:
        """
        Returns:
          The approximate (moving average) time in ms it takes to transmit a packet to the robot.
        """
        stats = self._robotCommunicator.getCommsTimingStats()
        return stats[0]

    def getTransactionAverageMS(self) -> int:
        """
        Returns:
          The approximate (moving average) time in ms it takes to complete a transaction with the robot.
          A transaction is an attribute write or non-cached attribute read
        """
        stats = self._robotCommunicator.getCommsTimingStats()
        return stats[2]

    def stopRover(self):
        """
        Attempts to stop the rover by setting motor speeds to 0, turning off the buzzer,
        turning sensor spam off, and taking it out of running mode.

        Returns:
          None
        """
        waitForAck = False
        timeout = 0.5
        try:
            self.writePacket(OPCODE.WRITE, OPTYPE.SPAM_MODE, [0], waitForAck, timeout)
            self.writePacket(
                OPCODE.WRITE, OPTYPE.MOTOR_SET, [0] * 7, waitForAck, timeout
            )
            self.writePacket(
                OPCODE.WRITE, OPTYPE.BUZZER_FREQ, [0, 0], waitForAck, timeout
            )
            if not self._robotCommunicator.isInSerialMode():
                self.writePacket(
                    OPCODE.WRITE,
                    OPTYPE.BUTTON_PRESS,
                    [RUNNING_STATES.CLOSED.value],
                    waitForAck,
                    timeout,
                )
        except Exception as e:
            logger.debug("Not all robot stop commands completed")
            logger.debug(e)

    def end(self):
        """
        Stops all communication threads and ends the entire Python program.
        """
        self._robotCommunicator.stop()
        self._robotCommunicator.join()
        try:
            sys.exit(0)
        except Exception:
            # Sometimes threading module has a shutdown exception
            # TODO: investigate further
            os._exit(0)

    def writeAttribute(self, opType, data, timeout=None):
        """
        Blocking Write - writes an attribute and returns once the ACK packet is received from the robot.

        Args:
          opType (int or MicromelonOpType): Attribute to write to.
          data (list of bytes): data to write.
          timeout (number): time in seconds to wait for completion.
                          Uses the default timeout of this controller if not provided

        Raises:
          TimeoutError on timeout.
          Exception on comms failure.

        Returns:
          True on success, False otherwise.
        """
        if timeout is None:
            timeout = self._defaultCommunicationTimeout
        return self._robotCommunicator.writeAttribute(opType, data, timeout)

    def readAttribute(self, opType, data=None, timeout=None):
        """
        Blocking read - returns the raw data from robot response

        Args:
          opType (int or MicromelonOpType): Attribute to write to.
          data (list of bytes): extra read configuration data.
          timeout (number): time in seconds to wait for result.
                          Uses the default timeout of this controller if not provided

        Raises:
          TimeoutError on timeout.
          Exception on comms failure.

        Returns:
          List of bytes on success, None otherwise.
        """
        if data is None:
            data = []
        if timeout is None:
            timeout = self._defaultCommunicationTimeout
        return self._robotCommunicator.readAttribute(opType, data, timeout)

    def writePacket(self, opCode, opType, data=None, waitForAck=True, timeout=None):
        """
        Blocking write - Writes the packet over transport.
        Waits for ack by default.

        Args:
          opCode (int or MicromelonOpCode): Flag for type of operation.
          opType (int or MicromelonOpType): Attribute to write to.
          data (list of bytes): data for packet, defaults to None.
          waitForAck (bool): whether or not to wait for the robot to acknowledge the packet. Defaults to true.
          timeout (number): time in seconds to wait for result. Defaults to None (block indefinitely).
                          Uses the default timeout of this controller if not provided

        Raises:
          TimeoutError on timeout.
          Exception on comms failure.

        Returns:
          True on success, False otherwise.
        """
        if data is None:
            data = []
        if timeout is None:
            timeout = self._defaultCommunicationTimeout
        return self._robotCommunicator.writePacket(
            opCode, opType, data, waitForAck, timeout
        )

    def doMotorOperation(self, opType, data, timeout=120):
        """
        Some motor operations that use encoders or IMU take an unknown amount of time to complete.
        In this case the robot acknowledges receipt of the command and then notifies completion at
        a later time.
        This function writes the motor command and waits for the completion notification.
        Only use this if you're sure you want to.

        Args:
          opType (int or MicromelonOpType): Attribute to write to.
          data (list of bytes): data for packet, defaults to None.
          timeout (number): time in seconds to wait for result. Defaults to 120.
                            If your operation should take more than 2 minutes maybe the approach isn't ideal.

        Raises:
          TimeoutError on timeout.
          Exception on comms failure.

        Returns:
          None
        """
        self._robotCommunicator.clearMotorNotificationWatchers()
        toWait = self._robotCommunicator.getNewMotorNotificationWatcherEvent()
        self.writeAttribute(opType, data)
        timedOut = not toWait.wait(timeout)
        if timedOut:
            raise TimeoutError("Motor Encoder operation timed out")

    def setRoverToUART(self, uartMode: bool) -> None:
        """
        Sets the robot's UART control mode.
        If set to True, the robot will respond to packets over the UART connection
        on the expansion header and will not be available for Bluetooth connections.
        If set to false, the robot will be in normal Bluetooth operation mode

        Args:
          uartMode (bool): Whether or not to be in UART mode.

        Raises:
          TimeoutError on timeout.
          Exception on comms failure.

        Returns:
          None
        """
        data = [0]
        if uartMode:
            data = [1]
        self.writePacket(OPCODE.WRITE, OPTYPE.CONTROL_MODE, data)

Methods

def connectBLE(self, botID)

Connects over Bluetooth LE to a robot displaying the given ID on its screen.

Args

botID : int
Robot ID number (shown on robot screen)

Returns

None

Expand source code
def connectBLE(self, botID):
    """
    Connects over Bluetooth LE to a robot displaying the given ID on its screen.

    Args:
      botID (int): Robot ID number (shown on robot screen)

    Returns:
      None
    """
    self._robotCommunicator.connectBLE(botID)
    self._postConnectionSetup()
def connectIP(self, address='127.0.0.1', port=9000)

Connects over TCP to the address and port provided.
To connect to a simulated robot choose the port to match the BotID shown in the robot
controls on the top left of the simulator window.

Args

address : string
IP address - defaults to IPv4 loopback (127.0.0.1)
port : int
TCP port number - defaults to 9000

Returns

None

Expand source code
def connectIP(self, address="127.0.0.1", port=9000):
    """
    Connects over TCP to the address and port provided.
    To connect to a simulated robot choose the port to match the BotID shown in the robot
      controls on the top left of the simulator window.

    Args:
      address (string): IP address - defaults to IPv4 loopback (127.0.0.1)
      port (int): TCP port number - defaults to 9000

    Returns:
      None
    """
    self._robotCommunicator.connectIP(address, port)
    self._postConnectionSetup()
def connectSerial(self, port='/dev/ttyS0')

Connects to the desired port and attempts to set the rover to UART mode
The default port is the miniUART on a Raspberry Pi (primary UART on Zero W, 3, and 4)
Other Raspberry Pi models have "/dev/ttyAMA0" as primary UART
Note: You will need to disable serial console on the UART you choose to use for it to function correctly

Args

port : string
Name of serial COM port

Returns

None

Expand source code
def connectSerial(self, port="/dev/ttyS0"):
    """
    Connects to the desired port and attempts to set the rover to UART mode
    The default port is the miniUART on a Raspberry Pi (primary UART on Zero W, 3, and 4)
      Other Raspberry Pi models have "/dev/ttyAMA0" as primary UART
      Note: You will need to disable serial console on the UART you choose to use for it to function correctly

    Args:
      port (string): Name of serial COM port

    Returns:
      None
    """
    self._robotCommunicator.connectSerial(port)
    self.setRoverToUART(True)
    self._postConnectionSetup()
def connectedRobotIsSimulated(self) ‑> bool
Expand source code
def connectedRobotIsSimulated(self) -> bool:
    return self.isConnected() and self._roverSimInfo != 0
def disconnect(self) ‑> None
Expand source code
def disconnect(self) -> None:
    self._robotCommunicator.disconnect()
def doMotorOperation(self, opType, data, timeout=120)

Some motor operations that use encoders or IMU take an unknown amount of time to complete.
In this case the robot acknowledges receipt of the command and then notifies completion at
a later time.
This function writes the motor command and waits for the completion notification.
Only use this if you're sure you want to.

Args

opType : int or MicromelonOpType
Attribute to write to.
data : list of bytes
data for packet, defaults to None.
timeout : number
time in seconds to wait for result. Defaults to 120.
If your operation should take more than 2 minutes maybe the approach isn't ideal.

Raises

TimeoutError on timeout.
Exception on comms failure.

Returns

None

Expand source code
def doMotorOperation(self, opType, data, timeout=120):
    """
    Some motor operations that use encoders or IMU take an unknown amount of time to complete.
    In this case the robot acknowledges receipt of the command and then notifies completion at
    a later time.
    This function writes the motor command and waits for the completion notification.
    Only use this if you're sure you want to.

    Args:
      opType (int or MicromelonOpType): Attribute to write to.
      data (list of bytes): data for packet, defaults to None.
      timeout (number): time in seconds to wait for result. Defaults to 120.
                        If your operation should take more than 2 minutes maybe the approach isn't ideal.

    Raises:
      TimeoutError on timeout.
      Exception on comms failure.

    Returns:
      None
    """
    self._robotCommunicator.clearMotorNotificationWatchers()
    toWait = self._robotCommunicator.getNewMotorNotificationWatcherEvent()
    self.writeAttribute(opType, data)
    timedOut = not toWait.wait(timeout)
    if timedOut:
        raise TimeoutError("Motor Encoder operation timed out")
def end(self)

Stops all communication threads and ends the entire Python program.

Expand source code
def end(self):
    """
    Stops all communication threads and ends the entire Python program.
    """
    self._robotCommunicator.stop()
    self._robotCommunicator.join()
    try:
        sys.exit(0)
    except Exception:
        # Sometimes threading module has a shutdown exception
        # TODO: investigate further
        os._exit(0)
def getTransactionAverageMS(self) ‑> int

Returns

The approximate (moving average) time in ms it takes to complete a transaction with the robot.
A transaction is an attribute write or non-cached attribute read

Expand source code
def getTransactionAverageMS(self) -> int:
    """
    Returns:
      The approximate (moving average) time in ms it takes to complete a transaction with the robot.
      A transaction is an attribute write or non-cached attribute read
    """
    stats = self._robotCommunicator.getCommsTimingStats()
    return stats[2]
def getTransmitAverageMS(self) ‑> int

Returns

The approximate (moving average) time in ms it takes to transmit a packet to the robot.

Expand source code
def getTransmitAverageMS(self) -> int:
    """
    Returns:
      The approximate (moving average) time in ms it takes to transmit a packet to the robot.
    """
    stats = self._robotCommunicator.getCommsTimingStats()
    return stats[0]
def isConnected(self) ‑> bool
Expand source code
def isConnected(self) -> bool:
    return self._robotCommunicator.isConnected()
def readAttribute(self, opType, data=None, timeout=None)

Blocking read - returns the raw data from robot response

Args

opType : int or MicromelonOpType
Attribute to write to.
data : list of bytes
extra read configuration data.
timeout : number
time in seconds to wait for result.
Uses the default timeout of this controller if not provided

Raises

TimeoutError on timeout.
Exception on comms failure.

Returns

List of bytes on success, None otherwise.

Expand source code
def readAttribute(self, opType, data=None, timeout=None):
    """
    Blocking read - returns the raw data from robot response

    Args:
      opType (int or MicromelonOpType): Attribute to write to.
      data (list of bytes): extra read configuration data.
      timeout (number): time in seconds to wait for result.
                      Uses the default timeout of this controller if not provided

    Raises:
      TimeoutError on timeout.
      Exception on comms failure.

    Returns:
      List of bytes on success, None otherwise.
    """
    if data is None:
        data = []
    if timeout is None:
        timeout = self._defaultCommunicationTimeout
    return self._robotCommunicator.readAttribute(opType, data, timeout)
def setDefaultCommunicationTimeout(self, newDefaultTimeout: float) ‑> None

This default timeout (in seconds) is used as a fallback for any communication
that happens with the robot.
Can be overridden for individual function calls.
Set a longer timeout if you expect slow communcation.

Args

newDefaultTimeout : float
time in seconds to timeout on a communication command

Returns

None

Expand source code
def setDefaultCommunicationTimeout(self, newDefaultTimeout: float) -> None:
    """
    This default timeout (in seconds) is used as a fallback for any communication
    that happens with the robot.
    Can be overridden for individual function calls.
    Set a longer timeout if you expect slow communcation.

    Args:
      newDefaultTimeout (float): time in seconds to timeout on a communication command

    Returns:
      None
    """
    self._defaultCommunicationTimeout = newDefaultTimeout
def setRoverToUART(self, uartMode: bool) ‑> None

Sets the robot's UART control mode.
If set to True, the robot will respond to packets over the UART connection
on the expansion header and will not be available for Bluetooth connections.
If set to false, the robot will be in normal Bluetooth operation mode

Args

uartMode : bool
Whether or not to be in UART mode.

Raises

TimeoutError on timeout.
Exception on comms failure.

Returns

None

Expand source code
def setRoverToUART(self, uartMode: bool) -> None:
    """
    Sets the robot's UART control mode.
    If set to True, the robot will respond to packets over the UART connection
    on the expansion header and will not be available for Bluetooth connections.
    If set to false, the robot will be in normal Bluetooth operation mode

    Args:
      uartMode (bool): Whether or not to be in UART mode.

    Raises:
      TimeoutError on timeout.
      Exception on comms failure.

    Returns:
      None
    """
    data = [0]
    if uartMode:
        data = [1]
    self.writePacket(OPCODE.WRITE, OPTYPE.CONTROL_MODE, data)
def startRover(self, overrideSensorSpamMode: bool = None) ‑> None

Start sequence depending on robot mode: Serial UART: Set rover to Expansion mode to respond to packets from UART on header
Serial TCP: Write the running state for program start
Bluetooth: Write the running state for program start and start sensor spam iff not overridden to False

Args

overrideSensorSpamMode (bool): - Defaults to None
- Sensor Spam mode will be activated by default for a Bluetooth connection to improve sensor read speeds
- It is not activated by default for serial and TCP connections

Returns

None

Expand source code
def startRover(self, overrideSensorSpamMode: bool = None) -> None:
    """
    Start sequence depending on robot mode:
      Serial UART: Set rover to Expansion mode to respond to packets from UART on header
      Serial TCP: Write the running state for program start
      Bluetooth: Write the running state for program start and start sensor spam iff not overridden to False

    Args:
      overrideSensorSpamMode (bool):
        - Defaults to None
        - Sensor Spam mode will be activated by default for a Bluetooth connection to improve sensor read speeds
        - It is not activated by default for serial and TCP connections

    Returns:
      None
    """
    if (
        self._robotCommunicator.isInBluetoothMode()
        and overrideSensorSpamMode is None
    ) or overrideSensorSpamMode:
        self._robotCommunicator.startSensorSpam()
    if not self._robotCommunicator.isInSerialMode():
        self.writeAttribute(OPTYPE.BUTTON_PRESS, [RUNNING_STATES.RUNNING.value])
def stopRover(self)

Attempts to stop the rover by setting motor speeds to 0, turning off the buzzer,
turning sensor spam off, and taking it out of running mode.

Returns

None

Expand source code
def stopRover(self):
    """
    Attempts to stop the rover by setting motor speeds to 0, turning off the buzzer,
    turning sensor spam off, and taking it out of running mode.

    Returns:
      None
    """
    waitForAck = False
    timeout = 0.5
    try:
        self.writePacket(OPCODE.WRITE, OPTYPE.SPAM_MODE, [0], waitForAck, timeout)
        self.writePacket(
            OPCODE.WRITE, OPTYPE.MOTOR_SET, [0] * 7, waitForAck, timeout
        )
        self.writePacket(
            OPCODE.WRITE, OPTYPE.BUZZER_FREQ, [0, 0], waitForAck, timeout
        )
        if not self._robotCommunicator.isInSerialMode():
            self.writePacket(
                OPCODE.WRITE,
                OPTYPE.BUTTON_PRESS,
                [RUNNING_STATES.CLOSED.value],
                waitForAck,
                timeout,
            )
    except Exception as e:
        logger.debug("Not all robot stop commands completed")
        logger.debug(e)
def writeAttribute(self, opType, data, timeout=None)

Blocking Write - writes an attribute and returns once the ACK packet is received from the robot.

Args

opType : int or MicromelonOpType
Attribute to write to.
data : list of bytes
data to write.
timeout : number
time in seconds to wait for completion.
Uses the default timeout of this controller if not provided

Raises

TimeoutError on timeout.
Exception on comms failure.

Returns

True on success, False otherwise.

Expand source code
def writeAttribute(self, opType, data, timeout=None):
    """
    Blocking Write - writes an attribute and returns once the ACK packet is received from the robot.

    Args:
      opType (int or MicromelonOpType): Attribute to write to.
      data (list of bytes): data to write.
      timeout (number): time in seconds to wait for completion.
                      Uses the default timeout of this controller if not provided

    Raises:
      TimeoutError on timeout.
      Exception on comms failure.

    Returns:
      True on success, False otherwise.
    """
    if timeout is None:
        timeout = self._defaultCommunicationTimeout
    return self._robotCommunicator.writeAttribute(opType, data, timeout)
def writePacket(self, opCode, opType, data=None, waitForAck=True, timeout=None)

Blocking write - Writes the packet over transport.
Waits for ack by default.

Args

opCode : int or MicromelonOpCode
Flag for type of operation.
opType : int or MicromelonOpType
Attribute to write to.
data : list of bytes
data for packet, defaults to None.
waitForAck : bool
whether or not to wait for the robot to acknowledge the packet. Defaults to true.
timeout : number
time in seconds to wait for result. Defaults to None (block indefinitely).
Uses the default timeout of this controller if not provided

Raises

TimeoutError on timeout.
Exception on comms failure.

Returns

True on success, False otherwise.

Expand source code
def writePacket(self, opCode, opType, data=None, waitForAck=True, timeout=None):
    """
    Blocking write - Writes the packet over transport.
    Waits for ack by default.

    Args:
      opCode (int or MicromelonOpCode): Flag for type of operation.
      opType (int or MicromelonOpType): Attribute to write to.
      data (list of bytes): data for packet, defaults to None.
      waitForAck (bool): whether or not to wait for the robot to acknowledge the packet. Defaults to true.
      timeout (number): time in seconds to wait for result. Defaults to None (block indefinitely).
                      Uses the default timeout of this controller if not provided

    Raises:
      TimeoutError on timeout.
      Exception on comms failure.

    Returns:
      True on success, False otherwise.
    """
    if data is None:
        data = []
    if timeout is None:
        timeout = self._defaultCommunicationTimeout
    return self._robotCommunicator.writePacket(
        opCode, opType, data, waitForAck, timeout
    )
class TUNES (value, names=None, *, module=None, qualname=None, type=None, start=1)

A collection of pre-programmed tunes the robot can play

TUNES.UP = 1
TUNES.DOWN = 2

Expand source code
class TUNES(Enum):
    """
    A collection of pre-programmed tunes the robot can play

    TUNES.UP = 1
    TUNES.DOWN = 2
    """

    UP = 1
    DOWN = 2

Ancestors

  • enum.Enum

Class variables

var DOWN
var UP