ROS Learning-030 (提高篇-008 A Mobile Base-06) 控制移动平台 --- (Python)odom导航的例子:移动一个方块路径
ROS 提高篇 之 A Mobile Base-06 — 控制移动平台 — (Python)再次使用odom导航的一个例子:移动一个方块路径
我使用的虚拟机软件:VMware Workstation 11 
使用的Ubuntu系统:Ubuntu 14.04.4 LTS 
ROS 版本:ROS Indigo
注意: 
1 . ROS 提高篇这个专栏的教学有门槛。 
2 . 如果你没有学习前面的教程,请想学习前面的 beginner_Tutorials 和 learning_tf 的ROS 相关教程。
一 . 前言:
上一节,我们使用odom 重写了前进和返回的程序。这次,我们尝试以一个方块形路径移动移动机器人。(方块的4个点设置航点)
二 . 运行程序,看看效果:
在查看代码之前,我们先来启动这个节点,看看运行效果:
新开一个终端,执行下面的命令,启动一个虚拟的 TurtleBot 机器人:
$ roslaunch rbx1_bringup fake_turtlebot.launch再开一个终端,启动 RViz :
$ rosrun rviz rviz -d `rospack find rbx1_nav`/sim.rviz最后开一个终端,运行 odom_out_and_back.py 节点:
$ rosrun rbx1_nav nav_square.py当你将这句命令执行完,在 RVIz模拟器 中,你就可以看到下面图片里的运行效果:程序在模拟器中航行一个方块路径,机器人在这个路径上移动。
三 . 程序代码: nav_square.py
#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist, Point, Quaternion
import tf
from rbx1_nav.transform_utils import quat_to_angle, normalize_angle
from math import radians, copysign, sqrt, pow, pi
class NavSquare():
    def __init__(self):
        # 给出节点的名字
        rospy.init_node('nav_square', anonymous=False)
        # 设置rospy在程序退出时执行的关机函数
        rospy.on_shutdown(self.shutdown)
        # 我们将用多快的速度更新控制机器人运动的命令?
        rate = 20
        # 设定相同的值给rospy.Rate()
        r = rospy.Rate(rate)
        # 为目标正方形设置参数
        goal_distance = rospy.get_param("~goal_distance", 1.0)      # 米
        goal_angle = rospy.get_param("~goal_angle", radians(90))    # 角度转换弧度
        linear_speed = rospy.get_param("~linear_speed", 0.2)        # m/s
        angular_speed = rospy.get_param("~angular_speed", 0.7)      # rad/s
        angular_tolerance = rospy.get_param("~angular_tolerance", radians(2)) # 角度到弧度的公差
        # 发布者控制机器人的速度
        self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=5)
        # 配置base坐标系: 如果是TurtleBot机器人为: base_footprint, 如果是Pi Robot机器人为: base_link
        self.base_frame = rospy.get_param('~base_frame', '/base_link')
        # odom坐标系通常就叫:/odom
        self.odom_frame = rospy.get_param('~odom_frame', '/odom')
        # 初始化tf 监听器
        self.tf_listener = tf.TransformListener()
        # 给tf一些时间填充它的缓冲区
        rospy.sleep(2)
        # 配置odom坐标系
        self.odom_frame = '/odom'
        # 询问机器人使用的是/base_link坐标系还是/base_footprint坐标系
        try:
            self.tf_listener.waitForTransform(self.odom_frame, '/base_footprint', rospy.Time(), rospy.Duration(1.0))
            self.base_frame = '/base_footprint'
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            try:
                self.tf_listener.waitForTransform(self.odom_frame, '/base_link', rospy.Time(), rospy.Duration(1.0))
                self.base_frame = '/base_link'
            except (tf.Exception, tf.ConnectivityException, tf.LookupException):
                rospy.loginfo("Cannot find transform between /odom and /base_link or /base_footprint")
                rospy.signal_shutdown("tf Exception")  
        # 初始化了一个Point类型的变量
        position = Point()
        # 周期循环:通过正方形的四边
        for i in range(4):
            # 初始化运动命令
            move_cmd = Twist()
            # 设定前进速度
            move_cmd.linear.x = linear_speed
            # 得到开始的姿态信息(位置和转角)
            (position, rotation) = self.get_odom()
            x_start = position.x
            y_start = position.y
            # 随时掌控机器人行驶的距离
            distance = 0
            # 进入循环,沿着一边移动
            while distance < goal_distance and not rospy.is_shutdown():
                # 发布一次Twist消息 和 sleep 1秒
                self.cmd_vel.publish(move_cmd)
                r.sleep()
                # 给出正确的姿态信息(位置和转角)
                (position, rotation) = self.get_odom()
                # 计算相对于开始位置的欧几里得距离(即位移)
                distance = sqrt(pow((position.x - x_start), 2) +
                                pow((position.y - y_start), 2))
            # 在转动机器人前,停止它
            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1.0)
            # 给旋转配置运动命令
            move_cmd.angular.z = angular_speed
            # 跟踪记录最后的角度
            last_angle = rotation
            # 跟踪我们已经转动了多少角度
            turn_angle = 0
            # Begin the rotation
            while abs(turn_angle + angular_tolerance) < abs(goal_angle) and not rospy.is_shutdown():
                # 发布一次Twist消息 和 sleep 1秒
                self.cmd_vel.publish(move_cmd)
                r.sleep()
                # 给出正确的姿态信息(位置和转角)
                (position, rotation) = self.get_odom()
                # 计算自每次的旋转量
                delta_angle = normalize_angle(rotation - last_angle)
                turn_angle += delta_angle
                last_angle = rotation
            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1.0)
        # 为了机器人好,停止它
        self.cmd_vel.publish(Twist())
    def get_odom(self):
        # Get the current transform between the odom and base frames
        try:
            (trans, rot)  = self.tf_listener.lookupTransform(self.odom_frame, self.base_frame, rospy.Time(0))
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            rospy.loginfo("TF Exception")
            return
        return (Point(*trans), quat_to_angle(Quaternion(*rot)))
    def shutdown(self):
        # 当关闭这个节点时,总是让机器人停止不动。
        rospy.loginfo("Stopping the robot...")
        self.cmd_vel.publish(Twist())
        rospy.sleep(1)
