当前位置:   article > 正文

ROS语音控制——小乌龟按设定图形路线运动_语音识别控制小海龟

语音识别控制小海龟

最近几天在学习语音识别、语音合成,应用到ROS当中实现一些简单的案例,下面是使用语音来控制turtle小乌龟走设定图形路线的案例。

ROS小乌龟走设定图形路线(键盘控制+Python代码实现)_笨小古的博客-CSDN博客

在上面代码的基础上加了一个语音控制函数 :

  1. # 接收到语音命令后发布速度指令
  2. def get_voice(data):
  3. voice_text=data.data
  4. rospy.loginfo("语音已接收")
  5. if voice_text == "走圆圈。":
  6. name = 'circle'
  7. rospy.loginfo("I said:: %s",voice_text)
  8. Turtlerun(name)
  9. elif voice_text == "走方形。":
  10. name = 'squ'
  11. rospy.loginfo("I said:: %s",voice_text)
  12. Turtlerun(name)
  13. elif voice_text == "走漏斗形。":
  14. name = 'hourglass'
  15. rospy.loginfo("I said:: %s",voice_text)
  16. Turtlerun(name)
  17. elif voice_text == "走60度三角形。":
  18. name = 'tri60'
  19. rospy.loginfo("I said:: %s",voice_text)
  20. Turtlerun(name)
  21. elif voice_text == "走直角三角形。":
  22. name = 'tri90'
  23. rospy.loginfo("I said:: %s",voice_text)
  24. Turtlerun(name)

