关键参数
cell_inflation_radius_ //通过膨胀半径/分辨率得到的膨胀栅格数
unsigned char** cached_costs_;
double** cached_distances_;
关键函数
构造函数:
void InflationLayer::onInitialize()
{
matchSize();
}
void InflationLayer::matchSize()
{
boost::unique_lock < boost::recursive_mutex > lock(*inflation_access_);
costmap_2d::Costmap2D* costmap = layered_costmap_->getCostmap();
resolution_ = costmap->getResolution();
//通过膨胀半径计算膨胀栅格个数
cell_inflation_radius_ = cellDistance(inflation_radius_);
//这里最重要,计算膨胀栅格的cost值
computeCaches();
unsigned int size_x = costmap->getSizeInCellsX(), size_y = costmap->getSizeInCellsY();
if (seen_)
delete[] seen_;
seen_size_ = size_x * size_y;
seen_ = new bool[seen_size_];
}
/*
* 分配二维数组,计算出栅格距离核心膨胀栅格的距离,然后根据距离计算出该膨胀
* 栅格的cost值
*/
void InflationLayer::computeCaches()
{
//cell_inflation_radius的缓存,出现变化,二者不同的时候,要重新计算kernel和costs
if (cell_inflation_radius_ != cached_cell_inflation_radius_)
{
deleteKernels();
//分配指针数组,为什么要加上2
cached_costs_ = new unsigned char*[cell_inflation_radius_ + 2];
cached_distances_ = new double*[cell_inflation_radius_ + 2];
for (unsigned int i = 0; i <= cell_inflation_radius_ + 1; ++i)
{//指针数组指向2×2 数组,存在costs 和 distances
cached_costs_[i] = new unsigned char[cell_inflation_radius_ + 2];
cached_distances_[i] = new double[cell_inflation_radius_ + 2];
for (unsigned int j = 0; j <= cell_inflation_radius_ + 1; ++j)
{//根据栅格个数cell_inflation_radius_,计算出距离
cached_distances_[i][j] = hypot(i, j);
}
}
cached_cell_inflation_radius_ = cell_inflation_radius_;
}
for (unsigned int i = 0; i <= cell_inflation_radius_ + 1; ++i)
{
for (unsigned int j = 0; j <= cell_inflation_radius_ + 1; ++j)
{//根据距离计算出cost 值,一共三种情况,距离为0时,cost=254 为致命障碍
//距离小于内切圆半径时,为253,
//距离大于内切圆半径时,cost=252* e-weight_*(距离—内切半径)
cached_costs_[i][j] = computeCost(cached_distances_[i][j]);
}
}
}
/*
*根据距离计算出cost 值,一共三种情况,距离为0时,cost=254 为致命障碍
*距离小于内切圆半径时,为253,
*距离大于内切圆半径时,cost=252* e(-weight_*(距离—内切半径))
*/
inline unsigned char computeCost(double distance) const
{
unsigned char cost = 0;
if (distance == 0)
cost = LETHAL_OBSTACLE;
else if (distance * resolution_ <= inscribed_radius_)
cost = INSCRIBED_INFLATED_OBSTACLE;
else
{
double euclidean_distance = distance * resolution_;
double factor = exp(-1.0 * weight_ * (euclidean_distance - inscribed_radius_));
cost = (unsigned char)((INSCRIBED_INFLATED_OBSTACLE - 1) * factor);
}
return cost;
}
/*
对于膨胀层,基本是在传入的地图边界信息的基础上在扩大一个膨胀半径更新地图边界信息
*/
void InflationLayer::updateBounds(double robot_x, double robot_y, double robot_yaw, double* min_x,double* min_y, double* max_x, double* max_y)
/*对于膨胀层,只是对已有的地图进行膨胀,因此其内部不会进行自身层更新。
在updateCosts函数中,该层对更新范围内的地图信息进行膨胀操作,
即在LETHA_OBSTACLE信息的像素周围进行膨胀
*/
void InflationLayer::updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j, int max_i,int max_j)
{
unsigned char* master_array = master_grid.getCharMap();
unsigned int size_x = master_grid.getSizeInCellsX(), size_y = master_grid.getSizeInCellsY();
if (seen_ == NULL) {
ROS_WARN("InflationLayer::updateCosts(): seen_ array is NULL");
seen_size_ = size_x * size_y;
seen_ = new bool[seen_size_];
}
else if (seen_size_ != size_x * size_y)
{
ROS_WARN("InflationLayer::updateCosts(): seen_ array size is wrong");
delete[] seen_;
seen_size_ = size_x * size_y;
seen_ = new bool[seen_size_];
}
memset(seen_, false, size_x * size_y * sizeof(bool));
//扩大一点范围,主要扩大local_costmap 的范围吧
min_i -= cell_inflation_radius_;
min_j -= cell_inflation_radius_;
max_i += cell_inflation_radius_;
max_j += cell_inflation_radius_;
min_i = std::max(0, min_i);
min_j = std::max(0, min_j);
max_i = std::min(int(size_x), max_i);
max_j = std::min(int(size_y), max_j);
for (int j = min_j; j < max_j; j++)
{
for (int i = min_i; i < max_i; i++)
{
//master costmap 中的索引
int index = master_grid.getIndex(i, j);
unsigned char cost = master_array[index];
//如果这个像素的cost值比现在的大,就覆盖更新
if (cost == LETHAL_OBSTACLE)
{
/*
*把master costmap障碍物的点添加到膨胀队列中,作为起始点,然后把该点的前后左右
* 距离符合条件的点加入到膨胀队列中,这样逐渐往外膨胀,并且在下一次计算前后左右
* 点时,起始点(原来master costmap中一系列点)不变,距离起始点距离变了
*/
enqueue(index, i, j, i, j);
}
}
}
//根据膨胀队列,进行膨胀
while (!inflation_queue_.empty())
{
// get the highest priority cell and pop it off the priority queue
const CellData& current_cell = inflation_queue_.top();
unsigned int index = current_cell.index_;
unsigned int mx = current_cell.x_;
unsigned int my = current_cell.y_;
unsigned int sx = current_cell.src_x_;
unsigned int sy = current_cell.src_y_;
// pop once we have our cell info
inflation_queue_.pop();
// set the cost of the cell being inserted
if (seen_[index])
{
continue;
}
seen_[index] = true;
//更新膨胀队列中点的cost 值
unsigned char cost = costLookup(mx, my, sx, sy);
unsigned char old_cost = master_array[index];
if (old_cost == NO_INFORMATION && cost >= INSCRIBED_INFLATED_OBSTACLE)
master_array[index] = cost;
else
master_array[index] = std::max(old_cost, cost);
// 尝试将当前单元的邻居(前后左右)放到队列中
if (mx > 0)
enqueue(index - 1, mx - 1, my, sx, sy);
if (my > 0)
enqueue(index - size_x, mx, my - 1, sx, sy);
if (mx < size_x - 1)
enqueue(index + 1, mx + 1, my, sx, sy);
if (my < size_y - 1)
enqueue(index + size_x, mx, my + 1, sx, sy);
}
}
/*
*作用:给出在master costmap 中的索引值(即一个点),将其放入优先队列中,以应对障碍膨胀
*/
inline void InflationLayer::enqueue(unsigned int index, unsigned int mx, unsigned int my,unsigned int src_x, unsigned int src_y)
{
if (!seen_[index])
{
double distance = distanceLookup(mx, my, src_x, src_y);
if (distance > cell_inflation_radius_)
return;
//保存膨胀栅格点的情况
CellData data(distance, index, mx, my, src_x, src_y);
//把该点放到膨胀队列中
inflation_queue_.push(data);
}
}
/*
*与起始点距离比对,并从cost 缓存中获取相应的cost值
*/
inline unsigned char costLookup(int mx, int my, int src_x, int src_y)
{
unsigned int dx = abs(mx - src_x);
unsigned int dy = abs(my - src_y);
return cached_costs_[dx][dy];
}