Esempio n. 1
0
    def __init__(self, pi=None, port=DEF_PORT, debug=False):
        """ __init__ """
        self._dbg = debug
        self._log = get_logger(__class__.__name__, debug)
        self._log.debug('pi=%s, port=%s', pi, port)

        if type(pi) == pigpio.pi:
            self._pi = pi
            self._mypi = False
        else:
            self._pi = pigpio.pi()
            self._mypi = True
        self._log.debug('mypi = %s', self._mypi)

        self._ctrl = OttoPiCtrl(self._pi, debug=self._dbg)
        self._ctrl.start()

        self._auto = OttoPiAuto(self._ctrl, debug=self._dbg)
        self._auto.start()

        self._dance = None
        self._dance2 = None

        time.sleep(1)

        self._port = port

        try:
            super().__init__(('', self._port), ServerHandler)
        except Exception as e:
            self._log.warning('%s:%s', type(e).__name__, e)
            return None
Esempio n. 2
0
    def __init__(self, debug=False):
        """ init """
        self.dbg = debug
        self._log = get_logger(__class__.__name__, debug)
        self._log.debug('')

        self.pi = pigpio.pi()

        self.robot_ctrl = OttoPiCtrl(self.pi, debug=self.dbg)
        self.robot_ctrl.start()

        self.robot_auto = OttoPiAuto(self.robot_ctrl, debug=self.dbg)
        self.robot_auto.start()

        self.active = True
Esempio n. 3
0
    def __init__(self, robot_ctrl=None, debug=False):
        """ init """
        self.dbg = debug
        self._log = get_logger(__class__.__name__, self.dbg)
        self._log.debug('')

        self.cmd_func = {
            self.CMD_NULL: self.cmd_null,
            self.CMD_ON: self.cmd_on,
            self.CMD_OFF: self.cmd_off,
            self.CMD_ENABLE: self.cmd_enable,
            self.CMD_DISABLE: self.cmd_disable,
            self.CMD_END: self.cmd_end
        }

        self.my_robot_ctrl = False
        self.robot_ctrl = robot_ctrl
        if self.robot_ctrl is None:
            self.my_robot_ctrl = True
            self.robot_ctrl = OttoPiCtrl(None, debug=self.dbg)
            self.robot_ctrl.start()

        self.tof = VL53L0X.VL53L0X()
        # self.tof.start_ranging(VL53L0X.VL53L0X_BEST_ACCURACY_MODE)
        self.tof.start_ranging(VL53L0X.VL53L0X_BETTER_ACCURACY_MODE)
        self.tof_timing = self.tof.get_timing()
        self._log.info('tof_timing = %.02f ms', self.tof_timing / 1000)
        self.d = 0

        self.cmdq = queue.Queue()

        self.active = True
        self.on = False
        self.enable = False

        self.prev_stat = self.STAT_NONE
        self.stat = self.STAT_NONE
        self.prev_rl = ""
        self.touch_count = 0
        self.ready_count = 0

        self.distance = self.D_FAR

        super().__init__(daemon=True)
Esempio n. 4
0
class OttoPiAutoApp:
    """ OttoPiAutoApp """
    def __init__(self, debug=False):
        """ init """
        self.dbg = debug
        self._log = get_logger(__class__.__name__, debug)
        self._log.debug('')

        self.pi = pigpio.pi()

        self.robot_ctrl = OttoPiCtrl(self.pi, debug=self.dbg)
        self.robot_ctrl.start()

        self.robot_auto = OttoPiAuto(self.robot_ctrl, debug=self.dbg)
        self.robot_auto.start()

        self.active = True

    def main(self):
        """ main """
        self._log.debug('')

        while self.active:
            cmdline = input()
            self._log.debug('cmdline = %s', cmdline)

            self.robot_auto.send(cmdline)
            time.sleep(1)

            if not self.robot_auto.is_active():
                self.active = False

        self._log.debug('done(active=%s)', self.active)

    def end(self):
        """ end """
        self._log.debug('')

        self.robot_auto.end()
        self._log.info('robot_auto thread: end')

        self.robot_ctrl.send(OttoPiCtrl.CMD_STOP)
        self.robot_ctrl.end()
        self._log.info('robot_ctrl thread: end')

        self.pi.stop()
        self._log.info('done')
