algorithmn

算法的解释

Dijkstra

其实就是A star或者Dijkstra(基于priority queue实现的)的路径规划算法,关键是相邻点之间的cost怎么计算,怎么从可行点找到path

Navfn's optimal path is based on a path's "potential"(可能可以行走的目标). The potential is the relative cost of a

path based on the distance from the goal and from the existing path itself.(怎么计算两个点之间的距离cost) It must be noted that Navfn update's each cell's potential in the potential map, or potarr(定义的potential array变量) as it's called in navfn, as it checks that cell. This way,it can step back through the potential array to find the best possible path. The potential is determined by the cost of traversing a cell (traversability factor, hf)

and the distance away that the next cell is from the previous cell.

parameter

navfn 参数

global planner

上面两个链接一个是navfn的配置,一个是具体哪个global planner的配置,具体的global planner 是可以覆盖navfn中的配置(要是大家有相同的参数)

比如下面这个参数global planner中的可以覆盖navfn中的配置:

~<name>/allow_unknown (bool, default: true)

这个参数可以让你看见potential array的图像,看计算出的cost是怎么样子(颜色深浅代表距离起始点的远近)

~<name>/visualize_potential (bool, default: false)

code

void GlobalPlanner::initialize(std::string name, costmap_2d::Costmap2D* costmap, std::string frame_id) {
if(!old_navfn_behavior_)
convert_offset_ = 0.5;
else
convert_offset_ = 0.0; if (use_quadratic)
p_calc_ = new QuadraticCalculator(cx, cy);
else
p_calc_ = new PotentialCalculator(cx, cy); if (use_dijkstra)
{
DijkstraExpansion* de = new DijkstraExpansion(p_calc_, cx, cy);
if(!old_navfn_behavior_)
de->setPreciseStart(true);
planner_ = de;
}
else
planner_ = new AStarExpansion(p_calc_, cx, cy); if (use_grid_path)
path_maker_ = new GridPath(p_calc_);
else
path_maker_ = new GradientPath(p_calc_);
//发布一个make_plan的service
make_plan_srv_ = private_nh.advertiseService("make_plan", &GlobalPlanner::makePlanService, this); } bool GlobalPlanner::makePlanService(nav_msgs::GetPlan::Request& req, nav_msgs::GetPlan::Response& resp) {
makePlan(req.start, req.goal, resp.plan.poses);
} bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal,
std::vector<geometry_msgs::PoseStamped>& plan) {
return makePlan(start, goal, default_tolerance_, plan);
} bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal,
double tolerance, std::vector<geometry_msgs::PoseStamped>& plan) {
double wx = start.pose.position.x;
double wy = start.pose.position.y; if (!costmap_->worldToMap(wx, wy, start_x_i, start_y_i)) {
ROS_WARN("The robot's start position is off the global costmap. Planning will always fail, are you sure the robot has been properly localized?");
return false;
} if(old_navfn_behavior_){
start_x = start_x_i;
start_y = start_y_i;
}else{
worldToMap(wx, wy, start_x, start_y);
} wx = goal.pose.position.x;
wy = goal.pose.position.y; if (!costmap_->worldToMap(wx, wy, goal_x_i, goal_y_i)) {
ROS_WARN_THROTTLE(1.0,"The goal sent to the global planner is off the global costmap. Planning will always fail to this goal.");
return false;
}
if(old_navfn_behavior_){
goal_x = goal_x_i;
goal_y = goal_y_i;
}else{
worldToMap(wx, wy, goal_x, goal_y);
}
//clear the starting cell within the costmap because we know it can't be an obstacle
//设置起点为FREE_SPACE
clearRobotCell(start_pose, start_x_i, start_y_i); int nx = costmap_->getSizeInCellsX(), ny = costmap_->getSizeInCellsY(); //make sure to resize the underlying array that Navfn uses
p_calc_->setSize(nx, ny);
planner_->setSize(nx, ny);
path_maker_->setSize(nx, ny);
potential_array_ = new float[nx * ny]; //将costmap的四周(边界)变为LETHAL_OBSTACLE
outlineMap(costmap_->getCharMap(), nx, ny, costmap_2d::LETHAL_OBSTACLE); // 寻找potential array
bool found_legal = planner_->calculatePotentials(costmap_->getCharMap(), start_x, start_y, goal_x, goal_y,
nx * ny * 2, potential_array_);
//对终点的处理
if(!old_navfn_behavior_)
planner_->clearEndpoint(costmap_->getCharMap(), potential_array_, goal_x_i, goal_y_i, 2);
if(publish_potential_)
publishPotential(potential_array_); if (found_legal) {
//extract the plan,提取路径
if (getPlanFromPotential(start_x, start_y, goal_x, goal_y, goal, plan)) {
//make sure the goal we push on has the same timestamp as the rest of the plan
geometry_msgs::PoseStamped goal_copy = goal;
goal_copy.header.stamp = ros::Time::now();
plan.push_back(goal_copy);
} else {
ROS_ERROR("Failed to get a plan from potential when a legal potential was found. This shouldn't happen.");
}
}else{
ROS_ERROR("Failed to get a plan.");
} // add orientations if needed,对方向的处理
orientation_filter_->processPath(start, plan); //publish the plan for visualization purposes
publishPlan(plan);
delete potential_array_;
return !plan.empty(); nx * ny * 2, potential_array_);
}

