9.4 Скрипт навигации с голосовым управлением

Узел recognizer.py в пакете pocketsphinx публикует распознанные речевые команды в разделе /ognizer / output. Чтобы сопоставить эти команды действиям робота, нам нужен второй узел, который подписывается на эту тему, ищет соответствующие сообщения, а затем заставляет робота выполнять различные действия в зависимости от полученного сообщения. Для начала Майкл Фергюсон включает скрипт Python voice_cmd_vel.py в пакет pocketsphinx, который отображает голосовые команды в сообщения Twist, которые можно использовать для управления мобильным роботом. Мы будем использовать слегка измененную версию этого скрипта с именем voice_nav.py, которая находится в подкаталоге rbx1_speech / node.

Давайте теперь посмотрим на скрипт voice_nav.py.

Ссылка на источник: voice_nav.py

#!/usr/bin/env python
"""
Based on the voice_cmd_vel.py script by Michael Ferguson in the pocketsphinx ROS package.
See http://wiki.ros.org/pocketsphinx
""" 
import rospy
from geometry_msgs.msg import Twist
from std_msgs.msg import String
from math import copysign
class VoiceNav:
def __init__(self):
rospy.init_node('voice_nav')
rospy.on_shutdown(self.cleanup) 21
# Set a number of parameters affecting the robot's speed
self.max_speed = rospy.get_param("~max_speed", 0.4)
self.max_angular_speed = rospy.get_param("~max_angular_speed", 1.5)
self.speed = rospy.get_param("~start_speed", 0.1)
self.angular_speed = rospy.get_param("~start_angular_speed", 0.5)
self.linear_increment = rospy.get_param("~linear_increment", 0.05)
self.angular_increment = rospy.get_param("~angular_increment", 0.4)
# We don't have to run the script very fast
self.rate = rospy.get_param("~rate", 5)
r = rospy.Rate(self.rate)
# A flag to determine whether or not voice control is paused
self.paused = False
# Initialize the Twist message we will publish.
self.cmd_vel = Twist()
# Publish the Twist message to the cmd_vel topic
self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
# Subscribe to the /recognizer/output topic to receive voice commands.
rospy.Subscriber('/recognizer/output', String, self.speech_callback)
# A mapping from keywords or phrases to commands
self.keywords_to_command = {'stop': ['stop', 'halt', 'abort', 'kill',
'panic', 'off', 'freeze', 'shut down', 'turn off', 'help', 'help me'],
'slower': ['slow down', 'slower'],
'faster': ['speed up', 'faster'],
'forward': ['forward', 'ahead',
'straight'],
'backward': ['back', 'backward', 'back up'],
'rotate left': ['rotate left'],
'rotate right': ['rotate right'],
'turn left': ['turn left'],
'turn right': ['turn right'],
'quarter': ['quarter speed'],
'half': ['half speed'],
'full': ['full speed'],
'pause': ['pause speech'],
'continue': ['continue speech']}
rospy.loginfo("Ready to receive voice commands")
# We have to keep publishing the cmd_vel message if we want # the robot to keep moving.
while not rospy.is_shutdown(): self.cmd_vel_pub.publish(self.cmd_vel) r.sleep()
for word in keywords: if data.find(word) return command
def speech_callback(self, msg):
# Get the motion command from the recognized phrase command = self.get_command(msg.data)
# Log the command to the screen
rospy.loginfo("Command: " + str(command))
# If the user has asked to pause/continue voice control, # set the flag accordingly
if command == 'pause':
self.paused = True elif command == 'continue':
self.paused = False
# If voice control is paused, simply return without # performing any action
if self.paused:
return
# The list of if-then statements should be fairly # self-explanatory
if command == 'forward':
self.cmd_vel.linear.x = self.speed self.cmd_vel.angular.z = 0
elif command == 'rotate left': self.cmd_vel.linear.x = 0 self.cmd_vel.angular.z = self.angular_speed
elif command == 'rotate right': self.cmd_vel.linear.x = 0 self.cmd_vel.angular.z = -self.angular_speed
elif command == 'turn left':
if self.cmd_vel.linear.x != 0:
self.cmd_vel.angular.z += self.angular_increment else:
self.cmd_vel.angular.z = self.angular_speed
def get_command(self, data):
# Attempt to match the recognized word or phrase to the
# keywords_to_command dictionary and return the appropriate # command
for (command, keywords) in
self.keywords_to_command.iteritems():
elif command == 'turn right':
if self.cmd_vel.linear.x != 0:
self.cmd_vel.angular.z -= self.angular_increment else:
self.cmd_vel.angular.z = -self.angular_speed
elif command == 'backward': self.cmd_vel.linear.x = -self.speed self.cmd_vel.angular.z = 0
elif command == 'stop':
# Stop the robot! Publish a Twist message consisting of all
self.cmd_vel = Twist()
self.cmd_vel.linear.x)
if self.cmd_vel.angular.z != 0:
self.cmd_vel.angular.z += copysign(self.angular_increment, self.cmd_vel.angular.z)
elif command == 'faster':
self.speed += self.linear_increment self.angular_speed += self.angular_increment if self.cmd_vel.linear.x != 0:
self.cmd_vel.linear.x += copysign(self.linear_increment,
self.cmd_vel.linear.x)
144 if self.cmd_vel.angular.z != 0:
145 self.cmd_vel.angular.z -= copysign(self.angular_increment, self.cmd_vel.angular.z)
elif command == 'slower':
self.speed -= self.linear_increment self.angular_speed -= self.angular_increment if self.cmd_vel.linear.x != 0:
self.cmd_vel.linear.x) 159
self.cmd_vel.linear.x -= copysign(self.linear_increment,
elif command in ['quarter', 'half', 'full']: if command == 'quarter':
self.speed = copysign(self.max_speed / 4, self.speed) elif command == 'half':
self.speed = copysign(self.max_speed / 2, self.speed) elif command == 'full':
self.speed = copysign(self.max_speed, self.speed) if self.cmd_vel.linear.x != 0:
self.cmd_vel.linear.x = copysign(self.speed,
if self.cmd_vel.angular.z != 0:
self.cmd_vel.angular.z = copysign(self.angular_speed, self.cmd_vel.angular.z)
else:
return
self.cmd_vel.linear.x = min(self.max_speed, max(-self.max_speed, self.cmd_vel.linear.x))
self.cmd_vel.angular.z = min(self.max_angular_speed, max(- self.max_angular_speed, self.cmd_vel.angular.z))
def cleanup(self):
# When shutting down be sure to stop the robot!
twist = Twist()
self.cmd_vel_pub.publish(twist)
rospy.sleep(1)
if __name__=="__main__":
try:
    VoiceNav()
rospy.spin()
except rospy.ROSInterruptException:
rospy.loginfo("Voice navigation terminated.")

Сценарий довольно прост и тщательно прокомментирован, поэтому мы опишем только основные моменты.

# A mapping from keywords or phrases to commands
self.keywords_to_command = {'stop': ['stop', 'halt', 'abort', 'kill',
'panic', 'off', 'freeze', 'shut down', 'turn off', 'help', 'help me'],
'slower': ['slow down', 'slower'],
'faster': ['speed up', 'faster'],
'forward': ['forward', 'ahead',
'straight'],
'backward': ['back', 'backward', 'back up'],
'rotate left': ['rotate left'],
'rotate right': ['rotate right'],
'turn left': ['turn left'],
'turn right': ['turn right'],
'quarter': ['quarter speed'],
'half': ['half speed'],
'full': ['full speed'],
'pause': ['pause speech'],
'continue': ['continue speech']}

Dictionary_to_command Python Dictionary позволяет нам отображать различные словесные произведения и фразы в одном действии. Например, очень важно иметь возможность остановить робота, когда он движется. Однако слово «стоп» не всегда распознается распознавателем PocketSphinx. Таким образом, мы предлагаем несколько альтернативных способов сказать роботу об остановке, таких как «остановка», «отмена», «помощь» и т. Д. Конечно, эти альтернативы должны быть включены в наш оригинальный словарь PocketSphinx (корпус).

Узел voice_nav.py подписывается на тему /ognizer / output и ищет распознанные ключевые слова, как указано в корпусе nav_commands.txt. Если совпадение найдено, словарь keys_to_commands отображает сопоставленную фразу в соответствующее командное слово. Затем наша функция обратного вызова отображает командное слово в соответствующее действие Twist, отправленное роботу.

Еще одна особенность скрипта voice_nav.py заключается в том, что он будет реагировать на две специальные команды: «приостановить речь» и «продолжить речь». Если вы голосом управляете своим роботом, но вы хотите сказать что-то другому человеку, при этом робот не интерпретирует ваши слова как команды движения, просто скажите «приостановить речь». Если вы хотите продолжить управлять роботом, скажите «продолжить речь».

Last updated