This project is a continous work after @tejus-gupta. Thanks to his great work.
This project implements Hybrid-A* Path Planning algorithm for a non-holonomic vehicle. It is inspired by this Demo Video.
My contributions are as below,
- Test and update the code to make it runnable in at least Linux Ubuntu and Mac OS.
- Refactor the code structure with Object Oriented Programming.
- Replace the Dijkstra's 2d search algorithm with A* search.
- Update the heuristic function as max(non-holonomic-without-obstacles, holonomic-with-obstacles).
The Hybrid-A* algorithm is described here, Practical Search Techniques in Path Planning for Autonomous Driving.
The code is ready to run a real Autonomous Vehicle with minor modifications, although it runs standalone as a demo in this repository.
.
├── CMakeLists.txt
├── README.md
├── data
│ ├── map1.png
│ ├── map2.png
│ └── map3.png
├── include
│ ├── algorithm.h
│ ├── gui.h
│ ├── map.h
│ ├── state.h
│ └── utils.h
└── src
├── algorithm.cpp
├── gui.cpp
├── main.cpp
├── map.cpp
└── state.cpp
- Build
mkdir build && cd build
cmake ..
make
- Run
./hybrid_astar
- Expected output
For a given map which is picked from those in /data folder, a given initial pose and a goal pose for the vehicle, the program is to generate a drivable path linking the initial to the goal.
In the terminal, a sequence of lines will be printed to show the running status until a final message is printed as in the following,
Obstacle present inside box
Obstacle present inside box
Obstacle present inside box
Obstacle present inside box
Obstacle present inside box
Obstacle present inside box
Reached goal.
After that, a new window will appear and display the generated path as a sequence of rectangles from the goal to the initial as in the following,
In line 14 in ./src/main.cpp, we pass a path name to the map instance.
Map map("../data/map1.png");
In line 16 - 17 in ./src/map.cpp, the Map class will load the given map as a matrix using OpenCV as below,
// Load the map using OpenCV as a gray image.
cv::Mat obsmap = cv::imread(map_file, 0);
For example, the program constructs the collected algorithms as a class, Algorithm, in ./include/algorithm.h and ./src/algorithm.cpp.
And Gui, Map, State, etc.
For example, in ./include/gui.h, we set some method functions as public and some variables as private.
The method Algorithm::hybridAstarPlanning()
is a public method function in Algorithm class, which users car access it as an interface.
The method Algorithm::astarPlanning()
is a private method function in Algorithm class.
In line 49 - 60 in algorithm.cpp, the arguments of the overloaded operator "()" are passed by references.
/**
* 2d coordinate comparator
*
* Will be used in the heap.
*/
struct Compare2d {
bool operator()(const State &a, const State &b) {
// return a.cost2d > b.cost2d; //simple dijkstra
return a.cost2d + abs(Algorithm::goal.dx - a.dx) + abs(Algorithm::goal.dy - a.dy) >
b.cost2d + abs(Algorithm::goal.dx - b.dx) + abs(Algorithm::goal.dy - b.dy);
}
};
- A 3D discrete search space is used but unlike traditional A*, hybrid-A* associates with each grid cell a continuous 3D state of the vehicle. The resulting path is guaranteed to be drivable (standard A* can only produce piece-wise linear paths).
- The search algorithm is guided by two heuristics -
- 'non-holonomic-without-obstacles' uses Dubin's path length ignoring obstacles
- 'holonomic-with-obstacles' uses shortest path in 2D computed using A* (or Dijkstra's) ignoring holonomic constraints of vehicle
- To improve search speed, the algorithm analytically expands nodes closer to goal using dubins path and checks it for collision with current obstacle map.
- map
- initial
- goal
- velocity
- Path Smoothing
- Reverse Motion
- User Interaction
- Viusalization Optimization
- Motion Control