00001
00002
00003 """
00004 voice_nav.py - Version 1.1 2013-12-20
00005
00006 Allows controlling a mobile base using simple speech commands.
00007
00008 Based on the voice_cmd_vel.py script by Michael Ferguson in
00009 the pocketsphinx ROS package.
00010
00011 See http://www.ros.org/wiki/pocketsphinx
00012 """
00013 import rospy
00014 from geometry_msgs.msg import Twist
00015 from std_msgs.msg import String
00016 from math import copysign
00017
00018 class VoiceNav:
00019 def __init__(self):
00020
00021 rospy.init_node('voice_teleop')
00022 rospy.on_shutdown(self.cleanup)
00023
00024
00025 self.max_speed = rospy.get_param("~max_speed", 0.4)
00026 self.max_angular_speed = rospy.get_param("~max_angular_speed", 1.5)
00027 self.speed = rospy.get_param("~start_speed", 0.1)
00028 self.angular_speed = rospy.get_param("~start_angular_speed", 0.5)
00029 self.linear_increment = rospy.get_param("~linear_increment", 0.05)
00030 self.angular_increment = rospy.get_param("~angular_increment", 0.4)
00031
00032
00033 self.rate = rospy.get_param("~rate", 5)
00034 r = rospy.Rate(self.rate)
00035
00036
00037 self.paused = False
00038
00039
00040 self.cmd_vel = Twist()
00041
00042
00043 self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)
00044
00045
00046 rospy.Subscriber('/recognizer/output', String, self.speech_callback)
00047
00048
00049
00050 self.keywords_to_command = {'stop': ['stop', 'halt', 'abort', 'kill', 'panic', 'off', 'freeze', 'shut down', 'turn off', 'help', 'help me'],
00051 'slower': ['slow down', 'slower'],
00052 'faster': ['speed up', 'faster'],
00053 'forward': ['forward', 'ahead', 'straight'],
00054 'backward': ['back', 'backward', 'back up'],
00055 'rotate left': ['rotate left'],
00056 'rotate right': ['rotate right'],
00057 'turn left': ['turn left'],
00058 'turn right': ['turn right'],
00059 'quarter': ['quarter speed'],
00060 'half': ['half speed'],
00061 'full': ['full speed'],
00062 'pause': ['pause speech'],
00063 'continue': ['continue speech']}
00064
00065 rospy.loginfo("Ready to receive voice commands")
00066
00067
00068 while not rospy.is_shutdown():
00069 self.cmd_vel_pub.publish(self.cmd_vel)
00070 r.sleep()
00071
00072 def get_command(self, data):
00073
00074
00075
00076 for (command, keywords) in self.keywords_to_command.iteritems():
00077 for word in keywords:
00078 if data.find(word) > -1:
00079 return command
00080
00081 def speech_callback(self, msg):
00082
00083 command = self.get_command(msg.data)
00084
00085
00086 rospy.loginfo("Command: " + str(command))
00087
00088
00089
00090 if command == 'pause':
00091 self.paused = True
00092 elif command == 'continue':
00093 self.paused = False
00094
00095
00096
00097 if self.paused:
00098 return
00099
00100
00101
00102 if command == 'forward':
00103 self.cmd_vel.linear.x = self.speed
00104 self.cmd_vel.angular.z = 0
00105
00106 elif command == 'rotate left':
00107 self.cmd_vel.linear.x = 0
00108 self.cmd_vel.angular.z = self.angular_speed
00109
00110 elif command == 'rotate right':
00111 self.cmd_vel.linear.x = 0
00112 self.cmd_vel.angular.z = -self.angular_speed
00113
00114 elif command == 'turn left':
00115 if self.cmd_vel.linear.x != 0:
00116 self.cmd_vel.angular.z += self.angular_increment
00117 else:
00118 self.cmd_vel.angular.z = self.angular_speed
00119
00120 elif command == 'turn right':
00121 if self.cmd_vel.linear.x != 0:
00122 self.cmd_vel.angular.z -= self.angular_increment
00123 else:
00124 self.cmd_vel.angular.z = -self.angular_speed
00125
00126 elif command == 'backward':
00127 self.cmd_vel.linear.x = -self.speed
00128 self.cmd_vel.angular.z = 0
00129
00130 elif command == 'stop':
00131
00132 self.cmd_vel = Twist()
00133
00134 elif command == 'faster':
00135 self.speed += self.linear_increment
00136 self.angular_speed += self.angular_increment
00137 if self.cmd_vel.linear.x != 0:
00138 self.cmd_vel.linear.x += copysign(self.linear_increment, self.cmd_vel.linear.x)
00139 if self.cmd_vel.angular.z != 0:
00140 self.cmd_vel.angular.z += copysign(self.angular_increment, self.cmd_vel.angular.z)
00141
00142 elif command == 'slower':
00143 self.speed -= self.linear_increment
00144 self.angular_speed -= self.angular_increment
00145 if self.cmd_vel.linear.x != 0:
00146 self.cmd_vel.linear.x -= copysign(self.linear_increment, self.cmd_vel.linear.x)
00147 if self.cmd_vel.angular.z != 0:
00148 self.cmd_vel.angular.z -= copysign(self.angular_increment, self.cmd_vel.angular.z)
00149
00150 elif command in ['quarter', 'half', 'full']:
00151 if command == 'quarter':
00152 self.speed = copysign(self.max_speed / 4, self.speed)
00153
00154 elif command == 'half':
00155 self.speed = copysign(self.max_speed / 2, self.speed)
00156
00157 elif command == 'full':
00158 self.speed = copysign(self.max_speed, self.speed)
00159
00160 if self.cmd_vel.linear.x != 0:
00161 self.cmd_vel.linear.x = copysign(self.speed, self.cmd_vel.linear.x)
00162
00163 if self.cmd_vel.angular.z != 0:
00164 self.cmd_vel.angular.z = copysign(self.angular_speed, self.cmd_vel.angular.z)
00165
00166 else:
00167 return
00168
00169 self.cmd_vel.linear.x = min(self.max_speed, max(-self.max_speed, self.cmd_vel.linear.x))
00170 self.cmd_vel.angular.z = min(self.max_angular_speed, max(-self.max_angular_speed, self.cmd_vel.angular.z))
00171
00172 def cleanup(self):
00173
00174 twist = Twist()
00175 self.cmd_vel_pub.publish(twist)
00176 rospy.sleep(1)
00177
00178 if __name__=="__main__":
00179 try:
00180 VoiceNav()
00181 rospy.spin()
00182 except rospy.ROSInterruptException:
00183 rospy.loginfo("Voice navigation terminated.")