主要是以下三个函数

可能不同的配置有不同的实现,但是每个函数的实现功能是一样的。

计算所有的可行点

namespace global_planner {
bool DijkstraExpansion::calculatePotentials(unsigned char* costs, double start_x, double start_y, double end_x, double end_y,
int cycles, float* potential) {
cells_visited_ = 0;
// priority buffers
threshold_ = lethal_cost_;
currentBuffer_ = buffer1_;
currentEnd_ = 0;
nextBuffer_ = buffer2_;
nextEnd_ = 0;
overBuffer_ = buffer3_;
overEnd_ = 0;
memset(pending_, 0, ns_ * sizeof(bool));
std::fill(potential, potential + ns_, POT_HIGH); // set goal
int k = toIndex(start_x, start_y); if(precise_)
{
double dx = start_x - (int)start_x, dy = start_y - (int)start_y;
dx = floorf(dx * 100 + 0.5) / 100;
dy = floorf(dy * 100 + 0.5) / 100;
potential[k] = neutral_cost_ * 2 * dx * dy;
potential[k+1] = neutral_cost_ * 2 * (1-dx)*dy;
potential[k+nx_] = neutral_cost_*2*dx*(1-dy);
potential[k+nx_+1] = neutral_cost_*2*(1-dx)*(1-dy);//*/ push_cur(k+2);
push_cur(k-1);
push_cur(k+nx_-1);
push_cur(k+nx_+2); push_cur(k-nx_);
push_cur(k-nx_+1);
push_cur(k+nx_*2);
push_cur(k+nx_*2+1);
}else{
potential[k] = 0;
push_cur(k+1);
push_cur(k-1);
push_cur(k-nx_);
push_cur(k+nx_);
} int nwv = 0; // max priority block size
int nc = 0; // number of cells put into priority blocks
int cycle = 0; // which cycle we're on // set up start cell
int startCell = toIndex(end_x, end_y); for (; cycle < cycles; cycle++) // go for this many cycles, unless interrupted
{
//
if (currentEnd_ == 0 && nextEnd_ == 0) // priority blocks empty
return false; // stats
nc += currentEnd_;
if (currentEnd_ > nwv)
nwv = currentEnd_; // reset pending_ flags on current priority buffer
int *pb = currentBuffer_;
int i = currentEnd_;
while (i-- > 0)
pending_[*(pb++)] = false; // process current priority buffer
pb = currentBuffer_;
i = currentEnd_;
while (i-- > 0)
updateCell(costs, potential, *pb++); // swap priority blocks currentBuffer_ <=> nextBuffer_
currentEnd_ = nextEnd_;
nextEnd_ = 0;
pb = currentBuffer_; // swap buffers
currentBuffer_ = nextBuffer_;
nextBuffer_ = pb; // see if we're done with this priority level
if (currentEnd_ == 0) {
threshold_ += priorityIncrement_; // increment priority threshold
currentEnd_ = overEnd_; // set current to overflow block
overEnd_ = 0;
pb = currentBuffer_; // swap buffers
currentBuffer_ = overBuffer_;
overBuffer_ = pb;
} // check if we've hit the Start cell
if (potential[startCell] < POT_HIGH)
break;
}
//ROS_INFO("CYCLES %d/%d ", cycle, cycles);
if (cycle < cycles)
return true; // finished up here
else
return false;计算路径path
}
}

