Esempio n. 1
0
    def __init__(self, pinBTN=27, pinLED=17, startVolume=70, imuAddress=0x6a, limit=350, changeDelta=1000):
        GPIO.setmode(GPIO.BCM)

        led = LED(pinLED)

        self.ledStrip = LEDStrip()
        self.audio = Audio(startVolume)

        self.mixer = AudioMixer()
        self.initAudioMixer()

        self.btn = Button(pinBTN)
        self.btn.setListener(self.audioBtnListener)

        self.ledControl = LEDController(led)
        self.ledControl.start()

        self.changeDelta = changeDelta
        self.currentMode = -1

        # self.imuController = IMUController(imuAddress, limit=limit)
        self.imuController = LSMController(imuAddress, limit=limit)
        self.initImuController()

        self.animDrive = TheaterChaseAnimation(LEDAnimation.COLOR_CYAN, 20, 50, 15, True)
        self.animIdle = FadeCycleAnimation(RGBColor(0, 0, 0), RGBColor(0, 80, 0), 25, 20)

        self.ledStrip = LEDStrip()
        self.ledStrip.start()

        self.speed = 0
        self.lastLoop = self.getMillis()
Esempio n. 2
0
 def __init__(self, config, image_files):
     self.box_surface = pygame.image.load(image_files[config.INPUT_BOX])
     self.font = pygame.font.Font(config.FONT_MYRAID_PATH, 30)
     self.input_str = []
     self.confirm_button = Button(
         "Confirm", config.CONFIRM_POS,
         pygame.image.load(image_files[config.BUTTON_CONFIRM]), None)
     self.return_button = Button(
         "Return", config.RETURN_POS,
         pygame.image.load(image_files[config.BUTTON_RETURN]), None)
Esempio n. 3
0
class MyObj:
    def __init__(self):
        self.value = 0
        self.button = Button(XY(5, 5), XY(10, 10), 'Button', self.method, XY)

    def click(self, point):
        self.button.click(point)

    def method(self):
        self.value += 1
Esempio n. 4
0
    def _configure_default_features(self):
        '''
            Import dependencies and configure default features.
        '''
        self._log.warning('configure default features...')
        from lib.button import Button
        self._log.info('configuring button...')
        self._ros._button = Button(self._ros._config,
                                   self._ros.get_message_queue(),
                                   self._ros._mutex)

        from lib.bumpers import Bumpers
        self._log.info('configuring bumpers...')
        self._ros._bumpers = Bumpers(self._ros._config,
                                     self._ros.get_message_queue(), None,
                                     Level.INFO)

        from lib.infrareds import Infrareds
        self._log.info('configuring infrared trio...')
        self._ros._infrareds = Infrareds(self._ros._config,
                                         self._ros.get_message_queue(),
                                         Level.INFO)

        from lib.player import Sound, Player
        self._log.info('configuring player...')
        self._ros._player = Player(Level.INFO)

        self._log.warning('default features ready.')
Esempio n. 5
0
def main():
    global activated
    activated = False

    print('button_test       :' + Fore.CYAN + ' INFO  : starting test...' + Style.RESET_ALL)

    _pin = 12
    _button = Button(_pin, callback_method, Level.INFO)

    try:
        while not activated:
            print(Fore.BLACK + 'waiting for button press on pin {:d}...'.format(_pin) + Style.RESET_ALL)
            time.sleep(1.0)
    except KeyboardInterrupt:
        print(Fore.RED + "caught Ctrl-C." + Style.RESET_ALL)
    finally:
        print("closing button...")
        _button.close()
Esempio n. 6
0
    def read(self, config, data, button_cell, nums_new, nums_new_over):
        a, b = self.no % 3 * 3, self.no // 3 * 3
        self.index = [(i, j) for i in range(b, b + 3) for j in range(a, a + 3)]

        x, y = self.pos
        k = 0
        for l in range(9):
            i, j = self.index[l]
            bias_x, bias_y = self.cell_bias[l]
            if data[i][j] == 0:
                self.buttons.append(Button([i, j, l, k], (x + bias_x, y + bias_y),
                                           button_cell[0], None, button_cell[1], None))
                config.CELL_BUTTON_NUM += 1
                k += 1

            elif data[i][j] < 0:
                self.buttons.append(Button([i, j, l, k], (x + bias_x, y + bias_y),
                                           nums_new[-data[i][j] - 1], None,
                                           nums_new_over[-data[i][j] - 1], None))
                k += 1
Esempio n. 7
0
    def __init__(self, config, image_files):
        self.image_files = image_files

        self.difficulty = config.DIFFICULTY
        self.cells = None
        self.font = pygame.font.Font(config.FONT_MYRAID_PATH, 30)

        self.game_buttons = [
            Button(0, config.UNDO_POS,
                   pygame.image.load(image_files[config.BUTTON_UNDO]), None,
                   pygame.image.load(image_files[config.BUTTON_UNDO_INACTIVE]),
                   None),
            Button(0, config.REDO_POS,
                   pygame.image.load(image_files[config.BUTTON_REDO]), None,
                   pygame.image.load(image_files[config.BUTTON_REDO_INACTIVE]),
                   None),
            Button("Menu", config.GAME_MENU_POS,
                   pygame.image.load(image_files[config.BUTTON_GAME_MENU]),
                   None),
            Button("Flush", config.FLUSH_POS,
                   pygame.image.load(image_files[config.BUTTON_FLUSH]), None),
        ]

        self.congratulation = pygame.image.load(image_files[config.TEXT_CONG])
        self.clear_buttons = [
            Button("Restart", config.CLEAR_RE_POS,
                   pygame.image.load(image_files[config.BUTTON_CLEAR_RESTART]),
                   None),
            Button("Menu", config.CLEAR_MENU_POS,
                   pygame.image.load(image_files[config.BUTTON_CLEAR_MENU]),
                   None)
        ]
Esempio n. 8
0
def audioTest():
    print("Start audio test")
    audio = Audio(70)

    def onPressed(mode):
        vol = audio.getVolume()
        if mode is Button.NORMAL_PRESS:
            if vol == 100:
                audio.setVolume(70)
            else:
                audio.volumeUp()

        else:
            if audio.isMute:
                audio.unmute()
            else:
                audio.mute()

        print("volume {}".format(audio.getVolume()))

    btn = Button(pinBTN)
    btn.setListener(onPressed)

    try:
        print(audio.getVolume())
        print(audio.setVolume(20))
        print(audio.getVolume())

        while True:
            btn.loop()
    except KeyboardInterrupt:
        print("Cancel audio test")
Esempio n. 9
0
class InputBox:
    def __init__(self, config, image_files):
        self.box_surface = pygame.image.load(image_files[config.INPUT_BOX])
        self.font = pygame.font.Font(config.FONT_MYRAID_PATH, 30)
        self.input_str = []
        self.confirm_button = Button(
            "Confirm", config.CONFIRM_POS,
            pygame.image.load(image_files[config.BUTTON_CONFIRM]), None)
        self.return_button = Button(
            "Return", config.RETURN_POS,
            pygame.image.load(image_files[config.BUTTON_RETURN]), None)

    def key_input(self, config, event, game):
        key = event.key

        if key is pygame.K_BACKSPACE:
            self.input_str = self.input_str[0:-1]

        elif key is pygame.K_RETURN:
            self.random_game(config, game)

        elif 32 <= key < 127:
            self.input_str.append(chr(key))

    def check_input_button_is_press(self, config, point, game):
        if self.return_button.is_press(point):
            config.GAME_STATE = config.GAME_STATE_PREV = config.GAME_STATE_MENU
        elif self.confirm_button.is_press(point):
            self.random_game(config, game)

    def random_game(self, config, game):
        seed_str = "".join(self.input_str)
        if seed_str == "":
            config.GAME_STATE = config.GAME_STATE_PREV = config.GAME_STATE_GAMING
            seed = randint(0, 9223372036854775806)
            game.init(config, seed=seed)

        elif seed_str.isdigit():
            config.GAME_STATE = config.GAME_STATE_PREV = config.GAME_STATE_GAMING
            seed = int("".join(self.input_str)) % 9223372036854775806
            game.init(config, seed=seed)

        else:
            config.GAME_STATE = config.GAME_STATE_PREV = config.GAME_STATE_MENU
            root = tk.Tk()
            root.withdraw()
            msg.showerror('Error', 'Seed must be a number.')

    def render(self, config, surface):
        surface.blit(self.box_surface, config.INPUT_BOX_POS)
        self.confirm_button.render(surface)
        self.return_button.render(surface)

        text = "".join(self.input_str[-32:])
        height, width = self.font.size(text)
        text_render = self.font.render(text, True, config.INPUT_COLOR)
        text_x = config.INPUT_TEXT_POS[0] - height // 2
        text_y = config.INPUT_TEXT_POS[1]
        surface.blit(text_render, (text_x, text_y))
