我正在用 C++ 为我的主要机器人探索行为实现 A* 路径规划算法。随着机器人的移动,它会将自身周围的环境映射为二维图形。从这个图中,我设置了一个 Vector2D 元组 {x, y}
,它保存了这个路点的位置,我希望机器人也导航到那里。
我对 A* 做的第一件事是有一个 Node
类,它保存有关当前节点的信息;
double f; // F, final score
double g; // Movement cost
double h; // Hueristic cost (Manhatten)
Node* parent;
Vector2d position;
当 A* 开始时,我将我的起始节点作为我的机器人起始位置(我还将此位置作为 Vector 以方便访问)。然后,我进入一个 while 循环,直到找到最终目标。我在此循环中做的第一件事是生成八个相邻节点(左、下、右、上、左上、右上、左下、右下),然后我将其返回到 OpenList
vector 。
//Open List是当前要检查的节点 std::vector 位置;
positions.push_back(Vector2d(current->position.getX() - gridSize, current->position.getY())); // Left of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize, current->position.getY())); // right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX(), current->position.getY() + gridSize)); // Top of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX(), current->position.getY() - gridSize)); // Bottom of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize,current->position.getY() + gridSize)); // Top Right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() - gridSize,current->position.getY() + gridSize)); // Top Left of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() + gridSize,current->position.getY() - gridSize)); // Bottom Right of my current grid space (parent node)
positions.push_back(Vector2d(current->position.getX() - gridSize,current->position.getY() - gridSize)); // Bottom Left of my current grid space (parent node)
// moving diagnolly has a bigger cost
int movementCost[8] = { 10, 10, 10, 10, 14, 14, 14, 14 };
// loop through all my positions and calculate their g, h and finally, f score.
for (int i = 0; i < positions.size(); i++)
{
Node* node = new Node(positions[i]);
node->parent = current;
node->movementCost = movementCost[i];
if (!presentInClosedList(node))
{
// if the probability value of the current node is less then 0.5 (not an obstacle) then add to the open list, else skip it as an obstacle
// Set astar grid occupancy
if (grid->getProbabilityValue(node->position) < 0.51)
{
node->g = current->g + movementCost[i];
node->h = (abs(positions[i].getX() - wantedLocation.getX())) + (abs(positions[i].getY() - wantedLocation.getY()));
node->f = node->g + node->h;
openList.push_back(node);
}
}
}
这是查看当前节点是否存在于我的 closedList 中的代码
bool 存在=假;
for (int i = 0; i < closedList.size(); i++)
{
if (closedList[i]->position == currentNode->position)
{
closedList[i]->f = currentNode->f;
closedList[i]->g = currentNode->g;
closedList[i]->h = currentNode->h;
closedList[i]->parent = currentNode->parent;
exists = true;
break;
}
}
return exists;
这将返回一个可能路径的openlist
。接下来,我选择 F
分数最小的那个,并将其添加到我的 closedList
中。我一直这样做,直到找到最终目标。最后,一旦找到,我就使用 parent
对象返回列表。这是其余的代码
// If my parents location is the same as my wanted location, then we've found our position.
if (locationFound(current, wantedLocation))
{
// Now we need to backtrack from our wantedNode looking at the parents of each node to reconstruct the AStar path
Node* p = current->parent;
rollingDist = p->g;
while (!wantedFound)
{
if (p->position == startLocation)
{
wantedFound = true;
wantedNodeFound = true;
break;
}
path.push_back(p);
p = p->parent;
}
}
现在这是我的问题。在每次尝试中,它总能找到想要的位置,但从来没有找到最短路径。见下图一。
图一。黄色标记是想要的位置,红色飞镖是我想要的位置的“路径”,最后,“蓝色”标记是 A 星开始的地方。
这是我的问题。我似乎无法重建这条路径。
最佳答案
回顾一下评论,有两个重要的问题
- 曼哈顿距离不允许用于您的移动成本,因为实际的最短路径可以采用曼哈顿距离不会考虑的对角线捷径。
- 在将新节点添加到Open列表之前,不仅要检查它是否在Closed列表中,还要检查它是否已经在Open列表中。如果它已经在 Open 列表中,则必须比较 G 并选择最小的(连同相应的父指针)。[1]
由于您有 10/14 成本的八次运动,您的启发式函数可以是(来自 http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html)
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
D = 10,D2 = 14。当然你也可以使用任何其他可接受的值,但这个公式已经反射(reflect)了开阔平原上的实际距离,因此不容易改进。
在 Open 列表中查找和更新节点是 A* 中令人讨厌的部分,我敢肯定很多人会假装没有必要,因为这意味着您不能合理地使用任何预定义的优先级队列(他们缺乏有效的查找)。这可以通过手动实现的二进制堆和将坐标映射到堆中相应索引的哈希表来完成。每当节点移动时,哈希表都必须由堆更新。
[1]:来自 wikipedia article 的相关伪代码片段是:
tentative_gScore := gScore[current] + dist_between(current, neighbor)
if neighbor not in openSet // Discover a new node
openSet.Add(neighbor)
else if tentative_gScore >= gScore[neighbor]
continue // This is not a better path.
// This path is the best until now. Record it!
cameFrom[neighbor] := current
gScore[neighbor] := tentative_gScore
fScore[neighbor] := gScore[neighbor] + heuristic_cost_estimate(neighbor, goal)
关于c++ - 机器人路径规划 - A*(星级),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43310743/