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

最近几天在学习语音识别、语音合成,应用到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 python3
# 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 Turtle:
    def __init__(self, name, graph):
        rospy.init_node(name)  # 初始化节点
        rospy.Subscriber('/turtle1/pose', Pose, self.control)  # 实例化订阅者,参数为订阅的话题名,消息类型,回调函数
        self.pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)  # 实例化发布者,参数为发布的话题名,消息类型,队列长度
        self._graph = graph
        self.size = 5  # 图形的大小(3-5)
        self.kp1 = 6  # 走直线的比例控制参数
        self.kp2 = 4  # 转角度的比例控制参数
        self.kd = 0  # 走直线的微分控制参数
        self.aim = 0.025  # 直走的误差值
        self.aim_rotate = 0.005  # 转弯的误差值
        self.vel_cmd = Twist()  # 实例化Twist消息类型的消息
        self.point = {}  # 储存所走路径目标点
        self.x = None  # 乌龟目前所在x坐标
        self.y = None  # 乌龟目前所在y坐标
        self.theta = None  # 乌龟目前角度
        self.goal = 0  # 乌龟下一个要到达的目标点
        self.error = None  # 现在距离目标点的误差值
        self.flag = 0  # flag和lock实现走直线和转角度的互锁,执行完一个才能执行另一个
        self.lock = 0
        self.key = 0
        self.theta_list = []
        self.speed = 4  # 控制旋转时的方向,顺or逆

    def control(self, pose):
        """订阅的回调函数"""
        self.choose_graph(self._graph, pose)  # 设定要走什么形状

    def choose_graph(self, graph, pose):
        """根据传入的图形设定目标点,获取当前位置,控制运动"""
        self.set_goal_points(pose, self.size)
        rospy.loginfo(self.point['squ'][0][0])
        self.get_present_point(pose)
        self.go_graph(graph, self.kp1, self.kp2, self.kd, self.aim)

    def set_goal_points(self, pose, size=5):
        """设定不同形状的目标点,坐标和角度"""
        if self.key == 0:  # 只设定一次
            self.point = {
                'squ': [
                    [pose.x + size, pose.y, math.pi / 2],
                    [pose.x + size, pose.y + size, math.pi],
                    [pose.x, pose.y + size, - math.pi / 2],
                    [pose.x, pose.y, 0],
                ],

                'squ2': [
                    [pose.x + size, pose.y, -math.pi / 2],
                    [pose.x + size, pose.y - size, -math.pi],
                    [pose.x, pose.y - size, math.pi / 2],
                    [pose.x, pose.y, 0],
                ],

                'squ3': [
                    [pose.x, pose.y, math.pi / 2],
                    [pose.x, pose.y + size, 0],
                    [pose.x + size, pose.y + size, -math.pi / 2],
                    [pose.x + size, pose.y, -math.pi]
                ],

                'rec': [
                    [pose.x + 5, pose.y, math.pi / 2],
                    [pose.x + 5, pose.y + 3, math.pi],
                    [pose.x, pose.y + 3, math.pi / 2],
                    [pose.x, pose.y, 0],
                ],

                'tri_60': [
                    [pose.x + size, pose.y, math.pi * 2 / 3],
                    [pose.x + size / 2, pose.y + (size / 2 * math.tan(math.pi / 3)), - math.pi * 2 / 3],
                    [pose.x, pose.y, 0]
                ],

                'tri_60_2': [
                    [pose.x + size, pose.y, -math.pi * 2 / 3],
                    [pose.x + size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), math.pi * 2 / 3],
                    [pose.x, pose.y, 0]
                ],

                'tri_60_3': [
                    [pose.x, pose.y, -math.pi / 3],
                    [pose.x + size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), -math.pi],
                    [pose.x - size / 2, pose.y - (size / 2 * math.tan(math.pi / 3)), math.pi / 3]
                ],

                'hourglass': [
                    [pose.x, pose.y, -math.pi / 3],
                    [pose.x + 3 / 2, pose.y - (3 / 2 * math.tan(math.pi / 3)), -math.pi],
                    [pose.x - 3 / 2, pose.y - (3 / 2 * math.tan(math.pi / 3)), math.pi / 3],
                    [pose.x + 3 / 2, pose.y + (3 / 2 * math.tan(math.pi / 3)), math.pi],
                    [pose.x - 3 / 2, pose.y + (3 / 2 * math.tan(math.pi / 3)), -math.pi / 3]
                ],

                'tri_90': [
                    [pose.x + size, pose.y, math.pi / 2],
                    [pose.x + size, pose.y + size, -3 * math.pi / 4],
                    [pose.x, pose.y, 0]
                ]
            }
            self.key += 1

    def get_present_point(self, pose):
        """获取当前坐标和角度"""
        self.x = pose.x
        self.y = pose.y
        self.theta = pose.theta

    def go_graph(self, graph, kp1=4, kp2=4, kd=15, aim=0.025):
        """控制运动"""
        self.go_line(graph, kp1, kd, aim)
        self.rotate(graph, kp2)

    def set_goal(self, graph):
        """设定下一个目标点"""
        if self.lock == 1:
            print(self.goal)
            self.goal = self.goal + 1 if self.goal != len(self.point[graph]) - 1 else 0

    def go_line(self, graph, kp=2, kd=15, aim=0.08, ):
        """控制走直线"""
        if self.lock == 0:  # 和旋转互锁
            if self.flag == 0:  # 第一次进函数执行一次初始化
                self.error = self.size  # 初始误差为设定的图形大小
                self.flag += 1  # 保证初始化只执行一次
            last_error = self.error  # 上一次的误差
            self.error = math.sqrt(
                (self.x - self.point[graph][self.goal][0]) ** 2 + (
                        self.y - self.point[graph][self.goal][1]) ** 2)  # 计算现在的误差
            if abs(self.error) > aim:  # 误差大于设定精度时前进
                self.vel_cmd.linear.x = kp * self.error + kd * (self.error - last_error)  # pd控制计算当前速度
                rospy.loginfo('mode:going')
                rospy.loginfo('goal:{},error:{},speed:{}'.format(self.goal, self.error, self.vel_cmd.linear.x))
            else:
                self.vel_cmd.linear.x = 0
                self.lock = 1  # 解锁旋转
            self.pub.publish(self.vel_cmd)  # 发布乌龟速度

    def rotate(self, graph, kp=2):
        """控制旋转"""
        if self.lock == 1:  # 和直走互锁
            if self.flag == 1:  # 第一次进函数执行一次初始化函数
                self.set_goal(graph)
                theta1 = self.theta + 2 * math.pi if self.theta < 0 else self.theta  # 将现在的角度换算成0-2π
                theta2 = theta1 + math.pi if theta1 <= math.pi else theta1 - math.pi  # 和现在的角度差π的角
                target = self.point[graph][self.goal - 1][2] + 2 * math.pi if self.point[graph][self.goal - 1][2] < 0 \
                    else self.point[graph][self.goal - 1][2]  # 将目标角度换算到0-2π
                self.speed = kp if theta1 < target < theta2 or theta1 > theta2 and not (theta1 > target > theta2) \
                    else -kp  # 判断顺时针转还是逆时针转距离最短
                self.flag += 1  # 保证只执行一次初始化
            self.error = abs(self.theta - self.point[graph][self.goal - 1][2])  # 计算当前误差
            if self.error > self.aim_rotate:  # 误差大于0.01时保持旋转
                self.vel_cmd.angular.z = self.speed * (self.error + 0.1)  # p控制计算旋转速度
                rospy.loginfo('mode:rotating')
                rospy.loginfo('goal:{},error:{},speed:{}'.format(self.goal, self.error, self.vel_cmd.angular.z))
            else:
                self.vel_cmd.angular.z = 0
                self.flag = 0
                self.lock = 0
            self.pub.publish(self.vel_cmd)  # 发布乌龟速度