if __name__ == '__main__':
    try:
        NavSquare()
    except rospy.ROSInterruptException:
        rospy.loginfo("Navigation terminated.")
四 . 讲解程序
略,就不讲了,因为这个程序,相比前两节(编写一个out_and_back 程序 和 使用 odometry 消息类型 重写 out_and_back 程序),没有什么新的知识点。
五 . 航位推算的问题:
这个问题的根源:随时间积累的测量出现的小误差。如何解决这个问题?幸运的是,机器人学家好久以前就开始研究各种方法来在导航中 合并地标或者使用其他外部参考,我们将会在SLAM章节学习到。
搞定
总结: 
下一节,我们讲如何人机交互,并在Rviz 中看到机器人的运动。
ROS Learning-030 (提高篇-008 A Mobile Base-06) 控制移动平台 --- (Python)odom导航的例子:移动一个方块路径的更多相关文章
- ROS Learning-025  (提高篇-003 A Mobile Base-01) 控制移动平台
		ROS 提高篇 A Mobile Base-01 - 控制移动平台 - 基本知识 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 ... 
- ROS Learning-031  (提高篇-009 A Mobile Base-07) 控制移动平台 --- (操作)人机交互
		ROS 提高篇 之 A Mobile Base-07 - 控制移动平台 - (操作)人机交互 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14 ... 
