coverage_path.cpp
Go to the documentation of this file.
1 #include "coverage_path.h"
2 
7 bool generate_path ()
8 {
9  // get area to cover
10  nav_msgs::GetMap division;
11  if (map_getter.call(division) == false){
12  ROS_ERROR("Failed to get the assigned map, cannot compute coverage path!");
13  return false;
14  }
15 
16  ROS_INFO("Generate new coverage path...");
17 
18  // construct minimum spanning tree
19  ROS_DEBUG("Construct minimum-spanning-tree...");
20  tree.initialize_graph(division.response.map);
21  tree.construct();
22 
23  // generate path
24  ROS_DEBUG("Generate coverage path...");
25  path.initialize_graph(division.response.map);
27  path.generate_path(pose.position);
28 
29  // visualize path
30  if (visualize)
31  path_publisher.publish(path.get_path());
32 
33  reconfigure = false;
34 
35  return true;
36 }
37 
44 bool get_path (nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &res)
45 {
46  // compute new path if swarm configuration changed
47  if (reconfigure) {
48  if (generate_path() == false)
49  return false;
50  }
51 
52  // return coverage path
53  res.plan = path.get_path();
54 
55  return true;
56 }
57 
64 bool get_waypoint (cpswarm_msgs::GetWaypoint::Request &req, cpswarm_msgs::GetWaypoint::Response &res)
65 {
66  // compute new path if swarm configuration changed
67  if (reconfigure) {
68  if (generate_path() == false)
69  return false;
70  }
71 
72  // return waypoint
73  res.point = path.get_waypoint(pose.position, req.tolerance);
74  res.valid = path.valid();
75 
76  // visualize waypoint
77  if (visualize) {
78  geometry_msgs::PointStamped wp;
79  wp.header.stamp = Time::now();
80  wp.header.frame_id = "local_origin_ned";
81  wp.point = res.point;
82  wp_publisher.publish(wp);
83  }
84 
85  return true;
86 }
87 
92 void pose_callback (const geometry_msgs::PoseStamped::ConstPtr& msg)
93 {
94  // store new position and orientation in class variables
95  pose = msg->pose;
96 
97  // valid pose received
98  if (msg->header.stamp.isValid())
99  pose_valid = true;
100 }
101 
106 void state_callback (const cpswarm_msgs::StateEvent::ConstPtr& msg)
107 {
108  // store new position and orientation in class variables
109  state = msg->state;
110 
111  // valid state received
112  if (msg->header.stamp.isValid())
113  state_valid = true;
114 }
115 
120 void swarm_callback (const cpswarm_msgs::ArrayOfStates::ConstPtr& msg)
121 {
122  // update cps uuids
123  for (auto cps : msg->states) {
124  // only consider cpss in the same state, i.e., coverage
125  if (cps.state != state)
126  continue;
127 
128  // index of cps in map
129  auto idx = swarm.find(cps.swarmio.node);
130 
131  // add new cps
132  if (idx == swarm.end()) {
133  swarm.emplace(cps.swarmio.node, Time::now());
134 
135  // recompute path
136  reconfigure = true;
137  ROS_DEBUG("New CPS %s", cps.swarmio.node.c_str());
138  }
139 
140  // update existing cps
141  else {
142  idx->second = Time::now();
143  }
144  }
145 
146  // remove old cps
147  for (auto cps=swarm.cbegin(); cps!=swarm.cend();) {
148  if (cps->second + Duration(swarm_timeout) < Time::now()) {
149  ROS_DEBUG("Remove CPS %s", cps->first.c_str());
150  swarm.erase(cps++);
151 
152  // recompute path
153  reconfigure = true;
154  }
155  else {
156  ++cps;
157  }
158  }
159 
160  swarm_valid = true;
161 }
162 
169 int main (int argc, char **argv)
170 {
171  // init ros node
172  init(argc, argv, "coverage_path");
173  NodeHandle nh;
174 
175  // init global variables
176  reconfigure = true;
177 
178  // read parameters
179  double loop_rate;
180  nh.param(this_node::getName() + "/loop_rate", loop_rate, 1.5);
181  int queue_size;
182  nh.param(this_node::getName() + "/queue_size", queue_size, 1);
183  nh.param(this_node::getName() + "/swarm_timeout", swarm_timeout, 5.0);
184  nh.param(this_node::getName() + "/visualize", visualize, false);
185 
186  // initialize flags
187  pose_valid = false;
188  state_valid = false;
189  swarm_valid = false;
190 
191  // publishers, subscribers, and service clients
192  Subscriber pose_subscriber = nh.subscribe("pos_provider/pose", queue_size, pose_callback);
193  Subscriber state_subscriber = nh.subscribe("state", queue_size, state_callback);
194  Subscriber swarm_subscriber = nh.subscribe("swarm_state", queue_size, swarm_callback);
195  if (visualize) {
196  path_publisher = nh.advertise<nav_msgs::Path>("coverage_path/path", queue_size, true);
197  wp_publisher = nh.advertise<geometry_msgs::PointStamped>("coverage_path/waypoint", queue_size, true);
198  }
199  map_getter = nh.serviceClient<nav_msgs::GetMap>("area/assigned");
200  map_getter.waitForExistence();
201 
202  // init loop rate
203  Rate rate(loop_rate);
204 
205  // init position
206  while (ok() && pose_valid == false) {
207  ROS_DEBUG_ONCE("Waiting for valid position information...");
208  rate.sleep();
209  spinOnce();
210  }
211 
212  // init state
213  while (ok() && state_valid == false) {
214  ROS_DEBUG_ONCE("Waiting for valid state information...");
215  rate.sleep();
216  spinOnce();
217  }
218 
219  // init swarm
220  while (ok() && swarm_valid == false) {
221  ROS_DEBUG_ONCE("Waiting for valid swarm information...");
222  rate.sleep();
223  spinOnce();
224  }
225 
226  // provide coverage path services
227  ServiceServer path_service = nh.advertiseService("coverage_path/path", get_path);
228  ServiceServer wp_service = nh.advertiseService("coverage_path/waypoint", get_waypoint);
229  spin();
230 
231  return 0;
232 }
bool get_path(nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &res)
Callback function to get the coverage path.
ServiceClient map_getter
Service client to get the assigned area.
Definition: coverage_path.h:34
bool get_waypoint(cpswarm_msgs::GetWaypoint::Request &req, cpswarm_msgs::GetWaypoint::Response &res)
Callback function to get the current waypoint of the path.
void construct()
Generate the MST using Kruskal&#39;s algorithm.
Publisher path_publisher
Publisher to visualize the coverage path.
Definition: coverage_path.h:24
void swarm_callback(const cpswarm_msgs::ArrayOfStates::ConstPtr &msg)
Callback function to receive the states of the other CPSs.
vector< edge > get_mst_edges()
Get the edges of the MST.
void generate_path(geometry_msgs::Point)
Generate all way points for the path.
Definition: mst_path.cpp:7
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
bool swarm_valid
Whether valid swarm information has been received.
Definition: coverage_path.h:64
double swarm_timeout
Time in seconds after which it is assumed that a swarm member has left the swarm if no position updat...
Definition: coverage_path.h:84
Publisher wp_publisher
Publisher to visualize the current waypoint.
Definition: coverage_path.h:29
void pose_callback(const geometry_msgs::PoseStamped::ConstPtr &msg)
Callback function for position updates.
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
bool visualize
Whether to publish the coverage path on a topic for visualization.
Definition: coverage_path.h:89
spanning_tree tree
The minimum-spanning-tree (MST) that defines the coverage path.
Definition: coverage_path.h:74
mst_path path
The coverage path.
Definition: coverage_path.h:79
string state
Current state of the CPS.
Definition: coverage_path.h:49
bool reconfigure
Whether the swarm configuration has changed which requires a replanning of the path.
Definition: coverage_path.h:94
bool generate_path()
Generate an optimal coverage path for a given area.
map< string, Time > swarm
The UUIDs of the other swarm members.
Definition: coverage_path.h:59
bool state_valid
Whether a valid state has been received.
Definition: coverage_path.h:54
void initialize_graph(nav_msgs::OccupancyGrid gridmap, bool connect4=true)
Initialize the internal tree structure from a given grid map.
bool valid()
Check whether the current waypoint index is valid.
Definition: mst_path.cpp:235
bool pose_valid
Whether a valid position has been received.
Definition: coverage_path.h:44
void initialize_tree(vector< edge > mst)
Remove edges of the graph that overlap with the tree.
Definition: mst_path.cpp:209
void state_callback(const cpswarm_msgs::StateEvent::ConstPtr &msg)
Callback function for state updates.
int main(int argc, char **argv)
A ROS node that computes the optimal paths for area coverage with a swarm of CPSs.
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