mst_path.cpp
Go to the documentation of this file.
1 #include "lib/mst_path.h"
2 
4 {
5 }
6 
7 void mst_path::generate_path (geometry_msgs::Point start)
8 {
9  // starting vertex
10  geometry_msgs::Point wp = start;
11  path.push_back(wp);
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);
15 
16  // visited vertices
17  unordered_set<int> removed;
18 
19  // previous vertex
20  int previous;
21 
22  // last movement
23  int offset;
24 
25  // possible movements
26  vector<int> movement;
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);
31 
32  // valid movement
33  bool found = false;
34 
35  // look for valid first step
36  for (int idx=0; idx<movement.size(); idx++) {
37  if (nodes[current].count(current + movement[idx]) > 0) {
38  previous = current + movement[idx];
39  found = true;
40  break;
41  }
42  }
43 
44  // no valid first step found
45  if (!found) {
46  ROS_ERROR("No path found!");
47  return;
48  }
49 
50  // generate path
51  do {
52  // remember visited vertices
53  removed.insert(current);
54 
55  // last movement
56  offset = distance(movement.begin(), find(movement.begin(), movement.end(), previous-current));
57 
58  // look for valid step
59  found = false;
60  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()];
65  found = true;
66  break;
67  }
68  }
69  if (!found) {
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);
71  return;
72  }
73 
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);
75 
76  // remove vertices from sets
77  nodes[current].erase(previous);
78  nodes[previous].erase(current);
79 
80  // convert index to waypoint position on map
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;
83 
84  // shift waypoint to center path on cell
85  wp.x += 0.25 * map.info.resolution;
86  wp.y += 0.25 * map.info.resolution;
87 
88  // add vertex to path
89  path.push_back(wp);
90  } while (found);
91 
92  // final waypoint
93  wp = path.front();
94  path.push_back(wp);
95 }
96 
97 geometry_msgs::PoseArray mst_path::get_grid ()
98 {
99  geometry_msgs::PoseArray grid;
100  vector<geometry_msgs::Pose> poses;
101  geometry_msgs::Pose pose;
102 
103  for (int i=0; i<nodes.size(); ++i) {
104  // from
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;
107 
108  // orientation
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);
115 
116  poses.push_back(pose);
117  }
118  }
119 
120  grid.poses = poses;
121  grid.header.stamp = Time::now();
122  grid.header.frame_id = "local_origin_ned";
123  return grid;
124 }
125 
126 nav_msgs::Path mst_path::get_path ()
127 {
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);
134  }
135  nav_path.poses = poses;
136  nav_path.header.stamp = Time::now();
137  nav_path.header.frame_id = "local_origin_ned";
138  return nav_path;
139 }
140 
141 geometry_msgs::Point mst_path::get_waypoint (geometry_msgs::Point position, double tolerance)
142 {
143  // close enough to or past current waypoint
144  if (dist(position, get_wp()) < tolerance || dist(position, get_wp(1)) < dist(position, get_wp())) {
145  // select next waypoint
146  ++wp;
147  }
148 
149  return get_wp();
150 }
151 
152 void mst_path::initialize_graph (nav_msgs::OccupancyGrid gridmap, bool connect4)
153 {
154  map = gridmap;
155  int rows = gridmap.info.height;
156  int cols = gridmap.info.width;
157  nodes.clear();
158  nodes.resize(2*rows*2*cols);
159  edges.clear();
160  path.clear();
161 
162  // double graph resolution
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);
167  }
168  }
169 
170  // iterate all rows and columns
171  for (int i=0; i<2*rows; i++) {
172  for (int j=0; j<2*cols; j++) {
173  // found a vertex
174  if (inflated[2*i*cols+j]) {
175  // check von neumann neighborhood for connected vertices
176  if (i>0 && inflated[(i-1)*2*cols+j]) {
177  add_edge(i*2*cols+j, (i-1)*2*cols+j, 1);
178  }
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);
181  }
182  if (j>0 && inflated[i*2*cols+j-1]) {
183  add_edge(i*2*cols+j, i*2*cols+j-1, 1);
184  }
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);
187  }
188 
189  // check moore neighborhood for connected vertices
190  if (!connect4) {
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);
193  }
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);
196  }
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);
199  }
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);
202  }
203  }
204  }
205  }
206  }
207 }
208 
209 void mst_path::initialize_tree (vector<edge> mst)
210 {
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);
216 
217  if (vmax - vmin == 1) {
218  alpha = (4*vmin + 3) - 2 * (vmax % cols);
219  remove_edge(edge(alpha, alpha + 2*cols, 1));
220  remove_edge(edge(alpha + 2*cols, alpha, 1));
221  remove_edge(edge(alpha+1, alpha+1 + 2*cols, 1));
222  remove_edge(edge(alpha+1 + 2*cols, alpha+1, 1));
223 
224  }
225  else{
226  alpha = (4*vmin + 2*cols) - 2 * (vmax % cols);
227  remove_edge(edge(alpha, alpha+1, 1));
228  remove_edge(edge(alpha+1, alpha, 1));
229  remove_edge(edge(alpha + 2*cols, alpha+1 + 2*cols, 1));
230  remove_edge(edge(alpha+1 + 2*cols, alpha + 2*cols, 1));
231  }
232  }
233 }
234 
236 {
237  return 0 <= wp && wp < path.size();
238 }
239 
240 void mst_path::add_edge (int from, int to, int cost)
241 {
242  // add edge to priority queue
243  edge e(from,to,cost);
244  edges.insert(e);
245 
246  // add vertices to sets
247  nodes[from].insert(to);
248  nodes[to].insert(from);
249 }
250 
251 double mst_path::dist (geometry_msgs::Point p1, geometry_msgs::Point p2)
252 {
253  return hypot(p1.x - p2.x, p1.y - p2.y);
254 }
255 
256 geometry_msgs::Point mst_path::get_wp (int offset)
257 {
258  geometry_msgs::Point waypoint;
259 
260  if (0 <= wp+offset && wp+offset < path.size()) {
261  waypoint = path[wp+offset];
262  }
263 
264  return waypoint;
265 }
266 
268 {
269  if (edges.count(e) > 0) {
270  edges.erase(e);
271  nodes[e.from].erase(e.to);
272  nodes[e.to].erase(e.from);
273  }
274 }
nav_msgs::OccupancyGrid gridmap
The grid map representing the environment to be covered.
Definition: coverage_path.h:69
void generate_path(geometry_msgs::Point)
Generate all way points for the path.
Definition: mst_path.cpp:7
int wp
The current way point.
Definition: mst_path.h:127
geometry_msgs::Point get_waypoint(geometry_msgs::Point position, double tolerance)
Get the current waypoint and possibly select next waypoint, if close enough.
Definition: mst_path.cpp:141
geometry_msgs::Point get_wp(int offset=0)
Get the current way point.
Definition: mst_path.cpp:256
int to
The ending vertex of the edge.
Definition: edge.h:35
A class for representing edges.
Definition: edge.h:9
geometry_msgs::Pose pose
Current position of the CPS.
Definition: coverage_path.h:39
void initialize_graph(nav_msgs::OccupancyGrid gridmap, bool connect4=true)
Initialize the internal graph structure that represents the area division.
Definition: mst_path.cpp:152
int from
The starting vertex of the edge.
Definition: edge.h:30
mst_path()
Constructor.
Definition: mst_path.cpp:3
void add_edge(int from, int to, int cost)
Add an edge to the tree graph.
Definition: mst_path.cpp:240
vector< unordered_set< int > > nodes
The sets of connected vertices.
Definition: mst_path.h:117
nav_msgs::OccupancyGrid map
The grid map that needs to be covered by the MST path.
Definition: mst_path.h:122
deque< geometry_msgs::Point > path
The boustrophedon path.
Definition: mst_path.h:107
double dist(geometry_msgs::Point p1, geometry_msgs::Point p2)
Calculate the distance between two points.
Definition: mst_path.cpp:251
geometry_msgs::PoseArray get_grid()
Get the graph generated from the grid map.
Definition: mst_path.cpp:97
void remove_edge(edge e)
Remove an edge from the tree graph.
Definition: mst_path.cpp:267
bool valid()
Check whether the current waypoint index is valid.
Definition: mst_path.cpp:235
void initialize_tree(vector< edge > mst)
Remove edges of the graph that overlap with the tree.
Definition: mst_path.cpp:209
unordered_set< edge, hash_edge > edges
Priority queue of edge objects sorted by cost.
Definition: mst_path.h:112
nav_msgs::Path get_path()
Get the complete path.
Definition: mst_path.cpp:126


coverage_path
Author(s): Micha Sende
autogenerated on Thu Oct 31 2019 10:37:30