costmap_2d详解3:costmap_2d_ros.cpp

整体概述:

    Costmap2DROS 类,它是move_base 调用costmap_2d 生成代价地图的入口,整体的逻辑都在这里面。

Costmap2DROS构造函数,实例化LayeredCostmap的指针,根据yaml配置文件中plugins参数生成相应类型的各个层Layer plugin,并添加到LayeredCostmap 的plugins_指针列表中后面使用,调用到各层的初始化函数,调用重配置函数reconfigureCB,创建多线程,同时更新地图

reconfigureCB 创建多线程,并调用mapUpdateLoop,在它中调用updateMap() 函数更新各层costmap 边界和cost值,之后在发布出去

在updateMap()中,得到global_frame_ 与robot_base_frame_ tf转换信息中的 translation 坐标信息,并调用LayeredCostmap 的updateMap(x, y, yaw) 函数,更新各层costmap 边界和cost 值

 

关键变量:

LayeredCostmap* layered_costmap_; //LayeredCostmap 类指针,管理各层costmap
global_frame_;
robot_base_frame_;
tf_;
plugin_loader_; //加载各层costmap 到 LayeredCostmap 中

 

关键函数

/*作用: 构造函数,

*name : costmap 名称,如global_costmap和local_costmap

* tf :  从move_base 传过来的tf 转换

*/

Costmap2DROS::Costmap2DROS(std::string name, tf::TransformListener& tf)

{

  //在这里可以区分global_costmap 和local_costmap
  ros::NodeHandle private_nh("~/" + name);

/*如果是global_costmap,两参数分别是
*   global_frame: /map
*  robot_base_frame: /base_footprint
*****************************************************
* 如果是local_costmap 两参数分别是
*   global_frame: /odom_combined
*  robot_base_frame: /base_footprint
*/
  private_nh.param("global_frame", global_frame_, std::string("/map"));
  private_nh.param("robot_base_frame", robot_base_frame_, std::string("base_link"));


/*如果是global_costmap,rolling_window=false
*如果是local_costmap,rolling_window=true
*track_unknown_space 都默认是false
*/
private_nh.param("rolling_window", rolling_window, false);private_nh.param("track_unknown_space", track_unknown_space, false);

//实例化LayeredCostmap的指针,也初始化来master costmap
layered_costmap_ = new LayeredCostmap(global_frame_, rolling_window, track_unknown_space);

/*
*判断导入的参数是否有plugins
*/
if (private_nh.hasParam("plugins"))
{
XmlRpc::XmlRpcValue my_list;

//把要加载的costmap 插件层添加进来
private_nh.getParam("plugins", my_list);
for (int32_t i = 0; i < my_list.size(); ++i)
{
//创建一个以 type为类类型的实例变量,然后让plugin这个指针指向这个实例
/* 两个值例如为:
* name: static_layer,       type: "costmap_2d::StaticLayer”
*/
std::string pname = static_cast(my_list[i]["name"]);
std::string type = static_cast(my_list[i]["type"]);

/* 创建一个以 type为类类型的实例变量,然后让plugin这个指针指向这个实例
并把这层地图加入到layered_costmap_ 中统一管理
*/

//定义Layer 的智能指针,并实例化
boost::shared_ptr plugin = plugin_loader_.createInstance(type);

//添加到 LayeredCostmap 中的plugins_ 列表末尾
layered_costmap_->addPlugin(plugin);

/*这里就会调用到Layer的initialize 函数,initialize 在父类layer.cpp 中,它会调用虚函数onInitialize,
* 最后各个plugin 层会实现该方法
*/
plugin->initialize(layered_costmap_, name + "/" + pname, &tf_);


/*还没详细看*/    
setUnpaddedRobotFootprint(makeFootprintFromParams(private_nh));


//把地图更新过的部分发布出去

  publisher_ = new Costmap2DPublisher(&private_nh, layered_costmap_->getCostmap(), global_frame_, "costmap",always_send_full_costmap);

  // create a thread to handle updating the map
  stop_updates_ = false;
  initialized_ = true;
  stopped_ = false;

  // Create a time r to check if the robot is moving
  robot_stopped_ = false;
  /*回调函数movementCB 实现,是通过比较前后两个pose的差,判断机器人是否在移动*/
  timer_ = private_nh.createTimer(ros::Duration(.1), &Costmap2DROS::movementCB, this);
  dsrv_ = new dynamic_reconfigure::Server(ros::NodeHandle("~/" + name));

  /*除了对一些类成员的配置值做赋值以外,还会开启一个更新map的线程*/

  dynamic_reconfigure::Server::CallbackType \

cb = boost::bind(&Costmap2DROS::reconfigureCB, this, _1, _2);
  dsrv_->setCallback(cb);

}
}
}

 

/*根据参数对地图进行调整,另外还会重新启动地图更新线程mapUpdateLoop(因此,地图更新线程在这里启动)。*/

