机器人路径规划 - A *(星级)

问题描述 投票:3回答:1

我正在为C ++中的主要机器人探索行为实现A *路径规划算法。当机器人移动时,它将环境周围的环境映射为2D图形。从这张图中,我设置了一个Vector2D Tuple {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向量中返回它。

// 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 exists = false;

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;

        }

    }

现在这是我的问题。在每次尝试时,它总是找到想要的位置,但绝不是最短的路径。见下图1。

enter image description here

图一。黄色标记是想要的位置,红色飞镖是我想要的位置的“路径”,最后,“蓝色”标记是A星开始的地方。

这是我的问题。我似乎无法重建这条道路。

c++ a-star
1个回答
1
投票

回顾一下评论,有两个重要问题

  • 曼哈顿距离不允许您的移动费用,因为实际的最短路径可以采用曼哈顿距离不考虑的对角快捷方式。
  • 在将新节点添加到“打开”列表之前,不仅需要检查它是否在“已关闭”列表中,还要检查它是否已在“打开”列表中。如果它已经在打开列表中,则必须比较G并且必须选择最小值(与相应的父指针一起)。[1]

由于你有10/14成本的octile运动,你的启发函数可能是(来自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.当然你也可以使用其他任何可接受的东西,但是这个公式已经反映了开放平原上的实际距离,因此无法轻易改进。

在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)
© www.soinside.com 2019 - 2024. All rights reserved.