Esempio n. 5
0
def main(max_sleep_sec, debug):
    _log = get_logger(__name__, debug)
    _log.info('max_sleep_sec=%d', max_sleep_sec)

    try:
        pi = pigpio.pi()
        robot_ctrl = OttoPiCtrl(pi)
        robot_ctrl.start()
        obj = Dance(robot_ctrl, max_sleep_sec, debug=debug)
        obj.start()
        cmdline = input('> ')
        print('cmdline=%a' % (cmdline))
        obj.end()
        while not robot_ctrl.cmdq.empty():
            time.sleep(1)
            print('.', end='', flush=True)

    finally:
        _log.info('finally')
        robot_ctrl.end()
Esempio n. 6
0
class OttoPiServer(socketserver.ThreadingTCPServer):
    """ server """
    DEF_PORT = 12345
    CMD_PREFIX = ':'  # word command
    CMD_PREFIX2 = '.'  # interupt off
    CMD_AUTO_PREFIX = 'auto_'  # auto command

    def __init__(self, pi=None, port=DEF_PORT, debug=False):
        """ __init__ """
        self._dbg = debug
        self._log = get_logger(__class__.__name__, debug)
        self._log.debug('pi=%s, port=%s', pi, port)

        if type(pi) == pigpio.pi:
            self._pi = pi
            self._mypi = False
        else:
            self._pi = pigpio.pi()
            self._mypi = True
        self._log.debug('mypi = %s', self._mypi)

        self._ctrl = OttoPiCtrl(self._pi, debug=self._dbg)
        self._ctrl.start()

        self._auto = OttoPiAuto(self._ctrl, debug=self._dbg)
        self._auto.start()

        self._dance = None
        self._dance2 = None

        time.sleep(1)

        self._port = port

        try:
            super().__init__(('', self._port), ServerHandler)
        except Exception as e:
            self._log.warning('%s:%s', type(e).__name__, e)
            return None

    def end(self):
        """ end """
        self._log.debug('')

        if self._auto.is_active():
            self._auto.end()
            self._log.debug('_auto thread: done')

        if self._ctrl.is_active():
            self._ctrl.end()
            self._log.debug('_ctrl thread: done')

        if self._mypi:
            self._log.debug('clean up pigpio')
            self._pi.stop()
            self._mypi = False

        self._log.debug('done')

    def _del_(self):
        """ _del_ """
        self._log.debug('')
        self.end()
