bricknil.sensor.sensor

Actual sensor and motor peripheral definitions from Boost and PoweredUp

Classes

Button(name[, port, capabilities]) Register to be notified of button presses on the Hub (Boost or PoweredUp)
CurrentSensor(name[, port, capabilities]) Voltage sensor
DuploSpeedSensor(name[, port, capabilities]) Speedometer on Duplo train base that measures front wheel speed.
DuploVisionSensor(name[, port, capabilities]) Access the Duplo Vision/Distance Sensor
ExternalMotionSensor(name[, port, capabilities]) Access the external motion sensor (IR) provided in the Wedo sets
ExternalTiltSensor(name[, port, capabilities]) Access the External tilt sensor provided in the Wedo sets
InternalTiltSensor(name[, port, capabilities]) Access the internal tilt sensor in the Boost Move Hub.
RemoteButtons(name[, port, capabilities]) Represents one set of ‘+’, ‘-‘, ‘red’ buttons on the PoweredHub Remote
VisionSensor(name[, port, capabilities]) Access the Boost Vision/Distance Sensor
VoltageSensor(name[, port, capabilities]) Voltage sensor

Members

class bricknil.sensor.sensor.VisionSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Access the Boost Vision/Distance Sensor

Only the sensing capabilities of this sensor is supported right now.

  • sense_color: Returns one of the 10 predefined colors
  • sense_distance: Distance from 0-7 in roughly inches
  • sense_count: Running count of waving your hand/item over the sensor (32-bit)
  • sense_reflectivity: Under distances of one inch, the inverse of the distance
  • sense_ambient: Distance under one inch (so inverse of the preceeding)
  • sense_rgb: R, G, B values (3 sets of uint16)

Any combination of sense_color, sense_distance, sense_count, sense_reflectivity, and sense_rgb is supported.

Examples:

# Basic distance sensor
@attach(VisionSensor, name='vision', capabilities=['sense_color'])
# Or use the capability Enum
@attach(VisionSensor, name='vision', capabilities=[VisionSensor.capability.sense_color])

# Distance and color sensor
@attach(VisionSensor, name='vision', capabilities=['sense_color', 'sense_distance'])

# Distance and rgb sensor with different thresholds to trigger updates
@attach(VisionSensor, name='vision', capabilities=[('sense_color', 1), ('sense_rgb', 5)])

The values returned by the sensor will always be available in the instance variable self.value. For example, when the sense_color and sense_rgb capabilities are enabled, the following values will be stored and updated:

self.value = { VisionSensor.capability.sense_color:  uint8,
               VisionSensor.capability.sense_rgb:
                                [ uint16, uint16, uint16 ]
             }

Notes

The actual modes supported by the sensor are as follows:

  • 0 = color (0-10)
  • 1 = IR proximity (0-7)
  • 2 = count (32-bit int)
  • 3 = Reflt (inverse of distance when closer than 1”)
  • 4 = Amb (distance when closer than 1”)
  • 5 = COL (output) ?
  • 6 = RGB I
  • 7 = IR tx (output) ?
  • 8 = combined: Color byte, Distance byte, 0xFF, Reflected light
class capability

Bases: enum.Enum

An enumeration.

sense_ambient = 4
sense_color = 0
sense_count = 2
sense_distance = 1
sense_reflectivity = 3
sense_rgb = 6
datasets = {<capability.sense_color: 0>: (1, 1), <capability.sense_distance: 1>: (1, 1), <capability.sense_count: 2>: (1, 4), <capability.sense_reflectivity: 3>: (1, 1), <capability.sense_ambient: 4>: (1, 1), <capability.sense_rgb: 6>: (3, 2)}
allowed_combo = [<capability.sense_color: 0>, <capability.sense_distance: 1>, <capability.sense_count: 2>, <capability.sense_reflectivity: 3>, <capability.sense_rgb: 6>]
class bricknil.sensor.sensor.InternalTiltSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Access the internal tilt sensor in the Boost Move Hub.