Esempio n. 10
0
    def __init__(self, config, image_files, no, pos):
        self.index = None

        self.no = no
        self.pos = pos
        self.cell_bias = config.CELL_BUTTON_BIAS
        self.expand_bias = config.EXPAND_NUM_BIAS

        self.buttons = []
        self.expand_buttons = [Button(i, (0, 0),
                                      pygame.image.load(image_files[config.EXPAND_NUM + i]), None,
                                      pygame.image.load(image_files[config.EXPAND_NUM_OVER + i]), None)
                               for i in range(9)]
Esempio n. 11
0
def ledStripTest():
    print("Start led strip test")
    ledStrip = LEDStrip()

    animations = []


    animations.append(ColorSetAnimation(LEDAnimation.COLOR_BLACK))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_YELLOW, 100, 50, 15, True))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_CYAN, 100, 50, 15))


    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_BLUE, 500, 10, 15))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_GREEN, 50, 10, 15))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_RED, 50, 50, 15))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_MAGENTA, 20, 50, 15))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_CYAN, 20, 50, 15))
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_YELLOW, 20, 100, 15))
    animations.append(FadeCycleAnimation(RGBColor(0, 0, 0), RGBColor(255, 255, 255), 25, int(1000 / 200)))
    animations.append(FadeAnimation(RGBColor(255, 0, 0), RGBColor(0, 255, 0), 50, int(1000 / 50)))
    animations.append(FadeAnimation(RGBColor(0, 255, 0), RGBColor(0, 0, 255), 50, int(1000 / 50)))
    animations.append(RainbowAnimation())
    animations.append(TheaterChaseAnimation(LEDAnimation.COLOR_WHITE))
    animations.append(ColorWipeAnimation(LEDAnimation.COLOR_RED))
    animations.append(RainbowCycleAnimation())
    animations.append(TheaterChaseRainbowAnimation())
    animations.append(ColorSetAnimation(LEDAnimation.COLOR_BLACK))

    ledStrip.start()

    def setNextAnimation():
        global animIndex
        animIndex += 1
        if animIndex >= len(animations):
            animIndex = 0

        a = animations[animIndex]
        ledStrip.setAnimation(a)

    def onButtonClick(mode):
        if mode is Button.NORMAL_PRESS:
            setNextAnimation()

        else:
            a = ColorWipeAnimation(LEDAnimation.COLOR_BLACK)
            ledStrip.setAnimation(a)

    button = Button(pinBTN)
    button.setListener(onButtonClick)
    setNextAnimation()

    try:
        while True:
            button.loop()
    except KeyboardInterrupt:
        print("Cancel button-LED test")

    ledStrip.stop()
Esempio n. 12
0
def buttonTest():
    print("Start button test")

    button = Button(pinBTN)
    button.setListener(printResult)
    try:

        while True:
            button.loop()
    except KeyboardInterrupt:
        print("Cancel button test")
Esempio n. 13
0
def main():

    print('button_test       :' + Fore.CYAN + ' INFO  : starting test...' +
          Style.RESET_ALL)

    print('button_test       :' + Fore.BLUE + Style.BRIGHT +
          ' INFO  : to pass test, press button for both ON and OFF states...' +
          Style.RESET_ALL)

    # read YAML configuration
    _loader = ConfigLoader(Level.INFO)
    filename = 'config.yaml'
    _config = _loader.configure(filename)

    _message_factory = MessageFactory(Level.INFO)
    _queue = MessageQueue(_message_factory, Level.INFO)
    _button = Button(_config, _queue, _message_factory, threading.Lock())
    _button.start()

    while not _button.get():
        print('button_test       : ' + Fore.RED + Style.BRIGHT + "button OFF" +
              Fore.CYAN + Style.NORMAL + ' (press button to turn ON)' +
              Style.RESET_ALL)
        time.sleep(1)
    while _button.get():
        print('button_test       : ' + Fore.GREEN + Style.BRIGHT +
              "button ON" + Fore.CYAN + Style.NORMAL +
              ' (press button to turn OFF)' + Style.RESET_ALL)
        time.sleep(1)
    while not _button.get():
        print('button_test       : ' + Fore.RED + Style.BRIGHT + "button OFF" +
              Fore.CYAN + Style.NORMAL + ' (press button to turn ON)' +
              Style.RESET_ALL)
        time.sleep(1)

    print("button task close()")
    _button.close()
Esempio n. 14
0
    def __init__(self, config, image_files):
        self.image_files = image_files
        self.box = InputBox(config, image_files)

        self.menu_buttons = [
            Button(config.DIFFICULTY_EASY, config.EASY_POS,
                   pygame.image.load(self.image_files[config.BUTTON_EASY]), None),
            Button(config.DIFFICULTY_NORMAL, config.NORMAL_POS,
                   pygame.image.load(self.image_files[config.BUTTON_NORMAL]), None),
            Button(config.DIFFICULTY_HARD, config.HARD_POS,
                   pygame.image.load(self.image_files[config.BUTTON_HARD]), None),
            Button("Random", config.RANDOM_POS,
                   pygame.image.load(self.image_files[config.BUTTON_RANDOM]), None),
            Button(True, config.LOAD_POS,
                   pygame.image.load(self.image_files[config.BUTTON_LOAD]), None,
                   pygame.image.load(self.image_files[config.BUTTON_LOAD_INACTIVE]), None),
        ]
        self.utils_buttons = [
            Button(r"Quit", config.QUIT_POS,
                   pygame.image.load(self.image_files[config.BUTTON_EXIT]), None),
            Button(r"Setting", config.SETTING_POS,
                   pygame.image.load(self.image_files[config.BUTTON_SETTING]), None)
        ]
Esempio n. 15
0
def audioMixerTest():
    print("Start audio mixer test")

    import os
    from os import path

    appPath = os.path.dirname(os.path.abspath(__file__))
    audioFolder = path.join(appPath, "audio")

    audio = Audio(70)
    mixer = AudioMixer()
 
    mixer.addSound("start", path.join(audioFolder, "h_start.wav"))
    mixer.addSound("stop", path.join(audioFolder, "h_stop.wav"))
    mixer.addSound("speedUp", path.join(audioFolder, "h_speedup.wav"))
    mixer.addSound("idle", path.join(audioFolder, "h_idle.wav"))
    mixer.addSound("drive", path.join(audioFolder, "h_drive.wav"))


    def onPressed(mode):
        if mode is Button.NORMAL_PRESS:
            mixer.clearQueue()
            mixer.playSound("speedUp", False, 300)
            mixer.queue("drive", True)
        else:
            mixer.clearQueue()
            mixer.playSound("stop", False, 300)
            mixer.queue("idle", True)

    btn = Button(pinBTN)
    btn.setListener(onPressed)

    mixer.playSound("start", False, 0)
    mixer.queue("idle", True)

    try:
        while True:
            btn.loop()
    except KeyboardInterrupt:
        print("Cancel audio mixer test")

    mixer.stop()
