实验编号: 实验指导书 实验项目: 机器人导航包 所属课程: ROS机器人操作系统基础与实战 课程代码: 面向专业: 机电专业 课程负责人: 朱笑笑 年月 日
实验编号: 实 验 指 导 书 实验项目: 机器人导航包 所属课程: ROS 机器人操作系统基础与实战 课程代码: 面向专业: 机电专业 课程负责人: 朱笑笑 年 月 日
一、实验目的 让学生掌握导航包中机器人的搭建方法。掌握导航包需要的一些信息量,对 导航包的工作流程有直观的了解。 二、 实验内容 1. 创建transform 2. 发布传感器信息 3. 发布里程计信息 4. 创建一个基座控制器 5. 创建一个环境地图 二、 实验过程或其他示意图 导航包提供了一组使用传感器、里程仪,和对机器人进行标准化控制的算法集合。可以 让你的机器人从一个位置移动到另外一个位置,而不发生意外情况如,碰撞、堵在一个位置 或者走丢了。 可以认为这个包可以用在任何移动机器人的导航应用中,但是也需要针对不同的机器人 平台做一些配置文件修改或者写一些node来调用这个导航包的功能等等。 在使用导航包前机器人必须满足一些要求: 导航包只能处理差分驱动器和全向轮机器人。机器人的形状必须是正方形或长方形。 但是,它也可以用双足机器人做某些事情,比如机器人定位,只要机器人不做侧身移动。 它要求机器人发布有关所有的关节和传感器的位置之间关系的信息。 机器人能够接受线性速度和角速度的控制 平面激光必须安装在机器人上用以创建地图和定位。或者,你可以生成一些相当于几个 激光或一个声纳,或者你可以把这些值投影到地面上,如果传感器安装在机器人的另一 个位置。 下图显示了导航包的组织结构。在白色实线框的里面是导航包提供的信息。深灰色虚线框是 可以选择的node,浅灰色虚线框内是机器人平台需要提供的node。 -2
- 2 - 一、 实验目的 让学生掌握导航包中机器人的搭建方法。掌握导航包需要的一些信息量,对 导航包的工作流程有直观的了解。 二、 实验内容 1. 创建transform 2. 发布传感器信息 3. 发布里程计信息 4. 创建一个基座控制器 5. 创建一个环境地图 三、 实验过程或其他示意图 导航包提供了一组使用传感器、里程仪,和对机器人进行标准化控制的算法集合。可以 让你的机器人从一个位置移动到另外一个位置,而不发生意外情况如,碰撞、堵在一个位置 或者走丢了。 可以认为这个包可以用在任何移动机器人的导航应用中,但是也需要针对不同的机器人 平台做一些配置文件修改或者写一些 node 来调用这个导航包的功能等等。 在使用导航包前机器人必须满足一些要求: 导航包只能处理差分驱动器和全向轮机器人。 机器人的形状必须是正方形或长方形。 但是,它也可以用双足机器人做某些事情,比如机器人定位,只要机器人不做侧身移动。 它要求机器人发布有关所有的关节和传感器的位置之间关系的信息。 机器人能够接受线性速度和角速度的控制 平面激光必须安装在机器人上用以创建地图和定位。或者,你可以生成一些相当于几个 激光或一个声纳,或者你可以把这些值投影到地面上,如果传感器安装在机器人的另一 个位置。 下图显示了导航包的组织结构。在白色实线框的里面是导航包提供的信息。深灰色虚线框是 可以选择的 node,浅灰色虚线框内是机器人平台需要提供的 node
"move base_simple/goal" geometry_msgs/PoseStamped map_server amcl nove_base /map" nav msgs/GetMap giobal_planner global_costmap intema nav msgs/Pa ecovery beha transtorms sensor topics ocaI olann cal_costmap provided node optional provided node platform specific node 1. 创建transform 导航包需要知道传感器,车轮和关节相对于机器人的位置。 为此,我们使用TF(Transform Frames)软件库。TF管理一个变换树。当然你可以手 动用数学公式来做这个变换,但是如果有很多帧需要计算,这会有点复杂和凌乱。 利用TF,我们可以为机器人添加更多的传感器和部件,而T℉将会为我们处理好所有的位 姿关系。 如果我们把激光放在坐标系base_1ink的原点以上20厘米,以后10厘米的我们需要添加 在转换树中添加一个带有这些偏移量的新的坐标系。 一旦插入和创建成功,我们可以很容易地知道激光 相对于base_link或车轮的位置。我们唯一需要做的是调用TF库并获得这个转换。 1.1发布传感器信息 在chapter7?_tutorials/src下创建一个新文件名为tf_broadcaster.cpp,输入一下代码 #include <ros/ros.h> #include <tf/transform_broadcaster.h> int main(int argc,char**argv)( ros::init(argc,argv,"robot_tf_publisher"); ros::NodeHandle n; ros::Rate r(100); tf::TransformBroadcaster broadcaster; while(n.ok0){ broadcaster.sendTransform( tf::StampedTransform( tf::Transform(tf::Quaternion(0,0,0,1),tf::Vector3(0.1, 0.0,0.2) 3
- 3 - 1. 创建transform 导航包需要知道传感器,车轮和关节相对于机器人的位置。 为此,我们使用TF(Transform Frames)软件库。TF管理一个变换树。 当然你可以手 动用数学公式来做这个变换,但是如果有很多帧需要计算,这会有点复杂和凌乱。 利用TF,我们可以为机器人添加更多的传感器和部件,而TF将会为我们处理好所有的位 姿关系。 如果我们把激光放在坐标系base_link的原点以上20厘米,以后10厘米的我们需要添加 在转换树中添加一个带有这些偏移量的新的坐标系。 一旦插入和创建成功,我们可以很容易地知道激光 相对于base_link或车轮的位置。 我们唯一需要做的是调用TF库并获得这个转换。 1.1发布传感器信息 在chapter7_tutorials/src下创建一个新文件名为tf_broadcaster.cpp,输入一下代码 #include <ros/ros.h> #include <tf/transform_broadcaster.h> int main(int argc, char** argv){ ros::init(argc, argv, "robot_tf_publisher"); ros::NodeHandle n; ros::Rate r(100); tf::TransformBroadcaster broadcaster; while(n.ok()){ broadcaster.sendTransform( tf::StampedTransform( tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0.1, 0.0, 0.2))
ros::Time::now(,"base_link","base_laser")); r.sleep(; } 在CMakelist.txt中添加以下代码创建新的可执行文件 rosbuild_add_executable(tf_broadcaster src/tf_broadcaster.cpp) 这样我们可以创建另一个node来使用这个变换,可以得到传感器坐标系的一个点在 base link坐标系下的坐标。 1.2创建一个监听器 在chapter77_tutorials/src下创建一个新文件名为tf_listener.cpp,输入一下代码 #include <ros/ros.h> #include <geometry_msgs/PointStamped.h> #include <tf/transform_listener.h> void transformPoint(const tf::TransformListener&listener){ //we'll create a point in the base_laser frame that we'd like to transform to the base_link frame geometry_msgs::PointStamped laser_point; laser_point.header.frame_id ="base_laser"; //we'll just use the most recent transform available for our simple example laser_point.header.stamp ros::Time0; //just an arbitrary point in space laser_point.point.x =1.0; laser_point.point.y =2.0; laser_point.point.z =0.0; geometry_msgs::PointStamped base_point; listener.transformPoint("base_link",laser_point,base_point); ROS_INFO("base_laser:(%.2f,%.2f.%.2f)----->base_link:(%.2f, %.2f,%.2f)at time %.2f", laser_point.point.x,laser_point.point.y,laser_point.point.z, base_point.point.x,base_point.point.y,base_point.point.z, base_point.header.stamp.toSec(); ROS_ERROR("Received an exception trying to transform a point from -4-
- 4 - ros::Time::now(),"base_link", "base_laser")); r.sleep(); } } 在CMakelist.txt中添加以下代码创建新的可执行文件 rosbuild_add_executable(tf_broadcaster src/tf_broadcaster.cpp) 这样我们可以创建另一个node来使用这个变换,可以得到传感器坐标系的一个点在 base_link坐标系下的坐标。 1.2创建一个监听器 在chapter7_tutorials/src下创建一个新文件名为tf_listener.cpp,输入一下代码 #include <ros/ros.h> #include <geometry_msgs/PointStamped.h> #include <tf/transform_listener.h> void transformPoint(const tf::TransformListener& listener){ //we'll create a point in the base_laser frame that we'd like to transform to the base_link frame geometry_msgs::PointStamped laser_point; laser_point.header.frame_id = "base_laser"; //we'll just use the most recent transform available for our simple example laser_point.header.stamp = ros::Time(); //just an arbitrary point in space laser_point.point.x = 1.0; laser_point.point.y = 2.0; laser_point.point.z = 0.0; geometry_msgs::PointStamped base_point; listener.transformPoint("base_link", laser_point, base_point); ROS_INFO("base_laser: (%.2f, %.2f. %.2f) -----> base_link: (%.2f, %.2f, %.2f) at time %.2f", laser_point.point.x, laser_point.point.y, laser_point.point.z, base_point.point.x, base_point.point.y, base_point.point.z, base_point.header.stamp.toSec()); ROS_ERROR("Received an exception trying to transform a point from
\"base_laser to \"base_link\":%s",ex.what(); int main(int argc,char**argv)( ros::init(argc,argv,"robot_tf_listener"); ros::NodeHandle n; tf::TransformListener listener(ros::Duration(10)); //we'll transform a point once every second ros::Timer timer n.createTimer(ros::Duration(1.0), boost::bind(&transformPoint,boost::ref(listener))); ros::spin(; } 同样在CMakelist..tbxt中添加新可执行文件。编译包并运行两个node rosmake chapter7_tutorials rosrun chapter7_tutorials tf_broadcaster rosrun chapter7_tutorials tf_listener 可以在终端上获得以下输出 [INFO][1368521854.336910465J:base_laser::(1.00,2.00.0.00)--> base_link:(1.10,2.00,0.20)at time1368521854.33 [INFo][1368521855.336347545J:base_laser::(1.00,2.00.0.00)--> base_link:(1.10,2.00,0.20)at time1368521855.33 这就意味着在节点中发布的相对于base_laser的一个(1,2,0)的点,在base_Iink中的位 置为(1.1,2,0.2)。 这样可以看到,tf函数库提供了所以需要数学函数可以用来获得一个点或者joit在其他 坐标系中的位姿。 一个TF树定义了所有不同坐标系间的移动和旋转变换。 测试以下例子,进一步理解℉。使用前面D模型和仿真实验中完成的一个小车,并在车 背上添加一个其它的laser -5-
- 5 - \"base_laser\" to \"base_link\": %s", ex.what()); } int main(int argc, char** argv){ ros::init(argc, argv, "robot_tf_listener"); ros::NodeHandle n; tf::TransformListener listener(ros::Duration(10)); //we'll transform a point once every second ros::Timer timer = n.createTimer(ros::Duration(1.0), boost::bind(&transformPoint, boost::ref(listener))); ros::spin(); } 同样在CMakelist.txt中添加新可执行文件。编译包并运行两个node $ rosmake chapter7_tutorials $ rosrun chapter7_tutorials tf_broadcaster $ rosrun chapter7_tutorials tf_listener 可以在终端上获得以下输出 [ INFO] [1368521854.336910465]: base_laser: (1.00, 2.00. 0.00) -----> base_link: (1.10, 2.00, 0.20) at time 1368521854.33 [ INFO] [1368521855.336347545]: base_laser: (1.00, 2.00. 0.00) -----> base_link: (1.10, 2.00, 0.20) at time 1368521855.33 这就意味着在节点中发布的相对于base_laser的一个(1,2,0)的点,在base_link中的位 置为(1.1,2,0.2)。 这样可以看到,tf函数库提供了所以需要数学函数可以用来获得一个点或者joint在其他 坐标系中的位姿。 一个TF树定义了所有不同坐标系间的移动和旋转变换。 测试以下例子,进一步理解TF。使用前面3D模型和仿真实验中完成的一个小车,并在车 背上添加一个其它的laser