机器人算法——costmap膨胀层InflationLaye

news/2025/1/12 22:03:58/

如下图是更新地图膨胀

void InflationLayer::updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j, int max_i, int max_j)
{//用指针master_array指向主地图,并获取主地图的尺寸,确认seen_数组被正确设置。boost::unique_lock < boost::recursive_mutex > lock(*inflation_access_);if (!enabled_ || (cell_inflation_radius_ == 0))return;// make sure the inflation list is empty at the beginning of the cycle (should always be true)ROS_ASSERT_MSG(inflation_cells_.empty(), "The inflation list must be empty at the beginning of inflation");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));// We need to include in the inflation cells outside the bounding// box min_i...max_j, by the amount cell_inflation_radius_.  Cells// up to that distance outside the box can still influence the costs// stored in cells inside the box.//边际膨胀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);// Inflation list; we append cells to visit in a list associated with its distance to the nearest obstacle// We use a map<distance, list> to emulate the priority queue used before, with a notable performance boost//接下来遍历bound中的cell,找到cost为LETHAL_OBSTACLE,即障碍物cell,将其以CellData形式放进inflation_cells_[0.0]中,inflation_cells_的定义如下://std::map<double, std::vector > inflation_cells_;//它是一个映射,由浮点数→CellData数组,CellData这个类定义在inflation_layer.h中,//是专门用来记录当前cell的索引和与它最近的障碍物的索引的。这个映射以距离障碍物的距离为标准给bound内的cell归类,为膨胀做准备;//自然距离为0对应的cell即障碍物cell本身,//目前得到的inflation_cells_只包括障碍物本身。// Start with lethal obstacles: by definition distance is 0.0std::vector<CellData>& obs_bin = inflation_cells_[0.0];for (int j = min_j; j < max_j; j++){for (int i = min_i; i < max_i; i++){int index = master_grid.getIndex(i, j);unsigned char cost = master_array[index];if (cost == LETHAL_OBSTACLE){obs_bin.push_back(CellData(index, i, j, i, j));}}}// Process cells by increasing distance; new cells are appended to the corresponding distance bin, so they// can overtake previously inserted but farther away cells//通过增加距离处理细胞;新的单元格被附加到相应的距离仓中,因此它们//可以超越先前插入但距离更远的单元格std::map<double, std::vector<CellData> >::iterator bin;for (bin = inflation_cells_.begin(); bin != inflation_cells_.end(); ++bin){for (int i = 0; i < bin->second.size(); ++i){// process all cells at distance dist_bin.firstconst CellData& cell = bin->second[i];unsigned int index = cell.index_;// ignore if already visitedif (seen_[index]){continue;}seen_[index] = true;unsigned int mx = cell.x_;unsigned int my = cell.y_;unsigned int sx = cell.src_x_;unsigned int sy = cell.src_y_;// assign the cost associated with the distance from an obstacle to the cellunsigned char cost = costLookup(mx, my, sx, sy);unsigned char old_cost = master_array[index];if (old_cost == NO_INFORMATION && (inflate_unknown_ ? (cost > FREE_SPACE) : (cost >= INSCRIBED_INFLATED_OBSTACLE)))master_array[index] = cost;elsemaster_array[index] = std::max(old_cost, cost);// attempt to put the neighbors of the current cell onto the inflation listif (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);}}inflation_cells_.clear();
}

InflationLayer没有自身的栅格地图要维护,直接在主地图上进行操作,它根据膨胀参数设置用来膨胀的“参考矩阵”,并在主地图上从障碍物出发,不断传播更新,完成对整个地图障碍的膨胀。
不断的从障碍物周围”上下左右“开始膨胀,并且根据参考矩阵去计算不同距离的栅格权重。

 // assign the cost associated with the distance from an obstacle to the cellunsigned char cost = costLookup(mx, my, sx, sy);unsigned char old_cost = master_array[index];if (old_cost == NO_INFORMATION && (inflate_unknown_ ? (cost > FREE_SPACE) : (cost >= INSCRIBED_INFLATED_OBSTACLE)))master_array[index] = cost;elsemaster_array[index] = std::max(old_cost, cost);

unsigned char cost = costLookup(mx, my, sx, sy);为参考矩阵计算, master_array[index] = cost;为当前cell栅格赋值。

 // attempt to put the neighbors of the current cell onto the inflation listif (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);}

这是考察下一个点,上下左右,如果在障碍物半径内,则继续循环到上述的“ unsigned char cost = costLookup(mx, my, sx, sy);为参考矩阵计算, master_array[index] = cost;为当前cell栅格赋值。”

