最近几天在学习语音识别、语音合成,应用到ROS当中实现一些简单的案例,下面是使用语音来控制turtle小乌龟走设定图形路线的案例。
ROS小乌龟走设定图形路线(键盘控制+Python代码实现)_笨小古的博客-CSDN博客
在上面代码的基础上加了一个语音控制函数 :
# 接收到语音命令后发布速度指令
def get_voice(data):
voice_text=data.data
rospy.loginfo("语音已接收")
if voice_text == "走圆圈。":
name = 'circle'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走方形。":
name = 'squ'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走漏斗形。":
name = 'hourglass'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走60度三角形。":
name = 'tri60'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走直角三角形。":
name = 'tri90'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
完整代码:
#! /usr/bin/env python2
# coding:UTF-8
import math
import rospy
import sys
from turtlesim.msg import Pose # Pose数据类型包含坐标和角度
from geometry_msgs.msg import Twist # Twist数据类型包含线速度和角速度
from std_msgs.msg import String
class Turtlerun:
""" 一个乌龟走图形路线的类 """
def __init__(self, graph):
""" 初始化 """
self.pub = rospy.Publisher("/turtle1/cmd_vel", Twist, queue_size=10) # 实例化发布者
rospy.Subscriber("/turtle1/pose", Pose, self.control, queue_size=10) # 实例化订阅者
self.twist = Twist()
self.graph = graph
self.x = None # 乌龟目前所在x坐标
self.y = None # 乌龟目前所在y坐标
self.size = 3.0 # 图形边长大小
self.rate = rospy.Rate(100) # 循环频率
self.theta = None # 乌龟初始角度
self.goal = [] # 选择的图形目标点
self.goals = {} # 储存的图形目标点
self.error = None # 距离目标点的差值
self.lock = 0 # 直线行走与旋转互锁
self.side = 0 # 乌龟移动目标点的索引值
self.aim_line = 0.035 # 乌龟转弯前走直线时距离目标距离的精度值
self.aim_angle = 0.01 # 乌龟直走前转弯时距离目标角度的精度值
self.i = 1
self.turns = 0
self.num = None # 图形边数索引量
def control(self, pose):
"""订阅的回调函数"""
self.turtle_run(self.graph, pose) # 设定要走什么形状
def turtle_run(self, graph, pose):
""" 控制乌龟运动 """
self.pose_get(pose)
if self.i == 1:
# 目标点只设定一次
self.set_goal(pose, graph)
self.i += 1
self.go_line()
self.rorate()
def pose_get(self, pose):
""" 获取当前坐标和角度 """
self.x = pose.x
self.y = pose.y
self.theta = pose.theta
def set_goal(self, pose, graph):
""" 设定目标点 """
self.goals = {
'squ': [[pose.x + self.size, pose.y, math.pi / 2],
[pose.x + self.size, pose.y + self.size, math.pi],
[pose.x, pose.y + self.size, - math.pi / 2],
[pose.x, pose.y, 0]],
'tri60': [[pose.x + self.size, pose.y, math.pi * 2 / 3],
[pose.x + self.size / 2, pose.y + (self.size / 2 * math.tan(math.pi / 3)), - math.pi * 2 / 3],
[pose.x, pose.y, 0]],
'tri90': [[pose.x + self.size, pose.y, math.pi / 2],
[pose.x + self.size, pose.y + self.size, -3 * math.pi / 4],
[pose.x, pose.y, 0]],
'hourglass': [[pose.x, pose.y, math.pi / 3],
[pose.x + self.size / 2, pose.y + (self.size * math.sin(math.pi / 3)), math.pi],
[pose.x - self.size / 2, pose.y + (self.size * math.sin(math.pi / 3)), - math.pi / 3],
[pose.x + self.size / 2, pose.y - (self.size * math.sin(math.pi / 3)), math.pi],
[pose.x - self.size / 2, pose.y - (self.size * math.sin(math.pi / 3)), math.pi / 3],
[pose.x, pose.y, math.pi / 3]],
}
# 条件选择图形目标
if graph == 'squ':
self.goal = self.goals['squ']
elif graph == 'tri60':
self.goal = self.goals['tri60']
elif graph == 'tri90':
self.goal = self.goals['tri90']
elif graph == 'hourglass':
self.goal = self.goals['hourglass']
elif graph == 'circle':
self.circle()
self.num = len(self.goal) - 1
def go_line(self):
""" 走直线 """
if self.lock == 0: # 和旋转互锁
# 计算现在的误差
self.error = math.sqrt(
(self.x - self.goal[self.side][0]) ** 2 + (self.y - self.goal[self.side][1]) ** 2)
if self.error > self.aim_line: # 未到设定精度时前进
self.twist.linear.x = 1.0
else:
self.twist.linear.x = 0
self.lock = 1 # 解锁旋转
self.pub.publish(self.twist) # 发布乌龟速度
def rorate(self):
""" 转动角度到达另一边 """
if self.lock == 1:
self.error = abs(self.theta - self.goal[self.side][2])
if self.error > self.aim_angle: # 未到达转动角度精度时继续旋转
self.twist.angular.z = 1.0
else:
self.twist.angular.z = 0
self.lock = 0
if self.side < self.num:
self.side = self.side + 1
else:
self.side = 0 # 走完一轮目标点后重置目标点
self.i = 1
self.turns += 1
print(self.turns)
self.pub.publish(self.twist) # 发布乌龟速度
def circle(self):
""" 走圆圈 """
while not rospy.is_shutdown():
self.twist.linear.x = 2.0
self.twist.angular.z = 1.0
self.pub.publish(self.twist)
rospy.loginfo("message have published x = %d angular z = %0.2f", self.twist.linear.x, self.twist.angular.z)
# 在终端打印一份日志
self.rate.sleep()
# 按照设置的速率进行延时
# 接收到语音命令后发布速度指令
def get_voice(data):
voice_text=data.data
rospy.loginfo("语音已接收")
if voice_text == "走圆圈。":
name = 'circle'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走方形。":
name = 'squ'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走漏斗形。":
name = 'hourglass'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走60度三角形。":
name = 'tri60'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
elif voice_text == "走直角三角形。":
name = 'tri90'
rospy.loginfo("I said:: %s",voice_text)
Turtlerun(name)
if __name__ == '__main__':
a = input("选择控制方式:1.命令行;2.语音控制n")
if a == 1:
graph_list = ['circle', 'squ', 'tri60', 'tri90', 'hourglass']
if len(sys.argv) > 1 and sys.argv[1] in graph_list: # 实现rosrun xx yy.py squ直接跑对应图形
name = sys.argv[1]
else:
name = input(
'Please input graph name(circle squ tri60 tri90 hourglass): ') # 没在命令输对图形名称时提示输入
try:
rospy.init_node('turtle_run', anonymous=True) # 对节点进行初始化,命名一个叫turtle_run的节点
name = str(name)
Turtlerun(name)
rospy.spin()
except rospy.ROSInterruptException:
pass
else:
rospy.init_node('voice_teleop')
while not rospy.is_shutdown():
rospy.loginfo("Starting voice Teleop")
# 订阅语音识别的输出字符
rospy.Subscriber("/voiceWords", String, get_voice)
rospy.spin()
这里的语音功能包使用的是科大讯飞的,需要到科大讯飞网站注册帐号(需要APPID),讯飞开放平台-以语音交互为核心的人工智能开放平台



