ROS小乌龟走设定图形路线(键盘控制+Python代码实现)

相信在很多人学习ROS的时候都会写一下这个demo,不仅是对代码能力的考察(代码语法、结构都还是相对简单的),还是对ROS话题通信这些基础概念的理解的考量。

首先命令运行

roscore
rosrun turtlesim turtlesim_node

 

如果要通过键盘控制小乌龟的运动,则运行

rosrun turtlesim turtle_teleop_key

 下面展示代码实现的小乌龟案例

1.圆形

#! /usr/bin/env python
# coding:UTF-8

import turtle
import rospy
from geometry_msgs.msg import Twist # Twist数据类型包含线速度和角速度


def turtle_publisher():
    rospy.init_node('turtle_publisher', anonymous=True)
    # 对节点进行初始化,命名一个叫turtle_publisher的节点
    turtle_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
    # 实例化一个发布者对象,发布的话题名为 /turtle1/cmd_vel ,消息类型为 Twist,队列长度为10
    rate = rospy.Rate(10)
    # 设置循环的频率
    while not rospy.is_shutdown():
        # 装载消息
        cmd_msg = Twist()
        cmd_msg.linear.x = 2.0
        cmd_msg.angular.z = 1.0
        turtle_pub.publish(cmd_msg)
        # 发布话题消息
        rospy.loginfo("message have published x = %d angular z = %0.2f", cmd_msg.linear.x, cmd_msg.angular.z)
        # 在终端打印一份日志
        rate.sleep()
        # 按照设置的速率进行延时


if __name__ == '__main__':
    try:
        turtle_publisher()
    except rospy.ROSInterruptException:
        pass

2.多种图形

#! /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数据类型包含线速度和角速度




class Turtlerun:
    """ 一个乌龟走图形路线的类 """

    def __init__(self, name):
        """ 初始化 """
        self.pub = rospy.Publisher("/turtle1/cmd_vel", Twist, queue_size=10)  # 实例化发布者
        rospy.Subscriber("/turtle1/pose", Pose, self.turtle_run, queue_size=10)  # 实例化订阅者
        self.twist = Twist()
        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 turtle_run(self, pose):
        """ 控制乌龟运动 """
        self.pose_get(pose)
        if self.i == 1:
            # 目标点只设定一次
            self.set_goal(pose)
            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):
        """ 设定目标点 """
        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 name == 'squ':
            self.goal = self.goals['squ']
        elif name == 'tri60':
            self.goal = self.goals['tri60']
        elif name == 'tri90':
            self.goal = self.goals['tri90']
        elif name == 'hourglass':
            self.goal = self.goals['hourglass']
        elif name == '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()
            # 按照设置的速率进行延时


if __name__ == '__main__':
    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)
        tgraph = Turtlerun(name)
        rospy.spin()
    except rospy.ROSInterruptException:
        pass

 下面是走方形的案例实现:

  • 4
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
ROS是一个机器人操作系统,其中包括了一个用于创建机器人应用程序的框架。其中,小乌龟绘图是ROS中一个经典的入门例子。 以下是实现小乌龟图形的C++代码: ``` #include <ros/ros.h> #include <geometry_msgs/Twist.h> #include <turtlesim/Pose.h> #include <iostream> using namespace std; const double PI = 3.14159265359; double degree2radian(double degree) { return degree * PI / 180.0; } class Turtle { public: Turtle() { // 初始化ROS节点 n = ros::NodeHandle(); // 订阅小乌龟的位置信息 pose_sub = n.subscribe("/turtle1/pose", 10, &Turtle::poseCallback, this); // 发布小乌龟的速度信息 velocity_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10); } void move(double speed, double distance, bool isForward) { // 初始化速度消息 geometry_msgs::Twist vel_msg; vel_msg.linear.x = abs(speed); if (isForward) { vel_msg.linear.x = abs(speed); } else { vel_msg.linear.x = -abs(speed); } vel_msg.linear.y = 0; vel_msg.linear.z = 0; vel_msg.angular.x = 0; vel_msg.angular.y = 0; vel_msg.angular.z = 0; double t0 = ros::Time::now().toSec(); double current_distance = 0; ros::Rate loop_rate(10); while (current_distance < distance) { velocity_pub.publish(vel_msg); double t1 = ros::Time::now().toSec(); current_distance = speed * (t1 - t0); ros::spinOnce(); loop_rate.sleep(); } // 停止小乌龟运动 vel_msg.linear.x = 0; velocity_pub.publish(vel_msg); } void rotate(double angular_speed, double angle, bool clockwise) { // 初始化速度消息 geometry_msgs::Twist vel_msg; vel_msg.linear.x = 0; vel_msg.linear.y = 0; vel_msg.linear.z = 0; vel_msg.angular.x = 0; vel_msg.angular.y = 0; if (clockwise) { vel_msg.angular.z = -abs(angular_speed); } else { vel_msg.angular.z = abs(angular_speed); } double current_angle = 0.0; double t0 = ros::Time::now().toSec(); ros::Rate loop_rate(10); while (current_angle < angle) { velocity_pub.publish(vel_msg); double t1 = ros::Time::now().toSec(); current_angle = angular_speed * (t1 - t0); ros::spinOnce(); loop_rate.sleep(); } // 停止小乌龟旋转 vel_msg.angular.z = 0; velocity_pub.publish(vel_msg); } void poseCallback(const turtlesim::Pose::ConstPtr &pose_msg) { this->pose = *pose_msg; } private: ros::NodeHandle n; ros::Publisher velocity_pub; ros::Subscriber pose_sub; turtlesim::Pose pose; }; int main(int argc, char **argv) { // 初始化ROS节点 ros::init(argc, argv, "turtle"); Turtle turtle; double speed, angular_speed; double distance, angle; bool isForward, clockwise; cout << "请输入线速度:"; cin >> speed; cout << "请输入角速度:"; cin >> angular_speed; cout << "请输入距离:"; cin >> distance; cout << "是否前进?(1为前进,0为后退):"; cin >> isForward; cout << "请输入旋转角度:"; cin >> angle; cout << "是否顺时针旋转?(1为顺时针,0为逆时针):"; cin >> clockwise; turtle.move(speed, distance, isForward); turtle.rotate(degree2radian(angular_speed), degree2radian(angle), clockwise); // 输出小乌龟的位置信息 ROS_INFO("Turtle position: (%.2f, %.2f)", turtle.pose.x, turtle.pose.y); ROS_INFO("Turtle orientation: %.2f", turtle.pose.theta); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笨小古

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

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

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

打赏作者

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

抵扣说明:

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

余额充值