如此循环即可,类似于A*算法的膨胀。

/**
*@brief给定成本图中某个单元格的索引,将其放入等待障碍物膨胀的列表中
*@param grid成本图
*@param index单元格的索引
*@param mx单元格的x坐标(可以根据索引计算,但可以节省存储时间)
*@param my单元格的y坐标(可以根据索引计算,但可以节省存储时间)
*@param src_x障碍点通货膨胀的x指数开始于
*@param src_y障碍点通货膨胀的y指数始于
*/
inline void InflationLayer::enqueue(unsigned int index, unsigned int mx, unsigned int my,unsigned int src_x, unsigned int src_y)
{if (!seen_[index]){// we compute our distance table one cell further than the inflation radius dictates so we can make the check belowdouble distance = distanceLookup(mx, my, src_x, src_y);// we only want to put the cell in the list if it is within the inflation radius of the obstacle pointif (distance > cell_inflation_radius_)return;// push the cell data onto the inflation list and markinflation_cells_[distance].push_back(CellData(index, mx, my, src_x, src_y));}
}
 double distance = distanceLookup(mx, my, src_x, src_y);

使用计算考察点和障碍物的距离,然后判断是否在膨胀半径内,如果是,则保存到nflation_cells_中用于下一次循环中。

Reference

  1. 机器人控制—代价地图Costmap的层概述

http://www.ppmy.cn/news/1246779.html

相关文章

【傻瓜级JS-DLL-WINCC-PLC交互】1.C#用windows窗体控件创建.net控件

思路 JS-DLL-WINCC-PLC之间进行交互&#xff0c;思路&#xff0c;先用Visual Studio创建一个C#的DLL控件&#xff0c;然后这个控件里面嵌入浏览器组件&#xff0c;实现JS与DLL通信&#xff0c;然后DLL放入到WINCC里面的图形编辑器中&#xff0c;实现DLL与WINCC的通信。然后PLC与…

Vue 双向数据绑定

之前通过v-bind来完成的数据绑定&#xff0c;属性值和表达式进行绑定&#xff0c;表达式的值发生变化了属性值也跟着发生变化。 单向数据绑定&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>首页</titl…

高质量短效SOCKS5代理IP是什么意思?作为技术你了解吗

小张是一位网络安全技术测试员&#xff0c;最近他接到了一个头疼的任务&#xff0c;那就是评估公司系统的安全性&#xff0c;因此他前来咨询&#xff0c;在得知SOCKS5代理IP可以帮他之后&#xff0c;他不禁产生疑问&#xff0c;这是什么原理&#xff1f;其实和小张一样的朋友不…

高翔:《自动驾驶与机器人中的SLAM技术 》-Slam_in_autonomous_driving 编译过程中遇到的问题

使用的环境是ubuntu20.04 问题1.安装g2o没有问题&#xff0c;不过在编译整个项目工程时候报错&#xff1a; ”openmp_mutex.h: 30:10: fatal error: g2o/config.h: No such file or directory“: 解决办法&#xff1a; 只需要将/thirdparty/g2o/build/g2o下的config.h放到/…

力扣labuladong——一刷day57

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣1379. 找出克隆二叉树中的相同节点二、力扣LCR 143. 子结构判断三、力扣110. 平衡二叉树四、力扣250. 统计同值子树 前言 有些题目&#xff0c;你按照拍…

优雅编写测试代码:在pytest中利用Fixture实现自动化测试!

什么是固件 Fixture 翻译成中文即是固件的意思。它其实就是一些函数&#xff0c;会在执行测试方法/测试函数之前&#xff08;或之后&#xff09;加载运行它们&#xff0c;常见的如接口用例在请求接口前数据库的初始连接&#xff0c;和请求之后关闭数据库的操作。 我们之前已经…

摄影网站的技术 SEO:提示和最佳实践

摄影就是要给人留下良好的第一印象。如果你想在竞争中领先&#xff0c;摄影师的SEO是您可以采用的最佳营销方法之一。 我们都曾有过这样的经历&#xff1a;你建立了一个漂亮的作品集网站来吸引更多的业务。网站上线并在社交媒体上推广后&#xff0c;您就可以坐等了。网站访问量…

【Linux】探索进程的父与子

目录 1.获取进程PID1.1进程PPID 2.通过系统调用创建进程-fork初识2.1为什么fork函数要给子进程返回0&#xff0c;给父进程返回pid&#xff1f;fork函数如何做到返回两次的&#xff1f;fork干了什么事情&#xff1f;怎么理解一个变量为什么有两个不同的值&#xff1f;如果父子进…