ROS navigation说明

10 篇文章 1 订阅
8 篇文章 1 订阅

介绍:

        二维的navigation堆栈通过采集传感器、里程计、全局位姿等信息,给移动设备发送安全速度指令(包括线速度、角速度)。navigation从概念上是很简单的,采集数据到发送指令,但从实现来看却很复杂,首先,设备得安装ROS系统,并且包含tf树,此外,要用准确的ROS数据类型发布传感器消息。

硬件支持:

        1、里程计   /差速驱动或轮式机器人,须以x、y方向速度和角速度theta控制机器运行/

        2、激光扫描仪,用于建图和定位

        3、体型要求,navigation是基于正方形机器人开发,因此最好是正方形或圆形; 若为其它形状须更改参数、算法

安装Navigation Stack

其它配置:

设置机器人使用TF

      首先要定义车体坐标系和激光雷达坐标系,并将变换存入tf设置中

创建包:robot_setup_tf

$ cd %TOP_DIR_YOUR_CATKIN_WS%/src
$ catkin_create_pkg robot_setup_tf roscpp tf geometry_msgs

或者在fuerte、groovy、hydo中,

$ sudo apt-get install ros-%YOUR_ROS_DISTRO%-navigation-tutorials 

创建节点广播tf变换

在robot_setup_tf包中,创建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();
  }
}

 使用变换:

#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 = 0.2;
  laser_point.point.z = 0.0;

  try{
    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());
  }
  catch(tf::TransformException& ex){
    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();

}

编译:

在CMakeLists.txt文件中添加:

add_executable(tf_broadcaster src/tf_broadcaster.cpp)
add_executable(tf_listener src/tf_listener.cpp)
target_link_libraries(tf_broadcaster ${catkin_LIBRARIES})
target_link_libraries(tf_listener ${catkin_LIBRARIES})

接下来,确保保存文件并构建包。

$ cd %TOP_DIR_YOUR_CATKIN_WS%
$ catkin_make

 运行代码:

三个终端

roscore

rosrun robot_setup_tf tf_broadcaster

rosrun robot_setup_tf tf_listener

步骤:

(1) 机器人导航需要那些准备?

在调整新机器人上的导航包时遇到的大部分问题都在本地规划器调谐参数之外的区域。机器人的里程计,定位,传感器以及有效运行导航的其他先决条件常常会出错。所以,我做的第一件事是确保机器人本身正在准备好导航。这包括三个组件检查:距离传感器,里程计和定位。

  • 距离传感器

如果机器人没有从其距离传感器(例如激光器)获取信息,那么导航将不起作用。我将确保我可以在rviz中查看传感器信息,它看起来相对正确,并以预期的速度进入。

  • 里程计

通常我会很难使机器人正确定位。它将不断迷失,我会花费大量的时间调试AMCL的参数,发现真正的罪魁祸首是机器人的测距。因此,我总是运行两个健全检查,以确保我相信机器人的里程计。

第一个测试检查角速度是否合理。我打开rviz,将坐标系设置为“odom”,显示机器人提供的激光扫描,将该主题的衰减时间设置为高(类似20秒),并执行原地旋转。然后,我看看扫描出来的边线在随后的旋转中如何相互匹配。理想情况下,每次扫描将刚好落在相互的顶端,会重叠在一起,但是有些旋转漂移是预期的,所以我只是确保扫描之间误差,不会超过一度或两度以上。

第二个测试检查线速度是否合理。机器人放置在与距离墙壁几米远地方,然后以上面相同的方式设置rviz。接着我将驱动机器人向墙壁前进,从rviz中聚合的激光扫描看看扫描出来边线的厚度。理想情况下,墙体应该看起来像一个扫描,但我只是确保它的厚度不超过几厘米。如果显示扫描边线的分散在半米以上,但有些可能是错误的测距。

其他的测试角速和线速方法:

  1. 线速标定:http://www.ncnynl.com/archives/201701/1217.html
  2. 角速标定:http://www.ncnynl.com/archives/201701/1218.html
  3. 线速标定:http://www.ncnynl.com/archives/201707/1812.html
  4. 角速标定:http://www.ncnynl.com/archives/201707/1813.html
  • 定位

假设里程计和激光扫描仪都能合理地执行,建图和调整AMCL通常并不会太糟糕。首先,我将运行gmapping或karto,并操纵机器人来生成地图。然后,我将使用该地图与AMCL,并确保机器人保持定位。如果我运行的机器人的距离不是很好,我会用AMCL的测距模型参数玩一下。对整个系统的一个很好的测试是确保激光扫描和地图可以在rviz的“地图”坐标系中可视化,并且激光扫描与环境地图很好地匹配。