完整代码:

  1. #!/usr/bin/env python3
  2. # coding: utf-8
  3. import math
  4. import rospy
  5. import sys
  6. from turtlesim.msg import Pose # Pose数据类型包含乌龟的坐标和角度
  7. from geometry_msgs.msg import Twist # Twist数据类型包含线速度和角速度
  8. from std_msgs.msg import String
  9. class Turtle:
  10. def __init__(self, name, graph):
  11. rospy.init_node(name) # 初始化节点
  12. rospy.Subscriber('/turtle1/pose', Pose, self.control) # 实例化订阅者,参数为订阅的话题名,消息类型,回调函数
  13. self.pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10) # 实例化发布者,参数为发布的话题名,消息类型,队列长度
  14. self._graph = graph
  15. self.size = 5 # 图形的大小(3-5)
  16. self.kp1 = 6 # 走直线的比例控制参数
  17. self.kp2 = 4 # 转角度的比例控制参数
  18. self.kd = 0 # 走直线的微分控制参数
  19. self.aim = 0.025 # 直走的误差值
  20. self.aim_rotate = 0.005 # 转弯的误差值
  21. self.vel_cmd = Twist() # 实例化Twist消息类型的消息
  22. self.point = {} # 储存所走路径目标点
  23. self.x = None # 乌龟目前所在x坐标
  24. self.y = None # 乌龟目前所在y坐标
  25. self.theta = None # 乌龟目前角度
  26. self.goal = 0 # 乌龟下一个要到达的目标点
  27. self.error = None # 现在距离目标点的误差值
  28. self.flag = 0 # flag和lock实现走直线和转角度的互锁,执行完一个才能执行另一个
  29. self.lock = 0
  30. self.key = 0
  31. self.theta_list = []
  32. self.speed = 4 # 控制旋转时的方向,顺or逆
  33. def control(self, pose):
  34. """订阅的回调函数"""
  35. self.choose_graph(self._graph, pose) # 设定要走什么形状
  36. def choose_graph(self, graph, pose):
  37. """根据传入的图形设定目标点,获取当前位置,控制运动"""
  38. self.set_goal_points(pose, self.size)
  39. rospy.loginfo(self.point['squ'][0][0])
  40. self.get_present_point(pose)
  41. self.go_graph(graph, self.kp1, self.kp2, self.kd, self.aim)
  42. def set_goal_points(self, pose, size=5):
  43. """设定不同形状的目标点,坐标和角度"""
  44. if self.key == 0: # 只设定一次
  45. self.point = {
  46. 'squ': [
  47. [pose.x + size, pose.y, math.pi / 2],
  48. [pose.x + size, pose.y + size, math.pi],
  49. [pose.x, pose.y + size, - math.pi / 2],
  50. [pose.x, pose.y, 0],
  51. ],
  52. 'squ2': [
  53. [pose.x + size, pose.y, -math.pi / 2],
  54. [pose.x + size, pose.y - size, -math.pi],
  55. [pose.x, pose.y - size, math.pi / 2],
  56. [pose.x, pose.y, 0],
  57. ],
  58. 'squ3': [
  59. [pose.x, pose.y, math.pi / 2],
  60. [pose.x, pose.y + size, 0],
  61. [pose.x + size, pose.y + size, -math.pi / 2],
  62. [pose.x + size, pose.y, -math.pi]
  63. ],
  64. 'rec': [
  65. [pose.x + 5, pose.y, math.pi / 2],
  66. [pose.x + 5, pose.y + 3, math.pi],
  67. [pose.x, pose.y + 3, math.pi / 2],
  68. [pose.x, pose.y, 0],
  69. ],
  70. 'tri_60': [
  71. [pose.x + size, pose.y, math.pi * 2 / 3],
  72. [pose.x + size / 2, pose.y + (size / 2 * math.tan(math.pi / 3)), - math.pi * 2 / 3],
  73. [pose.x, pose.y, 0]
  74. ],
  75. 'tri_60_2': [
  76. [pose.x + size, pose.y, -math.pi * 2 / 3],
  77. [pose.x + size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), math.pi * 2 / 3],
  78. [pose.x, pose.y, 0]
  79. ],
  80. 'tri_60_3': [
  81. [pose.x, pose.y, -math.pi / 3],
  82. [pose.x + size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), -math.pi],
  83. [pose.x - size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), math.pi / 3]
  84. ],
  85. 'hourglass': [
  86. [pose.x, pose.y, -math.pi / 3],
  87. [pose.x + 3 / 2, pose.y - (3 / 2 * math.tan(math.pi / 3)), -math.pi],
  88. [pose.x - 3 / 2, pose.y - (3 / 2 * math.tan(math.pi / 3)), math.pi / 3],
  89. [pose.x + 3 / 2, pose.y + (3 / 2 * math.tan(math.pi / 3)), math.pi],
  90. [pose.x - 3 / 2, pose.y + (3 / 2 * math.tan(math.pi / 3)), -math.pi / 3]
  91. ],
  92. 'tri_90': [
  93. [pose.x + size, pose.y, math.pi / 2],
  94. [pose.x + size, pose.y + size, -3 * math.pi / 4],
  95. [pose.x, pose.y, 0]
  96. ]
  97. }
  98. self.key += 1
  99. def get_present_point(self, pose):
  100. """获取当前坐标和角度"""
  101. self.x = pose.x
  102. self.y = pose.y
  103. self.theta = pose.theta
  104. def go_graph(self, graph, kp1=4, kp2=4, kd=15, aim=0.025):
  105. """控制运动"""
  106. self.go_line(graph, kp1, kd, aim)
  107. self.rotate(graph, kp2)
  108. def set_goal(self, graph):
  109. """设定下一个目标点"""
  110. if self.lock == 1:
  111. print(self.goal)
  112. self.goal = self.goal + 1 if self.goal != len(self.point[graph]) - 1 else 0
  113. def go_line(self, graph, kp=2, kd=15, aim=0.08, ):
  114. """控制走直线"""
  115. if self.lock == 0: # 和旋转互锁
  116. if self.flag == 0: # 第一次进函数执行一次初始化
  117. self.error = self.size # 初始误差为设定的图形大小
  118. self.flag += 1 # 保证初始化只执行一次
  119. last_error = self.error # 上一次的误差
  120. self.error = math.sqrt(
  121. (self.x - self.point[graph][self.goal][0]) ** 2 + (
  122. self.y - self.point[graph][self.goal][1]) ** 2) # 计算现在的误差
  123. if abs(self.error) > aim: # 误差大于设定精度时前进
  124. self.vel_cmd.linear.x = kp * self.error + kd * (self.error - last_error) # pd控制计算当前速度
  125. rospy.loginfo('mode:going')
  126. rospy.loginfo('goal:{},error:{},speed:{}'.format(self.goal, self.error, self.vel_cmd.linear.x))
  127. else:
  128. self.vel_cmd.linear.x = 0
  129. self.lock = 1 # 解锁旋转
  130. self.pub.publish(self.vel_cmd) # 发布乌龟速度
  131. def rotate(self, graph, kp=2):
  132. """控制旋转"""
  133. if self.lock == 1: # 和直走互锁
  134. if self.flag == 1: # 第一次进函数执行一次初始化函数
  135. self.set_goal(graph)
  136. theta1 = self.theta + 2 * math.pi if self.theta < 0 else self.theta # 将现在的角度换算成0-2π
  137. theta2 = theta1 + math.pi if theta1 <= math.pi else theta1 - math.pi # 和现在的角度差π的角
  138. target = self.point[graph][self.goal - 1][2] + 2 * math.pi if self.point[graph][self.goal - 1][2] < 0 \
  139. else self.point[graph][self.goal - 1][2] # 将目标角度换算到0-2π
  140. self.speed = kp if theta1 < target < theta2 or theta1 > theta2 and not (theta1 > target > theta2) \
  141. else -kp # 判断顺时针转还是逆时针转距离最短
  142. self.flag += 1 # 保证只执行一次初始化
  143. self.error = abs(self.theta - self.point[graph][self.goal - 1][2]) # 计算当前误差
  144. if self.error > self.aim_rotate: # 误差大于0.01时保持旋转
  145. self.vel_cmd.angular.z = self.speed * (self.error + 0.1) # p控制计算旋转速度
  146. rospy.loginfo('mode:rotating')
  147. rospy.loginfo('goal:{},error:{},speed:{}'.format(self.goal, self.error, self.vel_cmd.angular.z))
  148. else:
  149. self.vel_cmd.angular.z = 0
  150. self.flag = 0
  151. self.lock = 0
  152. self.pub.publish(self.vel_cmd) # 发布乌龟速度
  153. # 接收到语音命令后发布速度指令
  154. def get_voice(data):
  155. voice_text=data.data
  156. rospy.loginfo("语音已接收")
  157. if voice_text == "走方形。" or "squ":
  158. name = 'squ'
  159. rospy.loginfo("I said:: %s",voice_text)
  160. Turtle('voice_teleop',name)
  161. # Turtlerun.goal = Turtlerun.goals['squ']
  162. elif voice_text == "走漏斗形。":
  163. name = 'hourglass'
  164. rospy.loginfo("I said:: %s",voice_text)
  165. Turtle('voice_teleop',name)
  166. # Turtlerun.goal = Turtlerun.goals['hourglass']
  167. elif voice_text == "走60度三角形。":
  168. name = 'tri60'
  169. rospy.loginfo("I said:: %s",voice_text)
  170. Turtle('voice_teleop',name)
  171. # Turtlerun.goal = Turtlerun.goals['tri60']
  172. elif voice_text == "走直角三角形。":
  173. name = 'tri90'
  174. rospy.loginfo("I said:: %s",voice_text)
  175. Turtle('voice_teleop',name)
  176. if __name__ == '__main__':
  177. a = input("选择控制方式:1.命令行;2.语音控制\n")
  178. a = int(a)
  179. if a == 1:
  180. graph_list = ['circle', 'squ', 'tri60', 'tri90', 'hourglass']
  181. # print("input")
  182. # print("-------",sys.argv)
  183. if len(sys.argv) > 1 and sys.argv[1] in graph_list: # 实现rosrun xx yy.py squ直接跑对应图形
  184. name = sys.argv[1]
  185. # print("input finish")
  186. else:
  187. name = input(
  188. 'Please input graph name(circle squ tri60 tri90 hourglass): ') # 没在命令输对图形名称时提示输入
  189. try:
  190. name = str(name)
  191. Turtle('voice_graph',name)
  192. rospy.spin()
  193. except rospy.ROSInterruptException:
  194. pass
  195. else:
  196. rospy.init_node('voice_teleop')
  197. while not rospy.is_shutdown():
  198. rospy.loginfo("Starting voice Teleop")
  199. # 订阅语音识别的输出字符
  200. rospy.Subscriber("/voiceWords", String, get_voice)
  201. rospy.spin()

 这里的语音功能包使用的是科大讯飞的,需要到科大讯飞网站注册帐号(需要APPID),讯飞开放平台-以语音交互为核心的人工智能开放平台

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/671529
推荐阅读
相关标签
  

闽ICP备14008679号