# 接收到语音命令后发布速度指令
def get_voice(data):
    voice_text=data.data
    rospy.loginfo("语音已接收")

    if voice_text == "走方形。" or "squ":
        name = 'squ'
        rospy.loginfo("I said:: %s",voice_text)
        Turtle('voice_teleop',name)
        # Turtlerun.goal = Turtlerun.goals['squ']
    elif voice_text == "走漏斗形。":
        name = 'hourglass'
        rospy.loginfo("I said:: %s",voice_text)
        Turtle('voice_teleop',name)
        # Turtlerun.goal = Turtlerun.goals['hourglass']
    elif voice_text == "走60度三角形。":
        name = 'tri60'
        rospy.loginfo("I said:: %s",voice_text)
        Turtle('voice_teleop',name)
        # Turtlerun.goal = Turtlerun.goals['tri60']
    elif voice_text == "走直角三角形。":
        name = 'tri90'
        rospy.loginfo("I said:: %s",voice_text)
        Turtle('voice_teleop',name)
    
if __name__ == '__main__':
    a = input("选择控制方式:1.命令行;2.语音控制\n")
    a = int(a)


    if a == 1:
        graph_list = ['circle', 'squ', 'tri60', 'tri90', 'hourglass']
        # print("input")
        # print("-------",sys.argv)
        if len(sys.argv) > 1 and sys.argv[1] in graph_list:  # 实现rosrun xx yy.py squ直接跑对应图形
            name = sys.argv[1]   
            # print("input finish")
        else:
            name = input(
                'Please input graph name(circle squ tri60 tri90 hourglass): ')  # 没在命令输对图形名称时提示输入
        try:
            name = str(name)
            Turtle('voice_graph',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),讯飞开放平台-以语音交互为核心的人工智能开放平台

  • 0
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ROS小海龟是一个在ROS(Robot Operating System)中使用的仿真机器人。它被广泛用于教育和开发机器人技术。 在ROS小海龟中,定点移动是指让小海龟图形界面上的给定点上停留一段时间。下面是一个简单的300字中文回答,解释ROS小海龟如何进行定点移动: ROS小海龟可以通过使用turtlebot3_teleop包来进行定点移动。首先,我们需要打开一个终端窗口并输入以下命令来启动ROS小海龟仿真器: ``` roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch ``` 接下来,在另一个终端窗口中输入以下命令来启动ROS小海龟操作节点: ``` roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch ``` 现在,我们可以通过按键盘上的箭头键来控制小海龟的移动。当我们按住箭头键移动小海龟时,它会按照我们的指示移动。 要进行定点移动,我们需要使用turtlesim包提供的服务。在新的终端窗口中输入以下命令来调用turtlesim服务: ``` rosservice call /turtle1/teleport_absolute x y theta ``` 在这个命令中,x和y是小海龟需要移动到的坐标,theta是小海龟旋转的角度。 例如,如果我们想让小海龟移动到坐标(5, 5)的位置,并使其朝向角度为0度,则需要执行以下命令: ``` rosservice call /turtle1/teleport_absolute 5 5 0 ``` 小海龟将会移动到这个位置,并保持在那里一段时间。 通过使用这些命令,我们可以轻松地实现ROS小海龟的定点移动。这对于学习机器人控制和路径规划等领域非常有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨小古

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值