10 geometry_msgs::Point
wp = start;
12 int(round((wp.x -
map.info.origin.position.x) /
map.info.resolution));
13 int(round((wp.y -
map.info.origin.position.y) /
map.info.resolution));
14 int current = 2 * round((wp.y -
map.info.origin.position.y) /
map.info.resolution) * 2*
map.info.width + 2 * round((wp.x -
map.info.origin.position.x) /
map.info.resolution);
17 unordered_set<int> removed;
27 movement.push_back(2*
map.info.width);
28 movement.push_back(-1);
29 movement.push_back(-2*
map.info.width);
30 movement.push_back(1);
36 for (
int idx=0; idx<movement.size(); idx++) {
37 if (
nodes[current].count(current + movement[idx]) > 0) {
38 previous = current + movement[idx];
46 ROS_ERROR(
"No path found!");
53 removed.insert(current);
56 offset = distance(movement.begin(), find(movement.begin(), movement.end(), previous-current));
61 for (
int idx=0; idx<movement.size(); idx++){
62 if (
nodes[previous].count(previous + movement[(idx+offset) % movement.size()]) > 0 &&
63 removed.count(previous + movement[(idx+offset) % movement.size()]) <= 0) {
64 current = previous + movement[(idx+offset) % movement.size()];
70 ROS_DEBUG(
"Path terminated at %d (%.2f,%.2f)", current, (current % (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.x, (current / (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.y);
74 ROS_DEBUG(
"Path at %d (%.2f,%.2f)", current, (current % (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.x, (current / (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.y);
77 nodes[current].erase(previous);
78 nodes[previous].erase(current);
81 wp.x = (current % (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.x;
82 wp.y = (current / (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.y;
85 wp.x += 0.25 *
map.info.resolution;
86 wp.y += 0.25 *
map.info.resolution;
99 geometry_msgs::PoseArray grid;
100 vector<geometry_msgs::Pose> poses;
101 geometry_msgs::Pose
pose;
103 for (
int i=0; i<
nodes.size(); ++i) {
105 pose.position.x = (i % (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.x;
106 pose.position.y = (i / (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.y;
109 for (
auto it=
nodes[i].begin(); it!=
nodes[i].end(); ++it) {
110 double dx = (*it % (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.x - pose.position.x;
111 double dy = (*it / (2*
map.info.width)) / 2.0 *
map.info.resolution +
map.info.origin.position.y - pose.position.y;
112 tf2::Quaternion direction;
113 direction.setRPY(0, 0, atan2(dy, dx));
114 pose.orientation = tf2::toMsg(direction);
116 poses.push_back(pose);
121 grid.header.stamp = Time::now();
122 grid.header.frame_id =
"local_origin_ned";
128 nav_msgs::Path nav_path;
129 vector<geometry_msgs::PoseStamped> poses;
130 geometry_msgs::PoseStamped
pose;
131 for (
auto p :
path) {
132 pose.pose.position = p;
133 poses.push_back(pose);
135 nav_path.poses = poses;
136 nav_path.header.stamp = Time::now();
137 nav_path.header.frame_id =
"local_origin_ned";
155 int rows = gridmap.info.height;
156 int cols = gridmap.info.width;
158 nodes.resize(2*rows*2*cols);
163 valarray<bool> inflated(2*rows*2*cols);
164 for (
int i=0; i<2*rows; i++) {
165 for (
int j=0; j<2*cols; j++) {
166 inflated[i*2*cols + j] = (gridmap.data[(i/2)*cols + j/2] == 0);
171 for (
int i=0; i<2*rows; i++) {
172 for (
int j=0; j<2*cols; j++) {
174 if (inflated[2*i*cols+j]) {
176 if (i>0 && inflated[(i-1)*2*cols+j]) {
177 add_edge(i*2*cols+j, (i-1)*2*cols+j, 1);
179 if (i<2*rows-1 && inflated[(i+1)*2*cols+j]) {
180 add_edge(i*2*cols+j, (i+1)*2*cols+j, 1);
182 if (j>0 && inflated[i*2*cols+j-1]) {
183 add_edge(i*2*cols+j, i*2*cols+j-1, 1);
185 if (j<2*cols-1 && inflated[i*2*cols+j+1]) {
186 add_edge(i*2*cols+j, i*2*cols+j+1, 1);
191 if (i>0 && j>0 && inflated[(i-1)*2*cols+j-1]) {
192 add_edge(i*2*cols+j, (i-1)*2*cols+j-1, 1);
194 if (i<2*rows-1 && j<2*cols-1 && inflated[(i+1)*2*cols+j+1]) {
195 add_edge(i*2*cols+j, (i+1)*2*cols+j+1, 1);
197 if (i<2*rows-1 && j>0 && inflated[(i+1)*2*cols+j-1]) {
198 add_edge(i*2*cols+j, (i+1)*2*cols+j-1, 1);
200 if (i>0 && j<2*cols-1 && inflated[(i-1)*2*cols+j+1]) {
201 add_edge(i*2*cols+j, (i-1)*2*cols+j+1, 1);
211 int cols =
map.info.width;
212 int alpha, vmax, vmin;
213 for (
int i=0; i<mst.size(); i++) {
214 vmax = max(mst[i].from, mst[i].to);
215 vmin = min(mst[i].from, mst[i].to);
217 if (vmax - vmin == 1) {
218 alpha = (4*vmin + 3) - 2 * (vmax % cols);
226 alpha = (4*vmin + 2*cols) - 2 * (vmax % cols);
243 edge e(from,to,cost);
247 nodes[from].insert(to);
248 nodes[to].insert(from);
253 return hypot(p1.x - p2.x, p1.y - p2.y);
258 geometry_msgs::Point waypoint;
260 if (0 <=
wp+offset &&
wp+offset <
path.size()) {
261 waypoint =
path[
wp+offset];
269 if (
edges.count(e) > 0) {
nav_msgs::OccupancyGrid gridmap
The grid map representing the environment to be covered.
void generate_path(geometry_msgs::Point)
Generate all way points for the path.
int wp
The current way point.
geometry_msgs::Point get_waypoint(geometry_msgs::Point position, double tolerance)
Get the current waypoint and possibly select next waypoint, if close enough.
geometry_msgs::Point get_wp(int offset=0)
Get the current way point.
int to
The ending vertex of the edge.
A class for representing edges.
geometry_msgs::Pose pose
Current position of the CPS.
void initialize_graph(nav_msgs::OccupancyGrid gridmap, bool connect4=true)
Initialize the internal graph structure that represents the area division.
int from
The starting vertex of the edge.
void add_edge(int from, int to, int cost)
Add an edge to the tree graph.
vector< unordered_set< int > > nodes
The sets of connected vertices.
nav_msgs::OccupancyGrid map
The grid map that needs to be covered by the MST path.
deque< geometry_msgs::Point > path
The boustrophedon path.
double dist(geometry_msgs::Point p1, geometry_msgs::Point p2)
Calculate the distance between two points.
geometry_msgs::PoseArray get_grid()
Get the graph generated from the grid map.
void remove_edge(edge e)
Remove an edge from the tree graph.
bool valid()
Check whether the current waypoint index is valid.
void initialize_tree(vector< edge > mst)
Remove edges of the graph that overlap with the tree.
unordered_set< edge, hash_edge > edges
Priority queue of edge objects sorted by cost.
nav_msgs::Path get_path()
Get the complete path.