- ROS Learning-029  (提高篇-007 A Mobile Base-05) 控制移动平台 --- (Python编程)控制虚拟机器人的移动(精确的制定目标位置)
		ROS 提高篇 之 A Mobile Base-05 - 控制移动平台 - (Python编程)控制虚拟机器人的移动(精确的制定目标位置) 使用 odometry 消息类型 重写 out_and_ba ... 
- ROS Learning-028  (提高篇-006 A Mobile Base-04) 控制移动平台 --- (Python编程)控制虚拟机器人的移动(不精确的制定目标位置)
		ROS 提高篇 之 A Mobile Base-04 - 控制移动平台 - (Python编程)控制虚拟机器人的移动(不精确的制定目标位置) 我使用的虚拟机软件:VMware Workstation ... 
- ROS Learning-027  (提高篇-005 A Mobile Base-03) 控制移动平台 --- Twist 消息
		ROS 提高篇 之 A Mobile Base-03 - 控制移动平台 - Twist 消息 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14 ... 
- ROS Learning-026  (提高篇-004 A Mobile Base-02) 控制移动平台 --- “分封制”
		ROS 提高篇 之 A Mobile Base-02 - 控制移动平台 - "分封制" 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ub ... 
- ROS Learning-032  (提高篇-010 Launch)Launch 深入研究  --- (启动文件编程)ROS 的 XML语法简介
		ROS 提高篇 之 Launch 深入研究 - 01 - 启动文件的编程 - ROS 的 XML语法简介 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubu ... 
- ROS Learning-024  (提高篇-002) rviz的安装和使用
		ROS 提高篇-002 - rviz 的安装和使用 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 LTS ROS 版本:ROS ... 
- ROS Learning-023  (提高篇-001) 准备工作 --- 安装一些必要的软件包
		ROS 提高篇-001 - 准备工作 - 安装一些必要的软件 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 LTS ROS 版本 ... 
随机推荐
- GEF入门实例_总结_02_新建初始RCP空项目
			一.前言 本节承接上一节: GEF入门实例_总结_01_教程.源码.开发环境准备 这一节我们来创建一个空的RCP项目. 二.新建RCP项目 1. New 一个 Plug-in Project 2.输入 ... 
- 《Effective C++》——条款04:确定对象使用前已先被初始化
			读取未初始化的值会导致不明确的行为.在某些平台上,仅仅只是读取未初始化的值,就可能让你的程序终止运行.更可能的情况是读入一些“半随机”bits,污染了正在进行读取动作的那个对象,最终导致不可预知的程序 ... 
- 201621123014《Java程序设计》第九周学习总结
			1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 答: 2. 书面作业 本次作业题集集合 1. List中指定元素的删除(题集题目) 1.1 实验总结.并回答: ... 
- (转)SPFA算法
			原文地址:http://www.cnblogs.com/scau20110726/archive/2012/11/18/2776124.html 粗略讲讲SPFA算法的原理,SPFA算法是1994年西 ... 
- HihoCoder1407 后缀数组二·重复旋律2
			重复旋律2 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi在练习过很多 ... 
- 非maven项目下载maven的jar
			很多时候我们需要jar,可惜项目不是maven的,但是我们只有一个maven的坐标,那怎么办? 比如: <dependencies> <dependency> <grou ... 
- 难道调用ThreadPool.QueueUserWorkItem()的时候,真是必须调用Thread.Sleep(N)吗?
			开门见山,下面的例子中通过调用ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)的方式实现异步调用: 1: class ... 
- BZOJ3141:[HNOI2013]旅行
			浅谈队列:https://www.cnblogs.com/AKMer/p/10314965.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem.p ... 
- bzoj 3907 网格 bzoj2822 [AHOI2012]树屋阶梯——卡特兰数(阶乘高精度模板)
			题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3907 https://www.lydsy.com/JudgeOnline/problem.p ... 
- Spring Boot Starter 速查
			Spring Boot应用启动器基本的一共有40多种,常用的如下 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring ... 
