def __init__(self, id, description, update_interval): self.id = id self.description = description self.update_interval = update_interval self.value = None SensorThread(self) SensorServer(self)
def registerSensor(self, sensor): if self.sensorThread == None: self.sensorThread = SensorThread() self.sensorThread.start() self.sensorThread.add(sensor)
class MyRobot(object): """ Singleton class that represents a robot. Signature for the butten event callback: buttonEvent(int). (BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_LONGPRESSED defined in ShareConstants.) @param ipAddress the IP address (default: None for autonomous mode) @param buttonEvent the callback function for pushbutton events (default: None) """ _myInstance = None def __init__(self, ipAddress="", buttonEvent=None): """ Creates an instance of MyRobot and initalizes the GPIO. """ if MyRobot._myInstance != None: raise Exception("Only one instance of MyRobot allowed") global _isButtonEnabled, _buttonListener _buttonListener = buttonEvent # Use physical pin numbers GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) # Left motor GPIO.setup(SharedConstants.P_LEFT_FORWARD, GPIO.OUT) SharedConstants.LEFT_MOTOR_PWM[0] = GPIO.PWM(SharedConstants.P_LEFT_FORWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.LEFT_MOTOR_PWM[0].start(0) GPIO.setup(SharedConstants.P_LEFT_BACKWARD, GPIO.OUT) SharedConstants.LEFT_MOTOR_PWM[1] = GPIO.PWM(SharedConstants.P_LEFT_BACKWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.LEFT_MOTOR_PWM[1].start(0) # Right motor GPIO.setup(SharedConstants.P_RIGHT_FORWARD, GPIO.OUT) SharedConstants.RIGHT_MOTOR_PWM[0] = GPIO.PWM(SharedConstants.P_RIGHT_FORWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.RIGHT_MOTOR_PWM[0].start(0) GPIO.setup(SharedConstants.P_RIGHT_BACKWARD, GPIO.OUT) SharedConstants.RIGHT_MOTOR_PWM[1] = GPIO.PWM(SharedConstants.P_RIGHT_BACKWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.RIGHT_MOTOR_PWM[1].start(0) # IR sensors GPIO.setup(SharedConstants.P_FRONT_LEFT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_FRONT_CENTER, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_FRONT_RIGHT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_LINE_LEFT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_LINE_RIGHT, GPIO.IN, GPIO.PUD_UP) # Establish event recognition from battery monitor GPIO.setup(SharedConstants.P_BATTERY_MONITOR, GPIO.IN, GPIO.PUD_UP) GPIO.add_event_detect(SharedConstants.P_BATTERY_MONITOR, GPIO.RISING, _onBatteryDown) Tools.debug("Trying to detect I2C bus") isSMBusAvailable = True self._bus = None try: if GPIO.RPI_REVISION > 1: self._bus = smbus.SMBus(1) # For revision 2 Raspberry Pi Tools.debug("Found SMBus for revision 2") else: self._bus = smbus.SMBus(0) # For revision 1 Raspberry Pi Tools.debug("Found SMBus for revision 1") except: print "No SMBus found on this robot device." isSMBusAvailable = False # I2C PWM chip PCM9685 for LEDs and servos if isSMBusAvailable: self.pwm = PWM(self._bus, SharedConstants.PWM_I2C_ADDRESS) self.pwm.setFreq(SharedConstants.PWM_FREQ) # clear all LEDs for id in range(3): self.pwm.setDuty(3 * id, 0) self.pwm.setDuty(3 * id + 1, 0) self.pwm.setDuty(3 * id + 2, 0) # I2C analog extender chip if isSMBusAvailable: Tools.debug("Trying to detect PCF8591P I2C expander") channel = 0 try: self._bus.write_byte(SharedConstants.ADC_I2C_ADDRESS, channel) self._bus.read_byte(SharedConstants.ADC_I2C_ADDRESS) # ignore reply data = self._bus.read_byte(SharedConstants.ADC_I2C_ADDRESS) Tools.debug("Found PCF8591P I2C expander") except: Tools.debug("PCF8591P I2C expander not found") Tools.debug("Trying to detect 7-segment display") if isSMBusAvailable: self.displayType = "none" try: addr = 0x20 rc = self._bus.read_byte_data(addr, 0) if rc != 0xA0: # returns 255 for 4tronix raise Exception() Tools.delay(100) self.displayType = "didel1" except: Tools.debug("'didel1' display not found") if self.displayType == "none": try: addr = 0x20 self._bus.write_byte_data(addr, 0x00, 0x00) # Set all of bank 0 to outputs Tools.delay(100) self.displayType = "4tronix" except: Tools.debug("'4tronix' display not found") if self.displayType == "none": try: addr = 0x24 data = [0] * 4 self._bus.write_i2c_block_data(addr, data[0], data[1:]) # trying to clear display self.displayType = "didel" except: Tools.debug("'didel' display not found") Tools.debug("Display type '" + self.displayType + "'") # Initializing (clear) display, if available if self.displayType == "4tronix": Disp4tronix().clear() if self.displayType == "didel": DgTell().clear() if self.displayType == "didel1": DgTell1().clear() GPIO.setup(SharedConstants.P_BUTTON, GPIO.IN, GPIO.PUD_UP) # Establish event recognition from button event GPIO.add_event_detect(SharedConstants.P_BUTTON, GPIO.BOTH, _onButtonEvent) _isButtonEnabled = True Tools.debug("MyRobot instance created. Lib Version: " + SharedConstants.VERSION) self.sensorThread = None MyRobot._myInstance = self def registerSensor(self, sensor): if self.sensorThread == None: self.sensorThread = SensorThread() self.sensorThread.start() self.sensorThread.add(sensor) def exit(self): """ Cleans-up and releases all resources. """ global _isButtonEnabled Tools.debug("Calling Robot.exit()") self.setButtonEnabled(False) # Stop motors SharedConstants.LEFT_MOTOR_PWM[0].ChangeDutyCycle(0) SharedConstants.LEFT_MOTOR_PWM[1].ChangeDutyCycle(0) SharedConstants.RIGHT_MOTOR_PWM[0].ChangeDutyCycle(0) SharedConstants.RIGHT_MOTOR_PWM[1].ChangeDutyCycle(0) # Stop button thread, if necessary if _buttonThread != None: _buttonThread.stop() # Stop display display = Display._myInstance if display != None: display.stopTicker() display.clear() Led.clearAll() MyRobot.closeSound() if self.sensorThread != None: self.sensorThread.stop() self.sensorThread.join(2000) # GPIO.cleanup() Do not cleanup, otherwise button will not work any more when coming back # from remote execution Tools.delay(2000) # avoid "sys.excepthook is missing" def isButtonDown(self): """ Checks if button is currently pressed. @return: True, if the button is actually pressed """ Tools.delay(1) return GPIO.input(SharedConstants.P_BUTTON) == GPIO.LOW def isButtonHit(self): """ Checks, if the button was ever hit or hit since the last invocation. @return: True, if the button was hit; otherwise False """ global _isBtnHit Tools.delay(1) hit = _isBtnHit _isBtnHit = False return hit def isEscapeHit(self): """ Same as isButtonHit() for compatibility with remote mode. """ return self.isButtonHit() def isEnterHit(self): """ Empty method for compatibility with remote mode. """ pass def isUpHit(self): """ Empty method for compatibility with remote mode. """ pass def isDownHit(self): """ Empty method for compatibility with remote mode. """ pass def isLeftHit(self): """ Empty method for compatibility with remote mode. """ pass def isRightHit(self): """ Empty method for compatibility with remote mode. """ pass def addButtonListener(self, listener, enableClick=False, doubleClickTime=SharedConstants.BUTTON_DOUBLECLICK_TIME): """ Registers a listener function to get notifications when the pushbutton is pressed, released or long pressed. If enableClick = True, in addition click and double-click events are reported. The click event not immediately reported, but only if within the doubleClickTime no other click is gererated. The value are defined as ShareConstants.BUTTON_PRESSED, ShareConstants.BUTTON_LONGPRESSED, ShareConstants.BUTTON_RELEASED, ShareConstants.BUTTON_CLICKED, ShareConstants.BUTTON_DOUBLECLICKED. With enableClick = False and the button is long pressed and released the sequence is: BUTTON_PRESSED, BUTTON_LONGPRESSED, BUTTON_RELEASED. With enableClick = True the sequences are the following: click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_CLICKED double-click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_DOUBLECLICKED long pressed: BUTTON_PRESSED, BUTTON_LONGPRESSED, BUTTON_RELEASED @param listener: the listener function (with boolean parameter event) to register. @param enableClick: if True, the click/double-click is also registered (default: False) @param doubleClickTime: the time (in seconds) to wait for a double click (default: set in SharedContants) """ if enableClick: global _xButtonListener, _doubleClickTime _doubleClickTime = doubleClickTime self.addButtonListener(_onXButtonEvent) _xButtonListener = listener else: global _buttonListener _buttonListener = listener def setButtonEnabled(self, enable): """ Enables/disables the push button. The button is enabled, when the Robot is created. @param enable: if True, the button is enabled; otherwise disabled """ Tools.debug("Calling setButtonEnabled() with enable = " + str(enable)) global _isButtonEnabled _isButtonEnabled = enable def addBatteryMonitor(self, listener): """ There is a small processor on the PCB (an STM8S003F3P6) which handles the voltage monitoring, as well as trying to reduce the impact of direct light on the IR sensors. It has 2 threshold voltages: At about 6.5V (3 consecutive readings) it flashes the red LED and disables the motor drivers. At about 6.2V it turns the red LED on permanently and sends a signal on GPIO24 pin 18 to the Pi. The software on the Pi can monitor this and shut down gracefully if required. If the voltage goes back above 7.0V then the system resets to Green LED and all enabled. Registers a listener function to get notifications when battery voltage is getting low. @param listener: the listener function (with no parameter) to register """ batteryListener = listener # ---------------------------------------------- static methods ----------------------------------- @staticmethod def getVersion(): """ @return: the module library version """ return SharedConstants.VERSION @staticmethod def setSoundVolume(volume): """ Sets the sound volume. Value is kept when the program exits. @param volume: the sound volume (0..100) """ os.system("amixer sset PCM,0 " + str(volume) + "% >/dev/null") @staticmethod def playTone(frequency, duration): """ Plays a single sine tone with given frequency and duration. @param frequency: the frequency in Hz @param duration: the duration in ms """ os.system( "speaker-test -t sine -f " + str(frequency) + " >/dev/null & pid=$! ; sleep " + str(duration / 1000.0) + "s ; kill -9 $pid" ) @staticmethod def getIPAddresses(): """ @return: List of all IP addresses of machine """ p = Popen(["ifconfig"], stdout=PIPE) ifc_resp = p.communicate() patt = re.compile(r"inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})") resp = patt.findall(ifc_resp[0]) return resp @staticmethod def initSound(soundFile, volume): """ Prepares the given wav or mp3 sound file for playing with given volume (0..100). The sound sound channel is opened and a background noise is emitted. @param soundFile: the sound file in the local file system @volume: the sound volume (0..100) @returns: True, if successful; False if the sound system is not available or the sound file cannot be loaded """ try: pygame.mixer.init() except: # print "Error while initializing sound system" return False try: pygame.mixer.music.load(soundFile) except: pygame.mixer.quit() # print "Error while loading sound file", soundFile return False try: pygame.mixer.music.set_volume(volume / 100.0) except: return False return True @staticmethod def closeSound(): """ Stops any playing sound and closes the sound channel. """ try: pygame.mixer.stop() pygame.mixer.quit() except: pass @staticmethod def playSound(): """ Starts playing. """ try: pygame.mixer.music.play() except: pass @staticmethod def fadeoutSound(time): """ Decreases the volume slowly and stops playing. @param time: the fade out time in ms """ try: pygame.mixer.music.fadeout(time) except: pass @staticmethod def setSoundVolume(volume): """ Sets the volume while the sound is playing. @param volume: the sound volume (0..100) """ try: pygame.mixer.music.set_volume(volume / 100.0) except: pass @staticmethod def stopSound(): """ Stops playing sound. """ try: pygame.mixer.music.stop() except: pass @staticmethod def pauseSound(): """ Temporarily stops playing at current position. """ try: pygame.mixer.music.pause() except: pass @staticmethod def resumeSound(): """ Resumes playing from stop position. """ try: pygame.mixer.music.unpause() except: pass @staticmethod def rewindSound(): """ Resumes playing from the beginning. """ try: pygame.mixer.music.rewind() except: pass @staticmethod def isSoundPlaying(): """ @return: True, if the sound is playing; otherwise False """ try: return pygame.mixer.music.get_busy() except: return False
class MyRobot(object): ''' Singleton class that represents a robot. Signature for the butten event callback: buttonEvent(int). (BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_LONGPRESSED defined in ShareConstants.) @param ipAddress the IP address (default: None for autonomous mode) @param buttonEvent the callback function for pushbutton events (default: None) ''' _myInstance = None def __init__(self, ipAddress="", buttonEvent=None): ''' Creates an instance of MyRobot and initalizes the GPIO. ''' if MyRobot._myInstance != None: raise Exception("Only one instance of MyRobot allowed") global _isButtonEnabled, _buttonListener _buttonListener = buttonEvent # Use physical pin numbers GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) # Left motor GPIO.setup(SharedConstants.P_LEFT_FORWARD, GPIO.OUT) SharedConstants.LEFT_MOTOR_PWM[0] = GPIO.PWM( SharedConstants.P_LEFT_FORWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.LEFT_MOTOR_PWM[0].start(0) GPIO.setup(SharedConstants.P_LEFT_BACKWARD, GPIO.OUT) SharedConstants.LEFT_MOTOR_PWM[1] = GPIO.PWM( SharedConstants.P_LEFT_BACKWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.LEFT_MOTOR_PWM[1].start(0) # Right motor GPIO.setup(SharedConstants.P_RIGHT_FORWARD, GPIO.OUT) SharedConstants.RIGHT_MOTOR_PWM[0] = GPIO.PWM( SharedConstants.P_RIGHT_FORWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.RIGHT_MOTOR_PWM[0].start(0) GPIO.setup(SharedConstants.P_RIGHT_BACKWARD, GPIO.OUT) SharedConstants.RIGHT_MOTOR_PWM[1] = GPIO.PWM( SharedConstants.P_RIGHT_BACKWARD, SharedConstants.MOTOR_PWM_FREQ) SharedConstants.RIGHT_MOTOR_PWM[1].start(0) # IR sensors GPIO.setup(SharedConstants.P_FRONT_LEFT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_FRONT_CENTER, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_FRONT_RIGHT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_LINE_LEFT, GPIO.IN, GPIO.PUD_UP) GPIO.setup(SharedConstants.P_LINE_RIGHT, GPIO.IN, GPIO.PUD_UP) # Establish event recognition from battery monitor GPIO.setup(SharedConstants.P_BATTERY_MONITOR, GPIO.IN, GPIO.PUD_UP) GPIO.add_event_detect(SharedConstants.P_BATTERY_MONITOR, GPIO.RISING, _onBatteryDown) Tools.debug("Trying to detect I2C bus") self._bus = smbus.SMBus(1) # For revision 2 Raspberry Pi Tools.debug("Found SMBus for revision 2") # I2C PWM chip PCM9685 for LEDs and servos self.pwm = PWM(self._bus, SharedConstants.PWM_I2C_ADDRESS) self.pwm.setFreq(SharedConstants.PWM_FREQ) self.isPCA9685Available = self.pwm._isAvailable if self.isPCA9685Available: # clear all LEDs for id in range(3): self.pwm.setDuty(3 * id, 0) self.pwm.setDuty(3 * id + 1, 0) self.pwm.setDuty(3 * id + 2, 0) # I2C analog extender chip Tools.debug("Trying to detect PCF8591P I2C expander") channel = 0 try: self._bus.write_byte(SharedConstants.ADC_I2C_ADDRESS, channel) self._bus.read_byte( SharedConstants.ADC_I2C_ADDRESS) # ignore reply data = self._bus.read_byte(SharedConstants.ADC_I2C_ADDRESS) Tools.debug("Found PCF8591P I2C expander") except: Tools.debug("PCF8591P I2C expander not found") self.displayType = "none" Tools.debug("Trying to detect OLED display") self.oled = OLED1306() if self.oled.isDeviceAvailable(): self.displayType = "oled" else: Tools.debug("'oled' display not found") self.oled = None Tools.debug("Trying to detect 7-segment display") try: addr = 0x20 rc = self._bus.read_byte_data(addr, 0) if rc != 0xA0: # returns 255 for 4tronix raise Exception() Tools.delay(100) self.displayType = "didel1" except: Tools.debug("'didel1' display not found") if self.displayType == "none": try: addr = 0x20 self._bus.write_byte_data( addr, 0x00, 0x00) # Set all of bank 0 to outputs Tools.delay(100) self.displayType = "4tronix" except: Tools.debug("'4tronix' display not found") if self.displayType == "none": try: addr = 0x24 # old dgTell from didel data = [0] * 4 self._bus.write_i2c_block_data( addr, data[0], data[1:]) # trying to clear display self.displayType = "didel" except: Tools.debug("'didel (old type)' display not found") Tools.debug("Display type '" + self.displayType + "'") # Initializing (clear) display, if available if self.displayType == "4tronix": Disp4tronix().clear() elif self.displayType == "didel": DgTell().clear() elif self.displayType == "didel1": DgTell1().clear() GPIO.setup(SharedConstants.P_BUTTON, GPIO.IN, GPIO.PUD_UP) # Establish event recognition from button event GPIO.add_event_detect(SharedConstants.P_BUTTON, GPIO.BOTH, _onButtonEvent) _isButtonEnabled = True Tools.debug("MyRobot instance created. Lib Version: " + SharedConstants.VERSION) self.sensorThread = None MyRobot._myInstance = self def registerSensor(self, sensor): if self.sensorThread == None: self.sensorThread = SensorThread() self.sensorThread.start() self.sensorThread.add(sensor) def exit(self): """ Cleans-up and releases all resources. """ global _isButtonEnabled Tools.debug("Calling Robot.exit()") self.setButtonEnabled(False) # Stop motors SharedConstants.LEFT_MOTOR_PWM[0].ChangeDutyCycle(0) SharedConstants.LEFT_MOTOR_PWM[1].ChangeDutyCycle(0) SharedConstants.RIGHT_MOTOR_PWM[0].ChangeDutyCycle(0) SharedConstants.RIGHT_MOTOR_PWM[1].ChangeDutyCycle(0) # Stop button thread, if necessary if _buttonThread != None: _buttonThread.stop() # Stop display display = Display._myInstance if display != None: display.stopTicker() display.clear() if self.isPCA9685Available: Led.clearAll() MyRobot.closeSound() if self.sensorThread != None: self.sensorThread.stop() self.sensorThread.join(2000) # GPIO.cleanup() # Do not cleanup, otherwise button will not work any more when coming back from remote execution Tools.delay(2000) # avoid "sys.excepthook is missing" def isButtonDown(self): ''' Checks if button is currently pressed. @return: True, if the button is actually pressed ''' Tools.delay(1) return GPIO.input(SharedConstants.P_BUTTON) == GPIO.LOW def isButtonHit(self): ''' Checks, if the button was ever hit or hit since the last invocation. @return: True, if the button was hit; otherwise False ''' global _isBtnHit Tools.delay(1) hit = _isBtnHit _isBtnHit = False return hit def isEscapeHit(self): ''' Same as isButtonHit() for compatibility with remote mode. ''' return self.isButtonHit() def isEnterHit(self): ''' Empty method for compatibility with remote mode. ''' pass def isUpHit(self): ''' Empty method for compatibility with remote mode. ''' pass def isDownHit(self): ''' Empty method for compatibility with remote mode. ''' pass def isLeftHit(self): ''' Empty method for compatibility with remote mode. ''' pass def isRightHit(self): ''' Empty method for compatibility with remote mode. ''' pass def addButtonListener( self, listener, enableClick=False, doubleClickTime=SharedConstants.BUTTON_DOUBLECLICK_TIME): ''' Registers a listener function to get notifications when the pushbutton is pressed, released or long pressed. If enableClick = True, in addition click and double-click events are reported. The click event not immediately reported, but only if within the doubleClickTime no other click is gererated. The value are defined as ShareConstants.BUTTON_PRESSED, ShareConstants.BUTTON_LONGPRESSED, ShareConstants.BUTTON_RELEASED, ShareConstants.BUTTON_CLICKED, ShareConstants.BUTTON_DOUBLECLICKED. With enableClick = False and the button is long pressed and released the sequence is: BUTTON_PRESSED, BUTTON_LONGPRESSED, BUTTON_RELEASED. With enableClick = True the sequences are the following: click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_CLICKED double-click: BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_PRESSED, BUTTON_RELEASED, BUTTON_DOUBLECLICKED long pressed: BUTTON_PRESSED, BUTTON_LONGPRESSED, BUTTON_RELEASED @param listener: the listener function (with boolean parameter event) to register. @param enableClick: if True, the click/double-click is also registered (default: False) @param doubleClickTime: the time (in seconds) to wait for a double click (default: set in SharedContants) ''' if enableClick: global _xButtonListener, _doubleClickTime _doubleClickTime = doubleClickTime self.addButtonListener(_onXButtonEvent) _xButtonListener = listener else: global _buttonListener _buttonListener = listener def setButtonEnabled(self, enable): ''' Enables/disables the push button. The button is enabled, when the Robot is created. @param enable: if True, the button is enabled; otherwise disabled ''' Tools.debug("Calling setButtonEnabled() with enable = " + str(enable)) global _isButtonEnabled _isButtonEnabled = enable def addBatteryMonitor(self, listener): ''' There is a small processor on the PCB (an STM8S003F3P6) which handles the voltage monitoring, as well as trying to reduce the impact of direct light on the IR sensors. It has 2 threshold voltages: At about 6.5V (3 consecutive readings) it flashes the red LED and disables the motor drivers. At about 6.2V it turns the red LED on permanently and sends a signal on GPIO24 pin 18 to the Pi. The software on the Pi can monitor this and shut down gracefully if required. If the voltage goes back above 7.0V then the system resets to Green LED and all enabled. Registers a listener function to get notifications when battery voltage is getting low. @param listener: the listener function (with no parameter) to register ''' batteryListener = listener # ---------------------------------------------- static methods ----------------------------------- @staticmethod def getVersion(): ''' @return: the module library version ''' return SharedConstants.VERSION @staticmethod def setSoundVolume(volume): ''' Sets the sound volume. Value is kept when the program exits. @param volume: the sound volume (0..100) ''' os.system("amixer sset PCM,0 " + str(volume) + "% >/dev/null") @staticmethod def playTone(frequency, duration): ''' Plays a single sine tone with given frequency and duration. @param frequency: the frequency in Hz @param duration: the duration in ms ''' os.system("speaker-test -t sine -f " + str(frequency) + " >/dev/null & pid=$! ; sleep " + str(duration / 1000.0) + "s ; kill -9 $pid") @staticmethod def getIPAddresses(): ''' @return: List of all IP addresses of machine ''' ip = [] ifname = "wlan0" try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ip.append( socket.inet_ntoa( fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]))[20:24])) except: pass print "Got IP address:", ip return ip @staticmethod def initSound(soundFile, volume): ''' Prepares the given wav or mp3 sound file for playing with given volume (0..100). The sound sound channel is opened and a background noise is emitted. @param soundFile: the sound file in the local file system @volume: the sound volume (0..100) @returns: True, if successful; False if the sound system is not available or the sound file cannot be loaded ''' try: pygame.mixer.init() except: # print "Error while initializing sound system" return False try: pygame.mixer.music.load(soundFile) except: pygame.mixer.quit() # print "Error while loading sound file", soundFile return False try: pygame.mixer.music.set_volume(volume / 100.0) except: return False return True @staticmethod def closeSound(): ''' Stops any playing sound and closes the sound channel. ''' try: pygame.mixer.stop() pygame.mixer.quit() except: pass @staticmethod def playSound(): ''' Starts playing. ''' try: pygame.mixer.music.play() except: pass @staticmethod def fadeoutSound(time): ''' Decreases the volume slowly and stops playing. @param time: the fade out time in ms ''' try: pygame.mixer.music.fadeout(time) except: pass @staticmethod def setSoundVolume(volume): ''' Sets the volume while the sound is playing. @param volume: the sound volume (0..100) ''' try: pygame.mixer.music.set_volume(volume / 100.0) except: pass @staticmethod def stopSound(): ''' Stops playing sound. ''' try: pygame.mixer.music.stop() except: pass @staticmethod def pauseSound(): ''' Temporarily stops playing at current position. ''' try: pygame.mixer.music.pause() except: pass @staticmethod def resumeSound(): ''' Resumes playing from stop position. ''' try: pygame.mixer.music.unpause() except: pass @staticmethod def rewindSound(): ''' Resumes playing from the beginning. ''' try: pygame.mixer.music.rewind() except: pass @staticmethod def isSoundPlaying(): ''' @return: True, if the sound is playing; otherwise False ''' try: return pygame.mixer.music.get_busy() except: return False
def __init__(self, resolution, reduction, threshold=100, show_image=False, verbose=False): """ Initializes an instance of drone data class. Controller for the threads. :param resolution: a tuple of the number of pixels as height by width. :param reduction: the factor to reduce the frame size by. :param threshold: minimum distance for LiDAR to return that an object is within the danger zone. :param show_image: boolean that decides if image should be displayed. Should be set to fault if running program through ssh. :param verbose: boolean that decides that output on the frame. """ # Records variables given from constructor self.resolution = resolution self.reduction = reduction self.threshold = threshold self.show_image = show_image self.verbose = verbose # Creates queues. The first three are to communicate between the # threads. The last two are to output data after the program has # terminated. self.sensor_q = queue.Queue() self.analyze_q = queue.Queue() self.overlay_q = queue.Queue() self.screen_shots_q = queue.Queue() self.csv_q = queue.Queue() # Initializes threads and puts them into an array. self.sensor = SensorThread(self.sensor_q, threshold, resolution, name='pi_frame') self.analyze = AnalyzeThread(self.sensor_q, self.analyze_q, name='analyze') self.overlay = OverlayThread(self.analyze_q, self.overlay_q, resolution=self.resolution, reduction=self.reduction, name='overlay') self.threads = [self.sensor, self.analyze, self.overlay] for thread in self.threads: thread.setDaemon(True) # Gives variables to create a folder to record data self.image_folder_path = "./data/screen-shots" self.csv_file = './data/drone-data.csv' self._setup() # Variables used for the CSV file self.file = open(self.csv_file, 'w') self.writer = csv.writer(self.file) self.image_number = 1 # Other variables to record current state of the drone's safety. self.passed_safety_zone = False self.lookup = [] self.scores = []