00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <sstream>
00039 #include <string>
00040 #include <ros/ros.h>
00041 #include <ros/package.h>
00042 #include <move_base_msgs/MoveBaseAction.h>
00043 #include <actionlib/client/simple_action_client.h>
00044 #include <tf/transform_broadcaster.h>
00045 #include <tf/transform_listener.h>
00046 #include <nav_msgs/Odometry.h>
00047 #include <std_srvs/Empty.h>
00048
00049 #include "PatrolAgent.h"
00050
00051 using namespace std;
00052
00053 #define DELTA_TIME_SEQUENTIAL_START 15
00054 #define SIMULATE_FOREVER true //WARNING: Set this to false, if you want a finishing condition.
00055
00056 const std::string PS_path = ros::package::getPath("patrolling_sim");
00057
00058
00059 void PatrolAgent::init(int argc, char** argv) {
00060
00061
00062
00063
00064
00065
00066
00067 srand ( time(NULL) );
00068
00069
00070 if ( atoi(argv[3])>NUM_MAX_ROBOTS || atoi(argv[3])<-1 ){
00071 ROS_INFO("The Robot's ID must be an integer number between 0 an 99");
00072 return;
00073 }else{
00074 ID_ROBOT = atoi(argv[3]);
00075
00076 }
00077
00079 chdir(PS_path.c_str());
00080
00081 mapname = string(argv[2]);
00082 graph_file = "maps/"+mapname+"/"+mapname+".graph";
00083
00084
00085 dimension = GetGraphDimension(graph_file.c_str());
00086
00087
00088 vertex_web = new vertex[dimension];
00089
00090
00091 GetGraphInfo(vertex_web, dimension, graph_file.c_str());
00092
00093
00094 uint nedges = GetNumberEdges(vertex_web,dimension);
00095
00096 printf("Loaded graph %s with %d nodes and %d edges\n",mapname.c_str(),dimension,nedges);
00097
00098 #if 0
00099
00100 for (i=0;i<dimension;i++){
00101 printf ("ID= %u\n", vertex_web[i].id);
00102 printf ("X= %f, Y= %f\n", vertex_web[i].x, vertex_web[i].y);
00103 printf ("#Neigh= %u\n", vertex_web[i].num_neigh);
00104
00105 for (j=0;j<vertex_web[i].num_neigh; j++){
00106 printf("\tID = %u, DIR = %s, COST = %u\n", vertex_web[i].id_neigh[j], vertex_web[i].dir[j], vertex_web[i].cost[j]);
00107 }
00108
00109 printf("\n");
00110 }
00111 #endif
00112
00113 interference = false;
00114 ResendGoal = false;
00115 goal_complete = true;
00116 last_interference = 0;
00117 goal_canceled_by_user = false;
00118 aborted_count = 0;
00119 resend_goal_count = 0;
00120 communication_delay = 0.0;
00121 lost_message_rate = 0.0;
00122 goal_reached_wait = 0.0;
00123
00124
00125 ros::init(argc, argv, "patrol_agent");
00126 ros::NodeHandle nh;
00127
00128
00129 double r = 3.0 * ((rand() % 1000)/1000.0);
00130 ros::Duration wait(r);
00131 wait.sleep();
00132
00133 double initial_x, initial_y;
00134 std::vector<double> list;
00135 nh.getParam("initial_pos", list);
00136
00137 if (list.empty()){
00138 ROS_ERROR("No initial positions given: check \"initial_pos\" parameter.");
00139 ros::shutdown();
00140 exit(-1);
00141 }
00142
00143 int value = ID_ROBOT;
00144 if (value == -1){value = 0;}
00145
00146 initial_x = list[2*value];
00147 initial_y = list[2*value+1];
00148
00149
00150 current_vertex = IdentifyVertex(vertex_web, dimension, initial_x, initial_y);
00151
00152
00153
00154
00155 instantaneous_idleness = new double[dimension];
00156 last_visit = new double[dimension];
00157 for(size_t i=0; i<dimension; i++){
00158 instantaneous_idleness[i]= 0.0;
00159 last_visit[i]= 0.0;
00160
00161 if (i==current_vertex){
00162 last_visit[i]= 0.1;
00163 }
00164
00165 }
00166
00167
00168 positions_pub = nh.advertise<nav_msgs::Odometry>("positions", 1);
00169
00170
00171 positions_sub = nh.subscribe<nav_msgs::Odometry>("positions", 10, boost::bind(&PatrolAgent::positionsCB, this, _1));
00172
00173 char string1[40];
00174 char string2[40];
00175
00176 if(ID_ROBOT==-1){
00177 strcpy (string1,"odom");
00178 strcpy (string2,"cmd_vel");
00179 TEAMSIZE = 1;
00180 }else{
00181 sprintf(string1,"robot_%d/odom",ID_ROBOT);
00182 sprintf(string2,"robot_%d/cmd_vel",ID_ROBOT);
00183 TEAMSIZE = ID_ROBOT + 1;
00184 }
00185
00186
00187 listener = new tf::TransformListener();
00188
00189
00190 cmd_vel_pub = nh.advertise<geometry_msgs::Twist>(string2, 1);
00191
00192
00193 odom_sub = nh.subscribe<nav_msgs::Odometry>(string1, 1, boost::bind(&PatrolAgent::odomCB, this, _1));
00194
00195 ros::spinOnce();
00196
00197
00198 results_pub = nh.advertise<std_msgs::Int16MultiArray>("results", 100);
00199
00200 results_sub = nh.subscribe<std_msgs::Int16MultiArray>("results", 100, boost::bind(&PatrolAgent::resultsCB, this, _1) );
00201
00202
00203 last_communication_delay_time = ros::Time::now().toSec();
00204
00205 readParams();
00206 }
00207
00208 void PatrolAgent::ready() {
00209
00210 char move_string[40];
00211
00212
00213 if(ID_ROBOT==-1){
00214 strcpy (move_string,"move_base");
00215 }else{
00216 sprintf(move_string,"robot_%d/move_base",ID_ROBOT);
00217 }
00218
00219 ac = new MoveBaseClient(move_string, true);
00220
00221
00222 while(!ac->waitForServer(ros::Duration(5.0))){
00223 ROS_INFO("Waiting for the move_base action server to come up");
00224 }
00225 ROS_INFO("Connected with move_base action server");
00226
00227 initialize_node();
00228
00229 ros::Rate loop_rate(1);
00230
00231
00232 while(initialize){
00233 ros::spinOnce();
00234 loop_rate.sleep();
00235 }
00236
00237 }
00238
00239
00240 void PatrolAgent::readParams() {
00241
00242 if (! ros::param::get("/goal_reached_wait", goal_reached_wait)) {
00243
00244 ROS_WARN("Cannot read parameter /goal_reached_wait. Using default value!");
00245
00246 }
00247
00248 if (! ros::param::get("/communication_delay", communication_delay)) {
00249
00250 ROS_WARN("Cannot read parameter /communication_delay. Using default value!");
00251
00252 }
00253
00254 if (! ros::param::get("/lost_message_rate", lost_message_rate)) {
00255
00256 ROS_WARN("Cannot read parameter /lost_message_rate. Using default value!");
00257
00258 }
00259
00260 if (! ros::param::get("/initial_positions", initial_positions)) {
00261
00262 ROS_WARN("Cannot read parameter /initial_positions. Using default value '%s'!", initial_positions.c_str());
00263
00264 }
00265
00266 }
00267
00268 void PatrolAgent::run() {
00269
00270
00271 ready();
00272
00273
00274 std_srvs::Empty srv;
00275 std::string mb_string;
00276
00277 if (ID_ROBOT>-1){
00278 std::ostringstream id_string;
00279 id_string << ID_ROBOT;
00280 mb_string = "robot_" + id_string.str() + "/";
00281 }
00282 mb_string += "move_base/clear_costmaps";
00283
00284 if (ros::service::call(mb_string.c_str(), srv)){
00285
00286 ROS_INFO("Costmap correctly cleared before patrolling task.");
00287 }else{
00288 ROS_WARN("Was not able to clear costmap (%s) before patrolling...", mb_string.c_str());
00289 }
00290
00291
00292 ros::AsyncSpinner spinner(2);
00293 spinner.start();
00294
00295
00296
00297
00298 ros::Rate loop_rate(30);
00299
00300 while(ros::ok()){
00301
00302 if (goal_complete) {
00303 onGoalComplete();
00304 resend_goal_count=0;
00305 }
00306 else {
00307 if (interference) {
00308 do_interference_behavior();
00309 }
00310
00311 if (ResendGoal) {
00312
00313 if (resend_goal_count<3) {
00314 resend_goal_count++;
00315 ROS_INFO("Re-Sending goal (%d) - Vertex %d (%f,%f)", resend_goal_count, next_vertex, vertex_web[next_vertex].x, vertex_web[next_vertex].y);
00316 sendGoal(next_vertex);
00317 }
00318 else {
00319 resend_goal_count=0;
00320 onGoalNotComplete();
00321 }
00322 ResendGoal = false;
00323 }
00324
00325 processEvents();
00326
00327 if (end_simulation) {
00328 return;
00329 }
00330
00331 }
00332
00333 loop_rate.sleep();
00334
00335 }
00336 }
00337
00338
00339 void PatrolAgent::onGoalComplete()
00340 {
00341 if(next_vertex>-1) {
00342
00343 update_idleness();
00344 current_vertex = next_vertex;
00345 }
00346
00347
00348 next_vertex = compute_next_vertex();
00349
00350
00352 send_goal_reached();
00353 send_results();
00354
00355
00356 ROS_INFO("Sending goal - Vertex %d (%f,%f)\n", next_vertex, vertex_web[next_vertex].x, vertex_web[next_vertex].y);
00357
00358 sendGoal(next_vertex);
00359
00360 goal_complete = false;
00361 }
00362
00363 void PatrolAgent::onGoalNotComplete()
00364 {
00365 int prev_vertex = next_vertex;
00366
00367 ROS_INFO("Goal not complete - From vertex %d to vertex %d\n", current_vertex, next_vertex);
00368
00369
00370 next_vertex = compute_next_vertex();
00371
00372
00373
00374 int random_cnt=0;
00375 while (next_vertex == prev_vertex && random_cnt++<10) {
00376 int num_neighs = vertex_web[current_vertex].num_neigh;
00377 int i = rand() % num_neighs;
00378 next_vertex = vertex_web[current_vertex].id_neigh[i];
00379 ROS_INFO("Choosing another random vertex %d\n", next_vertex);
00380 }
00381
00382
00383 while (next_vertex == prev_vertex && next_vertex == current_vertex) {
00384 int i = rand() % dimension;
00385 next_vertex = i;
00386 ROS_INFO("Choosing another random vertex %d\n", next_vertex);
00387 }
00388
00389
00390 ROS_INFO("Re-Sending NEW goal - Vertex %d (%f,%f)\n", next_vertex, vertex_web[next_vertex].x, vertex_web[next_vertex].y);
00391
00392 sendGoal(next_vertex);
00393
00394 goal_complete = false;
00395 }
00396
00397
00398 void PatrolAgent::processEvents() {
00399
00400 }
00401
00402 void PatrolAgent::update_idleness() {
00403 double now = ros::Time::now().toSec();
00404
00405 for(size_t i=0; i<dimension; i++){
00406 if ((int)i == next_vertex){
00407 last_visit[i] = now;
00408 }
00409 instantaneous_idleness[i] = now - last_visit[i];
00410
00411
00412
00413 }
00414 }
00415
00416 void PatrolAgent::initialize_node (){
00417
00418 int value = ID_ROBOT;
00419 if (value==-1){value=0;}
00420 ROS_INFO("Initialize Node: Robot %d",value);
00421
00422 std_msgs::Int16MultiArray msg;
00423 msg.data.clear();
00424 msg.data.push_back(value);
00425 msg.data.push_back(INITIALIZE_MSG_TYPE);
00426 msg.data.push_back(1);
00427
00428 int count = 0;
00429
00430
00431 ros::Rate loop_rate(0.5);
00432
00433 while (count<3){
00434 results_pub.publish(msg);
00435
00436 ros::spinOnce();
00437 loop_rate.sleep();
00438 count++;
00439 }
00440 }
00441
00442 void PatrolAgent::getRobotPose(int robotid, float &x, float &y, float &theta) {
00443
00444 if (listener==NULL) {
00445 ROS_ERROR("TF listener null");
00446 return;
00447 }
00448
00449 std::stringstream ss; ss << "robot_" << robotid;
00450 std::string robotname = ss.str();
00451 std::string sframe = "/map";
00452 std::string dframe;
00453 if(ID_ROBOT>-1){
00454 dframe = "/" + robotname + "/base_link";
00455 }else{
00456 dframe = "/base_link";
00457 }
00458
00459 tf::StampedTransform transform;
00460
00461 try {
00462 listener->waitForTransform(sframe, dframe, ros::Time(0), ros::Duration(3));
00463 listener->lookupTransform(sframe, dframe, ros::Time(0), transform);
00464 }
00465 catch(tf::TransformException ex) {
00466 ROS_ERROR("Cannot transform from %s to %s\n",sframe.c_str(),dframe.c_str());
00467 ROS_ERROR("%s", ex.what());
00468 }
00469
00470 x = transform.getOrigin().x();
00471 y = transform.getOrigin().y();
00472 theta = tf::getYaw(transform.getRotation());
00473
00474 }
00475
00476 void PatrolAgent::odomCB(const nav_msgs::Odometry::ConstPtr& msg) {
00477
00478
00479 int idx = ID_ROBOT;
00480
00481 if (ID_ROBOT<=-1){
00482 idx = 0;
00483 }
00484
00485 float x,y,th;
00486 getRobotPose(idx,x,y,th);
00487
00488 xPos[idx]=x;
00489 yPos[idx]=y;
00490
00491
00492 }
00493
00494
00495
00496 void PatrolAgent::sendGoal(int next_vertex)
00497 {
00498 goal_canceled_by_user = false;
00499
00500 double target_x = vertex_web[next_vertex].x,
00501 target_y = vertex_web[next_vertex].y;
00502
00503
00504 move_base_msgs::MoveBaseGoal goal;
00505
00506 geometry_msgs::Quaternion angle_quat = tf::createQuaternionMsgFromYaw(0.0);
00507 goal.target_pose.header.frame_id = "map";
00508 goal.target_pose.header.stamp = ros::Time::now();
00509 goal.target_pose.pose.position.x = target_x;
00510 goal.target_pose.pose.position.y = target_y;
00511 goal.target_pose.pose.orientation = angle_quat;
00512 ac->sendGoal(goal, boost::bind(&PatrolAgent::goalDoneCallback, this, _1, _2), boost::bind(&PatrolAgent::goalActiveCallback,this), boost::bind(&PatrolAgent::goalFeedbackCallback, this,_1));
00513 }
00514
00515 void PatrolAgent::cancelGoal()
00516 {
00517 goal_canceled_by_user = true;
00518 ac->cancelAllGoals();
00519 }
00520
00521
00522 void PatrolAgent::goalDoneCallback(const actionlib::SimpleClientGoalState &state, const move_base_msgs::MoveBaseResultConstPtr &result){
00523
00524
00525
00526
00527
00528
00529 if(state.state_ == actionlib::SimpleClientGoalState::SUCCEEDED){
00530 ROS_INFO("Goal reached ... WAITING %.2f sec",goal_reached_wait);
00531 ros::Duration delay(goal_reached_wait);
00532 delay.sleep();
00533 ROS_INFO("Goal reached ... DONE");
00534 goal_complete = true;
00535 }else{
00536 aborted_count++;
00537 ROS_INFO("CANCELLED or ABORTED... %d",aborted_count);
00538 if (!goal_canceled_by_user) {
00539 ROS_INFO("Goal not cancelled by the interference...");
00540
00541
00542 backup();
00543
00544 ROS_INFO("Clear costmap!");
00545
00546 char srvname[80];
00547
00548 if(ID_ROBOT<=-1){
00549 sprintf(srvname,"/move_base/clear_costmaps");
00550 }else{
00551 sprintf(srvname,"/robot_%d/move_base/clear_costmaps",ID_ROBOT);
00552 }
00553
00554 ros::NodeHandle n;
00555 ros::ServiceClient client = n.serviceClient<std_srvs::Empty>(srvname);
00556 std_srvs::Empty srv;
00557 if (client.call(srv)) {
00558 ROS_INFO("Costmaps cleared.\n");
00559 }
00560 else {
00561 ROS_ERROR("Failed to call service move_base/clear_costmaps");
00562 }
00563
00564 ROS_INFO("Resend Goal!");
00565 ResendGoal = true;
00566 }
00567 }
00568 }
00569
00570 void PatrolAgent::goalActiveCallback(){
00571 goal_complete = false;
00572
00573 }
00574
00575 void PatrolAgent::goalFeedbackCallback(const move_base_msgs::MoveBaseFeedbackConstPtr &feedback){
00576
00577 send_positions();
00578
00579 int value = ID_ROBOT;
00580 if (value==-1){ value = 0;}
00581 interference = check_interference(value);
00582 }
00583
00584 void PatrolAgent::send_goal_reached() {
00585
00586 int value = ID_ROBOT;
00587 if (value==-1){ value = 0;}
00588
00589
00590 std_msgs::Int16MultiArray msg;
00591 msg.data.clear();
00592 msg.data.push_back(value);
00593 msg.data.push_back(TARGET_REACHED_MSG_TYPE);
00594 msg.data.push_back(current_vertex);
00595
00596
00597
00598 results_pub.publish(msg);
00599 ros::spinOnce();
00600 }
00601
00602 bool PatrolAgent::check_interference (int robot_id){
00603
00604 int i;
00605 double dist_quad;
00606
00607 if (ros::Time::now().toSec()-last_interference<10)
00608 return false;
00609
00610
00611 for (i=0; i<robot_id; i++){
00612
00613 dist_quad = (xPos[i] - xPos[robot_id])*(xPos[i] - xPos[robot_id]) + (yPos[i] - yPos[robot_id])*(yPos[i] - yPos[robot_id]);
00614
00615 if (dist_quad <= INTERFERENCE_DISTANCE*INTERFERENCE_DISTANCE){
00616
00617 last_interference = ros::Time::now().toSec();
00618 return true;
00619 }
00620 }
00621 return false;
00622
00623 }
00624
00625 void PatrolAgent::backup(){
00626
00627 ros::Rate loop_rate(100);
00628
00629 int backUpCounter = 0;
00630 while (backUpCounter<=100){
00631
00632 if(backUpCounter==0){
00633 ROS_INFO("The wall is too close! I need to do some backing up...");
00634
00635 geometry_msgs::Twist cmd_vel;
00636 cmd_vel.linear.x = -0.1;
00637 cmd_vel.angular.z = 0.0;
00638 cmd_vel_pub.publish(cmd_vel);
00639 }
00640
00641 if(backUpCounter==20){
00642
00643 geometry_msgs::Twist cmd_vel;
00644 cmd_vel.linear.x = 0.0;
00645 cmd_vel.angular.z = 0.5;
00646 cmd_vel_pub.publish(cmd_vel);
00647 }
00648
00649 if(backUpCounter==100){
00650
00651 geometry_msgs::Twist cmd_vel;
00652 cmd_vel.linear.x = 0.0;
00653 cmd_vel.angular.z = 0.0;
00654 cmd_vel_pub.publish(cmd_vel);
00655
00656
00657 }
00658
00659 ros::spinOnce();
00660 loop_rate.sleep();
00661 backUpCounter++;
00662
00663 }
00664
00665 }
00666
00667 void PatrolAgent::do_interference_behavior()
00668 {
00669 ROS_INFO("Interference detected! Executing interference behavior...\n");
00670 send_interference();
00671
00672 #if 1
00673
00674 cancelGoal();
00675 ROS_INFO("Robot stopped");
00676 ros::Duration delay(3);
00677 delay.sleep();
00678 ResendGoal = true;
00679 #else
00680
00681 ros::spinOnce();
00682
00683
00684 int value = ID_ROBOT;
00685 if (value == -1){ value = 0;}
00686 while(interference){
00687 interference = check_interference(value);
00688 if (goal_complete || ResendGoal){
00689 interference = false;
00690 }
00691 }
00692 #endif
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702 void PatrolAgent::send_positions()
00703 {
00704
00705 nav_msgs::Odometry msg;
00706
00707 int idx = ID_ROBOT;
00708
00709 if (ID_ROBOT <= -1){
00710 msg.header.frame_id = "map";
00711 idx = 0;
00712 }else{
00713 char string[20];
00714 sprintf(string,"robot_%d/map",ID_ROBOT);
00715 msg.header.frame_id = string;
00716 }
00717
00718 msg.pose.pose.position.x = xPos[idx];
00719 msg.pose.pose.position.y = yPos[idx];
00720
00721 positions_pub.publish(msg);
00722 ros::spinOnce();
00723 }
00724
00725
00726 void PatrolAgent::receive_positions()
00727 {
00728
00729 }
00730
00731 void PatrolAgent::positionsCB(const nav_msgs::Odometry::ConstPtr& msg) {
00732
00733
00734
00735 char id[20];
00736 strcpy( id, msg->header.frame_id.c_str() );
00737
00738
00739
00740
00741
00742 if (ID_ROBOT>-1){
00743
00744
00745 char str_idx[4];
00746 uint i;
00747
00748 for (i=6; i<10; i++){
00749 if (id[i]=='/'){
00750 str_idx[i-6] = '\0';
00751 break;
00752 }else{
00753 str_idx[i-6] = id[i];
00754 }
00755 }
00756
00757 int idx = atoi (str_idx);
00758
00759
00760 if (idx >= TEAMSIZE && TEAMSIZE <= NUM_MAX_ROBOTS){
00761
00762 TEAMSIZE = idx+1;
00763 }
00764
00765 if (ID_ROBOT != idx){
00766 xPos[idx]=msg->pose.pose.position.x;
00767 yPos[idx]=msg->pose.pose.position.y;
00768 }
00769
00770 }
00771
00772 receive_positions();
00773 }
00774
00775
00776 void PatrolAgent::send_results() {
00777
00778 }
00779
00780
00781 void PatrolAgent::do_send_message(std_msgs::Int16MultiArray &msg) {
00782 if (communication_delay>0.001) {
00783
00784
00785
00786 ros::Duration delay(communication_delay);
00787 delay.sleep();
00788
00789
00790 }
00791 results_pub.publish(msg);
00792 ros::spinOnce();
00793 }
00794
00795
00796 void PatrolAgent::receive_results() {
00797
00798 }
00799
00800 void PatrolAgent::send_interference(){
00801
00802
00803 int value = ID_ROBOT;
00804 if (value==-1){value=0;}
00805 printf("Send Interference: Robot %d\n",value);
00806
00807 std_msgs::Int16MultiArray msg;
00808 msg.data.clear();
00809 msg.data.push_back(value);
00810 msg.data.push_back(INTERFERENCE_MSG_TYPE);
00811
00812 results_pub.publish(msg);
00813 ros::spinOnce();
00814 }
00815
00816
00817
00818
00819 void PatrolAgent::resultsCB(const std_msgs::Int16MultiArray::ConstPtr& msg) {
00820
00821 std::vector<signed short>::const_iterator it = msg->data.begin();
00822
00823 vresults.clear();
00824
00825 for (size_t k=0; k<msg->data.size(); k++) {
00826 vresults.push_back(*it); it++;
00827 }
00828
00829 int id_sender = vresults[0];
00830 int msg_type = vresults[1];
00831
00832
00833
00834
00835 if (id_sender==-1 && msg_type==INITIALIZE_MSG_TYPE) {
00836 if (initialize==true && vresults[2]==100) {
00837 ROS_INFO("Let's Patrol!\n");
00838 double r = 1.0 * ((rand() % 1000)/1000.0);
00839
00840
00841
00842
00843 ros::Duration wait(r);
00844
00845 printf("Wait %.1f seconds (init pos:%s)\n",r,initial_positions.c_str());
00846
00847 wait.sleep();
00848 initialize = false;
00849 }
00850
00851 #if SIMULATE_FOREVER == false
00852 if (initialize==false && vresults[2]==999) {
00853 ROS_INFO("The simulation is over. Let's leave");
00854 end_simulation = true;
00855 }
00856 #endif
00857 }
00858
00859 if (!initialize) {
00860 #if 0
00861
00862 if(ID_ROBOT>-1){
00863 if ((communication_delay>0.001) && (id_sender!=ID_ROBOT)) {
00864 double current_time = ros::Time::now().toSec();
00865 if (current_time-last_communication_delay_time>1.0) {
00866 ROS_INFO("Communication delay %.1f",communication_delay);
00867 ros::Duration delay(communication_delay);
00868 delay.sleep();
00869 last_communication_delay_time = current_time;
00870 }
00871 }
00872 bool lost_message = false;
00873 if ((lost_message_rate>0.0001)&& (id_sender!=ID_ROBOT)) {
00874 double r = (rand() % 1000)/1000.0;
00875 lost_message = r < lost_message_rate;
00876 }
00877 if (lost_message) {
00878 ROS_INFO("Lost message");
00879 }
00880 }
00881 #endif
00882 receive_results();
00883 }
00884
00885 ros::spinOnce();
00886
00887 }