Esempio n. 16
0
def buttonLedTest():
    print("Start Button-LED test")

    led = LED(pinLED)
    button = Button(pinBTN)
    lc = LEDController(led)
    lc.start()

    def buttonListner(mode):
        printResult(mode)
        if mode is Button.NORMAL_PRESS:
            lc.blink(3, 0.5, 0.5)
        else:
            lc.blink(1, 3, 0)

    button.setListener(buttonListner)
    try:
        while True:
            button.loop()
    except KeyboardInterrupt:
        print("Cancel button-LED test")

    lc.stop()
Esempio n. 17
0
def main():
    global test_triggered, test_enabled
    # initial states
    test_triggered = False
    test_enabled = True

    _loader = ConfigLoader(_level)
    _config = _loader.configure('config.yaml')

    _pin_A = 12
    _button_24 = Button(_pin_A, callback_method_A, Level.INFO)
    _log.info(
        Style.BRIGHT +
        'press button A (connected to pin {:d}) to toggle or initiate action.'.
        format(_pin_A))

    _pin_B = 24
    _button_24 = Button(_pin_B, callback_method_B, Level.INFO)
    _log.info(Style.BRIGHT +
              'press button B connected to pin {:d}) to exit.'.format(_pin_B))

    try:

        # .........................................
        _motors = Motors(_config, None, Level.INFO)
        _pot = Potentiometer(_config, Level.WARN)

        _pot_min = 0.0000
        _pot_max = 0.1500
        _pot.set_output_limits(_pot_min, _pot_max)

        _limit = 90.0
        #       _min    = -127
        _stbd_setpoint = 0.0
        _port_setpoint = 0.0
        _scaled_value = 0.0
        _value = 0.0
        _port_pid = None
        _stbd_pid = None

        # rotary controller
        _min = 90
        _max = 0
        _step = 5
        _rotary_ctrl = RotaryControl(_config, _min, _max, _step, Level.INFO)

        # configure motors/PID controllers
        _port_motor = _motors.get_motor(Orientation.PORT)
        _port_pid = PIDController(_config, _port_motor, level=Level.INFO)
        _port_pid.set_limit(_limit)
        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
            _port_pid.enable()
        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.STBD:
            _stbd_motor = _motors.get_motor(Orientation.STBD)
            _stbd_pid = PIDController(_config, _stbd_motor, level=Level.INFO)
            _stbd_pid.set_limit(_limit)
            _stbd_pid.enable()


#       sys.exit(0)

        _fixed_value = 15.0  # fixed setpoint value
        DRY_RUN = False
        USE_POTENTIOMETER = False
        USE_ROTARY_ENCODER = False
        ANYTHING_ELSE = False

        try:
            while test_enabled:
                if test_triggered:
                    _log.info(Fore.BLUE + Style.BRIGHT + 'action A.')
                    test_triggered = False  # trigger once
                    rotate_in_place(_rotary_ctrl, _port_pid, _stbd_pid)
                    test_enabled = False  # quit after action
                    time.sleep(1.0)
                    # and we now return to our regularly scheduled broadcast...
                _kp = _pot.get_scaled_value(True)
                _stbd_pid._pid.kp = _kp
                _log.info(Fore.YELLOW + 'waiting for button A...;' +
                          Style.BRIGHT +
                          ' kp: {:8.5f}'.format(_stbd_pid._pid.kp))
                time.sleep(1.0)

            _log.info(Fore.YELLOW + 'end of test.')

        except KeyboardInterrupt:
            _log.info(Fore.CYAN + Style.BRIGHT + 'Ctrl-C caught: closing...')
        finally:
            if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
                _port_pid.disable()
            if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.STBD:
                _stbd_pid.disable()
            _motors.brake()
            if _rotary_ctrl:
                _log.info('resetting rotary encoder...')
                _rotary_ctrl.reset()
            time.sleep(1.0)
            _log.info('complete.')

    except Exception as e:
        _log.info(Fore.RED + Style.BRIGHT +
                  'error in test: {}'.format(e, traceback.format_exc()))
    finally:
        _log.info(Fore.YELLOW + Style.BRIGHT + 'finally.')
Esempio n. 18
0
def subject(mocker):
    mock_method = mocker.stub(name='my_method')
    return Button(XY(5, 5), XY(10, 10), 'MAH BUTTON', mock_method, XY)
Esempio n. 19
0
def main():
    global action_A, action_B
    # initial states
    action_A = False
    action_B = True

    _loader = ConfigLoader(_level)
    _config = _loader.configure('config.yaml')

    _pin_A = 12
    _button_12 = Button(_pin_A, callback_method_A, Level.INFO)
    _log.info(
        Style.BRIGHT +
        'press button A (connected to pin {:d}) to toggle or initiate action.'.
        format(_pin_A))

    _pin_B = 24
    _button_24 = Button(_pin_B, callback_method_B, Level.INFO)
    _log.info(Style.BRIGHT +
              'press button B connected to pin {:d}) to exit.'.format(_pin_B))

    try:

        _log.info('creating message factory...')
        _message_factory = MessageFactory(Level.INFO)
        _log.info('creating message bus...')
        _message_bus = MessageBus(Level.DEBUG)
        _log.info('creating clock...')
        _clock = Clock(_config, _message_bus, _message_factory, Level.WARN)
        _motor_configurer = MotorConfigurer(_config, _clock, Level.INFO)
        _motors = _motor_configurer.get_motors()

        _limit = 90.0
        _stbd_setpoint = 0.0
        _port_setpoint = 0.0
        _scaled_value = 0.0
        _value = 0.0
        _port_pid_ctrl = None
        _stbd_pid_ctrl = None

        # rotary controller
        _min_rot = 0
        _max_rot = 30
        _step_rot = 1
        _rotary_ctrl = RotaryControl(_config, _min_rot, _max_rot, _step_rot,
                                     Level.WARN)

        # configure motors/PID controllers
        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
            _port_motor = _motors.get_motor(Orientation.PORT)
            _port_pid_ctrl = PIDController(_config,
                                           _clock,
                                           _port_motor,
                                           level=Level.INFO)
            _port_pid_ctrl.limit = _limit
            _port_pid_ctrl.enable()
        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.STBD:
            _stbd_motor = _motors.get_motor(Orientation.STBD)
            _stbd_pid_ctrl = PIDController(_config,
                                           _clock,
                                           _stbd_motor,
                                           level=Level.INFO)
            _stbd_pid_ctrl.limit = _limit
            _stbd_pid_ctrl.enable()

        _max_pot = 1.0
        _min_pot = 0.0
        _pot = Potentiometer(_config, Level.WARN)
        _pot.set_output_limits(_min_pot, _max_pot)

        _motors.enable()

        try:
            while action_B:
                if action_A:
                    _log.info(Fore.BLUE + Style.BRIGHT + 'action A.')
                    action_A = False  # trigger once
                    _stbd_setpoint = 0.0
                    _port_setpoint = 0.0

                    while action_B:

                        # set PID constant
                        _scaled_value = _pot.get_scaled_value(True)
                        #                       _log.info(Style.DIM + 'PID TUNER kp: {:8.5f}   ================ '.format(_scaled_value))
                        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
                            _port_pid_ctrl.kp = _scaled_value
                        _stbd_pid_ctrl.kp = _scaled_value

                        _value = _rotary_ctrl.read()
                        #                       _log.info(Fore.BLUE + Style.BRIGHT + 'rotary value: {:<5.2f}'.format(_value))

                        #   if _value > -2.0 and _value < 2.0: # hysteresis?
                        #       _value = 0.0

                        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
                            _port_pid_ctrl.setpoint = ROTATE_VALUE * _value  #* 100.0
                            _port_setpoint = _port_pid_ctrl.setpoint
                        if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.STBD:
                            _stbd_pid_ctrl.setpoint = _value  #* 100.0
                            _stbd_setpoint = _stbd_pid_ctrl.setpoint


