A* Path Planning Algorithm

 

 

The A* path planning algorithm is a popular search algorithm used in robotics for identifying the most efficient path from one point to another, avoiding obstacles and adhering to defined constraints along the route.  This algorithm can guarantee the shortest travel path between two points and identifies the optimal path without performing any unnecessary exploration of the map.  The algorithm for identifying an efficient path between two points is, in itself, efficient.

 

I will outline how this algorithm is designed and how it identifies the most optimal path by efficiently exploring a map and calculating the cost of pursuing various routes between two defined points: origin and destination.  I’ve also written and published my own A* algorithm code to demo for various maps with and without obstacles!

 

The cost functions defining a node’s score are measured as distances, and some distance measurements serve specific purposes.  Two of the most popular distance calculations are:

·         Euclidean Distance: Measures straight-line distance between two points.  Allows diagonal movements.

 

·         Manhattan Distance: Measures distance along grid-based movement.  Allows horizontal and vertical steps only.

 

While the two distance methods above are popular, the list is not exhaustive.  After selecting a distance calculation method, we can begin exploring the map and assigning node scores to help identify the most optimal path between two points.  The h(n) heuristic function measures the distance between a node and the destination node.  The g(n) cost function measures the distance between a node and the origin node.  Summing h(n) and g(n) yield the node’s score, f(n), quantifying the cost of an agent traveling to that node.  The f(n) score is the primary metric for assessing the most optimized path for travel

 

Heuristic function measuring the distance from a node to the destination point

Cost function measuring the distance from a node to the origin point

Estimate a node’s score by summing  and

 

 

Plan a Path

 

In this example, the map indexes rows and columns from the top left node.  Nodes’ coordinates are presented as (row, col):

·         START: (3, 3)

·         END: (0, 0)

 

Each node displays the h(n) score at the top right, the g(n) score at the top left, and the f(n) score at the bottom.

 

A black background with red squares

AI-generated content may be incorrect.

 

Iteration 1

The algorithm starts at the origin node and calculates h(n) and g(n) for each of its immediate neighboring nodes.  The node from which we identify neighboring nodes will be called the ‘focus node’ throughout this post.  We will be using the Euclidean distance to score each node since we want to allow for diagonal movements along the map. 

Once these two metrics are calculated, they’re summed for each neighbor node to define its cost score, f(n).

 

 

As we iterate through the nodes, it’s important that we keep track of focus nodes so we don’t explore them again to eliminate exploration redundancy (i.e. not score a node and its neighbors more than once).  These focus nodes will enter a ‘closed’ state, meaning future iterations can’t access them as focus nodes for exploration anymore.  Scored neighbors remain in an ‘open’ state, meaning they can be selected as future focus nodes.  Unscored nodes cannot be selected as focus nodes until they have been scored from a focus node.

At this point we have one ‘closed’ node and 8 scored ‘open’ nodes. These open-state nodes must be sorted in ascending order along the f(n) score, then the h(n) score. Secondarily sorting open nodes along their h(n) score breaks potential ties between nodes that have the same f(n) score.  We choose to secondarily sort along h(n) because it encourages the algorithm to select the open node that’s closest to the destination node.

We can now consider the whole map as we sort all ‘open’ nodes and select the node with the LOWEST score (i.e. global minimum).  In this example, the lowest node score from exploration iteration one is 42, which makes sense since that node is closest to the destination – an indication that we are buidling a path to the destination node!  The node with score 42 now becomes the focus node in the next iteration.

 

Open Nodes

Node Coordinate

Parent Node

(2, 2)

28

14

42

(3, 3)

(3, 2)

36

10

46

(3, 3)

(2, 3)

36

10

46

(3, 3)

(4, 2)

45

14

59

(3, 3)

(2, 4)

45

14

59

(3, 3)

(4, 3)

50

10

60

(3, 3)

(3, 4)

50

10

60

(3, 3)

(4, 4)

57

14

71

(3, 3)

 

 

TIP:  Keep a log of what focus node a subsequent focus node comes from.  We will call this a focus node’s ‘parent’ node.  We will use this at the end!

 

 

Iteration 2

Now that we have identified the next iteration’s focus node and logged its parent node, we can proceed to score its immediate neighbors.  Again, we have one focus node and 8 neighbor nodes.  However, this time we have neighbor nodes that were scored in the previous iteration.  How do we handle this?  Easy! 

Calculate the new h(n), g(n), and f(n) scores for all 8 immediate neighbor nodes.  If a neighbor node already has a set of scores from a previous iteration, then we compare the scores to the current iteration scores.  If the f(n) score from the current iteration less than the existing scores, then replace the node’s score with the lower scores.  If f(n) score from the current iteration is greater than the existing scores, then leave the node scores as they are.

This makes sense because we are looking for the ‘cheapest’ cost path between origin and destination.  If a node’s score drops between iterations, then that may mean there was a more efficient rout for arriving at that node.

 

A screenshot of a game

AI-generated content may be incorrect.

 

 

At this point we have two ‘closed’ nodes and 12 open nodes from iterations 1 and 2, as indicated in the figure below.  We have to choose our next focus node by again sorting the open nodes in ascending order along the f(n) score, then the h(n) score and selecting the node with the lowest score.  Again, the lowest open-node score is 42 and that node becomes the focus node for the next iteration in the algorithm.

 