怎么计算一个点的可行点

namespace global_planner {

float QuadraticCalculator::calculatePotential(float* potential, unsigned char cost, int n, float prev_potential) {
// get neighbors
float u, d, l, r;namespace
l = potential[n - 1];
r = potential[n + 1];
u = potential[n - nx_];
d = potential[n + nx_];
// ROS_INFO("[Update] c: %f l: %f r: %f u: %f d: %f\n",
// potential[n], l, r, u, d);
// ROS_INFO("[Update] cost: %d\n", costs[n]); // find lowest, and its lowest neighbor
float ta, tc;
if (l < r)
tc = l;
else
tc = r;
if (u < d)
ta = u;
else
ta = d; float hf = cost; // traversability factor
float dc = tc - ta; // relative cost between ta,tc
if (dc < 0) // tc is lowest
{
dc = -dc;
ta = tc;
} // calculate new potential
if (dc >= hf) // if too large, use ta-only update
return ta + hf;
else // two-neighbor interpolation update
{
// use quadratic approximation
// might speed this up through table lookup, but still have to
// do the divide
float d = dc / hf;
float v = -0.2301 * d * d + 0.5307 * d + 0.7040;
return ta + hf * v;
}
}
};

从可行点中计算路径path

bool GradientPath::getPath(float* potential, double start_x, double start_y, double goal_x, double goal_y, std::vector<std::pair<float, float> >& path) {
std::pair<float, float> current;
int stc = getIndex(goal_x, goal_y); // set up offset
float dx = goal_x - (int)goal_x;
float dy = goal_y - (int)goal_y;
int ns = xs_ * ys_;
memset(gradx_, 0, ns * sizeof(float));
memset(grady_, 0, ns * sizeof(float)); int c = 0;
while (c++<ns*4) {
// check if near goal
double nx = stc % xs_ + dx, ny = stc / xs_ + dy; if (fabs(nx - start_x) < .5 && fabs(ny - start_y) < .5) {
current.first = start_x;
current.second = start_y;
path.push_back(current);
return true;
} if (stc < xs_ || stc > xs_ * ys_ - xs_) // would be out of bounds
{
printf("[PathCalc] Out of bounds\n");
return false;
} current.first = nx;
current.second = ny; //ROS_INFO("%d %d | %f %f ", stc%xs_, stc/xs_, dx, dy); path.push_back(current); bool oscillation_detected = false;
int npath = path.size();
if (npath > 2 && path[npath - 1].first == path[npath - 3].first
&& path[npath - 1].second == path[npath - 3].second) {
ROS_DEBUG("[PathCalc] oscillation detected, attempting fix.");
oscillation_detected = true;
} int stcnx = stc + xs_;
int stcpx = stc - xs_; // check for potentials at eight positions near cell
if (potential[stc] >= POT_HIGH || potential[stc + 1] >= POT_HIGH || potential[stc - 1] >= POT_HIGH
|| potential[stcnx] >= POT_HIGH || potential[stcnx + 1] >= POT_HIGH || potential[stcnx - 1] >= POT_HIGH
|| potential[stcpx] >= POT_HIGH || potential[stcpx + 1] >= POT_HIGH || potential[stcpx - 1] >= POT_HIGH
|| oscillation_detected) {
ROS_DEBUG("[Path] Pot fn boundary, following grid (%0.1f/%d)", potential[stc], (int) path.size());
// check eight neighbors to find the lowest
int minc = stc;
int minp = potential[stc];
int st = stcpx - 1;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st++;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st++;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st = stc - 1;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st = stc + 1;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st = stcnx - 1;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st++;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
st++;
if (potential[st] < minp) {
minp = potential[st];
minc = st;
}
stc = minc;
dx = 0;
dy = 0; //ROS_DEBUG("[Path] Pot: %0.1f pos: %0.1f,%0.1f",
// potential[stc], path[npath-1].first, path[npath-1].second); if (potential[stc] >= POT_HIGH) {
ROS_DEBUG("[PathCalc] No path found, high potential");
//savemap("navfn_highpot");
return 0;
}
} // have a good gradient here
else { // get grad at four positions near cell
gradCell(potential, stc);
gradCell(potential, stc + 1);
gradCell(potential, stcnx);
gradCell(potential, stcnx + 1); // get interpolated gradient
float x1 = (1.0 - dx) * gradx_[stc] + dx * gradx_[stc + 1];
float x2 = (1.0 - dx) * gradx_[stcnx] + dx * gradx_[stcnx + 1];
float x = (1.0 - dy) * x1 + dy * x2; // interpolated x
float y1 = (1.0 - dx) * grady_[stc] + dx * grady_[stc + 1];
float y2 = (1.0 - dx) * grady_[stcnx] + dx * grady_[stcnx + 1];
float y = (1.0 - dy) * y1 + dy * y2; // interpolated y // show gradients
ROS_DEBUG(
"[Path] %0.2f,%0.2f %0.2f,%0.2f %0.2f,%0.2f %0.2f,%0.2f; final x=%.3f, y=%.3f\n", gradx_[stc], grady_[stc], gradx_[stc+1], grady_[stc+1], gradx_[stcnx], grady_[stcnx], gradx_[stcnx+1], grady_[stcnx+1], x, y); // check for zero gradient, failed
if (x == 0.0 && y == 0.0) {
ROS_DEBUG("[PathCalc] Zero gradient");
return 0;
} // move in the right direction
float ss = pathStep_ / hypot(x, y);
dx += x * ss;
dy += y * ss; // check for overflow
if (dx > 1.0) {
stc++;
dx -= 1.0;
}
if (dx < -1.0) {
stc--;
dx += 1.0;
}
if (dy > 1.0) {
stc += xs_;
dy -= 1.0;
}
if (dy < -1.0) {
stc -= xs_;
dy += 1.0;
} } //printf("[Path] Pot: %0.1f grad: %0.1f,%0.1f pos: %0.1f,%0.1f\n",
// potential[stc], dx, dy, path[npath-1].first, path[npath-1].second);
} return false;
}