Esempio n. 7
0
    def handle(self):
        """ handle """
        self._log.debug('')

        # Telnet Protocol
        #
        # mode character
        #  0xff IAC
        #  0xfd D0
        #  0x22 LINEMODE
        # self.net_write(b'\xff\xfd\x22')

        self.net_write('#Ready\r\n'.encode('utf-8'))

        net_data = b''
        flag_continue = True
        while flag_continue:
            # データー受信
            try:
                net_data = self.request.recv(512)
            except ConnectionResetError as e:
                self._log.warning('%s:%s.', type(e), e)
                return
            except BaseException as e:
                self._log.warning('BaseException:%s:%s.', type(e), e)
                self._log.warning('send: OttoPiCtrl.CMD_STOP')
                self._ctrl.send(OttoPiCtrl.CMD_STOP)
                return
            else:
                self._log.debug('net_data:%a', net_data)

            # デコード(UTF-8)
            try:
                decoded_data = net_data.decode('utf-8')
            except UnicodeDecodeError as e:
                self._log.warning('%s:%s .. ignored', type(e), e)
                continue
            else:
                self._log.debug('decoded_data:%a', decoded_data)

            self.net_write('\r\n'.encode('utf-8'))

            # 文字列抽出(コントロールキャラクター削除)
            data = ''
            for ch in decoded_data:
                if ord(ch) >= 0x20:
                    data += ch
            self._log.debug('data=%a', data)

            # 文字数が0の場合、コネクションが切断されたと判断し終了
            if len(data) == 0:
                msg = 'No data .. disconnect'
                self._log.warning(msg)
                self.net_write((msg + '\r\n').encode('utf-8'))
                break

            # 制御スレッドが動いていない場合は(異常終了など?)、再起動
            if not self._ctrl.is_active():
                self._log.warning('robot control thread is dead !? .. restart')
                self._svr._ctrl = OttoPiCtrl(self._svr._pi,
                                             debug=self._svr._dbg)

                self._ctrl = self._svr._ctrl
                self._ctrl.start()

            # 自動運転スレッドが動いていない場合は(異常終了など?)、再起動
            if not self._auto.is_active():
                self._log.warning('auto control thread is dead !? .. restart')
                self._svr._auto = OttoPiAuto(self._ctrl, debug=self._svr._dbg)

                self._auto = self._svr._auto
                self._auto.start()

            # word command
            #   ex. ":.forward 2", ":happy 1", ":auto_off"
            if data[0] == OttoPiServer.CMD_PREFIX:
                cmd = data[1:]
                interrupt_flag = True

                if data[1] == OttoPiServer.CMD_PREFIX2:
                    cmd = data[2:]
                    interrupt_flag = False

                cmd_name = cmd.split()[0]

                self._log.info('cmd=%s, cmd_name=%s, interrupt_flag=%s', cmd,
                               cmd_name, interrupt_flag)
                """ dance """
                if cmd_name in ['dance_on', 'dance_true']:
                    if self._svr._dance2 is not None:
                        self._svr._dance2.end()
                        self._svr._dance2 = None

                    if self._svr._dance is None:
                        self._svr._dance = Dance(self._svr._ctrl,
                                                 max_sleep_sec=3,
                                                 debug=True)
                        self._svr._dance.start()

                    self.send_reply(data, True, '')
                    continue
                """ dance2 """
                if cmd_name in ['dance2_on', 'dance2_true']:
                    if self._svr._dance is not None:
                        self._svr._dance.end()
                        self._svr._dance = None

                    if self._svr._dance2 is None:
                        self._svr._dance2 = Dance2(self._svr._ctrl,
                                                   max_sleep_sec=3,
                                                   debug=True)
                        self._svr._dance2.start()

                    self.send_reply(data, True, '')
                    continue
                """ dance and dance2 off """
                if cmd_name in [
                        'dance_off', 'dance_false', 'dance2_off',
                        'dance2_false'
                ]:
                    if self._svr._dance is not None:
                        self._svr._dance.end()
                        self._svr._dance = None

                    if self._svr._dance2 is not None:
                        self._svr._dance2.end()
                        self._svr._dance2 = None

                    self.send_reply(data, True, '')
                    continue
                """ auto """
                if cmd.startswith(OttoPiServer.CMD_AUTO_PREFIX):
                    """
                    auto command

                    注意
                    ----
                    auto commandは、回数パラメータがないため、
                    cmd_nameだけをsendする。

                    """
                    auto_cmd = cmd.replace(OttoPiServer.CMD_AUTO_PREFIX, '')
                    cmd_name = cmd_name.replace(OttoPiServer.CMD_AUTO_PREFIX,
                                                '')
                    self._log.info('auto_cmd=%s, cmd_name=%s', auto_cmd,
                                   cmd_name)

                    if cmd_name in self._auto.cmd_func.keys():
                        d = self._auto.send(cmd_name)
                        self._log.info('d=%smm', '{:,}'.format(d))

                        self.send_reply(data, True, {'d': d})
                    else:
                        self._log.warning('%s: invalid auto command', auto_cmd)
                        self.send_reply(data, False, 'invalid auto command')

                    continue
                """ control command """
                if cmd_name in self._ctrl.cmd_func.keys():
                    self._ctrl.send(cmd, interrupt_flag)
                    self.send_reply(data, True, '')
                else:
                    msg = 'invalid control command'
                    self._log.warning('%s: %s', cmd, msg)
                    self.send_reply(data, False, msg)

                continue

            # one-key command
            for ch in data:
                self._log.info('ch=%a', ch)

                if ch not in self.cmd_key.keys():
                    self._ctrl.send(OttoPiCtrl.CMD_STOP)
                    self._log.warning('invalid 1-key command:%a .. stop', ch)
                    self.send_reply(ch, False, 'invalid 1-key command')
                    continue

                cmd = self.cmd_key[ch]
                self._log.info('cmd=%s', cmd)

                if cmd.startswith(OttoPiServer.CMD_AUTO_PREFIX):
                    # auto command
                    auto_cmd = cmd.replace(OttoPiServer.CMD_AUTO_PREFIX, '')
                    self._log.info('auto_cmd=%s', auto_cmd)

                    self._auto.send(auto_cmd)
                    self.send_reply('%s(%s)' % (ch, cmd), True, '')

                else:
                    # control command
                    self._ctrl.send(cmd)
                    self.send_reply('%s(%s)' % (ch, cmd), True, '')

        self._log.debug('done')
