Source code for Sensor

# Sensor - represents a single value sensor supported by the BrickPython library
#
# Copyright (c) 2014 Charles Weir.  Shared under the MIT Licence.

import BrickPi

[docs]class Sensor(): '''Sensor, representing a sensor attached to one of the BrickPi ports. Parameter *port* may be either a value (BrickPi.PORT_1) or an integer '1'-'5' There are class attributes with the types defined in the BrickPi module, e.g. Sensor.ULTRASONIC_CONT You can configure the sensor type for each port in the initialization parameters to BrickPiWrapper (and derived classes) Used both as class in its own right, and as superclass for other sensor types. ''' RAW = BrickPi.TYPE_SENSOR_RAW LIGHT_OFF = BrickPi.TYPE_SENSOR_LIGHT_OFF LIGHT_ON = BrickPi.TYPE_SENSOR_LIGHT_ON TOUCH = BrickPi.TYPE_SENSOR_TOUCH ULTRASONIC_CONT = BrickPi.TYPE_SENSOR_ULTRASONIC_CONT ULTRASONIC_SS = BrickPi.TYPE_SENSOR_ULTRASONIC_SS RCX_LIGHT = BrickPi.TYPE_SENSOR_RCX_LIGHT COLOR_FULL = BrickPi.TYPE_SENSOR_COLOR_FULL COLOR_RED = BrickPi.TYPE_SENSOR_COLOR_RED COLOR_GREEN = BrickPi.TYPE_SENSOR_COLOR_GREEN COLOR_BLUE = BrickPi.TYPE_SENSOR_COLOR_BLUE COLOR_NONE = BrickPi.TYPE_SENSOR_COLOR_NONE I2C = BrickPi.TYPE_SENSOR_I2C I2C_9V = BrickPi.TYPE_SENSOR_I2C_9V @staticmethod def portNumFromId(portNumOrIdChar): # Answers the port number given either port number or the ID Char. if isinstance(portNumOrIdChar, int): result = portNumOrIdChar else: result = int(portNumOrIdChar) - 1 assert( result in range(0,4)) # Yes, there are 5 sensor ports, but brickpi_python doesn't support #5 return result def __init__(self, port, sensorType=RAW): self.port = Sensor.portNumFromId(port) self.type = sensorType #: Character identifying the sensor: 1 through 5. self.idChar = chr(self.port + ord('1')) #: The most recent value to return self.recentValue = self.cookValue(0) #: The most recent raw value received from the BrickPi self.rawValue = 0 #: Function that gets called with new value as parameter when the value changes - default, none. self.callbackFunction = lambda x: 0 def updateValue(self, newValue): # Called by the framework to set the new value for the sensor. # We ignore zero values - probably means a comms failure. if newValue == 0: return self.rawValue = newValue previousValue = self.recentValue self.recentValue = self.cookValue(newValue) if self.recentValue != previousValue: self.callbackFunction(self.recentValue)
[docs] def waitForChange(self): 'Coroutine that completes when the sensor value changes' previousValue = self.recentValue while self.recentValue == previousValue: yield
[docs] def value(self): 'Answers the latest sensor value received' return self.recentValue
[docs] def cookValue(self, rawValue): 'Answers the value to return for a given input sensor reading' return rawValue
def __repr__(self): return "%s %s: %r (%d)" % (self.__class__.__name__, self.idChar, self.displayValue(), self.rawValue)
[docs] def displayValue(self): 'Answers a good representation of the current value for display' return self.value()
[docs]class TouchSensor(Sensor): '''TouchSensor, representing an NXT touch sensor attached to one of the BrickPi ports. Parameter *port* may be either a value (BrickPi.PORT_1) or an integer '1'-'5' value() is True if the button is pressed; False otherwise. ''' def __init__(self, port): # Just using the BrickPi TYPE_SENSOR_TOUCH didn't work for me; hence raw. Sensor.__init__(self, port, Sensor.RAW) def cookValue(self, rawValue): return True if rawValue < 500 else False
[docs]class UltrasonicSensor(Sensor): '''Represents an NXT ultrasonic sensor attached to one of the BrickPi ports. Parameter *port* may be either a value (BrickPi.PORT_1) or an integer '1'-'5' value() is distance to the nearest 5 cm, with a maximum of MAX_VALUE ''' #: The reading when no object is in sight: MAX_VALUE = 30 #: Round readings to nearest centimeters. ROUND_TO = 5 #: How many readings to smooth over. SMOOTHING_RANGE=10 def __init__(self, port): self.recentRawValues = [0] Sensor.__init__(self, port, Sensor.ULTRASONIC_CONT) def cookValue(self, rawValue): self.recentRawValues.append( rawValue ) if len(self.recentRawValues) > UltrasonicSensor.SMOOTHING_RANGE: del self.recentRawValues[0] smoothedValue = min(self.recentRawValues) result = int(self.ROUND_TO * round(float(smoothedValue)/self.ROUND_TO)) # Round to nearest 5 return min(result, UltrasonicSensor.MAX_VALUE) # def displayValue(self): # return self.recentRawValues
[docs]class LightSensor(Sensor): '''Represents my NXT color sensor. The BrickPi_Python COLOR_FULL setting didn't work for me at all - always has value 1. (though it did light up a red LED on the device). But in RAW mode the sensor does seem to detect the difference between light and dark backgrounds. value() is either LIGHT or DARK ''' #: Detected a light background: LIGHT = 1 #: Detected a dark background: DARK = 0 def __init__(self, port): Sensor.__init__(self, port, Sensor.RAW) def cookValue(self, rawValue): return LightSensor.LIGHT if rawValue < 740 else LightSensor.DARK def displayValue(self): return ("Dark","Light")[self.value()]