#                       _log.info(Fore.MAGENTA + 'rotary value: {:<5.2f}; setpoint: '.format(_value) \
#                               + Fore.RED + ' {:5.2f};'.format(_port_setpoint) + Fore.GREEN + ' {:5.2f};'.format(_stbd_setpoint) \
#                               + Fore.WHITE + ' action_B: {}'.format(action_B))
# end of loop

                    action_B = False  # quit after action
                    time.sleep(1.0)
                    # and we now return to our regularly scheduled broadcast...

                else:
                    pass
                _log.info(Fore.BLACK + Style.BRIGHT + 'waiting on button A...')
                time.sleep(0.5)

            _log.info(Fore.YELLOW + 'end of test.')

        except KeyboardInterrupt:
            _log.info(Fore.CYAN + Style.BRIGHT + 'Ctrl-C caught: closing...')
        finally:
            if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.PORT:
                _port_pid_ctrl.disable()
            if ORIENTATION == Orientation.BOTH or ORIENTATION == Orientation.STBD:
                _stbd_pid_ctrl.disable()
            _motors.brake()
            if _rotary_ctrl:
                _log.info('resetting rotary encoder...')
                _rotary_ctrl.reset()
            time.sleep(1.0)
            _log.info('complete.')

    except Exception as e:
        _log.info(Fore.RED + Style.BRIGHT +
                  'error in test: {}'.format(e, traceback.format_exc()))
    finally:
        _log.info(Fore.YELLOW + Style.BRIGHT + 'finally.')
Esempio n. 20
0
    def _configure(self):
        '''
            Configures ROS based on both KR01 standard hardware as well as
            optional features, the latter based on devices showing up (by 
            address) on the I²C bus. Optional devices are only enabled at
            startup time via registration of their feature availability.
        '''
        scanner = I2CScanner(Level.WARN)
        self._addresses = scanner.getAddresses()
        hexAddresses = scanner.getHexAddresses()
        self._addrDict = dict(
            list(map(lambda x, y: (x, y), self._addresses, hexAddresses)))
        for i in range(len(self._addresses)):
            self._log.debug(
                Fore.BLACK + Style.DIM +
                'found device at address: {}'.format(hexAddresses[i]) +
                Style.RESET_ALL)

        self._log.info('configure default features...')
        # standard devices ...........................................
        self._log.info('configuring integrated front sensors...')
        self._ifs = IntegratedFrontSensor(self._config, self._queue,
                                          Level.INFO)
        self._log.info('configure ht0740 switch...')
        self._switch = Switch(Level.INFO)
        # since we're using the HT0740 Switch, turn it on to enable sensors that rely upon its power
        #       self._switch.enable()
        self._switch.on()
        self._log.info('configuring button...')
        self._button = Button(self._config, self.get_message_queue(),
                              self._mutex)

        self._log.info('configure battery check...')
        _battery_check = BatteryCheck(self._config, self.get_message_queue(),
                                      Level.INFO)
        self.add_feature(_battery_check)

        self._log.info('configure CPU temperature check...')
        _temperature_check = Temperature(self._config, self._queue, Level.INFO)
        self.add_feature(_temperature_check)

        ultraborg_available = (0x36 in self._addresses)
        if ultraborg_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- UltraBorg available at 0x36.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no UltraBorg available at 0x36.' +
                            Style.RESET_ALL)
        self._set_feature_available('ultraborg', ultraborg_available)

        thunderborg_available = (0x15 in self._addresses)
        if thunderborg_available:  # then configure motors
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- ThunderBorg available at 0x15' +
                            Style.RESET_ALL)
            _motor_configurer = MotorConfigurer(self, self._config, Level.INFO)
            self._motors = _motor_configurer.configure()
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no ThunderBorg available at 0x15.' +
                            Style.RESET_ALL)
        self._set_feature_available('thunderborg', thunderborg_available)

        # optional devices ...........................................
        # the 5x5 RGB Matrix is at 0x74 for port, 0x77 for starboard
        rgbmatrix5x5_stbd_available = (0x74 in self._addresses)
        if rgbmatrix5x5_stbd_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- RGB Matrix available at 0x74.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no RGB Matrix available at 0x74.' +
                            Style.RESET_ALL)
        self._set_feature_available('rgbmatrix5x5_stbd',
                                    rgbmatrix5x5_stbd_available)
        rgbmatrix5x5_port_available = (0x77 in self._addresses)
        if rgbmatrix5x5_port_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- RGB Matrix available at 0x77.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no RGB Matrix available at 0x77.' +
                            Style.RESET_ALL)
        self._set_feature_available('rgbmatrix5x5_port',
                                    rgbmatrix5x5_port_available)

        if rgbmatrix5x5_stbd_available or rgbmatrix5x5_port_available:
            self._log.info('configure rgbmatrix...')
            self._rgbmatrix = RgbMatrix(Level.INFO)
            self.add_feature(self._rgbmatrix)  # FIXME this is added twice

        # ............................................
        # the 11x7 LED matrix is at 0x75 for starboard, 0x77 for port. The latter
        # conflicts with the RGB LED matrix, so both cannot be used simultaneously.
        matrix11x7_stbd_available = (0x75 in self._addresses)
        if matrix11x7_stbd_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- 11x7 Matrix LEDs available at 0x75.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no 11x7 Matrix LEDs available at 0x75.' +
                            Style.RESET_ALL)
        self._set_feature_available('matrix11x7_stbd',
                                    matrix11x7_stbd_available)

        # device availability ........................................

        bno055_available = (0x28 in self._addresses)
        if bno055_available:
            self._log.info('configuring BNO055 9DoF sensor...')
            self._bno055 = BNO055(self._config, self.get_message_queue(),
                                  Level.INFO)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no BNO055 orientation sensor available at 0x28.' +
                            Style.RESET_ALL)
        self._set_feature_available('bno055', bno055_available)

        # NOTE: the default address for the ICM20948 is 0x68, but this conflicts with the PiJuice
        icm20948_available = (0x69 in self._addresses)
        if icm20948_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'ICM20948 available at 0x69.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no ICM20948 available at 0x69.' + Style.RESET_ALL)
        self._set_feature_available('icm20948', icm20948_available)

        lsm303d_available = (0x1D in self._addresses)
        if lsm303d_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'LSM303D available at 0x1D.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no LSM303D available at 0x1D.' + Style.RESET_ALL)
        self._set_feature_available('lsm303d', lsm303d_available)

        vl53l1x_available = (0x29 in self._addresses)
        if vl53l1x_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'VL53L1X available at 0x29.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no VL53L1X available at 0x29.' + Style.RESET_ALL)
        self._set_feature_available('vl53l1x', vl53l1x_available)

        as7262_available = (0x49 in self._addresses)
        if as7262_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- AS7262 Spectrometer available at 0x49.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no AS7262 Spectrometer available at 0x49.' +
                            Style.RESET_ALL)
        self._set_feature_available('as7262', as7262_available)

        pijuice_available = (0x68 in self._addresses)
        if pijuice_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'PiJuice hat available at 0x68.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no PiJuice hat available at 0x68.' +
                            Style.RESET_ALL)
        self._set_feature_available('pijuice', pijuice_available)

        self._log.info('configured.')
Esempio n. 21
0
 def __init__(self):
     self.value = 0
     self.button = Button(XY(5, 5), XY(10, 10), 'Button', self.method, XY)