todo

sbpl,这也是个global planner,没有试过

move_base的全局路径规划代码研究的更多相关文章

  1. move_base的 局部路径规划代码研究

    base_local_planner teb_local_planner parameter code g2o base_local_planner ROS wiki Given a plan to ...

  2. ROS源码解读(二)--全局路径规划

    博客转载自:https://blog.csdn.net/xmy306538517/article/details/79032324 ROS中,机器人全局路径规划默认使用的是navfn包 ,move_b ...

  3. 全局路径规划算法Dijkstra(迪杰斯特拉算法)- matlab

    参考博客链接:https://www.cnblogs.com/kex1n/p/4178782.html Dijkstra是常用的全局路径规划算法,其本质上是一个最短路径寻优算法.算法的详细介绍参考上述 ...

  4. [python] A*算法基于栅格地图的全局路径规划

    # 所有节点的g值并没有初始化为无穷大 # 当两个子节点的f值一样时,程序选择最先搜索到的一个作为父节点加入closed # 对相同数值的不同对待,导致不同版本的A*算法找到等长的不同路径 # 最后c ...

  5. ROS探索总结(十四)——move_base(路径规划)

    在上一篇的博客中,我们一起学习了ROS定位于导航的总体框架,这一篇我们主要研究其中最重要的move_base包. 在总体框架图中可以看到,move_base提供了ROS导航的配置.运行.交互接口,它主 ...

  6. ROS机器人路径规划介绍--全局规划

    ROS机器人路径规划算法主要包括2个部分:1)全局路径规划算法:2)局部路径规划算法: 一.全局路径规划 global planner ROS 的navigation官方功能包提供了三种全局路径规划器 ...

  7. 【路径规划】 Optimal Trajectory Generation for Dynamic Street Scenarios in a Frenet Frame (附python代码实例)

    参考与前言 2010年,论文 Optimal Trajectory Generation for Dynamic Street Scenarios in a Frenet Frame 地址:https ...

  8. DWA局部路径规划算法论文阅读:The Dynamic Window Approach to Collision Avoidance。

    DWA(动态窗口)算法是用于局部路径规划的算法,已经在ROS中实现,在move_base堆栈中:http://wiki.ros.org/dwa_local_planner DWA算法第一次提出应该是1 ...

  9. ROS源码解读(一)--局部路径规划

    博客转载自:https://blog.csdn.net/xmy306538517/article/details/78772066 ROS局部路径导航包括Trajectory Rollout 和 Dy ...