void Costmap2DROS::reconfigureCB(costmap_2d::Costmap2DConfig &config, uint32_t level)
{
 //都是1.0
  transform_tolerance_ = config.transform_tolerance;

//如果已经更新则不用更新
  if (map_update_thread_ != NULL)
  {
    map_update_thread_shutdown_ = true;
    map_update_thread_->join();
    delete map_update_thread_;
  }
  map_update_thread_shutdown_ = false;
  //配置地图更新频率
  double map_update_frequency = config.update_frequency;

  double map_publish_frequency = config.publish_frequency;
/*
如果是global_costmap:
map_width_meters = config.width  //暂时不知
map_height_meters = config.height  //暂时不知
resolution = config.resolution //0.05
origin_x = config.origin_x  //应该是地图左下角坐标(即像素坐标系原点)
origin_y = config.origin_y

**************************************
如果是local_costmap:
map_width_meters = config.width  //3.0
map_height_meters = config.height  //3.0
resolution = config.resolution //0.05
origin_x = config.origin_x  //应该是机器人局部costmap左下角
origin_y = config.origin_y      
*/

double map_width_meters = config.width, map_height_meters = config.height, resolution = config.resolution, origin_x =config.origin_x,origin_y = config.origin_y;

//如果已经膨胀填充,重新计算填充一次
  if (footprint_padding_ != config.footprint_padding)
  {
    footprint_padding_ = config.footprint_padding;
    setUnpaddedRobotFootprint(unpadded_footprint_);
  }

  readFootprintFromConfig(config, old_config_);
//记录现在的配置为旧的配置,可能用于恢复以前的配置
  old_config_ = config;

  //启动地图更新线程mapUpdateLoop
  map_update_thread_ = new boost::thread(boost::bind(&Costmap2DROS::mapUpdateLoop, this, map_update_frequency));
}

 

void Costmap2DROS::mapUpdateLoop(double frequency)
{
  while (nh.ok() && !map_update_thread_shutdown_)
  {
    //更新边界和地图
    updateMap();
  }
}

 

/*updateMap函数是地图信息更新的地方,其内部调用了LayeredCostmap->updateMap(double robot_x, double robot_y, double robot_yaw)函数。

 * 在该函数中,先依据各层的更新情况,判断地图更新过的范围的边界。然后用初始值重置全局地图更新

 * 边界范围内的地图信息,并用各层的信息在更新边界内部更新地图信息

*/

void Costmap2DROS::updateMap()
{
  if (!stop_updates_)
  {
tf::Stamped < tf::Pose > pose;
//得到global_frame_ 与robot_base_frame_ tf转换信息中的 translation 坐标信息
    if (getRobotPose (pose))
    {
      //获取当前机器人位置,必须要弄清楚这个x,y 代表什么意思
      double x = pose.getOrigin().x(),
      y = pose.getOrigin().y(),
      yaw = tf::getYaw(pose.getRotation());

/*调用LayeredCostmap 类中的updateMap 更新边界和cost值
*先依据各层的更新情况,判断地图更新过的范围的边界。
* 然后用初始值重置全局地图更新边界范围内的地图信息,
* 并用各层的信息在更新边界内部更新地图信息
*/
      layered_costmap_->updateMap(x, y, yaw);

      geometry_msgs::PolygonStamped footprint;
      footprint.header.frame_id = global_frame_;
      footprint.header.stamp = ros::Time::now();
      transformFootprint(x, y, yaw, padded_footprint_, footprint);
      footprint_pub_.publish(footprint);
      initialized_ = true;
    }
  }
}

bool Costmap2DROS::getRobotPose(tf::Stamped& global_pose) const
{
  //local_costmap和global_costmap的robot_base_frame_都是是/base_footprint
  robot_pose.frame_id_ = robot_base_frame_;

  try
  {
    /*
    *如果是local_costmap,global_frame_是/map
    * 如果是global_costmap 是/odom_combined
    * 然后根据tf信息,转换的到global_pose,即机器人当前位置??
    *得到global_frame_ 与robot_base_frame_ tf转换信息中的 translation 坐标信息
    */
    tf_.transformPose(global_frame_, robot_pose, global_pose);
  }
  return true;
}

 

/*启动地图运行,内部包括激活各层、启动地图更新循环。可以在stop或者

 * pause调用之后用于重新启动地图

*/

void Costmap2DROS::start()

 

/*停止地图运行,内部包括去激活各层、停止地图更新循环*/

void Costmap2DROS::stop()

/*暂停地图运行,内部包括停止地图更新循环*/

void Costmap2DROS::pause()

/*复位地图运行,内部包括恢复地图更新循环*/

void Costmap2DROS::resume()

/*重置地图,内部包括重置总地图、重置地图各层*/

void Costmap2DROS::resetLayers()

 

你可能感兴趣的:(ros)