1 #include "area_division.h" 15 geometry_msgs::PoseStamped goal_pose;
16 goal_pose.header.stamp = Time::now();
17 goal_pose.pose =
pose;
34 if (msg->header.stamp.isValid())
65 ROS_DEBUG(
"Add CPS %s", msg->swarmio.node.c_str());
68 swarm_pose.emplace(msg->swarmio.node, msg->pose);
73 ROS_DEBUG(
"Update CPS %s", msg->swarmio.node.c_str());
76 idx->second.header.stamp = Time::now();
77 idx->second = msg->pose;
108 if (msg->header.stamp.isValid())
119 for (
auto cps : msg->states) {
125 auto idx =
swarm.find(cps.swarmio.node);
128 if (idx ==
swarm.end()) {
129 swarm.emplace(cps.swarmio.node, Time::now());
131 ROS_DEBUG(
"New CPS %s", cps.swarmio.node.c_str());
136 idx->second = Time::now();
141 for (
auto cps=
swarm.cbegin(); cps!=
swarm.cend();) {
143 ROS_DEBUG(
"Remove CPS %s", cps->first.c_str());
182 nh.param(this_node::getName() +
"/queue_size", queue_size, 10);
188 pos_pub = nh.advertise<geometry_msgs::PoseStamped>(
"pos_controller/goal_position", queue_size,
true);
189 swarm_pub = nh.advertise<cpswarm_msgs::AreaDivisionEvent>(
"area_division", queue_size,
true);
190 area_pub = nh.advertise<nav_msgs::OccupancyGrid>(
"area/assigned", queue_size,
true);
192 map_rot_pub = nh.advertise<nav_msgs::OccupancyGrid>(
"area/rotated", queue_size,
true);
193 map_ds_pub = nh.advertise<nav_msgs::OccupancyGrid>(
"area/downsampled", queue_size,
true);
195 rotater_cli = nh.serviceClient<cpswarm_msgs::GetDouble>(
"area/get_rotation");
196 rotater_cli.waitForExistence();
199 while (
ok() &&
uuid ==
"") {
264 cpswarm_msgs::AreaDivisionEvent event;
265 event.header.stamp = Time::now();
266 event.swarmio.name =
"area_division";
267 geometry_msgs::PoseStamped ps;
268 ps.header.frame_id =
"local_origin_ned";
285 geometry_msgs::Point
rotate (geometry_msgs::Point point,
double angle)
292 geometry_msgs::Point rotated;
293 rotated.x = point.x*cos(angle) - point.y*sin(angle);
294 rotated.y = point.x*sin(angle) + point.y*cos(angle);
303 double rotate (nav_msgs::OccupancyGrid& map)
306 cpswarm_msgs::GetDouble angle;
311 double a = angle.response.value;
316 geometry_msgs::Pose origin_new;
317 origin_new.position.x = map.info.origin.position.x*cos(a) - map.info.origin.position.y*sin(a);
318 origin_new.position.y = map.info.origin.position.x*sin(a) + map.info.origin.position.y*cos(a);
321 vector<vector<signed char>> rt;
322 for (
int i=0; i<2*map.info.height; ++i) {
323 vector<signed char> row(2*map.info.width, 100);
328 int i_new, j_new, width_new=0, height_new=0;
329 double x, y, x_new, y_new;
330 for (
int i=0; i<map.info.height; ++i) {
331 for (
int j=0; j<map.info.width; ++j) {
333 x = double(j) * map.info.resolution + map.info.origin.position.x;
334 y = double(i) * map.info.resolution + map.info.origin.position.y;
335 x_new = x*cos(a) - y*sin(a);
336 y_new = x*sin(a) + y*cos(a);
337 j_new = int(round((x_new - origin_new.position.x) / map.info.resolution));
338 i_new = int(round((y_new - origin_new.position.y) / map.info.resolution));
341 if (i_new >= rt.size()) {
344 if (j_new >= rt[i_new].size()) {
349 rt[i_new][j_new] = map.data[i*map.info.width + j];
352 if (rt[i_new][j_new] == 0) {
353 if (i_new > height_new)
355 if (j_new > width_new)
362 rt.resize(height_new);
363 for (
int i=0; i<rt.size(); ++i)
364 rt[i].resize(width_new);
367 vector<signed char> rt_col;
368 for (
int i=0; i<rt.size(); ++i) {
369 for (
int j=0; j<rt[i].size(); ++j) {
370 rt_col.push_back(rt[i][j]);
378 map.info.map_load_time = Time::now();
379 map.info.width = width_new;
380 map.info.height= height_new;
381 map.info.origin = origin_new;
393 translation.x = round(map.info.origin.position.x) - map.info.origin.position.x;
394 translation.y = round(map.info.origin.position.y) - map.info.origin.position.y;
402 map.info.map_load_time = Time::now();
416 int f = int(round(
resolution / map.info.resolution));
421 vector<signed char> lr;
422 for (
int i=0; i+f<=map.info.height; i+=f) {
423 for (
int j=0; j+f<=map.info.width; j+=f) {
425 vector<unsigned int> values(256, 0);
426 for (
int m=i; m<i+f; ++m) {
427 for (
int n=j; n<j+f; ++n) {
428 values[map.data[m*map.info.width + n]]++;
433 unsigned char value = 0;
434 unsigned int freq = 0;
435 for (
int k=0; k<values.size(); ++k) {
436 if (values[k] > freq) {
449 map.info.map_load_time = Time::now();
451 map.info.width = int(floor(
double(map.info.width) /
double(f)));
452 map.info.height = int(floor(
double(map.info.height) /
double(f)));
455 for (
int i=0; i<map.info.height; ++i) {
458 for (
int j=0; j<map.info.width; ++j) {
459 if (map.data[i*map.info.width + j] == 100) {
465 if (obst == map.info.width) {
467 map.data.erase(map.data.begin() + i*map.info.width, map.data.begin() + (i+1)*map.info.width);
470 map.info.map_load_time = Time::now();
472 map.info.origin.position.y += map.info.resolution;
489 double angle =
rotate(gridmap);
506 map<string, vector<int>> swarm_grid;
508 geometry_msgs::Point rotated =
rotate(cps.second.pose.position, angle);
512 pos[0] = int(round((rotated.x - gridmap.info.origin.position.x) / gridmap.info.resolution));
513 pos[1] = int(round((rotated.y - gridmap.info.origin.position.y) / gridmap.info.resolution));
514 swarm_grid.emplace(cps.first, pos);
515 ROS_DEBUG(
"Other CPS %s at (%d,%d)", cps.first.c_str(), pos[0], pos[1]);
519 geometry_msgs::Point rotated =
rotate(
pose.position, angle);
523 pos[0] = int(round((rotated.x - gridmap.info.origin.position.x) / gridmap.info.resolution));
524 pos[1] = int(round((rotated.y - gridmap.info.origin.position.y) / gridmap.info.resolution));
525 swarm_grid.emplace(
uuid, pos);
530 vector<signed char, allocator<signed char>> map = gridmap.data;
539 Time sleep_start = Time::now();
555 int main (
int argc,
char **argv)
558 init(argc, argv,
"area_division");
563 nh.param(this_node::getName() +
"/loop_rate", loop_rate, 1.5);
564 rate =
new Rate(loop_rate);
566 nh.param(this_node::getName() +
"/queue_size", queue_size, 10);
567 nh.param(this_node::getName() +
"/resolution",
resolution, 1.0);
568 nh.param(this_node::getName() +
"/swarm_timeout",
swarm_timeout, 5.0);
569 nh.param(this_node::getName() +
"/visualize",
visualize,
false);
570 nh.getParam(this_node::getName() +
"/states",
behaviors);
Publisher map_ds_pub
Publisher to visualize the downsampled map.
Publisher area_pub
Publisher to visualize the assigned area grid map.
bool visualize
Whether to publish the area division on a topic for visualization.
bool swarm_valid
Whether valid state information has been received from the other swarm members.
A class to divide the environment optimally among multiple cyber physical systems (CPSs)...
void translate(nav_msgs::OccupancyGrid &map)
Shift a map to be aligned with the grid, i.e., the origin should be an even number.
void divide_area()
Divide the area of the grid map equally among multiple CPSs.
void uuid_callback(const swarmros::String::ConstPtr &msg)
Callback function to receive the UUID from the communication library.
Publisher map_rot_pub
Publisher to visualize the rotated map.
double swarm_timeout
The time in seconds communication in the swarm can be delayed at most. Used to wait after an area div...
bool pose_valid
Whether a valid position has been received.
void division_callback(const cpswarm_msgs::AreaDivisionEvent::ConstPtr &msg)
Callback function to receive area division requests from other CPSs.
Subscriber division_sub
Subscriber to get area division requests from other CPSs.
bool behavior_valid
Whether a valid state has been received.
geometry_msgs::Pose pose
Current position of the CPS.
#define ROS_DEBUG_ONCE(...)
state_t state
The state of the area division node.
Publisher swarm_pub
Publisher to syncronize with other CPSs.
void pose_callback(const geometry_msgs::PoseStamped::ConstPtr &msg)
Callback function for position updates.
ServiceClient rotater_cli
Service client to get the angle which the area has to be rotated by.
void swarm_state_callback(const cpswarm_msgs::ArrayOfStates::ConstPtr &msg)
Callback function to receive the states of the other CPSs.
Subscriber pose_sub
Subscriber to get CPS position.
Time sync_start
The time at which the synchronization for the area division started.
void initialize_cps(map< string, vector< int >> cpss)
Define the CPS positions.
void divide()
Perform the area division.
area_division * division
The object encapsulating the area division optimization algorithm.
map< string, Time > swarm
The UUIDs of the other swarm members.
nav_msgs::OccupancyGrid global_map
The complete grid map.
Subscriber map_sub
Subscriber to get grid map.
geometry_msgs::Vector3 translation
The translation by which the area has been shifted.
string uuid
UUID of this CPS.
void initialize_map(int r, int c, vector< signed char > src)
Define the grid map.
geometry_msgs::Point rotate(geometry_msgs::Point point, double angle)
Rotate a point by a given angle around the origin.
vector< string > behaviors
The behavior states in which area division is active.
double resolution
The grid map underlying the area division will be downsampled to this resolution in meter / cell...
void init()
Initialize this node.
void sync()
Synchronize The CPSs by exchanging an event.
map< string, geometry_msgs::PoseStamped > swarm_pose
The positions of the other swarm members.
int main(int argc, char **argv)
A ROS node that divides the available area among a swarm of CPSs.
Subscriber uuid_sub
Subscriber to get CPS UUID.
Publisher pos_pub
Publisher to stop the CPS.
void behavior_state_callback(const cpswarm_msgs::StateEvent::ConstPtr &msg)
Callback function for behavior state updates.
void deinit()
Shutdown ROS communication.
nav_msgs::OccupancyGrid get_grid(nav_msgs::OccupancyGrid map, string cps)
Get the region assigned to a CPS.
bool map_valid
Whether a valid grid map has been received.
void downsample(nav_msgs::OccupancyGrid &map)
Decrease the resolution of a occupancy grid map.
Subscriber swarm_sub
Subscriber to get information about other CPSs in the swarm.
void to_sync()
Switch to the synchronization state.
string behavior
The current behavior state of this CPS.
ROSCPP_DECL void spinOnce()
Rate * rate
ROS rate object for controlling loop rates.
void map_callback(const nav_msgs::OccupancyGrid::ConstPtr &msg)
Callback function to receive the grid map.