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 "SSIPatrolAgent.h"
00039
00040 using namespace std;
00041
00042 SSIPatrolAgent::SSIPatrolAgent() : cf(CONFIG_FILENAME)
00043 {
00044 pthread_mutex_init(&lock, NULL);
00045 }
00046
00047
00048 void SSIPatrolAgent::onGoalComplete()
00049 {
00050 printf("DTAP onGoalComplete!!!\n");
00051 if (first_vertex){
00052
00053 next_vertex = compute_next_vertex(current_vertex);
00054
00055 first_vertex = false;
00056 } else {
00057
00058
00059
00060 update_global_idleness();
00061
00062 current_vertex = next_vertex;
00063
00064 next_vertex = next_next_vertex;
00065
00066
00067 if (next_vertex>=0 && next_vertex< dimension){
00068 pthread_mutex_lock(&lock);
00069 global_instantaneous_idleness[next_vertex] = 0.0;
00070 pthread_mutex_unlock(&lock);
00071 }
00072
00073 }
00074
00076 send_goal_reached();
00077 send_results();
00078
00079
00080 ROS_INFO("Sending goal - Vertex %d (%f,%f)\n", next_vertex, vertex_web[next_vertex].x, vertex_web[next_vertex].y);
00081
00082 sendGoal(next_vertex);
00083
00084 goal_complete = false;
00085
00086
00087
00088
00089 next_next_vertex = compute_next_vertex(next_vertex);
00090
00091 printf("<<< DONE Computed next vertices: current_vertex = %d, next_vertex=%d, next_next_vertex=%d >>>\n",current_vertex, next_vertex,next_next_vertex);
00092
00093 }
00094
00095
00096 bool* SSIPatrolAgent::create_selected_vertices(){
00097 bool* sv = new bool[dimension];
00098 for(size_t i=0; i<dimension; i++) {
00099 selected_vertices[i] = false;
00100 }
00101 return sv;
00102 }
00103
00104 void SSIPatrolAgent::reset_selected_vertices(bool* sv){
00105 for(size_t i=0; i<dimension; i++) {
00106 sv[i] = false;
00107 }
00108 if (current_vertex >= 0 && current_vertex < dimension){
00109 selected_vertices[current_vertex] = true;
00110 }
00111 }
00112
00113 void SSIPatrolAgent::select_faraway_vertices(bool* sv, int cv){
00114 for(size_t i=0; i<dimension; i++) {
00115 sv[i] = true;
00116 }
00117 uint num_neighs = vertex_web[cv].num_neigh;
00118 for (size_t i=0; i<num_neighs; i++){
00119 size_t neighbor = vertex_web[cv].id_neigh[i];
00120 sv[neighbor] = false;
00121 }
00122 if (current_vertex >= 0 && current_vertex < dimension){
00123 selected_vertices[current_vertex] = true;
00124 }
00125
00126
00127
00128
00129
00130
00131 }
00132
00133 bool SSIPatrolAgent::all_selected(bool* sv){
00134 for(size_t i=0; i<dimension; i++) {
00135 if (!sv[i]){
00136 return false;
00137 }
00138 }
00139 return true;
00140 }
00141
00142
00143 void SSIPatrolAgent::init(int argc, char** argv) {
00144
00145 PatrolAgent::init(argc,argv);
00146
00147
00148 next_vertex = -1;
00149 next_next_vertex = -1;
00150
00151 taskRequests = new int[dimension];
00152 tasks = new bool[dimension];
00153 bids = new bid_tuple[dimension];
00154 global_instantaneous_idleness = new double[dimension];
00155 selected_vertices = new bool[dimension];
00156 bid_tuple noBid = {BIG_NUMBER,-1};
00157 for(size_t i=0; i<dimension; i++) {
00158 taskRequests[i] = 0;
00159 tasks[i] = false;
00160 selected_vertices[i] = false;
00161 bids[i] = noBid;
00162 global_instantaneous_idleness[i]=dimension*2;
00163 }
00164 nactivetasks=0;
00165
00166 last_update_idl = ros::Time::now().toSec();
00167
00168 first_vertex = true;
00169
00170
00171 timeout = cf.getDParam("timeout");
00172 theta_idl = cf.getDParam("theta_idleness");
00173 theta_cost = cf.getDParam("theta_navigation");
00174 theta_hop = cf.getDParam("theta_hop");
00175 threshold = cf.getDParam("threshold");
00176 hist = cf.getDParam("hist");
00177
00178 std::stringstream paramss;
00179 paramss << timeout << "," << theta_idl << "," << theta_cost << "," << theta_hop << "," << threshold << "," << hist;
00180
00181 ros::param::set("/algorithm_params",paramss.str());
00182
00183 }
00184
00185 double SSIPatrolAgent::compute_cost(int vertex)
00186 {
00187 uint elem_s_path;
00188 int *shortest_path = new int[dimension];
00189 int id_neigh;
00190
00191 dijkstra( current_vertex, vertex, shortest_path, elem_s_path, vertex_web, dimension);
00192 double distance = 0;
00193
00194 for(uint j=0; j<elem_s_path; j++){
00195
00196
00197 if (j<elem_s_path-1){
00198 id_neigh = is_neigh(shortest_path[j], shortest_path[j+1], vertex_web, dimension);
00199 distance += vertex_web[shortest_path[j]].cost[id_neigh];
00200 }
00201 }
00202
00203 return distance;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 double SSIPatrolAgent::compute_cost(int cv, int nv)
00232 {
00233 uint elem_s_path;
00234 int *shortest_path = new int[dimension];
00235 int id_neigh;
00236
00237 dijkstra( cv, nv, shortest_path, elem_s_path, vertex_web, dimension);
00238 double distance = 0;
00239
00240 for(uint j=0; j<elem_s_path; j++){
00241
00242
00243 if (j<elem_s_path-1){
00244 id_neigh = is_neigh(shortest_path[j], shortest_path[j+1], vertex_web, dimension);
00245 distance += vertex_web[shortest_path[j]].cost[id_neigh];
00246 }
00247 }
00248
00249 return distance;
00250 }
00251
00252
00253 size_t SSIPatrolAgent::compute_hops(int cv, int nv)
00254 {
00255 uint elem_s_path;
00256 int *shortest_path = new int[dimension];
00257 int id_neigh;
00258
00259 dijkstra( cv, nv, shortest_path, elem_s_path, vertex_web, dimension);
00260
00261 #if 1
00262 return elem_s_path-1;
00263 #else
00264 size_t hops = 0;
00265
00266 for(uint j=0; j<elem_s_path; j++){
00267
00268
00269 if (j<elem_s_path-1){
00270 id_neigh = is_neigh(shortest_path[j], shortest_path[j+1], vertex_web, dimension);
00271 hops++;
00272 }
00273 }
00274 return hops;
00275 #endif
00276 }
00277
00278
00279 double SSIPatrolAgent::utility(int cv,int nv) {
00280 double idl = global_instantaneous_idleness[nv];
00281
00282 size_t hops = compute_hops(cv,nv);
00283 double U = theta_idl * idl + theta_hop * hops * dimension;
00284
00285
00286
00287 #if DEBUG_PRINT
00288 if (U>-1000)
00289 printf(" HOPSUtil:: node: %d --> U[%d] ( %.1f, %zu ) = %.1f\n",cv,nv,idl,hops,U);
00290 #endif
00291 return U;
00292 }
00293
00294
00295 void SSIPatrolAgent::update_global_idleness()
00296 {
00297 double now = ros::Time::now().toSec();
00298
00299 pthread_mutex_lock(&lock);
00300 for(size_t i=0; i<dimension; i++) {
00301 global_instantaneous_idleness[i] += (now-last_update_idl);
00302 }
00303
00304 if (current_vertex>=0 && current_vertex<dimension){
00305 global_instantaneous_idleness[current_vertex] = 0.0;
00306 }
00307 pthread_mutex_unlock(&lock);
00308
00309 last_update_idl = now;
00310 }
00311
00312 int SSIPatrolAgent::return_next_vertex(int cv,bool* sv){
00313 double maxUtility = -1e9;
00314 int i_maxUtility = 0;
00315
00316 for(size_t i=0; i<dimension; i++){
00317
00318 double U = utility(cv,i);
00319 if (U > maxUtility && !sv[i]){
00320 maxUtility = U;
00321 i_maxUtility = i;
00322 }
00323
00324 }
00325
00326 int nv = i_maxUtility;
00327 sv[nv] = true;
00328 printf("DTASSI: returned vertex = %d (U = %.2f)\n",nv,maxUtility);
00329 return nv;
00330 }
00331
00332 int SSIPatrolAgent::select_next_vertex(int cv,bool* sv){
00333
00334 double maxUtility = -1e9;
00335 int i_maxUtility = 0;
00336
00337
00338
00339 if (all_selected(selected_vertices)) {
00340 reset_selected_vertices(sv);
00341 }
00342 for(size_t i=0; i<dimension; i++){
00343
00344 double U = utility(cv,i);
00345
00346 if (U > maxUtility && !sv[i]){
00347 maxUtility = U;
00348 i_maxUtility = i;
00349 }
00350 }
00351
00352 int nv = i_maxUtility;
00353 sv[nv] = true;
00354
00355
00356 return nv;
00357 }
00358
00359 double SSIPatrolAgent::compute_bid(int nv){
00360
00361 printf("## computing bid for vertex %d \n",nv);
00362
00363
00364
00365
00366
00367
00368 if (nv==next_vertex || nv==next_next_vertex){
00369
00370 return 0.;
00371 }
00372
00373
00374 bool* my_tasks = new bool[dimension];
00375
00376 for (size_t i = 0; i<dimension; i++){
00377
00378 my_tasks[i] = !tasks[i];
00379 }
00380
00381
00382
00383 my_tasks[nv] = false;
00384
00385
00386
00387
00388
00389
00390
00391
00392 double path_cost = 0.;
00393
00394
00395 int ci = -1;
00396 if (next_vertex != -1){
00397 ci = next_vertex;
00398 path_cost = compute_cost(ci);
00399 my_tasks[ci] = true;
00400
00401 } else {
00402 ci = return_next_vertex(current_vertex,my_tasks);
00403 path_cost = compute_cost(ci);
00404
00405 }
00406
00407 while (!all_selected(my_tasks)){
00408 int ni = return_next_vertex(ci,my_tasks);
00409 path_cost += compute_cost(ci,ni);
00410
00411 ci=ni;
00412 }
00413 if (ci >= 0 && ci < dimension){
00414 printf("returning back from (last task) %d to (current vertex) %d (cost = %.2f) \n",ci,current_vertex,path_cost);
00415 path_cost += compute_cost(ci,current_vertex);
00416 }
00417 printf("## total cost = %.2f \n",path_cost);
00418
00419 delete[] my_tasks;
00420
00421 return path_cost;
00422 }
00423
00424 void SSIPatrolAgent::force_bid(int nv,double bv,int rid){
00425
00426 bids[nv].bidValue = bv;
00427 bids[nv].robotId = rid;
00428 }
00429
00430 void SSIPatrolAgent::wait(){
00431 double t = std::min(timeout,1.0+nactivetasks*0.1);
00432 #if DEBUG_PRINT
00433 printf(" --- waiting %.1f second ---\n",t);
00434 #endif
00435 ros::Duration delay = ros::Duration(t);
00436 delay.sleep();
00437
00438
00439
00440
00441
00442
00443
00444
00445 }
00446
00447
00448 int SSIPatrolAgent::compute_next_vertex() {
00449 compute_next_vertex(current_vertex);
00450 }
00451
00452
00453 int SSIPatrolAgent::compute_next_vertex(int cv) {
00454
00455 update_global_idleness();
00456
00457
00458
00459 reset_selected_vertices(selected_vertices);
00460
00461
00462
00463
00464 if (cv >= 0 && cv < dimension){
00465 selected_vertices[cv] = true;
00466 }
00467
00468 int mnv = select_next_vertex(cv,selected_vertices);
00469 double bidvalue = compute_bid(mnv);
00470 int value = ID_ROBOT;
00471 if (value==-1){value=0;}
00472 force_bid(mnv,bidvalue,value);
00473 send_target(mnv,bidvalue);
00474 #if DEBUG_PRINT
00475 printf("DTAP [%.1f] compute_next_vertex: waiting for bids\n",ros::Time::now().toSec());
00476 #endif
00477 wait();
00478 #if DEBUG_PRINT
00479 printf("DTAP compute_next_vertex: bids timeout - current value for target node %d = %.2f \n",mnv,bidvalue);
00480 #endif
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 while (true){
00493
00494 if (best_bid(mnv)){
00495 update_tasks();
00496
00497 break;
00498 } else {
00499 if (greedy_best_bid(cv,mnv)){
00500 #if DEBUG_PRINT
00501
00502 time_t rawtime;
00503 struct tm * timeinfo;
00504 char strnow[80];
00505 time (&rawtime);
00506 timeinfo = localtime(&rawtime);
00507 sprintf(strnow,"%d%02d%02d_%02d%02d%02d", timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec);
00508
00509 FILE* fp = fopen("greedy-actions.txt","a");
00510 fprintf(fp,"time: %s; robot: %d; target vertex: %d; current vertex: %d\n",strnow,value,mnv,cv);
00511 fclose(fp);
00512 #endif
00513
00514 break;
00515 } else {
00516 mnv = select_next_vertex(cv,selected_vertices);
00517 bidvalue = compute_bid(mnv);
00518 force_bid(mnv,bidvalue,value);
00519 send_target(mnv,bidvalue);
00520
00521 wait();
00522
00523
00524
00525
00526
00527 }
00528 }
00529 }
00530
00531
00532 return mnv;
00533
00534 }
00535
00536
00537
00538 void SSIPatrolAgent::update_tasks(){
00539 int value = ID_ROBOT;
00540 if (value==-1){value=0;}
00541 for (size_t i = 0; i< dimension; i++){
00542 tasks[i] = (bids[i].robotId == value);
00543 }
00544 }
00545
00546 void SSIPatrolAgent::send_target(int nv,double bv) {
00547
00548 int value = ID_ROBOT;
00549 if (value==-1){value=0;}
00550
00551 int msg_type = DTASSI_TR;
00552 std_msgs::Int16MultiArray msg;
00553 msg.data.clear();
00554
00555 msg.data.push_back(value);
00556 msg.data.push_back(msg_type);
00557 msg.data.push_back(nv);
00558 #if DEBUG_PRINT
00559 printf("DTAP [%.1f] ** sending Task Request [robot:%d, msgtype:%d, next_vertex:%d, bid:%.2f ] \n",
00560 ros::Time::now().toSec(),value,msg_type,nv,bv);
00561 #endif
00562 int ibv = (int)(bv);
00563 if (ibv>32767) {
00564 ROS_WARN("Wrong conversion when sending bid value in messages!!!");
00565 ibv=32000;
00566 }
00567 msg.data.push_back(ibv);
00568
00569 do_send_message(msg);
00570
00571 }
00572
00573
00574 void SSIPatrolAgent::send_bid(int nv,double bv) {
00575 int value = ID_ROBOT;
00576 if (value==-1){value=0;}
00577
00578
00579 int msg_type = DTASSI_BID;
00580 std_msgs::Int16MultiArray msg;
00581 msg.data.clear();
00582
00583 msg.data.push_back(value);
00584 msg.data.push_back(msg_type);
00585 msg.data.push_back(nv);
00586 #if DEBUG_PRINT
00587 printf("DTAP ** sending Bid [robot:%d, msgtype:%d, next_vertex:%d, bid:%.2f ] \n",value,msg_type,nv,bv);
00588 #endif
00589 int ibv = (int)(bv);
00590 if (ibv>32767) {
00591 ROS_WARN("Wrong conversion when sending bid value in messages!!!");
00592 ibv=32000;
00593 }
00594 msg.data.push_back(ibv);
00595 do_send_message(msg);
00596 }
00597
00598
00599
00600 bool SSIPatrolAgent::greedy_best_bid(int cv, int nv){
00601
00602
00603
00604
00605
00606
00607 bool adj = (compute_hops(cv,nv) <= 1);
00608
00609 double avg_idleness = 0.;
00610 for(size_t i=0; i<dimension; i++) {
00611 avg_idleness += global_instantaneous_idleness[i];
00612 }
00613 avg_idleness = avg_idleness/((double) dimension);
00614 double std_idleness = 0.;
00615 for(size_t i=0; i<dimension; i++) {
00616 std_idleness += (global_instantaneous_idleness[i] - avg_idleness)*(global_instantaneous_idleness[i] - avg_idleness);
00617 }
00618 std_idleness = sqrt(std_idleness/((double) dimension));
00619 bool high_idleness = (global_instantaneous_idleness[nv] > (2*std_idleness + avg_idleness));
00620 bool conflict = (bids[nv].bidValue == 0);
00621 bool greedy_cond = adj && high_idleness && !conflict;
00622
00623 #if DEBUG_PRINT
00624 printf("CHECK ADJ: cv %d, nv %d, hops: %d, result: %d \n",cv,nv,compute_hops(cv,nv),(int)adj);
00625 printf("CHECK HIGH IDLNESS: idl %f, avg %f, std %f, result: %d \n",global_instantaneous_idleness[nv],avg_idleness,std_idleness,high_idleness);
00626 printf("CHECK CONF: bid value %f, result: %d \n",bids[nv].bidValue,conflict);
00627 printf("CHECK GREEDY: result: %d \n",greedy_cond);
00628 #endif
00629
00630
00631 return greedy_cond;
00632 }
00633
00634
00635
00636 bool SSIPatrolAgent::best_bid(int nv){
00637
00638
00639
00640
00641
00642
00643
00644
00645 int value = ID_ROBOT;
00646 if (value==-1){value=0;}
00647 return (bids[nv].robotId==value);
00648 }
00649
00650
00651
00652
00653
00654 void SSIPatrolAgent::send_results() {
00655 int value = ID_ROBOT;
00656 if (value==-1){value=0;}
00657
00658
00659 int msg_type = DTAGREEDY_MSG_TYPE;
00660 std_msgs::Int16MultiArray msg;
00661 msg.data.clear();
00662 msg.data.push_back(value);
00663 msg.data.push_back(msg_type);
00664
00665 pthread_mutex_lock(&lock);
00666 for(size_t i=0; i<dimension; i++) {
00667
00668 int ms = (int)(global_instantaneous_idleness[i]*10);
00669 if (ms>32767) {
00670 ROS_WARN("Wrong conversion when sending idleness value in messages!!!");
00671 printf("*** idleness value = %.1f -> int16 value = %d\n",global_instantaneous_idleness[i],ms);
00672 ms=32000;
00673 }
00674
00675
00676
00677 msg.data.push_back(ms);
00678 }
00679 pthread_mutex_unlock(&lock);
00680 msg.data.push_back(next_vertex);
00681
00682
00683 do_send_message(msg);
00684 }
00685
00686 void SSIPatrolAgent::update_bids(int nv, double bv, int senderId){
00687 if (bids[nv].bidValue >= (1 + hist)*bv) {
00688 bids[nv].bidValue = bv;
00689 bids[nv].robotId = senderId;
00690 }
00691 update_tasks();
00692 }
00693
00694 void SSIPatrolAgent::idleness_msg_handler(std::vector<int>::const_iterator it){
00695
00696 double now = ros::Time::now().toSec();
00697 pthread_mutex_lock(&lock);
00698 for(size_t i=0; i<dimension; i++) {
00699 int ms = *it; it++;
00700
00701
00702 double rgi = (double)ms/10.0;
00703 global_instantaneous_idleness[i] = std::min(
00704 global_instantaneous_idleness[i]+(now-last_update_idl), rgi);
00705
00706 }
00707 pthread_mutex_unlock(&lock);
00708 last_update_idl = now;
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 }
00727
00728 #if 0
00729 void SSIPatrolAgent::task_request_msg_handler(std::vector<int>::const_iterator it, int senderId){
00730 int nv = *it; it++;
00731 double bv = *it; it++;
00732 #if DEBUG_PRINT
00733 printf("DTAP handling task request message form %d: [ vertex: %d, bid value: %.2f]\n",senderId,nv,bv);
00734 #endif
00735 double now = ros::Time::now().toSec();
00736 taskRequests[nv] = now;
00737 double my_bidValue = compute_bid(nv);
00738 update_bids(nv,bv,senderId);
00739 if (my_bidValue<bv*(1+hist)){
00740 send_bid(nv,my_bidValue);
00741 }
00742 }
00743 #else
00744 void SSIPatrolAgent::task_request_msg_handler(std::vector<int>::const_iterator it, int senderId){
00745 int nv = *it; it++;
00746 double bv = *it; it++;
00747 double now = ros::Time::now().toSec();
00748 #if DEBUG_PRINT
00749 printf("DTAP [%.1f] handling task request message form %d: [ vertex: %d, bid value: %.2f]\n",now,senderId,nv,bv);
00750 #endif
00751
00752 taskRequests[nv] = now;
00753
00754 update_bids(nv,bv,senderId);
00755
00756
00757
00758 double my_bidValue = compute_bid(nv);
00759 int value = ID_ROBOT;
00760 if (value==-1){value=0;}
00761 update_bids(nv,my_bidValue,value);
00762
00763
00764
00765 if (bids[nv].robotId==value){
00766
00767 send_bid(nv,bids[nv].bidValue);
00768 }
00769 }
00770 #endif
00771
00772
00773 void SSIPatrolAgent::bid_msg_handler(std::vector<int>::const_iterator it, int senderId){
00774 int nv = *it; it++;
00775 double bv = *it; it++;
00776 #if DEBUG_PRINT
00777 printf("DTAP [%.1f] handling bid message from %d: [ vertex: %d, bid value: %.2f]\n",ros::Time::now().toSec(),senderId,nv,bv);
00778 #endif
00779 update_bids(nv,bv,senderId);
00780 }
00781
00782
00783 void SSIPatrolAgent::receive_results() {
00784
00785
00786 std::vector<int>::const_iterator it = vresults.begin();
00787 int id_sender = *it; it++;
00788 int value = ID_ROBOT;
00789 if (value==-1){value=0;}
00790 if (id_sender==value) return;
00791 int msg_type = *it; it++;
00792
00793 switch (msg_type){
00794 case (DTAGREEDY_MSG_TYPE):
00795 {
00796 idleness_msg_handler(it);
00797 }
00798 break;
00799 case (DTASSI_TR):
00800 {
00801 task_request_msg_handler(it,id_sender);
00802 }
00803 break;
00804 case (DTASSI_BID):
00805 {
00806 bid_msg_handler(it,id_sender);
00807 }
00808 break;
00809 }
00810 }
00811
00812
00813
00814