-
Notifications
You must be signed in to change notification settings - Fork 2
Understanding the Code
The code consists of a struct GraphNode and three classes ,viz , Color,PathVisualizer and AStarPlanner. Each of them has been explained one by one in the following section of the page.
It consists of :
- an unsigned integer which is used for indices later in the code
- an Eigen::Vector3d point which is simply a column vector having three double values.
- a vector of pointers of the struct which is used to contain the info about neighbours
- a function to add neighbours to a particular GraphNode
- a constructor which has
- the first argument as a PointXYZI from pcl library which simply is a collection of 3 coordinate values and one intensity value
- the second argument is an unsigned integer.
It is a class inherited from std_msgs::ColorRGBA class which consists of 4 float values.
This class has 3 constructors:
- a default one
- one which initialises RGB values
- and the last which initialises RGBA values
This class consists of functions like white, black ,etc which return constructors having initialised the RGB values corresponding to them .
The functions of this class are used to decide that in which color do we want the vertices/edges of our graph and path to be visualized inside rviz using visualizeGraph and visualizePath.
It is used to visualize the path as the name suggests.
It has the following functions:
It takes the nodeHandles as it's arguments. It fetches the parameter visualize and voxel_size from the server. It creates colour maps for the colours like white,black,etc. Their first arguments are values like 0,1,2.. and the second arguments are the functions white,black,etc.
It takes the reference of a string as an argument.It makes a publisher object whose message type is visualization_msgs::MarkerArray and the topic name is the same as the argument of the function.It then creates a map the topic and the publisher.
This function is used to visualize the graph(whose smallest unit is struct Graphnode) generated by function createGraph which is a part of class AStarPlanner.
If the graph is empty then the function ends simply and does nothing.
For a non-empty graph it does the following things:
-
It creates a variable
markersof the message typevisualization_msgs::MarkerArrayand uses thismarkersas the second entry to create a publish map (publisher_map_) whose first entry istopic_name. -
The
markerscontainsvertex_markerandedge_markerwhich are of message typevisualization_msgs::Marker.-
vertex_marker,as the name suggests, is used to visualize vertices of the graph.To understand the different initialization of it's fields (which is included in the code) you can have a look at this .For every unit node of the graph, it copies the values of the three coordinates from it'sposition_variable into ageometry_msgs::Pointvariable and pushes it into thevertex_marker. After doing the aforementioned step with every node, it simply pushesvertex_markerintomarkers. -
edge_marker,as the name suggests, is used to visualize the edges connecting the nodes of the graph.It initializes different fields of this marker in a similar way as did forvertex_marker. For every unit node in the graph,it copies the values of the three coordinates from it'sposition_variable into ageometry_msgs::Pointvariablestart_pointand the coordinates of all of it's neighbours are also copied into variables calledend_pointand pushed intoedge_marker. Finally theedge_markeris pushed intomarkers.
-
-
Eventually the
markersis published.
This function is used to visualize the path found by the function findPath.
If the path is empty it simply ends and does nothing.
For a non-empty path it does the following things:
- A
markeris created of the message typevisualization_msgs::Marker.It is initialised in a similar fashion asedge_markerin the previous function because this marker is also going to give us some curve and not vertices. - The
pathis a vector ofEigen::Vector3dpoints. For every point of the path, it copies it's three coordinates into a variables of typegeometry_msgs::Pointand pushes them intopointsfield of themarker. - A
markersis created of the message typevisualization_msgs::MarkerArrayand then themarkeris pushed into it. - Eventually
markersis published after it has been incorporated intopublisher_map_as done intovisualizeGraph.
This class has a constructor and a few functions which are described below:
It initializes some variables,fetches some parameters,creates some publishers,some subscribers and some services and sets up some planners and other functions.
In particular,it does the following things:
- fetches parameters like
robot_radius,visualizeandframe_idfrom parameter server. - creates the following publishers:
-
path_marker_pubto publish themarkersfor visualizing the path. -
sparse_graph_pubto publish themarkersfor visualizing the graph generated. -
esdf_slice_pub_to publish the pointCloud of points of typepcl::PointXYZI. -
waypoint_list_pubto publish the list of points that constitute the path.
-
- creates a subscriber
esdf_slice_sub_to subscribe to the topic on which the slices are being published. - creates the following services:
-
planner_srv_which responds when requested to plan the path usingPlannerServiceCallback. -
path_pub_srv_which responds when requested to publish the path usingpublishPathCallback.
-
- sets the traversability radius which simply means minimum distance from the obstacles that our robot should maintain in order to avoid collisions.
- sets up the skeleton generator
- sets up the A* planner
- sets up the shortener.
It takes two points start and end as it's arguments of the type Eigen::Vector3d and then copies them into Start and End of the type pcl::PointXYZI.
It clears the graph graph_ first so that nothing is inside it beforehand and then pushes Start and End into it.Then iteratively it pushes all those points from pointCloud whose intensity values are greater than robot_radius_ into the graph.
Then it clears the tree_ (which is an Rtree) .For every node of the graph_ it takes their coordinates and make pairs with their id_ and pushes them inside the tree_.
Then for each node of the graph_ it does the following things:
- It creates a vector of a data type which is a pair of a Point from boost library and an unsigned integer and calls it
neighbours. - It copies the coordinates of the
position_of the node into thePointand pushes 5 nearest points intoneighbours. - Then for each neighbour from
neighbours,if it'sid_is not equal to the second argument of the neighbour ,then adds into the neighbour field of the node by using theaddNeighbourfunction.
This function is used to search the path based on A* search algorithm.
The basic idea of A* algorithm is explained below:
- At each step it picks the node according to a value-
fwhich is a parameter equal to the sum of two other parameters –gandh. - The first parameeter
gis a movement cost parameter that is used to calculate the distance from starting point to the current location. - The second parameter
his a heuristic parameter that is to calculate our estimated distance from the current location to the end location. - The
hparameter can be calculated using Euclidean distance , Manhattan distance , Diagonal distance, etc. In our case we use the Euclidean one.
The containers that has been used in the code for this are :
-
f_score_mapwhich is a pair of double value and an unsigned int value to calculate thefparameter. -
open_setwhich is a priority_queue off_score_mapwhich keeps it sorted into non-decreasing order. -
g_scorewhich is vector of doubles and keeps record of thegparameter. -
parentwhich is a vector of unsigned integers which keeps the record of the previous index of the current node.
This function is used to find the path as the name suggests.
It first creates the graph using createGraph, visualize it using visualizeGraph and eventually searches the path between the points using searcPath.
This function is used to generate a sparse graph. A sparse graph is a graph in which the number of edges is much less than the possible number of edges.
It first updates the skeleton from layer after removing any pre-existing points in the skeleton.Then it calls the generateSparseGraph function which is in voxblox::SkeletonGenerator and is different from the generateSparseGraph of class AStarPlanner.
It then visualizes the graph using visualization_msgs::MarkerArray and publishing it using the publisher sparse_graph_pub_ on the topic sparse_graph.
This function is used to make a skeleton from the esdf layer.
It does the following things:
- sets the esdf layer.
- gets the minimum separation angle ( Minimum separation angle between two edges of a sparse graph node in radians) from
getMinSeparationAnglefunction which is used to set the default value ofmin_seperation_angle. Then it fetches it from the parameter server and uses it to set themin_seperation_angleusingsetMinSeperationAnglefunction. - In the very similar fashion as the previous point,
generate_by_layer_neighbors( which decides whether to generate vertices/edges by number of basis points (false, default) or number of neighbors on the discretized medial axis (true) ) andnum_neighbors_for_edgeare processed. - Finally it sets the minimum GVD distance ( GVD stands for Generalized Voronoi Diagram which is commonly used as a safe roadmap in the context of path planning and it is used to compute distance between robots and points in the environment).
This function responds by planning the path once requested to do so using rviz.
It does the following things :
- generates the skeleton
- generates the sparse graph
- finds the path
- creates a
marker_arrayof the typevisualization_msgs::MarkerArrayin order to visualize the generated path inside rviz - gets the path using Esdf and diagram
- shortens the path if possible
- publishes the
marker_arrayusingpath_marker_pub - and finally visualizes the path inside rviz.
This funtion is used to publish waypoints of the path searched.
It creates a variable pose_array of the type geometry_msgs::PoseArray. For every point in the last_waypoints_ (a variable of type mav_msgs::EigenTrajectoryPointVector) ,it creates a variable pose_stamped of type geometry_msgs::PoseStamped ,uses the point and the pose_stamped to create a pose and finally pushes it inside the pose_array.
Finally it publishes the pose_array using waypoint_list_pub_ on the topic waypoint_list.
It takes a pointcloud and publishes it using the esdf_slice_pub_ publisher on the esdf_slice_out topic.
Then it declares and initializes start and end points of the type Eigen::Vector3d and passes them as arguments into createGraph to create the graph.
It finally calls the visualizeGraph function which visualizes the graph into rviz.