mirror of
https://github.com/undera/pylgbst.git
synced 2020-11-18 19:37:26 -08:00
* Cosmetics * Harmonograph demo * Cleanup * Original * Original * Cosmetics * Original file * Fixes * cosmetics * separate classes * Cosmetics * Cosmetics * fix tests * Remove plotter tests * Add bluegiga * Rename it * Progress * Fix tests * Cosmetics * Found a way for pygatt! * Playing with gatt * Fix hung subscribe * rename class * add test * skeleton for autodetect * safer order * Fix tests * Fix test * Add dbus install * another try * 2 * 3 * 34 * 6 * 7 * Isolate some tests * 8 * back to roots * Try more * 9 * Help * rep * site-packs * Fix? * Py3 come on * dbus * busss * dev null! * Fix test * Cleanup * Fix tests * Fix after review * add package * FIx package paths * Cosmetics * Update * More doc
182 lines
6.3 KiB
Python
182 lines
6.3 KiB
Python
# coding=utf-8
|
|
import hashlib
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import time
|
|
|
|
from pylgbst import *
|
|
from pylgbst.comms import DebugServerConnection
|
|
from pylgbst.movehub import MoveHub
|
|
|
|
try:
|
|
import gtts
|
|
|
|
|
|
def say(text):
|
|
print("%s" % text)
|
|
if isinstance(text, str):
|
|
text = text.decode("utf-8")
|
|
md5 = hashlib.md5(text.encode('utf-8')).hexdigest()
|
|
fname = "/tmp/%s.mp3" % md5
|
|
if not os.path.exists(fname):
|
|
myre = re.compile('[[A-Za-z]', re.UNICODE)
|
|
lang = 'en' if myre.match(text) else 'ru'
|
|
|
|
logging.getLogger('requests').setLevel(logging.getLogger('').getEffectiveLevel())
|
|
tts = gtts.gTTS(text=text, lang=lang, slow=False)
|
|
tts.save(fname)
|
|
|
|
with open(os.devnull, 'w') as fnull:
|
|
subprocess.call("mplayer %s" % fname, shell=True, stderr=fnull, stdout=fnull)
|
|
except BaseException:
|
|
def say(text):
|
|
print("%s" % text)
|
|
|
|
forward = FORWARD = right = RIGHT = 1
|
|
backward = BACKWARD = left = LEFT = -1
|
|
straight = STRAIGHT = 0
|
|
|
|
SPEECH_LANG_MAP = {
|
|
'en': {
|
|
'ready': "Vernie the Robot is ready.",
|
|
"commands help": "Available commands are: "
|
|
"forward, backward, turn left, turn right, "
|
|
"head left, head right, head straight, shot and say",
|
|
"finished": "Thank you! Robot is now turning off",
|
|
"text is empty": "Please, enter not empty text to say!"
|
|
},
|
|
"ru": {
|
|
"ready": "Робот Веернии готов к работе",
|
|
"type commands": "печатайте команды",
|
|
"ok": "хорошо",
|
|
"commands help": "Доступные команды это: вперёд, назад, влево, вправо, "
|
|
"голову влево, голову вправо, голову прямо, выстрел, скажи",
|
|
"finished": "Робот завершает работу. Спасибо!",
|
|
"commands from file": "Исполняю команды из файла",
|
|
"fire": "Выстрел!",
|
|
"text is empty": "Пожалуйста, наберите не пустой текст!"
|
|
}
|
|
}
|
|
|
|
VERNIE_TO_MOTOR_DEGREES = 2.6
|
|
VERNIE_SINGLE_MOVE = 430
|
|
|
|
|
|
class Vernie(MoveHub):
|
|
def __init__(self, language='en'):
|
|
try:
|
|
conn = DebugServerConnection()
|
|
except BaseException:
|
|
logging.warning("Failed to use debug server: %s", traceback.format_exc())
|
|
conn = get_connection_auto()
|
|
|
|
super(Vernie, self).__init__(conn)
|
|
self.language = language
|
|
|
|
while True:
|
|
required_devices = (self.color_distance_sensor, self.motor_external)
|
|
if None not in required_devices:
|
|
break
|
|
log.debug("Waiting for required devices to appear: %s", required_devices)
|
|
time.sleep(1)
|
|
|
|
self._head_position = 0
|
|
self.motor_external.subscribe(self._external_motor_data)
|
|
|
|
self._reset_head()
|
|
self.say("ready")
|
|
time.sleep(1)
|
|
|
|
def say(self, phrase):
|
|
if phrase in SPEECH_LANG_MAP[self.language]:
|
|
phrase = SPEECH_LANG_MAP[self.language][phrase]
|
|
say(phrase)
|
|
|
|
def _external_motor_data(self, data):
|
|
log.debug("External motor position: %s", data)
|
|
self._head_position = data
|
|
|
|
def _reset_head(self):
|
|
self.motor_external.timed(1, -0.2)
|
|
self.head(RIGHT, angle=45)
|
|
|
|
def head(self, direction=RIGHT, angle=25, speed=0.1):
|
|
if direction == STRAIGHT:
|
|
angle = -self._head_position
|
|
direction = 1
|
|
|
|
self.motor_external.angled(direction * angle, speed)
|
|
|
|
def turn(self, direction, degrees=90, speed=0.3):
|
|
self.head(STRAIGHT, speed=0.5)
|
|
self.head(direction, 35, 1)
|
|
self.motor_AB.angled(int(VERNIE_TO_MOTOR_DEGREES * degrees), speed * direction, -speed * direction)
|
|
self.head(STRAIGHT, speed=0.5)
|
|
|
|
def move(self, direction, distance=1, speed=0.2):
|
|
self.head(STRAIGHT, speed=0.5)
|
|
self.motor_AB.angled(distance * VERNIE_SINGLE_MOVE, speed * direction, speed * direction)
|
|
|
|
def shot(self):
|
|
self.motor_external.timed(0.5)
|
|
self.head(STRAIGHT)
|
|
self.head(STRAIGHT)
|
|
|
|
def interpret_command(self, cmd, confirm):
|
|
cmd = cmd.strip().lower().split(' ')
|
|
if cmd[0] in ("head", "голова", "голову"):
|
|
if cmd[-1] in ("right", "вправо", "направо"):
|
|
confirm(cmd)
|
|
self.head(RIGHT)
|
|
elif cmd[-1] in ("left", "влево", "налево"):
|
|
confirm(cmd)
|
|
self.head(LEFT)
|
|
else:
|
|
confirm(cmd)
|
|
self.head(STRAIGHT)
|
|
elif cmd[0] in ("say", "скажи", "сказать"):
|
|
if not cmd[1:]:
|
|
self.say("text is empty")
|
|
return
|
|
say(' '.join(cmd[1:]))
|
|
elif cmd[0] in ("fire", "shot", "огонь", "выстрел"):
|
|
say("fire")
|
|
self.shot()
|
|
elif cmd[0] in ("end", "finish", "конец", "стоп"):
|
|
self.say("finished")
|
|
raise KeyboardInterrupt()
|
|
elif cmd[0] in ("forward", "вперёд", "вперед"):
|
|
try:
|
|
dist = int(cmd[-1])
|
|
except BaseException:
|
|
dist = 1
|
|
confirm(cmd)
|
|
self.move(FORWARD, distance=dist)
|
|
elif cmd[0] in ("backward", "назад"):
|
|
try:
|
|
dist = int(cmd[-1])
|
|
except BaseException:
|
|
dist = 1
|
|
confirm(cmd)
|
|
self.move(BACKWARD, distance=dist)
|
|
elif cmd[0] in ("turn", "поворот", 'повернуть'):
|
|
if cmd[-1] in ("right", "вправо", "направо"):
|
|
confirm(cmd)
|
|
self.turn(RIGHT)
|
|
elif cmd[-1] in ("left", "влево", "налево"):
|
|
confirm(cmd)
|
|
self.turn(LEFT)
|
|
else:
|
|
confirm(cmd)
|
|
self.turn(RIGHT, degrees=180)
|
|
elif cmd[0] in ("right", "вправо", "направо"):
|
|
confirm(cmd)
|
|
self.turn(RIGHT)
|
|
elif cmd[0] in ("left", "влево", "налево"):
|
|
confirm(cmd)
|
|
self.turn(LEFT)
|
|
elif cmd[0]:
|
|
self.say("Unknown command")
|
|
self.say("commands help")
|