Esempio n. 8
0
class OttoPiAuto(threading.Thread):
    """ auto pilot """
    CMD_NULL = 'null'
    CMD_ON = 'on'
    CMD_OFF = 'off'
    CMD_ENABLE = 'enable'
    CMD_DISABLE = 'disable'
    CMD_READY = 'ready'
    CMD_END = 'end'

    DEF_RECV_TIMEOUT = 0.2  # sec

    D_TOUCH = 40
    D_TOO_NEAR = 180
    D_NEAR = 250
    D_FAR = 8000
    D_READY_MIN = D_TOUCH + 10
    D_READY_MAX = 120

    STAT_NONE = 'none'
    STAT_YELLOW = 'yellow'
    STAT_TOO_NEAR = 'too_near'
    STAT_NEAR = 'near'
    STAT_FAR = 'far'
    STAT_READY = 'ready'

    TOUCH_COUNT_COMMIT = 3
    READY_COUNT_COMMIT = 2

    def __init__(self, robot_ctrl=None, debug=False):
        """ init """
        self.dbg = debug
        self._log = get_logger(__class__.__name__, self.dbg)
        self._log.debug('')

        self.cmd_func = {
            self.CMD_NULL: self.cmd_null,
            self.CMD_ON: self.cmd_on,
            self.CMD_OFF: self.cmd_off,
            self.CMD_ENABLE: self.cmd_enable,
            self.CMD_DISABLE: self.cmd_disable,
            self.CMD_END: self.cmd_end
        }

        self.my_robot_ctrl = False
        self.robot_ctrl = robot_ctrl
        if self.robot_ctrl is None:
            self.my_robot_ctrl = True
            self.robot_ctrl = OttoPiCtrl(None, debug=self.dbg)
            self.robot_ctrl.start()

        self.tof = VL53L0X.VL53L0X()
        # self.tof.start_ranging(VL53L0X.VL53L0X_BEST_ACCURACY_MODE)
        self.tof.start_ranging(VL53L0X.VL53L0X_BETTER_ACCURACY_MODE)
        self.tof_timing = self.tof.get_timing()
        self._log.info('tof_timing = %.02f ms', self.tof_timing / 1000)
        self.d = 0

        self.cmdq = queue.Queue()

        self.active = True
        self.on = False
        self.enable = False

        self.prev_stat = self.STAT_NONE
        self.stat = self.STAT_NONE
        self.prev_rl = ""
        self.touch_count = 0
        self.ready_count = 0

        self.distance = self.D_FAR

        super().__init__(daemon=True)

    def __del__(self):
        """ del """
        self._log.debug('')

    def end(self):
        """ end """
        self._log.debug('')
        self.active = False

        self.robot_ctrl.send(OttoPiCtrl.CMD_STOP)

        if self.my_robot_ctrl:
            self.robot_ctrl.end()

        self.join()

        self.tof.stop_ranging()

        self._log.debug('done')

    def cmd_null(self):
        """ do nothing (to get distance) """
        self._log.debug('')

    def cmd_on(self):
        """ cmd on """
        self._log.debug('')
        if not self.enable:
            self._log.warning('enable=%s .. ignored', self.enable)
            return
        self.robot_ctrl.send('forward')
        self.on = True
        self.touch_count = 0
        self.stat = self.STAT_NONE

    def cmd_off(self):
        """ cmd off """
        self._log.debug('')
        self.robot_ctrl.send('stop')
        self.on = False
        self.ready_count = 0
        self.stat = self.STAT_NONE

    def cmd_enable(self):
        """ cmd enable """
        self._log.debug('')
        self.enable = True
        self._log.debug('enable=%s', self.enable)
        self.ready_count = 0
        self.stat = self.STAT_NONE

    def cmd_disable(self):
        """ cmd disable """
        self._log.debug('')
        self.cmd_off()
        self.enable = False
        self._log.debug('enable=%s', self.enable)
        self.ready_count = 0
        self.stat = self.STAT_NONE

    def cmd_end(self):
        """ cmd end """
        self._log.debug('')
        self.cmd_off()
        self.active = False

    def is_active(self):
        """ """
        self._log.debug('active=%s', self.active)
        return self.active

    def send(self, cmd):
        """ """
        self._log.debug('cmd=\'%s\'', cmd)
        self.cmdq.put(cmd)
        d = self.get_distance()
        self._log.debug('d=%smm', '{:,}'.format(d))
        return d

    def recv(self, timeout=DEF_RECV_TIMEOUT):
        """ """
        self._log.debug('timeout=%.1f', timeout)
        try:
            cmd = self.cmdq.get(timeout=timeout)
        except queue.Empty:
            cmd = ''
        else:
            self._log.debug('cmd=\'%s\'', cmd)

        return cmd

    def get_distance(self):
        """ """
        self.distance = self.tof.get_distance()
        if self.distance == 0:
            # ???
            self.distance = self.D_FAR
            self._log.warning('Crrection: distance = %smm',
                              '{:,}'.format(self.distance))

        return self.distance

    def run(self):
        """ run """
        self._log.debug('')

        while self.active:
            cmd = self.recv()
            if cmd != '':
                self._log.debug('cmd=%a', cmd)
                cmdline = cmd.split()
                cmd_name = cmdline[0]
                self._log.info('cmd_name=%a', cmd_name)
                if cmd_name in self.cmd_func.keys():
                    self.cmd_func[cmd_name]()
                else:
                    self._log.error('%s: invalid command .. ignore', cmd)

            d = self.get_distance()
            # self._log.debug('d = %smm', '{:,}'.format(d))
            if d < 0:
                continue

            if not self.enable:
                continue

            if not self.on:
                if self.ready_count > 0:
                    self._log.info('ready_count=%d/%d', self.ready_count,
                                   self.READY_COUNT_COMMIT)

                if self.ready_count < self.READY_COUNT_COMMIT:
                    if d >= self.D_READY_MIN and d <= self.D_READY_MAX:
                        self._log.warn('%dmm <= %dmm <= %dmm',
                                       self.D_READY_MIN, d, self.D_READY_MAX)
                        self.ready_count += 1
                        self.robot_ctrl.send('happy')
                        time.sleep(1)
                    else:
                        self.ready_count = 0

                else:  # self.ready_count >= self.READY_COUNT_COMMIT
                    self.cmd_on()

                continue

            self.prev_stat = self.stat

            if d <= self.D_TOUCH:
                self._log.warn('touched(%dmm <= %dmm)', d, self.D_TOUCH)
                self.robot_ctrl.send('suprised')
                time.sleep(1)

                if self.touch_count < self.TOUCH_COUNT_COMMIT:
                    self.touch_count += 1
                    self._log.info('touch_count=%d', self.touch_count)
                    if self.touch_count >= self.TOUCH_COUNT_COMMIT:
                        self._log.warn('STOP!')
                        self.cmd_off()
                        # self.robot_ctrl.send('suprised')
                        time.sleep(3)
                    else:
                        self.robot_ctrl.send('backward')
                    continue
            else:
                self.touch_count = 0

            if d <= self.D_TOO_NEAR:
                self._log.warn('TOO_NEAR(%dmm <= %dmm)', d, self.D_TOO_NEAR)
                self.stat = self.STAT_NEAR

                if self.prev_stat != self.STAT_NEAR:
                    self.robot_ctrl.send('suprised')
                    time.sleep(1)
                else:
                    self.robot_ctrl.send('backward')
                    time.sleep(2)

            elif d <= self.D_NEAR:
                self._log.warn('NEAR(%dmm <= %dmm)', d, self.D_NEAR)
                self.stat = self.STAT_NEAR
                if self.prev_stat != self.STAT_NEAR:
                    if random.random() < 0.5:
                        self.prev_rl = "right"
                        self.robot_ctrl.send('slide_right')
                    else:
                        self.prev_rl = "left"
                        self.robot_ctrl.send('slide_left')
                else:
                    if self.prev_rl == "right":
                        self.robot_ctrl.send('turn_right')
                    else:
                        self.robot_ctrl.send('turn_left')
                    time.sleep(1)
                time.sleep(1.5)

            elif d >= self.D_FAR:
                self._log.info('FAR(%dmm >= %dmm)', d, self.D_FAR)
                self.stat = self.STAT_FAR
                if self.prev_stat in [self.STAT_NEAR, self.STAT_YELLOW]:
                    self.robot_ctrl.send('forward')

            else:
                if self.prev_stat == self.STAT_NEAR:
                    self.stat = self.STAT_NONE
                    if d <= self.D_NEAR + 50:
                        self.stat = self.STAT_YELLOW
                        self._log.info('stat: %s', self.stat)
                        self.robot_ctrl.send('suriashi_fwd')
                    else:
                        self._log.info('stat: %s', self.stat)
                        self.robot_ctrl.send('forward')

            self.touch_count = 0
            self._log.debug('stat=%s', self.stat)

        self._log.info('done(active=%s)', self.active)