随机推荐

  1. 2.0 flume、sqoop、oozie/Azkaban

    在一个完整的大数据处理系统中,除了hdfs+mapreduce+hive组成分析系统的核心之外,还需要数据采集.结果数据导出.任务调度等不可或缺的辅助系统,而这些辅助工具在hadoop生态体系中都有便 ...

  2. P,V操作及同步互斥实例

    无论是计算机考研.计算机软件水平考试.计算机操作系统期末考试还是其他计算机岗位考试,P.V原语操作都是一个常考点.下面笔者总结了关于P.V操作的一些知识. 信号量是最早出现的用来解决进程同步与互斥问题 ...

  3. 4星|《亿万》:FBI大战华尔街对冲基金大鳄

    亿万:围剿华尔街大白鲨 全书尝试还原2008-2013年前后FBI指控赛克资本老板科恩通过内幕交易盈利的案件细节. 作者花了数年时间,采访了200多位当事人,阅读了海量的相关资料.书中交代了科恩的发家 ...

  4. python sys.argv是什么?

    1.sys.argv 是获取运行python文件的时候命令行参数,且以list形式存储参数 2.sys.argv[0] 代表当前module的名字 下面的代码文件是a.py,当我不用IDE工具,只用命 ...

  5. underscore.js源码解析(五)—— 完结篇

    最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...

  6. 哈夫曼(Huffman)树+哈夫曼编码

    前天acm实验课,老师教了几种排序,抓的一套题上有一个哈夫曼树的题,正好之前离散数学也讲过哈夫曼树,这里我就结合课本,整理一篇关于哈夫曼树的博客. 主要摘自https://www.cnblogs.co ...

  7. 探路者 Alpha阶段中间产物

     版本控制 git地址:https://git.coding.net/clairewyd/toReadSnake.git   贪吃蛇(单词版)软件功能说明书 1 开发背景 “贪吃蛇”这个游戏对于80, ...

  8. Scrum7

    冲刺阶段的总结 一.各个成员今日完成的任务 组员 任务分工 贡献 林泽宇 团队分工.撰写博客.修改完善需求规格说明书.整理代码规范 李涵 后端架构设计 尹海川 logo设计修改.数据库数据 郏敏杰 课 ...

  9. Python:Python的运行过程

    1.Python是什么 和Java以及c#一样,Python也是一门基于虚拟机的语言.熟悉Java开发的人在命令行执行一个Java程序的过程通常如下: javac hello.java java he ...

  10. Mac安装jee开发环境,webservice环境搭建

    一.下载安装包 jdk(去官网下载) eclipse (去官网下载) tomcat(官网有9.0了)http://tomcat.apache.org/download-80.cgi#8.0.32 下载 ...