The various modes are:

  • sense_angle - X, Y angles. Both are 0 if hub is lying flat with button up
  • sense_tilt - value from 0-9 if hub is tilted around any of its axis. Seems to be a rough mesaure of how much the hub is tilted away from lying flat. There is no update for just a translation along an axis
  • sense_orientation - returns one of the nine orientations below (0-9)
    • InternalTiltSensor.orientation.up = flat with button on top
    • InternalTiltSensor.orientation.right - standing up on side closest to button
    • InternalTiltSensor.orientation.left - standing up on side furthest from button
    • InternalTiltSensor.orientation.far_side - on long face facing away
    • InternalTiltSensor.orientation.near_side - on long face facing you
    • InternalTiltSensor.orientation.down - upside down
  • sense_impact - 32-bit count of impacts to sensor
  • sense_acceleration_3_axis - 3 bytes of raw accelerometer data.

Any combination of the above modes are allowed.

Examples:

# Basic tilt sensor
@attach(InternalTiltSensor, name='tilt', capabilities=['sense_tilt'])
# Or use the capability Enum
@attach(InternalTiltSensor, name='tilt', capabilities=[InternalTiltSensor.sense_tilt])

# Tilt and orientation sensor
@attach(InternalTiltSensor, name='tilt', capabilities=['sense_tilt, sense_orientation'])

The values returned by the sensor will always be available in the instance variable self.value. For example, when the sense_angle and sense_orientation capabilities are enabled, the following values will be stored and updated:

self.value = { InternalTiltSensor.capability.sense_angle:  [uint8, uint8],
               InternalTiltSensor.capability.sense_orientation:
                                Enum(InternalTiltSensor.orientation)
             }
class capability

Bases: enum.Enum

An enumeration.

sense_acceleration_3_axis = 4
sense_angle = 0
sense_impact = 3
sense_orientation = 2
sense_tilt = 1
datasets = {<capability.sense_angle: 0>: (2, 1), <capability.sense_tilt: 1>: (1, 1), <capability.sense_orientation: 2>: (1, 1), <capability.sense_impact: 3>: (1, 4), <capability.sense_acceleration_3_axis: 4>: (3, 1)}
allowed_combo = [<capability.sense_angle: 0>, <capability.sense_tilt: 1>, <capability.sense_orientation: 2>, <capability.sense_impact: 3>, <capability.sense_acceleration_3_axis: 4>]
class orientation

Bases: enum.Enum

An enumeration.

down = 5
far_side = 3
left = 2
near_side = 4
right = 1
up = 0
update_value(msg_bytes)[source]

If sense_orientation, then substitute the IntenalTiltSensor.orientation enumeration value into the self.value dict. Otherwise, don’t do anything special to the self.value dict.

class bricknil.sensor.sensor.ExternalMotionSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Access the external motion sensor (IR) provided in the Wedo sets

Measures distance to object, or if an object is moving (distance varying).

  • sense_distance - distance in inches from 0-10
  • sense_count - Increments every time it detects motion (32-bit value)

These are mutually exclusive (non-combinable)

Examples:

# Distance measurement
@attach(ExternalMotionSensor, name='motion_sensor', capabilities=['sense_distance'])


# Motion detection
@attach(ExternalMotionSensor, name='motion_sensor', capabilities=['sense_count'])
class capability

Bases: enum.Enum

An enumeration.

sense_count = 1
sense_distance = 0
datasets = {<capability.sense_distance: 0>: (1, 1), <capability.sense_count: 1>: (1, 4)}
allowed_combo = []
class bricknil.sensor.sensor.ExternalTiltSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Access the External tilt sensor provided in the Wedo sets

Three modes are supported (non-combinable):

  • sense_angle - X (around long axis), Y (around short axis) angles. -45 to 45 degrees
  • sense_orientation - returns one of the orientations below (wrt looking at the sensor from the side opposite the wiring harness)
    • ExternalTiltSensor.orientation.up = flat with studs on top
    • ExternalTiltSensor.orientation.right = studs facing rigth
    • ExternalTiltSensor.orientation.left = studs facing left
    • ExternalTiltSensor.orientation.far_side = studs facing away from you
    • ExternalTiltSensor.orientation.near_side = studs facing towards you
  • sense_impact - Keeps a count of impacts, but sends three bytes (direction of hit?)