Esempio n. 22
0
class ROS(AbstractTask):
    '''
        Extends AbstractTask as a Finite State Machine (FSM) basis of a Robot 
        Operating System (ROS) or behaviour-based system (BBS), including 
        spawning the various tasks and an Arbitrator as separate threads, 
        inter-communicating over a common message queue.
    
        This establishes a message queue, an Arbitrator and a Controller, as
        well as an optional RESTful flask-based web service.
    
        The message queue receives Event-containing messages, which are passed 
        on to the Arbitrator, whose job it is to determine the highest priority 
        action to execute for that task cycle.

        Example usage:

            try:
                _ros = ROS()
                _ros.start()
            except Exception:
                _ros.close()

      
        There is also a rosd linux daemon, which can be used to start, enable
        and disable ros (actually via its Arbitrator).
    '''

    # ..........................................................................
    def __init__(self):
        '''
            This initialises the ROS and calls the YAML configurer.
        '''
        self._queue = MessageQueue(Level.INFO)
        self._mutex = threading.Lock()
        super().__init__("ros", self._queue, None, None, self._mutex)
        self._log.info('initialising...')
        self._active = False
        self._closing = False
        self._disable_leds = False
        #       self._switch        = None
        self._motors = None
        self._arbitrator = None
        self._controller = None
        self._gamepad = None
        self._features = []
        #       self._flask_wrapper = None
        # read YAML configuration
        _loader = ConfigLoader(Level.INFO)
        filename = 'config.yaml'
        self._config = _loader.configure(filename)
        self._gamepad_enabled = self._config['ros'].get('gamepad').get(
            'enabled')
        self._log.info('initialised.')
        self._configure()

    # ..........................................................................
    def _configure(self):
        '''
            Configures ROS based on both KR01 standard hardware as well as
            optional features, the latter based on devices showing up (by 
            address) on the I²C bus. Optional devices are only enabled at
            startup time via registration of their feature availability.
        '''
        scanner = I2CScanner(Level.WARN)
        self._addresses = scanner.getAddresses()
        hexAddresses = scanner.getHexAddresses()
        self._addrDict = dict(
            list(map(lambda x, y: (x, y), self._addresses, hexAddresses)))
        for i in range(len(self._addresses)):
            self._log.debug(
                Fore.BLACK + Style.DIM +
                'found device at address: {}'.format(hexAddresses[i]) +
                Style.RESET_ALL)

        self._log.info('configure default features...')
        # standard devices ...........................................
        self._log.info('configuring integrated front sensors...')
        self._ifs = IntegratedFrontSensor(self._config, self._queue,
                                          Level.INFO)
        self._log.info('configure ht0740 switch...')
        self._switch = Switch(Level.INFO)
        # since we're using the HT0740 Switch, turn it on to enable sensors that rely upon its power
        #       self._switch.enable()
        self._switch.on()
        self._log.info('configuring button...')
        self._button = Button(self._config, self.get_message_queue(),
                              self._mutex)

        self._log.info('configure battery check...')
        _battery_check = BatteryCheck(self._config, self.get_message_queue(),
                                      Level.INFO)
        self.add_feature(_battery_check)

        self._log.info('configure CPU temperature check...')
        _temperature_check = Temperature(self._config, self._queue, Level.INFO)
        self.add_feature(_temperature_check)

        ultraborg_available = (0x36 in self._addresses)
        if ultraborg_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- UltraBorg available at 0x36.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no UltraBorg available at 0x36.' +
                            Style.RESET_ALL)
        self._set_feature_available('ultraborg', ultraborg_available)

        thunderborg_available = (0x15 in self._addresses)
        if thunderborg_available:  # then configure motors
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- ThunderBorg available at 0x15' +
                            Style.RESET_ALL)
            _motor_configurer = MotorConfigurer(self, self._config, Level.INFO)
            self._motors = _motor_configurer.configure()
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no ThunderBorg available at 0x15.' +
                            Style.RESET_ALL)
        self._set_feature_available('thunderborg', thunderborg_available)

        # optional devices ...........................................
        # the 5x5 RGB Matrix is at 0x74 for port, 0x77 for starboard
        rgbmatrix5x5_stbd_available = (0x74 in self._addresses)
        if rgbmatrix5x5_stbd_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- RGB Matrix available at 0x74.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no RGB Matrix available at 0x74.' +
                            Style.RESET_ALL)
        self._set_feature_available('rgbmatrix5x5_stbd',
                                    rgbmatrix5x5_stbd_available)
        rgbmatrix5x5_port_available = (0x77 in self._addresses)
        if rgbmatrix5x5_port_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- RGB Matrix available at 0x77.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no RGB Matrix available at 0x77.' +
                            Style.RESET_ALL)
        self._set_feature_available('rgbmatrix5x5_port',
                                    rgbmatrix5x5_port_available)

        if rgbmatrix5x5_stbd_available or rgbmatrix5x5_port_available:
            self._log.info('configure rgbmatrix...')
            self._rgbmatrix = RgbMatrix(Level.INFO)
            self.add_feature(self._rgbmatrix)  # FIXME this is added twice

        # ............................................
        # the 11x7 LED matrix is at 0x75 for starboard, 0x77 for port. The latter
        # conflicts with the RGB LED matrix, so both cannot be used simultaneously.
        matrix11x7_stbd_available = (0x75 in self._addresses)
        if matrix11x7_stbd_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- 11x7 Matrix LEDs available at 0x75.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no 11x7 Matrix LEDs available at 0x75.' +
                            Style.RESET_ALL)
        self._set_feature_available('matrix11x7_stbd',
                                    matrix11x7_stbd_available)

        # device availability ........................................

        bno055_available = (0x28 in self._addresses)
        if bno055_available:
            self._log.info('configuring BNO055 9DoF sensor...')
            self._bno055 = BNO055(self._config, self.get_message_queue(),
                                  Level.INFO)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no BNO055 orientation sensor available at 0x28.' +
                            Style.RESET_ALL)
        self._set_feature_available('bno055', bno055_available)

        # NOTE: the default address for the ICM20948 is 0x68, but this conflicts with the PiJuice
        icm20948_available = (0x69 in self._addresses)
        if icm20948_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'ICM20948 available at 0x69.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no ICM20948 available at 0x69.' + Style.RESET_ALL)
        self._set_feature_available('icm20948', icm20948_available)

        lsm303d_available = (0x1D in self._addresses)
        if lsm303d_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'LSM303D available at 0x1D.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no LSM303D available at 0x1D.' + Style.RESET_ALL)
        self._set_feature_available('lsm303d', lsm303d_available)

        vl53l1x_available = (0x29 in self._addresses)
        if vl53l1x_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'VL53L1X available at 0x29.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no VL53L1X available at 0x29.' + Style.RESET_ALL)
        self._set_feature_available('vl53l1x', vl53l1x_available)

        as7262_available = (0x49 in self._addresses)
        if as7262_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            '-- AS7262 Spectrometer available at 0x49.' +
                            Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            '-- no AS7262 Spectrometer available at 0x49.' +
                            Style.RESET_ALL)
        self._set_feature_available('as7262', as7262_available)

        pijuice_available = (0x68 in self._addresses)
        if pijuice_available:
            self._log.debug(Fore.CYAN + Style.BRIGHT +
                            'PiJuice hat available at 0x68.' + Style.RESET_ALL)
        else:
            self._log.debug(Fore.RED + Style.BRIGHT +
                            'no PiJuice hat available at 0x68.' +
                            Style.RESET_ALL)
        self._set_feature_available('pijuice', pijuice_available)

        self._log.info('configured.')

    # ..........................................................................
    def summation():
        '''
            Displays unaccounted I2C addresses. This is currently non-functional,
            as we don't remove a device from the list when its address is found.
        '''
        self._log.info(Fore.YELLOW + '-- unaccounted for self._addresses:')
        for i in range(len(self._addresses)):
            hexAddr = self._addrDict.get(self._addresses[i])
            self._log.info(Fore.YELLOW + Style.BRIGHT +
                           '-- address: {}'.format(hexAddr) + Style.RESET_ALL)

    # ..........................................................................
    def _set_feature_available(self, name, value):
        '''
            Sets a feature's availability to the boolean value.
        '''
        self._log.debug(Fore.BLUE + Style.BRIGHT +
                        '-- set feature available. name: \'{}\' value: \'{}\'.'
                        .format(name, value))
        self.set_property('features', name, value)

    # ..........................................................................
    def get_message_queue(self):
        return self._queue

    # ..........................................................................
    def get_controller(self):
        return self._controller

    # ..........................................................................
    def get_configuration(self):
        return self._config

    # ..........................................................................
    def get_property(self, section, property_name):
        '''
            Return the value of the named property of the application
            configuration, provided its section and property name.
        '''
        return self._config[section].get(property_name)

    # ..........................................................................
    def set_property(self, section, property_name, property_value):
        '''
            Set the value of the named property of the application
            configuration, provided its section, property name and value.
        '''
        self._log.debug(
            Fore.GREEN +
            'set config on section \'{}\' for property key: \'{}\' to value: {}.'
            .format(section, property_name, property_value))
        if section == 'ros':
            self._config[section].update(property_name=property_value)
        else:
            _ros = self._config['ros']
            _ros[section].update(property_name=property_value)

    # ..........................................................................
    def _set_pi_leds(self, enable):
        '''
            Enables or disables the Raspberry Pi's board LEDs.
        '''
        sudo_name = self.get_property('pi', 'sudo_name')
        led_0_path = self._config['pi'].get('led_0_path')
        led_1_path = self._config['pi'].get('led_1_path')
        if enable:
            self._log.info('re-enabling LEDs...')
            os.system('echo 1 | {} tee {}'.format(sudo_name, led_0_path))
            os.system('echo 1 | {} tee {}'.format(sudo_name, led_1_path))
        else:
            self._log.debug('disabling LEDs...')
            os.system('echo 0 | {} tee {}'.format(sudo_name, led_0_path))
            os.system('echo 0 | {} tee {}'.format(sudo_name, led_1_path))

    # ..........................................................................
    def _connect_gamepad(self):
        if not self._gamepad_enabled:
            self._log.info('gamepad disabled.')
            return
        if self._gamepad is None:
            self._log.info('creating gamepad...')
            try:
                self._gamepad = Gamepad(self._config, self._queue, Level.INFO)
            except GamepadConnectException as e:
                self._log.error('unable to connect to gamepad: {}'.format(e))
                self._gamepad = None
                self._gamepad_enabled = False
                self._log.info('gamepad unavailable.')
                return
        if self._gamepad is not None:
            self._log.info('enabling gamepad...')
            self._gamepad.enable()
            _count = 0
            while not self._gamepad.has_connection():
                _count += 1
                if _count == 1:
                    self._log.info('connecting to gamepad...')
                else:
                    self._log.info(
                        'gamepad not connected; re-trying... [{:d}]'.format(
                            _count))
                self._gamepad.connect()
                time.sleep(0.5)
                if self._gamepad.has_connection() or _count > 5:
                    break

    # ..........................................................................
    def has_connected_gamepad(self):
        return self._gamepad is not None and self._gamepad.has_connection()

    # ..........................................................................
    def get_arbitrator(self):
        return self._arbitrator

    # ..........................................................................
    def add_feature(self, feature):
        '''
            Add the feature to the list of features. Features must have 
            an enable() method.
        '''
        self._features.append(feature)
        self._log.info('added feature {}.'.format(feature.name()))

    # ..........................................................................
    def _callback_shutdown(self):
        _enable_self_shutdown = self._config['ros'].get('enable_self_shutdown')
        if _enable_self_shutdown:
            self._log.critical('callback: shutting down os...')
            self.close()
            sys.exit(0)
        else:
            self._log.critical('self-shutdown disabled.')

    # ..........................................................................
    def run(self):
        '''
            This first disables the Pi's status LEDs, establishes the
            message queue arbitrator, the controller, enables the set
            of features, then starts the main OS loop.
        '''
        super(AbstractTask, self).run()
        loop_count = 0
        # display banner!
        _banner = '\n' \
                  'ros\n' \
                  'ros                         █▒▒▒▒▒▒▒     █▒▒▒▒▒▒     █▒▒▒▒▒▒    █▒▒  \n' \
                + 'ros                         █▒▒   █▒▒   █▒▒   █▒▒   █▒▒         █▒▒  \n' \
                + 'ros                         █▒▒▒▒▒▒     █▒▒   █▒▒    █▒▒▒▒▒▒    █▒▒  \n' \
                + 'ros                         █▒▒  █▒▒    █▒▒   █▒▒         █▒▒        \n' \
                + 'ros                         █▒▒   █▒▒    █▒▒▒▒▒▒     █▒▒▒▒▒▒    █▒▒  \n' \
                + 'ros\n'
        self._log.info(_banner)

        self._disable_leds = self._config['pi'].get('disable_leds')
        if self._disable_leds:
            # disable Pi LEDs since they may be distracting
            self._set_pi_leds(False)

        self._log.info('enabling features...')
        for feature in self._features:
            self._log.info('enabling feature {}...'.format(feature.name()))
            feature.enable()