Open Nodes

Node Coordinate

Parent Node

(1, 1)

14

28

42

(2,2)

(2, 1)

22

24

46

(2,2)

(1, 2)

22

24

46

(2,2)

(3, 2)

36

10

46

(3, 3)

(2, 3)

36

10

46

(3, 3)

(4, 2)

45

14

59

(3, 3)

(2, 4)

45

14

59

(3, 3)

(3, 1)

32

28

60

(2,2)

(1, 3)

32

28

60

(2,2)

(4, 3)

50

10

60

(3, 3)

(3, 4)

50

10

60

(3, 3)

(4, 4)

57

14

71

(3, 3)

 

 

Iteration 3

For the third iteration, we set the minimum-score node from iteration 2 as the new focus node and score its immediate neighbors.  Again, we calculate the new h(n), g(n), and f(n) scores for all 8 immediate neighbor nodes. 

If a neighbor node already has a set of scores from a previous iteration, then we compare the scores to the current iteration scores.  If the f(n) score from the current iteration less than the existing scores, then replace the node’s score with the lower scores.  If f(n) score from the current iteration is greater than the existing scores, then leave the node scores as they are.

 

A screenshot of a game

AI-generated content may be incorrect.

 

 

We now have 16 open nodes from iterations 1, 2, and 3 to sort along f(n) then h(n) and determine the next focus node.  Based on the score map above, we identify the open node with f(n) score of 42 as the global minimum, making it the next node for exploration...if there is a next iteration!  Notice that h(n) at this node is 0, and h(n) measures the distance from the current node to the destination node.  Since h(n)=0, this indicates that we have arrived at our destination and do not need to continue exploring nodes.

 

Open Nodes

Node Coordinate

Parent Node

(0, 0)

42

0

42

(1, 1)

(2, 1)

24

22

46

(2, 2)

(1, 2)

24

22

46

(2, 2)

(3, 2)

10

36

46

(3, 3)

(2, 3)

10

36

46

(3, 3)

(1, 0)

38

10

48

(1, 1)

(0, 1)

38

10

48

(1, 1)

(4, 2)

14

44

58

(3, 3)

(2, 4)

14

44

58

(3, 3)

(3, 1)

28

31

59

(2, 2)

(1, 3)

28

31

59

(2, 2)

(4, 3)

10

50

60

(3, 3)

(3, 4)

10

50

60

(3, 3)

(2, 0)

42

20

62

(1, 1)

(0, 2)

42

20

62

(1, 1)

(4, 4)

14

56

70

(3, 3)

 

Algorithm complete!

 

A game of numbers on a black background

AI-generated content may be incorrect.

A black background with squares and a black line

AI-generated content may be incorrect.

 

 

Plan a Path with an Obstacle

 

This next example will follow the same steps in the previous example, but now the agent will navigate around a known obstacle in the map.

 

A black background with red squares

AI-generated content may be incorrect.

 

The algorithm from the previous example holds true in this obstacle example.  Nodes that have an obstacle are inaccessible, and so they remain unscored for the duration of path planning.  By leaving the obstacle nodes unscored, they’re omitted from the iterative selection of focus nodes, so they are never selected as potential path nodes.

 

Below is a complete table of focus nodes and parent nodes in the order that they were identified by the algorithm for the obstacle map.  The map is comprised of 25 nodes, of which 21 are accessible.  18 Focus nodes were explored but traversing all 18 to arrive at the destination node is not the most efficient path from the origin node.

 

All Focus and Parent Nodes

Focus Nodes

Parent Node

(3, 3)

-

(2, 2)

(3, 3)

(2, 1)

(2, 2)

(2, 3)

(3, 3)

(3, 2)

(3, 3)

(3, 1)

(2, 2)

(2, 0)

(2, 1)

(2, 4)

(3, 3)

(4, 2)

(3, 3)

(3, 0)

(2, 1)

(3, 4)

(3, 3)

(4, 3)

(3, 3)

(1, 4)

(2, 3)

(4, 1)

(3, 2)

(0, 3)

(1, 4)

(0, 2)

(0, 3)

(0, 1)

(0, 2)

(0, 0)

(0, 1)

 

Remember when I advised tracking each focus node’s parent node?  This is where we use that!

 

Starting with the destination node (this should be the last focus node logged chronologically), take the parent node and make that the next focus node.  Check this new focus node’s parent node and make it the next focus node.  Continue this iterative process until you’ve worked your way backwards to the origin node and that will reveal the most optimized path between the origin node and the destination node.

 

Optimized Path Focus and Parent Nodes

Focus Nodes

Parent Node

(3, 3)

-

(2, 3)

(3, 3)

(1, 4)

(2, 3)

(0, 3)

(1, 4)

(0, 2)

(0, 3)

(0, 1)

(0, 2)

(0, 0)

(0, 1)

 

Plotting the optimized path focus nodes confirms that we have selected a viable.

 

Algorithm complete!

A black background with red squares

AI-generated content may be incorrect.

 

 

 

Helpful Resources