Open darewolf007 opened 1 year ago
lesson1
#include "Astar_searcher.h"
using namespace std;
using namespace Eigen;
void AstarPathFinder::initGridMap(double _resolution, Vector3d global_xyz_l, Vector3d global_xyz_u, int max_x_id, int max_y_id, int max_z_id)
{
gl_xl = global_xyz_l(0);
gl_yl = global_xyz_l(1);
gl_zl = global_xyz_l(2);
gl_xu = global_xyz_u(0);
gl_yu = global_xyz_u(1);
gl_zu = global_xyz_u(2);
GLX_SIZE = max_x_id;
GLY_SIZE = max_y_id;
GLZ_SIZE = max_z_id;
GLYZ_SIZE = GLY_SIZE * GLZ_SIZE;
GLXYZ_SIZE = GLX_SIZE * GLYZ_SIZE;
resolution = _resolution;
inv_resolution = 1.0 / _resolution;
data = new uint8_t[GLXYZ_SIZE];
memset(data, 0, GLXYZ_SIZE * sizeof(uint8_t));
GridNodeMap = new GridNodePtr ** [GLX_SIZE];
for(int i = 0; i < GLX_SIZE; i++){
GridNodeMap[i] = new GridNodePtr * [GLY_SIZE];
for(int j = 0; j < GLY_SIZE; j++){
GridNodeMap[i][j] = new GridNodePtr [GLZ_SIZE];
for( int k = 0; k < GLZ_SIZE;k++){
Vector3i tmpIdx(i,j,k);
Vector3d pos = gridIndex2coord(tmpIdx);
GridNodeMap[i][j][k] = new GridNode(tmpIdx, pos);
}
}
}
}
void AstarPathFinder::resetGrid(GridNodePtr ptr)
{
ptr->id = 0;
ptr->cameFrom = NULL;
ptr->gScore = inf;
ptr->fScore = inf;
}
void AstarPathFinder::resetUsedGrids()
{
for(int i=0; i < GLX_SIZE ; i++)
for(int j=0; j < GLY_SIZE ; j++)
for(int k=0; k < GLZ_SIZE ; k++)
resetGrid(GridNodeMap[i][j][k]);
}
void AstarPathFinder::setObs(const double coord_x, const double coord_y, const double coord_z)
{
if( coord_x < gl_xl || coord_y < gl_yl || coord_z < gl_zl ||
coord_x >= gl_xu || coord_y >= gl_yu || coord_z >= gl_zu )
return;
int idx_x = static_cast<int>( (coord_x - gl_xl) * inv_resolution);
int idx_y = static_cast<int>( (coord_y - gl_yl) * inv_resolution);
int idx_z = static_cast<int>( (coord_z - gl_zl) * inv_resolution);
data[idx_x * GLYZ_SIZE + idx_y * GLZ_SIZE + idx_z] = 1;
}
vector<Vector3d> AstarPathFinder::getVisitedNodes()
{
vector<Vector3d> visited_nodes;
for(int i = 0; i < GLX_SIZE; i++)
for(int j = 0; j < GLY_SIZE; j++)
for(int k = 0; k < GLZ_SIZE; k++){
//if(GridNodeMap[i][j][k]->id != 0) // visualize all nodes in open and close list
if(GridNodeMap[i][j][k]->id == -1) // visualize nodes in close list only
visited_nodes.push_back(GridNodeMap[i][j][k]->coord);
}
ROS_WARN("visited_nodes size : %d", visited_nodes.size());
return visited_nodes;
}
Vector3d AstarPathFinder::gridIndex2coord(const Vector3i & index)
{
Vector3d pt;
pt(0) = ((double)index(0) + 0.5) * resolution + gl_xl;
pt(1) = ((double)index(1) + 0.5) * resolution + gl_yl;
pt(2) = ((double)index(2) + 0.5) * resolution + gl_zl;
return pt;
}
Vector3i AstarPathFinder::coord2gridIndex(const Vector3d & pt)
{
Vector3i idx;
idx << min( max( int( (pt(0) - gl_xl) * inv_resolution), 0), GLX_SIZE - 1),
min( max( int( (pt(1) - gl_yl) * inv_resolution), 0), GLY_SIZE - 1),
min( max( int( (pt(2) - gl_zl) * inv_resolution), 0), GLZ_SIZE - 1);
return idx;
}
Eigen::Vector3d AstarPathFinder::coordRounding(const Eigen::Vector3d & coord)
{
return gridIndex2coord(coord2gridIndex(coord));
}
inline bool AstarPathFinder::isOccupied(const Eigen::Vector3i & index) const
{
return isOccupied(index(0), index(1), index(2));
}
inline bool AstarPathFinder::isFree(const Eigen::Vector3i & index) const
{
return isFree(index(0), index(1), index(2));
}
inline bool AstarPathFinder::isOccupied(const int & idx_x, const int & idx_y, const int & idx_z) const
{
return (idx_x >= 0 && idx_x < GLX_SIZE && idx_y >= 0 && idx_y < GLY_SIZE && idx_z >= 0 && idx_z < GLZ_SIZE &&
(data[idx_x * GLYZ_SIZE + idx_y * GLZ_SIZE + idx_z] == 1));
}
inline bool AstarPathFinder::isFree(const int & idx_x, const int & idx_y, const int & idx_z) const
{
return (idx_x >= 0 && idx_x < GLX_SIZE && idx_y >= 0 && idx_y < GLY_SIZE && idx_z >= 0 && idx_z < GLZ_SIZE &&
(data[idx_x * GLYZ_SIZE + idx_y * GLZ_SIZE + idx_z] < 1));
}
inline void AstarPathFinder::AstarGetSucc(GridNodePtr currentPtr, vector<GridNodePtr> & neighborPtrSets, vector<double> & edgeCostSets)
{
neighborPtrSets.clear();
edgeCostSets.clear();
/*
*
STEP 4: finish AstarPathFinder::AstarGetSucc yourself
please write your code below
*
*
*/
// 从当前点向周围各个方向进行扩展
Eigen::Vector3i current_index = currentPtr->index;
int n_x, n_y, n_z;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
for (int k = -1; k <= 1; k++) {
// 不是相邻节点
if (i == 0 && j == 0 && k == 0) continue;
n_x = current_index(0) + i;
n_y = current_index(1) + j;
n_z = current_index(2) + k;
// 相邻节点在边界范围内并且不是障碍物
if (isFree(n_x, n_y, n_z)) {
neighborPtrSets.push_back(GridNodeMap[n_x][n_y][n_z]);
edgeCostSets.push_back(std::sqrt(i*i + j*j + k*k));
}
}
}
}
}
double AstarPathFinder::getHeu(GridNodePtr node1, GridNodePtr node2)
{
/*
choose possible heuristic function you want
Manhattan, Euclidean, Diagonal, or 0 (Dijkstra)
Remember tie_breaker learned in lecture, add it here ?
*
*
*
STEP 1: finish the AstarPathFinder::getHeu , which is the heuristic function
please write your code below
*
*
*/
double hScore = 0;
double gScore = node1->gScore;
switch (heuristic_type_)
{
case Manhattan:
{
double dx = abs(double(node1->index(0) - node2->index(0)));
double dy = abs(double(node1->index(1) - node2->index(1)));
double dz = abs(double(node1->index(2) - node2->index(2)));
hScore = dx + dy + dz;
break;
}
case Euclidean:
{
double dx = abs(double(node1->index(0) - node2->index(0)));
double dy = abs(double(node1->index(1) - node2->index(1)));
double dz = abs(double(node1->index(2) - node2->index(2)));
hScore = sqrt(dx*dx + dy*dy + dz*dz);
break;
}
case Diagonal:
{
double dx = abs(double(node1->index(0) - node2->index(0)));
double dy = abs(double(node1->index(1) - node2->index(1)));
double dz = abs(double(node1->index(2) - node2->index(2)));
double min_xyz = std::min({dx, dy, dz});
hScore = dx + dy + dz + (std::sqrt(3.0) - 3) * min_xyz;
break;
}
case Dijkstra:
{
hScore = 0;
break;
}
default:
break;
}
if (use_Tie_breaker_) {
double dx1 = abs(double(node1->index(0) - node2->index(0)));
double dy1 = abs(double(node1->index(1) - node2->index(1)));
double dz1 = abs(double(node1->index(2) - node2->index(2)));
double dx2 = abs(double(startIdx(0) - node2->index(0)));
double dy2 = abs(double(startIdx(1) - node2->index(1)));
double dz2 = abs(double(startIdx(2) - node2->index(2)));
double cross1 = abs(dx1*dy2 - dx2*dy1);
double cross2 = abs(dz1*dy2 + dz2*dy1);
hScore = hScore + cross1 * 0.001 + cross2 * 0.001;
}
double fScore = hScore + gScore;
return fScore;
}
// 在终端打印启发式函数类型以及是否使用tie Break
void AstarPathFinder::printHeuristicType() {
string heuristic_type;
string whether_use_tie_break = "false";
switch (heuristic_type_) {
case Manhattan:
{
heuristic_type = "Manhattan";
break;
}
case Euclidean:
{
heuristic_type = "Euclidean";
break;
}
case Diagonal:
{
heuristic_type = "Diagonal";
break;
}
case Dijkstra:
{
heuristic_type = "Dijkstra";
break;
}
default:
break;
}
if (use_Tie_breaker_) {
whether_use_tie_break = "true";
}
ROS_INFO("heuristic_type: %s, whether_use_tie_break: %s", heuristic_type.c_str(), whether_use_tie_break.c_str());
}
void AstarPathFinder::AstarGraphSearch(Vector3d start_pt, Vector3d end_pt)
{
printHeuristicType();
ros::Time time_1 = ros::Time::now();
//index of start_point and end_point
Vector3i start_idx = coord2gridIndex(start_pt);
Vector3i end_idx = coord2gridIndex(end_pt);
goalIdx = end_idx;
startIdx = start_idx;
//position of start_point and end_point
start_pt = gridIndex2coord(start_idx);
end_pt = gridIndex2coord(end_idx);
//Initialize the pointers of struct GridNode which represent start node and goal node
GridNodePtr startPtr = new GridNode(start_idx, start_pt);
GridNodePtr endPtr = new GridNode(end_idx, end_pt);
//openSet is the open_list implemented through multimap in STL library
openSet.clear();
// currentPtr represents the node with lowest f(n) in the open_list
GridNodePtr currentPtr = NULL;
GridNodePtr neighborPtr = NULL;
//put start node in open set
startPtr -> gScore = 0;
startPtr -> fScore = getHeu(startPtr,endPtr);
//STEP 1: finish the AstarPathFinder::getHeu , which is the heuristic function
startPtr -> id = 1;
startPtr -> coord = start_pt;
openSet.insert( make_pair(startPtr -> fScore, startPtr) );
/*
*
STEP 2 : some else preparatory works which should be done before while loop
please write your code below
*
*
*/
vector<GridNodePtr> neighborPtrSets;
vector<double> edgeCostSets;
// this is the main loop
while ( !openSet.empty() ){
/*
*
*
step 3: Remove the node with lowest cost function from open set to closed set
please write your code below
IMPORTANT NOTE!!!
This part you should use the C++ STL: multimap, more details can be find in Homework description
*
*
*/
// 从openSet中取出f值最小的节点,并删除
currentPtr = openSet.begin()->second;
currentPtr->id = -1; // 从openset 放到 closeset
openSet.erase(openSet.begin());
// if the current node is the goal
if( currentPtr->index == goalIdx ){
ros::Time time_2 = ros::Time::now();
terminatePtr = currentPtr;
ROS_WARN("[A*]{sucess} Time in A* is %f ms, path cost if %f m", (time_2 - time_1).toSec() * 1000.0, currentPtr->gScore * resolution );
return;
}
//get the succetion
// 获取相邻节点
AstarGetSucc(currentPtr, neighborPtrSets, edgeCostSets); //STEP 4: finish AstarPathFinder::AstarGetSucc yourself
/*
*
*
STEP 5: For all unexpanded neigbors "m" of node "n", please finish this for loop
please write your code below
*
*/
for(int i = 0; i < (int)neighborPtrSets.size(); i++){
/*
*
*
Judge if the neigbors have been expanded
please write your code below
IMPORTANT NOTE!!!
neighborPtrSets[i]->id = -1 : expanded, equal to this node is in close set
neighborPtrSets[i]->id = 1 : unexpanded, equal to this node is in open set
*
*/
neighborPtr = neighborPtrSets[i];
double neighbor_gScore = currentPtr->gScore + edgeCostSets[i];
if(neighborPtr -> id == 0){ //discover a new node, which is not in the closed set and open set
/*
*
*
STEP 6: As for a new node, hat you need do ,and then put neighbor in open set and record it
please write your code below
*
*/
neighborPtr->gScore = neighbor_gScore;
neighborPtr->fScore = getHeu(neighborPtr, endPtr);
neighborPtr->id = 1;
neighborPtr->cameFrom = currentPtr;
neighborPtr->nodeMapIt = openSet.insert(make_pair(neighborPtr -> fScore, neighborPtr));
continue;
}
else if(neighborPtr->id == 1){ //this node is in open set and need to judge if it needs to update, the "0" should be deleted when you are coding
/*
*
*
STEP 7: As for a node in open set, update it , maintain the openset ,and then put neighbor in open set and record it
please write your code below
*
*/
if (neighborPtr->gScore > neighbor_gScore) {
neighborPtr->gScore = neighbor_gScore;
neighborPtr->fScore = getHeu(neighborPtr, endPtr);
neighborPtr->cameFrom = currentPtr;
openSet.erase(neighborPtr->nodeMapIt);
neighborPtr->nodeMapIt = openSet.insert(make_pair(neighborPtr -> fScore, neighborPtr));
}
continue;
}
else{//this node is in closed set
/*
*
please write your code below
*
*/
continue;
}
}
}
//if search fails
ros::Time time_2 = ros::Time::now();
if((time_2 - time_1).toSec() > 0.1)
ROS_WARN("Time consume in Astar path finding is %f", (time_2 - time_1).toSec() );
}
vector<Vector3d> AstarPathFinder::getPath()
{
vector<Vector3d> path;
vector<GridNodePtr> gridPath;
/*
*
*
STEP 8: trace back from the curretnt nodePtr to get all nodes along the path
please write your code below
*
*/
GridNodePtr tempNode = terminatePtr;
while (tempNode->cameFrom != nullptr) {
gridPath.push_back(tempNode);
tempNode = tempNode->cameFrom;
}
for (auto ptr: gridPath)
path.push_back(ptr->coord);
reverse(path.begin(),path.end());
ROS_WARN("A* path size: %d", path.size());
return path;
}
#ifndef _ASTART_SEARCHER_H
#define _ASTART_SEARCHER_H
#include <iostream>
#include <ros/ros.h>
#include <ros/console.h>
#include <Eigen/Eigen>
#include <cstdlib>
#include <ctime>
#include "backward.hpp"
#include "node.h"
#define Euclidean 0
#define Manhattan 1
#define Diagonal 2
#define Dijkstra 3
// #define use_Tie_breaker 1
class AstarPathFinder
{
private:
protected:
uint8_t * data;
GridNodePtr *** GridNodeMap;
Eigen::Vector3i goalIdx;
Eigen::Vector3i startIdx;
int GLX_SIZE, GLY_SIZE, GLZ_SIZE;
int GLXYZ_SIZE, GLYZ_SIZE;
double resolution, inv_resolution;
double gl_xl, gl_yl, gl_zl;
double gl_xu, gl_yu, gl_zu;
int heuristic_type_; // 启发式函数
bool use_Tie_breaker_; // 是否使用Tie_breaker
GridNodePtr terminatePtr;
std::multimap<double, GridNodePtr> openSet;
double getHeu(GridNodePtr node1, GridNodePtr node2);
void AstarGetSucc(GridNodePtr currentPtr, std::vector<GridNodePtr> & neighborPtrSets, std::vector<double> & edgeCostSets);
bool isOccupied(const int & idx_x, const int & idx_y, const int & idx_z) const;
bool isOccupied(const Eigen::Vector3i & index) const;
bool isFree(const int & idx_x, const int & idx_y, const int & idx_z) const;
bool isFree(const Eigen::Vector3i & index) const;
Eigen::Vector3d gridIndex2coord(const Eigen::Vector3i & index);
Eigen::Vector3i coord2gridIndex(const Eigen::Vector3d & pt);
void printHeuristicType();
public:
AstarPathFinder(int heuristic_type = Manhattan, bool use_Tie_breaker = false): heuristic_type_(heuristic_type), use_Tie_breaker_(use_Tie_breaker) {};
~AstarPathFinder(){};
void AstarGraphSearch(Eigen::Vector3d start_pt, Eigen::Vector3d end_pt);
void resetGrid(GridNodePtr ptr);
void resetUsedGrids();
void initGridMap(double _resolution, Eigen::Vector3d global_xyz_l, Eigen::Vector3d global_xyz_u, int max_x_id, int max_y_id, int max_z_id);
void setObs(const double coord_x, const double coord_y, const double coord_z);
Eigen::Vector3d coordRounding(const Eigen::Vector3d & coord);
std::vector<Eigen::Vector3d> getPath();
std::vector<Eigen::Vector3d> getVisitedNodes();
};
#endif