#       __enable_player = self._config['ros'].get('enable_player')
#       if __enable_player:
#           self._log.info('configuring sound player...')
#           self._player = Player(Level.INFO)
#       else:
#           self._player = None

#       i2c_slave_address = config['ros'].get('i2c_master').get('device_id') # i2c hex address of I2C slave device

        vl53l1x_available = True  # self.get_property('features', 'vl53l1x')
        ultraborg_available = True  # self.get_property('features', 'ultraborg')
        if vl53l1x_available and ultraborg_available:
            self._log.critical('starting scanner tool...')
            self._lidar = Lidar(self._config, Level.INFO)
            self._lidar.enable()
        else:
            self._log.critical(
                'lidar scanner tool does not have necessary dependencies.')

        # wait to stabilise features?

        # configure the Controller and Arbitrator
        self._log.info('configuring controller...')
        self._controller = Controller(self._config, self._ifs, self._motors,
                                      self._callback_shutdown, Level.INFO)

        self._log.info('configuring arbitrator...')
        self._arbitrator = Arbitrator(self._config, self._queue,
                                      self._controller, Level.WARN)

        _flask_enabled = self._config['flask'].get('enabled')
        if _flask_enabled:
            self._log.info('starting flask web server...')
            self.configure_web_server()
        else:
            self._log.info(
                'not starting flask web server (suppressed from command line).'
            )

        # bluetooth gamepad controller
        if self._gamepad_enabled:
            self._connect_gamepad()

        self._log.warning('Press Ctrl-C to exit.')

        _wait_for_button_press = self._config['ros'].get(
            'wait_for_button_press')
        self._controller.set_standby(_wait_for_button_press)

        # begin main loop ..............................

        self._log.info('starting button thread...')
        self._button.start()

        #       self._log.info('enabling bno055 sensor...')
        #       self._bno055.enable()

        #       self._bumpers.enable()

        self._indicator = Indicator(Level.INFO)
        # add indicator as message consumer
        self._queue.add_consumer(self._indicator)

        self._log.info(Fore.MAGENTA + 'enabling integrated front sensor...')
        self._ifs.enable()
        #       self._log.info('starting info thread...')
        #       self._info.start()

        #       self._log.info('starting blinky thread...')
        #       self._rgbmatrix.enable(DisplayType.RANDOM)

        # enable arbitrator tasks (normal functioning of robot)

        main_loop_delay_ms = self._config['ros'].get('main_loop_delay_ms')
        self._log.info(
            'begin main os loop with {:d}ms delay.'.format(main_loop_delay_ms))
        _loop_delay_sec = main_loop_delay_ms / 1000
        _main_loop_count = 0
        self._arbitrator.start()
        self._active = True
        while self._active:
            #           The sensors and the flask service sends messages to the message queue,
            #           which forwards those messages on to the arbitrator, which chooses the
            #           highest priority message to send on to the controller. So the timing
            #           of this loop is inconsequential; it exists solely as a keep-alive.
            _main_loop_count += 1
            self._log.debug(Fore.BLACK + Style.DIM +
                            '[{:d}] main loop...'.format(_main_loop_count))
            time.sleep(_loop_delay_sec)
            # end application loop .........................

        if not self._closing:
            self._log.warning('closing following loop...')
            self.close()
        # end main ...................................

    # ..........................................................................
    def configure_web_server(self):
        '''
            Start flask web server.
        '''
        try:
            self._mutex.acquire()
            self._log.info('starting web service...')
            self._flask_wrapper = FlaskWrapperService(self._queue,
                                                      self._controller)
            self._flask_wrapper.start()
        except KeyboardInterrupt:
            self._log.error('caught Ctrl-C interrupt.')
        finally:
            self._mutex.release()
            time.sleep(1)
            self._log.info(Fore.BLUE + 'web service started.' +
                           Style.RESET_ALL)

    # ..........................................................................
    def emergency_stop(self):
        '''
            Stop immediately, something has hit the top feelers.
        '''
        self._motors.stop()
        self._log.info(Fore.RED + Style.BRIGHT +
                       'emergency stop: contact on upper feelers.')

    # ..........................................................................
    def send_message(self, message):
        '''
            Send the Message into the MessageQueue.
        '''
        self._queue.add(message)

    # ..........................................................................
    def enable(self):
        super(AbstractTask, self).enable()

    # ..........................................................................
    def disable(self):
        super(AbstractTask, self).disable()

    # ..........................................................................
    def close(self):
        '''
            This sets the ROS back to normal following a session.
        '''
        if self._closing:
            # this also gets called by the arbitrator so we ignore that
            self._log.info('already closing.')
            return
        else:
            self._active = False
            self._closing = True
            self._log.info(Style.BRIGHT + 'closing...')

            if self._gamepad:
                self._gamepad.close()
            if self._motors:
                self._motors.close()
            if self._ifs:
                self._ifs.close()

            # close features
            for feature in self._features:
                self._log.info('closing feature {}...'.format(feature.name()))
                feature.close()
            self._log.info('finished closing features.')

            if self._arbitrator:
                self._arbitrator.disable()
                self._arbitrator.close()
