3 * @brief Implementation of the A* algorithm. Main functions.
4 * @author Jose Maria Martin Laguna <jmmartin@etud.insa-toulouse.fr>
6 * @note The author asumes that the reader knows how A* algorithm
7 * works. In this documentation only the implementation is
8 * explained. More information "Principles of Robot Motion" by
9 * H. Choset&others (Algorithm 24, p531)
14 #define _ISOC99_SOURCE /* To have INFINITY */
15 #define _XOPEN_SOURCE /* To have M_SQRT2 etc. */
16 #include "aalgorithm.h"
17 #include "pathqueue.h"
26 #define SQRT2 M_SQRT2 /**< @brief Root square of two.*/
27 #define WALL_COST 1000 /**< Cost of jumping a wall. */
31 * @name A* Main Structure
34 static GraphMapCell graph[MAP_HEIGHT][MAP_WIDTH]; /**< @brief Graph structure used in A*. */
37 #ifndef CONFIG_PP_USES_RBTREE
38 static GraphMapCell *graph_queue; /**< Pointer to the first cell in the list */
40 static struct rb_root graph_queue; /**< rbtree root */
42 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) /* For GCC 4 */
43 #ifdef __compiler_offsetof
44 #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
46 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
50 * container_of - cast a member of a structure out to the containing structure
51 * @ptr: the pointer to the member.
52 * @type: the type of the container struct this is embedded in.
53 * @member: the name of the member within the struct.
56 #define container_of(ptr, type, member) ({ \
57 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
58 (type *)( (char *)__mptr - offsetof(type,member) );})
62 static void pushNodeInOrder(GraphMapCell *cell);
63 float cFunction(int x1, int y1, int x2, int y2);
64 void calculateMapHeuristic(int xgoal, int ygoal);
65 float calculateCost(int x1, int y1, int x2, int y2);
66 void initGraphStructure(void);
67 int getPathLength(int xstart, int ystart, int xgoal, int ygoal);
70 * Returns X and Y index of a graph cell identified by a pointer.
72 * @param[in] c Pointer to the cell in question.
73 * @param[out] x Cell's X index.
74 * @param[out] y Cell's Y index.
76 void GraphCell2XY(GraphMapCell *c, int *x, int *y)
78 *y = (c - &graph[0][0]) / MAP_WIDTH;
79 *x = (c - &graph[0][0]) % MAP_WIDTH;
84 * @name A* Main function
89 * @brief Search the shortest path between two points
90 * @param xstart_real Coordonate X of the start point
91 * @param ystart_real Coordonate Y of the start point
92 * @param xgoal_real Coordonate X of the goal point
93 * @param ygoal_real Coordonate Y of the goal point
94 * @param original_path [out] Pointer to the first map cell of the
95 * path is stored here. Use
96 * GraphMapCell.next to traverse the found
99 * @return -1 if the goal is not founded, the number of points to the goal is founded on success.
101 * This is an implementation of A* Algorithm (Algorithm 24, p531)
102 * defined in the book "Principles of Robot Motion" by
106 int aAlgorithm(double xstart_real,double ystart_real, double xgoal_real, double ygoal_real, GraphMapCell **original_path)
109 * prioritySet : Set of nodes to process order by heuristic distance
111 #ifndef CONFIG_PP_USES_RBTREE
114 graph_queue = RB_ROOT;
117 * nbest : Best node to reach the goal
119 GraphMapCell *nbest, *start, *goal, *contig;
121 int xcontig, ycontig, xstart, ystart, xgoal, ygoal;
122 struct map *map = ShmapIsMapInit();
126 // Transform real data in cell data
127 ShmapPoint2Cell(xstart_real, ystart_real, &xstart, &ystart, &valid);
130 start = &graph[ystart][xstart];
131 ShmapPoint2Cell(xgoal_real, ygoal_real, &xgoal, &ygoal, &valid);
134 goal = &graph[ygoal][xgoal];
138 /// <li> Init graph structure with default values.
139 initGraphStructure();
140 /// <li> Calculate Heuristic distances.
141 calculateMapHeuristic(xgoal, ygoal);
143 /// <li> Initial values : put start node in queue.
145 start->f = start->g + start->h;
146 start->backpointer = start;
147 pushNodeInOrder(start);
149 /// <li> REPEAT until the queue is empty.
153 /// <li> Pick nbest from prioritySet and remove
154 #ifndef CONFIG_PP_USES_RBTREE
156 graph_queue = graph_queue->next;
158 nbest = container_of(rb_first(&graph_queue), GraphMapCell, node);
159 rb_erase(&nbest->node, &graph_queue);
162 GraphCell2XY(nbest, &x, &y);
163 /* map->cells[y][x].detected_obstacle = 255; */
164 /* usleep(100000); */
166 /// <li> add to processed
167 nbest->processed = 1;
169 /// <li> IF nbest == goal ; EXIT
174 /// <li> Expand nbest :for all x E Star(nbest) that are not in C
175 const struct { int x; int y; } neighbours[] = { { 0, 1}, { 1, 1}, { 1, 0}, {-1, 1},
176 {-1, 0}, {-1,-1}, { 0,-1}, { 1,-1}};
177 for (i=0; i< sizeof(neighbours)/sizeof(neighbours[0]); i++) {
178 xcontig = x + neighbours[i].x;
179 ycontig = y + neighbours[i].y;
181 if(ShmapIsCellInMap(xcontig, ycontig) && (graph[ycontig][xcontig].processed == 0)){
182 double cost = cFunction(x, y, xcontig, ycontig);
183 contig = &graph[ycontig][xcontig];
184 /// <li> IF is not in Priorityset add to prioritySet.
185 if (!contig->in_queue) {
186 if(ShmapIsFreeCell(xcontig, ycontig)) {
187 // add to prioritySet.
188 contig->g=nbest->g + cost;
189 contig->f = contig->g + contig->h;
190 contig->backpointer=nbest;
191 pushNodeInOrder(contig);
193 } else if (nbest->g + cost < contig->g) {
194 /// <li> ELSE update backpointer to point to nbest.
195 contig->backpointer=nbest;
196 contig->g = nbest->g + cost;
201 #ifndef CONFIG_PP_USES_RBTREE
202 } while (graph_queue);
204 } while (!RB_EMPTY_ROOT(&graph_queue));
211 // Clear previous path
212 for (y=0;y<MAP_HEIGHT;y++){
213 for(x=0;x<MAP_WIDTH;x++){
214 map->cells[y][x].flags &= ~(MAP_FLAG_PATH | MAP_FLAG_START | MAP_FLAG_GOAL);
219 /* Construct forward list for the found path. */
223 while (cell != start) {
224 cell->backpointer->next = cell;
225 cell = cell->backpointer;
227 GraphCell2XY(cell, &x, &y);
228 map->cells[y][x].flags |= MAP_FLAG_PATH;
231 map->cells[ystart][xstart].flags |= MAP_FLAG_START | MAP_FLAG_PATH;
232 map->cells[ygoal][xgoal].flags |= MAP_FLAG_GOAL | MAP_FLAG_PATH;
234 *original_path = start;
243 * @name A* related functions
244 * This functions have a meaning in theorical A*.
249 * @brief Calculates the lenght of edge connecting two points
250 * @param x1 Coordonate X of the first cell
251 * @param y1 Coordonate Y of the first cell
252 * @param x2 Coordonate X of the second cell
253 * @param y2 Coordonate Y of the second cell
254 * @return Lenght of edge
257 float cFunction(int x1, int y1, int x2, int y2)
260 //if(GETMAPPOS(x2, y2)== MAP_WALL) c = WALL_COST;
261 if(!ShmapIsFreeCell(x2,y2)) c = WALL_COST;
262 else if( (x1==x2) || (y1 == y2) ) c=1.0;
271 * @brief Calculates Map Heuristic values.
272 * @param xgoal Coordonate X of the goal
273 * @param ygoal Coordonate Y of the goal
275 * This function calculates the map heuristic values (the distance to
276 * the goal that is supoused to be the shortest).
278 * The chosen method has been the euclidean distance. The distance
279 * between a point of the grid \f$(x,y)\f$ and the
280 * goal\f$(x_(goal),y_(goal))\f$ is
281 * \f$\sqrt{(x_(goal)-x)^2+(y_(goal)-y)^2}\f$.
283 * Another method explained in the book is coded but not used.It is
284 * called Brushfire algorithm. (section 4.3.2 of the book)
287 void calculateMapHeuristic(int xgoal, int ygoal)
290 for(i=0;i<MAP_HEIGHT;i++){
291 for (j=0;j<MAP_WIDTH;j++){
292 graph[i][j].h=sqrt(abs(xgoal-j)*abs(xgoal-j)+abs(ygoal-i)*abs(ygoal-i));
296 /* This is another way to compute heuristic without SQRT but it don't work properly */
299 NodeQueue * toProcess = malloc(sizeof(NodeQueue));
300 int xcontig, ycontig;
301 float h; // Heuristic distance of cell
302 float newh; // New Heuristic distance of cell
304 graph[ygoal][xgoal].h=0;
305 graph[ygoal][xgoal].processed=1;
307 pushNode(toProcess, xgoal, ygoal);
308 while(!queueIsEmpty(toProcess)){
309 //printPrioritySet(toProcess);
310 // Pop the first node in the queue
311 popNode(toProcess,&n);
312 graph[n.y][n.x].processed=1;
313 // Take node's heuristic distance
314 h = graph[n.y][n.x].h;
316 // Cross contiguous cells
317 for (xcontig = n.x-1 ; xcontig <= n.x + 1 ; xcontig++){
318 for (ycontig = n.y - 1 ; ycontig <= n.y + 1 ; ycontig++){
319 if(ShmapIsCellInMap(xcontig, ycontig) && (graph[ycontig][xcontig].processed==0)) {
320 //Add node to priority queue
321 if ((!isInQueue(toProcess,xcontig,ycontig))) pushNode(toProcess,xcontig,ycontig);
322 // Update heuristic if [ (Heuristic not set) OR [oldHeuristic is higher than newer)]
323 newh= h + calculateCost(n.x, n.y, xcontig, ycontig);
324 if( ( (graph[ycontig][xcontig].h < 0) || (graph[ycontig][xcontig].h > newh )) )
325 graph[ycontig][xcontig].h=newh ;
332 // Clear proccessed flag
333 for(i=0;i<MAP_HEIGHT;i++){
334 for (j=0;j<MAP_WIDTH;j++){
335 graph[i][j].processed=0;
343 * @brief Calculates the cost of moving from the first cell to the second cell.
344 * @param x1 Coordonate X of the first cell
345 * @param y1 Coordonate Y of the first cell
346 * @param x2 Coordonate X of the second cell
347 * @param y2 Coordonate Y of the second cell
349 * @warning Cells must be contiguous
351 float calculateCost(int x1, int y1, int x2, int y2){
353 if( (x1==x2) || (y1 == y2) ) return 1.0;
361 * @name A* Implementation Functions
362 * This functions have not a meaning in A* algorithm, but are needed for implementation.
367 * @brief Init Graph structure with default values
370 void initGraphStructure(void){
373 GraphMapCell g = { .h = -1, .g = -1, .f = INFINITY, .backpointer = NULL,
374 .processed = false, .in_queue = false, .next = NULL };
376 //Initialisation of graph structure
377 for(i=0;i<MAP_HEIGHT;i++){
378 for (j=0;j<MAP_WIDTH;j++){
385 * @brief Push the cell c in the queue ordered by heuristic value of the cell
389 * @todo Use some tree based data structure for this. -- Sojka
392 void pushNodeInOrder(GraphMapCell *c)
396 #ifndef CONFIG_PP_USES_RBTREE
397 GraphMapCell *current, *last;
401 // Put the node in right position
404 while (current!=NULL){
405 if (c->f < current->f ) {
406 if (last==NULL) graph_queue = c;
412 current=current->next;
415 // the node goes in the last position
420 struct rb_node **new = &(graph_queue.rb_node), *parent = NULL;
421 /* Figure out where to put new node */
423 GraphMapCell *this = container_of(*new, GraphMapCell, node);
427 new = &((*new)->rb_left);
429 new = &((*new)->rb_right);
432 /* Add new node and rebalance tree. */
433 rb_link_node(&c->node, parent, new);
434 rb_insert_color(&c->node, &graph_queue);