These are mutually exclusive (non-combinable).

class capability

Bases: enum.Enum

An enumeration.

sense_angle = 0
sense_impact = 2
sense_orientation = 1
datasets = {<capability.sense_angle: 0>: (2, 1), <capability.sense_orientation: 1>: (1, 1), <capability.sense_impact: 2>: (3, 1)}
allowed_combo = []
class orientation

Bases: enum.Enum

An enumeration.

far_side = 3
left = 5
near_side = 9
right = 7
up = 0
update_value(msg_bytes)[source]

If angle, convert the bytes being returned to twos complement ints If orientation, then convert to the orientation enumeration.

class bricknil.sensor.sensor.RemoteButtons(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Represents one set of ‘+’, ‘-‘, ‘red’ buttons on the PoweredHub Remote

Each remote has two sets of buttons, on the left and right side. Pick the one your want to attach to by using the port argument with either Port.L or Port.R.

There are actually a few different modes that the hardware supports, but we are only going to use one of them called ‘KEYSD’ (see the notes in the documentation on the raw values reported by the hub). This mode makes the remote send three values back in a list. To access each button state, there are three helper methods provided (see below)

Examples:

# Basic connection to the left buttons
@attach(RemoteButtons, name='left_buttons', port=RemoteButtons.Port.L)

# Getting values back in the handler
async def left_buttons_change(self):

    is_plus_pressed = self.left_buttons.plus_pressed()
    is_minus_pressed = self.left_buttons.minus_pressed()
    is_red_pressed = self.left_buttons.red_pressed()

Maps the port names L, R

class Port

Bases: enum.Enum

An enumeration.

L = 0
R = 1
class Button

Bases: enum.IntEnum

The button index in the value list returned by the sensor

MINUS = 2
PLUS = 0
RED = 1
class capability

Bases: enum.Enum

An enumeration.

sense_press = 4
datasets = {<capability.sense_press: 4>: (3, 1)}
allowed_combo = []
plus_pressed()[source]

Return whether value reflects that the PLUS button is pressed

minus_pressed()[source]

Return whether value reflects that the MINUS button is pressed

red_pressed()[source]

Return whether value reflects that the RED button is pressed

class bricknil.sensor.sensor.Button(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Register to be notified of button presses on the Hub (Boost or PoweredUp)

This is actually a slight hack, since the Hub button is not a peripheral that is attached like other sensors in the Lego protocol. Instead, the buttons are accessed through Hub property messages. We abstract away these special messages to make the button appear to be like any other peripheral sensor.

Examples:

@attach(Button, name='hub_btn')

Notes

Since there is no attach I/O message from the hub to trigger the activate_updates() method, we instead insert a fake “attaach” message from this fake sensor on port 255 in the BLEventQ.get_messages method that is used to register for updates from a given sensor.

Call super-class with port set to 255

class capability

Bases: enum.Enum

An enumeration.

sense_press = 0
datasets = {<capability.sense_press: 0>: (1, 1)}
allowed_combo = [<capability.sense_press: 0>]
activate_updates()[source]

Use a special Hub Properties button message updates activation message

class bricknil.sensor.sensor.DuploVisionSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Access the Duplo Vision/Distance Sensor

  • sense_color: Returns one of the 10 predefined colors
  • sense_ctag: Returns one of the 10 predefined tags
  • sense_reflectivity: Under distances of one inch, the inverse of the distance
  • sense_rgb: R, G, B values (3 sets of uint16)

Any combination of sense_color, sense_ctag, sense_reflectivity, and sense_rgb is supported.

Examples:

# Basic color sensor
@attach(DuploVisionSensor, name='vision', capabilities=['sense_color'])
# Or use the capability Enum
@attach(DuploVisionSensor, name='vision', capabilities=[DuploVisionSensor.capability.sense_color])

# Ctag and reflectivity sensor
@attach(DuploVisionSensor, name='vision', capabilities=['sense_ctag', 'sense_reflectivity'])

# Distance and rgb sensor with different thresholds to trigger updates
@attach(DuploVisionSensor, name='vision', capabilities=[('sense_color', 1), ('sense_rgb', 5)])

The values returned by the sensor will always be available in the instance variable self.value. For example, when the sense_color and sense_rgb capabilities are enabled, the following values will be stored and updated:

self.value = { DuploVisionSensor.capability.sense_color:  uint8,
               DuploVisionSensor.capability.sense_rgb:
                                [ uint16, uint16, uint16 ]
             }

Notes

The actual modes supported by the sensor are as follows:

  • 0 = color (0-10)
  • 1 = ctag (32-bit int)
  • 2 = Reflt (inverse of distance when closer than 1”)
  • 3 = RGB I
class capability

Bases: enum.Enum

An enumeration.

sense_color = 0
sense_ctag = 1
sense_reflectivity = 2
sense_rgb = 3
datasets = {<capability.sense_color: 0>: (1, 1), <capability.sense_ctag: 1>: (1, 1), <capability.sense_reflectivity: 2>: (1, 1), <capability.sense_rgb: 3>: (3, 2)}
allowed_combo = [<capability.sense_color: 0>, <capability.sense_ctag: 1>, <capability.sense_reflectivity: 2>, <capability.sense_rgb: 3>]
class bricknil.sensor.sensor.VoltageSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Voltage sensor

Returns the raw mV value (0-3893) which probably needs to be scaled to 0-9600.

It contains two capabilities, although they both appear to do the same thing: * sense_l * sense_s

Examples:

@attach(VoltageSensor, name='volts', capabilities=['sense_l'])
class capability

Bases: enum.Enum

An enumeration.

sense_l = 1
sense_s = 0
datasets = {<capability.sense_s: 0>: (1, 2), <capability.sense_l: 1>: (1, 2)}
allowed_combo = []
class bricknil.sensor.sensor.CurrentSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Voltage sensor

Returns the raw mA value (0-4095) which probably needs to be scaled to 0-2444.

It contains two capabilities, although they both appear to do the same thing: * sense_l * sense_s

Examples:

@attach(CurrentSensor, name='cur', capabilities=['sense_l'])
class capability

Bases: enum.Enum

An enumeration.

sense_l = 1
sense_s = 0
datasets = {<capability.sense_s: 0>: (1, 2), <capability.sense_l: 1>: (1, 2)}
allowed_combo = []
class bricknil.sensor.sensor.DuploSpeedSensor(name, port=None, capabilities=[])[source]

Bases: bricknil.sensor.peripheral.Peripheral

Speedometer on Duplo train base that measures front wheel speed.

This can measure the following values:

  • sense_speed: Returns the speed of the front wheels
  • sense_count: Keeps count of the number of revolutions the front wheels have spun

Either or both can be enabled for measurement.

Examples:

# Report speed changes
@attach(DuploSpeedSensor, name='speed_sensor', capabilities=['sense_speed'])

# Report all
@attach(DuploSpeedSensor, name='speed_sensor', capabilities=['sense_speed', 'sense_count'])

The values returned by the sensor will be in self.value. For the first example, get the current speed by:

speed = self.speed_sensor.value

For the second example, the two values will be in a dict:

speed = self.speed_sensor.value[DuploSpeedSensor.sense_speed]
revs  = self.speed_sensor.value[DuploSpeedSensor.sense_count]
class capability

Bases: enum.Enum

An enumeration.

sense_count = 1
sense_speed = 0
datasets = {<capability.sense_speed: 0>: Dataset(n=1, w=2, min=-300, max=300), <capability.sense_count: 1>: Dataset(n=1, w=4, min=-2147483648, max=1073741824)}
update_value(msg_bytes)[source]

Hack to negate reverse speeds. This should really be specified elsewehre

allowed_combo = [<capability.sense_speed: 0>, <capability.sense_count: 1>]