#               self._arbitrator.join(timeout=1.0)
            if self._controller:
                self._controller.disable()

#           if self._flask_wrapper is not None:
#               self._flask_wrapper.close()

            super().close()

            #           self._info.close()
            #           self._rgbmatrix.close()
            #           if self._switch:
            #               self._switch.close()
            #           super(AbstractTask, self).close()

            if self._disable_leds:
                # restore LEDs
                self._set_pi_leds(True)

#           GPIO.cleanup()
#           self._log.info('joining main thread...')
#           self.join(timeout=0.5)
            self._log.info('os closed.')
            sys.stderr = DevNull()
            sys.exit(0)
Esempio n. 23
0
class RockingMotorcycleGame:
    SOUND_START = "start"  # 11 sec
    SOUND_STOP = "stop"  # 6 sev
    SOUND_SPEEDUP = "speedUp"  # 13 sec
    SOUND_IDLE = "idle"  # 40 sec
    SOUND_DRIVE = "drive"  # 22 sec

    MODE_START = 0
    MODE_DRIVE = 1
    MODE_STOP = 2

    LED_SPEED = 100

    def __init__(self, pinBTN=27, pinLED=17, startVolume=70, imuAddress=0x6a, limit=350, changeDelta=1000):
        GPIO.setmode(GPIO.BCM)

        led = LED(pinLED)

        self.ledStrip = LEDStrip()
        self.audio = Audio(startVolume)

        self.mixer = AudioMixer()
        self.initAudioMixer()

        self.btn = Button(pinBTN)
        self.btn.setListener(self.audioBtnListener)

        self.ledControl = LEDController(led)
        self.ledControl.start()

        self.changeDelta = changeDelta
        self.currentMode = -1

        # self.imuController = IMUController(imuAddress, limit=limit)
        self.imuController = LSMController(imuAddress, limit=limit)
        self.initImuController()

        self.animDrive = TheaterChaseAnimation(LEDAnimation.COLOR_CYAN, 20, 50, 15, True)
        self.animIdle = FadeCycleAnimation(RGBColor(0, 0, 0), RGBColor(0, 80, 0), 25, 20)

        self.ledStrip = LEDStrip()
        self.ledStrip.start()

        self.speed = 0
        self.lastLoop = self.getMillis()

    def initImuController(self):
        self.imuChangeTime = 0
        self.imuController.setListener(self.imuListener)
        self.imuController.start()

    def initAudioMixer(self):
        appPath = path.dirname(path.abspath(__file__))
        audioFolder = path.join(appPath, "audio")

        self.mixer.addSound(self.SOUND_START, path.join(audioFolder, "h_start.wav"))
        self.mixer.addSound(self.SOUND_STOP, path.join(audioFolder, "h_stop.wav"))
        self.mixer.addSound(self.SOUND_SPEEDUP, path.join(audioFolder, "h_speedup.wav"))
        self.mixer.addSound(self.SOUND_IDLE, path.join(audioFolder, "h_idle.wav"))
        self.mixer.addSound(self.SOUND_DRIVE, path.join(audioFolder, "h_drive.wav"))

        self.mixer.setListener(self.mixerListener)

    def run(self):
        # indicate start
        self.ledControl.blink(2, 100, 100)

        while True:
            self.btn.loop()

            mode = self.getMode(self.imuChangeTime)

            accl = self.getAcceleration(mode, self.lastLoop)

            self.speed += accl

            if self.speed < 0:
                self.speed = 0
            elif self.speed > 100:
                self.speed = 100

            self.playLEDAnimation(mode, self.speed)

            self.playSound(mode)

            self.lastLoop = self.getMillis()

            self.currentMode = mode

            time.sleep(0.1)

    def mixerListener(self, id):
        return

    def playLEDAnimation(self, mode: int, speed: int):
        curAnim = self.ledStrip.getAnimation()

        if mode == self.MODE_START or speed <= 5:
            if curAnim != self.animIdle:
                self.ledStrip.setAnimation(self.animIdle)
        else:
            if curAnim is None or curAnim != self.animDrive:
                curAnim = self.animDrive
                self.ledStrip.setAnimation(curAnim)

            percentage = (100 - speed) / 100
            color = LEDAnimation.wheel(int(80 * (1 - percentage)))
            self.animDrive.update(color, int(10 + 200 * percentage), curAnim.iterations,
                                  curAnim.distance)

    def stop(self):
        self.mixer.stop()
        self.ledControl.stop()
        self.ledStrip.setAnimation(ColorSetAnimation(LEDAnimation.COLOR_BLACK))
        time.sleep(1)
        self.ledStrip.stop()
        self.imuController.stop()
        GPIO.cleanup()

    def imuListener(self):
        self.imuChangeTime = self.getMillis()

    def getMillis(self):
        return int(round(time.time() * 1000))

    def audioBtnListener(self, mode):
        vol = self.audio.getVolume()

        if mode is Button.NORMAL_PRESS:
            if vol == 100:
                self.audio.setVolume(70)
                vol = 70
            else:
                vol = self.audio.volumeUp()

        else:
            if self.audio.isMute:
                vol = self.audio.unmute()
            else:
                self.audio.mute()
                vol = 0

        if vol >= 70:
            self.ledControl.blink(int(vol / 10) - 6, self.LED_SPEED, self.LED_SPEED)
        else:
            self.ledControl.blink(1, 1000, self.LED_SPEED)

    def getMode(self, imuChangeTime: int):
        if imuChangeTime == 0:
            return self.MODE_START
        elif self.getMillis() - imuChangeTime < self.changeDelta:
            return self.MODE_DRIVE
        else:
            return self.MODE_STOP

    def playSound(self, mode: int):

        if self.currentMode == mode:
            return

        self.mixer.clearQueue()

        if mode == self.MODE_START:
            self.mixer.playSound(self.SOUND_START, False, 0)
            self.mixer.queue(self.SOUND_IDLE, True)
        elif mode == self.MODE_DRIVE:
            self.mixer.playSound(self.SOUND_SPEEDUP, False)
            self.mixer.queue(self.SOUND_DRIVE, True)
        elif mode == self.MODE_STOP:
            self.mixer.playSound(self.SOUND_STOP, False)
            self.mixer.queue(self.SOUND_IDLE, True)

    def getAcceleration(self, mode: int, lastLoop: int):

        accl = 0

        if mode != self.MODE_START:
            # get time between loops
            diff = self.getMillis() - lastLoop

            speedChange = (diff / 1000) * 5  # 17 kmh per sec

            if mode == self.MODE_DRIVE:
                # decreases speed
                accl = speedChange

            elif mode == self.MODE_STOP:
                # increase speed
                accl -= 2 * speedChange

        return accl