(2)代价地图

  • 一旦我的机器人满足导航的先决条件,我想确保代价地图的设置和配置正确。

  • 如下建议可用来调整代价地图:

    • 确保根据传感器实际发布的速率为每个观测源设置expected_update_rate参数。我通常在这里给出相当的容忍度,把检查的期限提高到我期望的两倍,但是当传感器低于预期速率时,它很容易从导航中接收警告。

    • 为系统适当设置transform_tolerance参数。查看使用tf从“base_link”坐标系到“map”坐标系的转换的预期延迟。我通常使用tf_monitor查看系统的延迟,并将参数保守地设置为关闭。另外,如果tf_monitor报告的延迟足够大,我可能会随时看看导致延迟的原因。这有时会导致我发现关于给定机器人的变换如何发布的问题。

    • 在缺乏处理能力的机器人上,我会考虑关闭map_update_rate参数。然而,在这样做时,我考虑到这将导致传感器数据快速进入代价地图的延迟,这反过来会降低机器人对障碍物的反应速度。

    • 该publish_frequency参数是在rviz可视化costmap有用。然而,特别是对于大型全局地图,该参数可能导致事情运行缓慢。在生产系统中,我考虑降低成本图发布的速度,当我需要可视化非常大的地图时,我确定设置速度真的很低。

    • 是否对代价地图使用voxel_grid或costmap模型的决定在很大程度上取决于机器人具有的传感器套件。调整代价地图为基于3D-based代价地图更多是涉及未知空间的考虑。如果我正在使用的机器人只有一个平面激光,我总是使用costmap模型的地图。

    • 有时,它只能在里程坐标系中运行导航。要做到这一点,我发现最容易做的事情就是我的复制local_costmap_params.yaml文件覆盖global_costmap_params.yaml文件并更改了地图宽度和高度比如10米。如果需要独立的定位性能来调整导航,这是一个简单易行的方法

  • 我倾向于根据机器人的尺寸和处理能力选择我使用的地图的分辨率。在具有很多处理能力并需要适应狭窄空间的机器人,如PR2,我会使用细粒度的地图...将分辨率设置为0.025米。对于像roomba这样的东西,我可能会以高达0.1米的分辨率去降低计算量。

  • Rviz是验证代价地图正常工作的好方法。我通常从代价地图中查看障碍物数据,并确保在操纵杆控制下驱动机器人时,它与地图和激光扫描相一致。这是对传感器数据以合理的方式进入代价地图的合理检查。如果我决定用机器人跟踪未知的空间,主要是这些机器人正在使用voxel_grid模型的代价地图,我一定要看看未知的空间可视化,看看未知的空间被以合理的方式清除。是否正确地从代价地图中清除障碍物的一个很好的检查方法是简单地走在机器人的前面,看看它是否都成功地看到我,并清除我。
  • 当导航包仅运行costmap时,检查系统负载是一个好主意。这意味着提高move_base节点,但不会发送目标点并查看负载。如果计算机在这个时候陷入僵局,我知道如果我想要运行规划器的话,我需要做一些CPU参数调整。

(3) 局部规划器

如果通过代价地图的操作令人满意,我将继续调整局部规划器参数。在具有合理加速度限制的机器人上,我通常使用dwa_local_planner,对于那些具有较低加速度限制的机器人,并且可以从每个步骤考虑到加速限制的,我将使用base_local_planner。调整dwa_local_planner比调整base_local_planner更为愉快,因为它的参数是动态可配置的。为导航包添加dynamic_reconfigure也已经在计划中。针对规划器的提示:

  • 对于给定的机器人最重要的是,正确设置了加速度限制参数。如果这些参数关闭,只能期望来自机器人的次优行为。如果我不知道机器人的加速度极限是什么,我会花点时间写出一个脚本,让电机以最大平移和旋转速度命令运行一段时间,看看报告的里程计速度(假设里程会给出合理的估计),并从中得出加速度极限。合理设置这些参数可以节省很多时间。

  • 如果我正在使用的机器人具有低加速度限制,我确保我正在运行base_local_planner,其中dwa设置为false。将dwa设置为true后,我还将确保根据处理能力将vx_samples参数更新为8到15之间的值。这将允许在展示中生成非圆形曲线。

  • 如果我正在使用的机器人的定位并不是很好,我将确保将目标公差参数设置得比我想象的要高一些。如果机器人具有较高的最小旋转速度以避免在目标点的振荡,那么我也将提高旋转公差。

  • 如果我使用低分辨率的CPU原因,我有时会提高sim_granularity参数,以节省一些周期。

  • 我实际上很少发现自己改变了path_distance_bias和goal_distance_bias(对于base_local_planner这些参数被称为pdist_scale和gdist_scale)参数在计划者上非常多。当我这样做时,通常是因为我试图限制本地规划器自由,让计划的路径与除NavFn以外的全局规划器合作。将path_distance_bias参数增大,将使机器人更紧密地跟随路径,同时以快速向目标向前移动。如果这个值设置得太高,机器人将会拒绝移动,因为移动的代价大于停留在路径上的位置。简单来说就是让实际移动更接近全局路径还是本地路径。

  • 如果我想以聪明的方式介绍代价函数,我将确保将meter_scoring参数设置为true。这使得它在代理函数中的距离以米而不是单元格,也意味着我可以调整一个地图分辨率的代价函数,并且当我移动到他人时期望合理的行为。此外,您现在可以通过将publish_cost_grid参数设置为true来显示本地计划程序在rviz中生成的代价函数。(这不管怎么说,从来没有把它放入文档,我会很快到那个时候)。考虑到以米为单位的代价函数,我可以计算出移动1米的成本与目标平衡的成本的折衷。这倾向于给我一个如何调整东西的体面的想法。

  • 轨迹从其端点得分。这意味着将sim_time参数设置为不同的值可能对机器人的行为有很大的影响。我通常将此参数设置在1-2秒之间,其中设置更高可以导致稍微平滑的轨迹,确保乘以sim_period的最小速度小于目标的两倍。否则,机器人将倾向于在其目标位置的范围之外的位置旋转,而不是朝向目标移动。

  • 精确的轨迹模拟也取决于距离测距的合理速度估计。这来自于dwa_local_planner和base_local_planner都使用这种速度估计以及机器人的加速度限制来确定规划周期的可行速度空间。虽然来自测距的速度估计不一定是完美的,但确保其至少接近得到最佳行为是重要的。

 

参考:

  • https://github.com/zkytony/ROSNavigationGuide/blob/master/main.pdf
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值