参考:
Hybrid A* Path Planner for the KTH Research Concept Vehicle
[PAPER] : Path Planning in Unstructured Environments
Hybrid A* 的使用场景
在斯坦福大学2007年参加的DARPA无人车城市挑战赛时使用的Junior,其在行为规划层提出了分层有限状态机的方式,如下图所示。
其中,BAD_RNDF状态表示的是,当前道路与系统的路网图不同的时候,无人车将采用Hybrid A*来进行规划路径。
Hybrid A 与 A
Hybrid A* 的主要特点是:
- 考虑物体的实际运动方向约束,不像A*假定所有的相邻节点都可以顺利转移
- A 的物体总是出现在栅格中心,而 Hybrid A 则不一定
- Hybrid A* 是连续路径
- Hybrid A 基于A
算法流程:
主要流程如下图所示,需要说明的是:
算法考虑了车辆的x,y坐标,偏航角。
G值更新策略如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33//###################################################
// MOVEMENT COST
//###################################################
void Node3D::updateG() {
// 前向行驶
if (prim < 3) {
// penalize turning 当前一个节点的prim与当前节点的prim不相等时,判断发生偏转。
if (pred->prim != prim) {
// 方向变化
if (pred->prim > 2) {
g += dx[0] * Constants::penaltyTurning * Constants::penaltyCOD;
} else {
g += dx[0] * Constants::penaltyTurning;
}
} else {
g += dx[0];
}
}
// 倒车行驶
else {
// penalize turning and reversing
if (pred->prim != prim) {
// penalize change of direction
if (pred->prim < 3) {
g += dx[0] * Constants::penaltyTurning * Constants::penaltyReversing * Constants::penaltyCOD;
} else {
g += dx[0] * Constants::penaltyTurning * Constants::penaltyReversing;
}
} else {
g += dx[0] * Constants::penaltyReversing;
}
}
}
H值更新策略如下:
可以支持倒车时计算当前节点到终点的Reeds-Shepp 曲线,仅支持前向行驶时计算Dubins曲线;
H值为Reeds-Shepp曲线、Dubins曲线、曼哈顿距离三种cost解算出来的最大值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61//###################################################
// COST TO GO
//###################################################
void updateH(Node3D& start, const Node3D& goal, Node2D* nodes2D, float* dubinsLookup, int width, int height, CollisionDetection& configurationSpace, Visualize& visualization) {
float dubinsCost = 0;
float reedsSheppCost = 0;
float twoDCost = 0;
float twoDoffset = 0;
// if dubins heuristic is activated calculate the shortest path
// constrained without obstacles
if (Constants::dubins) {
ompl::base::DubinsStateSpace dubinsPath(Constants::r);
State* dbStart = (State*)dubinsPath.allocState();
State* dbEnd = (State*)dubinsPath.allocState();
dbStart->setXY(start.getX(), start.getY());
dbStart->setYaw(start.getT());
dbEnd->setXY(goal.getX(), goal.getY());
dbEnd->setYaw(goal.getT());
dubinsCost = dubinsPath.distance(dbStart, dbEnd);
}
// if reversing is active use a
if (Constants::reverse && !Constants::dubins) {
// ros::Time t0 = ros::Time::now();
ompl::base::ReedsSheppStateSpace reedsSheppPath(Constants::r);
State* rsStart = (State*)reedsSheppPath.allocState();
State* rsEnd = (State*)reedsSheppPath.allocState();
rsStart->setXY(start.getX(), start.getY());
rsStart->setYaw(start.getT());
rsEnd->setXY(goal.getX(), goal.getY());
rsEnd->setYaw(goal.getT());
reedsSheppCost = reedsSheppPath.distance(rsStart, rsEnd);
// ros::Time t1 = ros::Time::now();
// ros::Duration d(t1 - t0);
// std::cout << "calculated Reed-Sheep Heuristic in ms: " << d * 1000 << std::endl;
}
// if twoD heuristic is activated determine shortest path
// unconstrained with obstacles
if (Constants::twoD && !nodes2D[(int)start.getY() * width + (int)start.getX()].isDiscovered()) {
// ros::Time t0 = ros::Time::now();
// create a 2d start node
Node2D start2d(start.getX(), start.getY(), 0, 0, nullptr);
// create a 2d goal node
Node2D goal2d(goal.getX(), goal.getY(), 0, 0, nullptr);
// run 2d astar and return the cost of the cheapest path for that node
nodes2D[(int)start.getY() * width + (int)start.getX()].setG(aStar(goal2d, start2d, nodes2D, width, height, configurationSpace, visualization));
}
if (Constants::twoD) {
// offset for same node in cell
twoDoffset = sqrt(((start.getX() - (long)start.getX()) - (goal.getX() - (long)goal.getX())) * ((start.getX() - (long)start.getX()) - (goal.getX() - (long)goal.getX())) +
((start.getY() - (long)start.getY()) - (goal.getY() - (long)goal.getY())) * ((start.getY() - (long)start.getY()) - (goal.getY() - (long)goal.getY())));
twoDCost = nodes2D[(int)start.getY() * width + (int)start.getX()].getG() - twoDoffset;
}
// return the maximum of the heuristics, making the heuristic admissable
start.setH(std::max(reedsSheppCost, std::max(dubinsCost, twoDCost)));
}
代码
参考:Hybrid A* Path Planner for the KTH Research Concept Vehicle
1 | //################################################### |