Esempio n. 24
0
def test_motors():
    global _port_motor, _stbd_motor, action_A, action_B

    # read YAML configuration
    _loader = ConfigLoader(Level.INFO)
    filename = 'config.yaml'
    _config = _loader.configure(filename)

    _log.info('creating message factory...')
    _message_factory = MessageFactory(Level.INFO)
    _log.info('creating message bus...')
    _message_bus = MessageBus(Level.WARN)
    _log.info('creating clock...')
    _clock = Clock(_config, _message_bus, _message_factory, Level.WARN)

    _motor_configurer = MotorConfigurer(_config, _clock, Level.INFO)
    _motors = _motor_configurer.get_motors()
    _motors.enable()

    _i2c_scanner = I2CScanner(Level.WARN)
    if ENABLE_MOTH:
        if _i2c_scanner.has_address([0x18]):
            _rgbmatrix = RgbMatrix(Level.WARN)
            #           _rgbmatrix.set_display_type(DisplayType.SOLID)
            _moth = Moth(_config, None, Level.WARN)
        else:
            _log.warning('cannot enable moth: no IO Expander found.')
            _moth = None

    _pin_A = 16
    _button_16 = Button(_pin_A, callback_method_A, Level.INFO)
    _log.info(
        Style.BRIGHT +
        'press button A (connected to pin {:d}) to toggle or initiate action.'.
        format(_pin_A))

    _pin_B = 24
    _button_24 = Button(_pin_B, callback_method_B, Level.INFO)
    _log.info(Style.BRIGHT +
              'press button B connected to pin {:d}) to exit.'.format(_pin_B))

    _log.info('starting motors...')
    _port_motor = _motors.get_motor(Orientation.PORT)
    _stbd_motor = _motors.get_motor(Orientation.STBD)
    if ENABLE_PORT:
        _port_motor.enable()
    if ENABLE_STBD:
        _stbd_motor.enable()

    _rot_ctrl = RotaryControl(_config, 0, 50, 2, Level.WARN)  # min, max, step
    _rate = Rate(5)
    _step_limit = 2312
    _velocity_stbd = 0.0
    _velocity_port = 0.0
    _start_time = dt.now()
    _moth_port = 1.0
    _moth_stbd = 1.0
    _moth_offset = 0.6
    _moth_bias = [0.0, 0.0]
    _moth_fudge = 0.7

    try:

        action_A = True  # if not using buttons at all set to True
        action_B = True

        while INFINITE or action_B or (_port_motor.steps < _step_limit
                                       and _stbd_motor.steps < _step_limit):
            if action_A:
                action_A = False  # trigger once
                while action_B:
                    if USE_ROTARY_CONTROL:
                        _target_velocity = _rot_ctrl.read()
                    else:
                        _target_velocity = 30.0
        #           _power = _target_velocity / 100.0
                    _power = Motor.velocity_to_power(_target_velocity)
                    if ENABLE_MOTH and _moth:
                        _moth_bias = _moth.get_bias()
                        #                       _log.info(Fore.WHITE + Style.BRIGHT + 'port: {:5.2f}; stbd: {:5.2f}'.format(_moth_port, _moth_stbd))
                        #                       _rgbmatrix.show_hue(_moth_hue, Orientation.BOTH)
                        _orientation = _moth.get_orientation()
                        if _orientation is Orientation.PORT:
                            _moth_port = _moth_bias[0] * _moth_fudge
                            _moth_stbd = 1.0
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.STBD)
                            _rgbmatrix.show_color(Color.RED, Orientation.PORT)
                        elif _orientation is Orientation.STBD:
                            _moth_port = 1.0
                            _moth_stbd = _moth_bias[1] * _moth_fudge
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.PORT)
                            _rgbmatrix.show_color(Color.GREEN,
                                                  Orientation.STBD)
                        else:
                            _moth_port = 1.0
                            _moth_stbd = 1.0
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.PORT)
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.STBD)
                    if ENABLE_STBD:
                        _stbd_motor.set_motor_power(_stbd_rotate * _power *
                                                    _moth_stbd)
                        _velocity_stbd = _stbd_motor.velocity
                    if ENABLE_PORT:
                        _port_motor.set_motor_power(_port_rotate * _power *
                                                    _moth_port)
                        _velocity_port = _port_motor.velocity
                    _log.info(Fore.YELLOW + 'power: {:5.2f}; bias: '.format(_power) \
                            + Fore.RED + ' {:5.2f} '.format(_moth_bias[0]) + Fore.GREEN + '{:5.2f};'.format(_moth_bias[1]) \
                            + Fore.BLACK + ' target velocity: {:5.2f};'.format(_target_velocity) \
                            + Fore.CYAN + ' velocity: ' \
                            + Fore.RED   + ' {:5.2f} '.format(_velocity_port) + Fore.GREEN + ' {:5.2f}'.format(_velocity_stbd))

                    #           _log.info(Fore.RED   + 'power {:5.2f}/{:5.2f}; {:>4d} steps; \t'.format(_stbd_motor.get_current_power_level(), _power, _port_motor.steps) \
                    #                   + Fore.GREEN + 'power {:5.2f}/{:5.2f}; {:>4d} steps.'.format(_port_motor.get_current_power_level(), _power, _stbd_motor.steps))
                    _rate.wait()
                action_B = True  # reentry into B loop, waiting for A
            _log.info('waiting for A button press...')
            time.sleep(1.0)
            # end wait loop ....................................................

        if ENABLE_PORT:
            _log.info('port motor: {:d} steps.'.format(_port_motor.steps))
        if ENABLE_STBD:
            _log.info('stbd motor: {:d} steps.'.format(_stbd_motor.steps))

    except KeyboardInterrupt:
        _log.info('Ctrl-C caught; exiting...')
    except Exception as e:
        _log.error('error: {}'.format(e))
    finally:
        close_motors(_log)
    _elapsed_ms = round((dt.now() - _start_time).total_seconds() * 1000.0)
    _log.info(Fore.YELLOW + 'complete: elapsed: {:d}ms'.format(_elapsed_ms))