net_thread.cpp

00001
00002 /***************************************************************************
00003  *  net_thread.cpp - Fawkes WorldModel Plugin Network Thread
00004  *
00005  *  Created: Fri Jun 29 16:56:15 2007 (on flight to RoboCup 2007, Atlanta)
00006  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include "net_thread.h"
00024
00025 #include <netcomm/worldinfo/transceiver.h>
00026 #include <interfaces/ObjectPositionInterface.h>
00027 #include <interfaces/GameStateInterface.h>
00028
00029 #include <string>
00030 #include <cstring>
00031 #include <cstdlib>
00032 #include <cstdio>
00033
00034 using namespace std;
00035 using namespace fawkes;
00036 
00037 /** @class WorldModelNetworkThread "net_thread.h"
00038  * Network thread of worldmodel plugin.
00039  * @author Tim Niemueller
00040  */
00041 
00042 /** Constructor.
00043  */
00044 WorldModelNetworkThread::WorldModelNetworkThread()
00045   : Thread("WorldModelNetworkThread", Thread::OPMODE_CONTINUOUS)
00046 {
00047   __worldinfo_transceiver = NULL;
00048   set_prepfin_conc_loop(true);
00049   __opponent_id = 0;
00050 }
00051
00052 
00053 /** Destructor. */
00054 WorldModelNetworkThread::~WorldModelNetworkThread()
00055 {
00056 }
00057
00058
00059 void
00060 WorldModelNetworkThread::init()
00061 {
00062   std::string multicast_addr;
00063   unsigned int port;
00064   std::string encryption_key;
00065   std::string encryption_iv;
00066   bool        cfg_multicast_loopback;
00067   try {
00068     multicast_addr = config->get_string("/worldinfo/multicast_addr");
00069     port = config->get_uint("/worldinfo/udp_port");
00070     encryption_key = config->get_string("/worldinfo/encryption_key");
00071     encryption_iv  = config->get_string("/worldinfo/encryption_iv");
00072     __cfg_sleep_time_msec   = config->get_uint("/worldinfo/sleep_time_msec");
00073     __cfg_max_msgs_per_recv = config->get_uint("/worldinfo/max_msgs_per_recv");
00074     __cfg_flush_time_sec    = config->get_uint("/worldinfo/flush_time_sec");
00075     cfg_multicast_loopback  = config->get_bool("/worldinfo/multicast_loopback");
00076   } catch (Exception &e) {
00077     e.append("Could not get required configuration data for worldmodel");
00078     e.print_trace();
00079     throw;
00080   }
00081
00082   __worldinfo_transceiver = new WorldInfoTransceiver(multicast_addr.c_str(), port,
00083                                                      encryption_key.c_str(), encryption_iv.c_str(),
00084                                                      nnresolver);
00085
00086   __worldinfo_transceiver->add_handler(this);
00087   __worldinfo_transceiver->set_loop(cfg_multicast_loopback);
00088
00089   try {
00090     __gamestate_if = blackboard->open_for_writing<GameStateInterface>("WI GameState");
00091   } catch (Exception &e) {
00092     delete __worldinfo_transceiver;
00093     e.print_trace();
00094     throw;
00095   }
00096 }
00097
00098
00099 void
00100 WorldModelNetworkThread::finalize()
00101 {
00102   // close all WI pose interfaces
00103   for (LockMap<string, ObjectPositionInterface*>::iterator i = __pose_ifs.begin();
00104        i != __pose_ifs.end();
00105        ++i) {
00106     blackboard->close(i->second);
00107   }
00108
00109   // close all WI ball interfaces
00110   for (LockMap<string, ObjectPositionInterface*>::iterator i = __ball_ifs.begin();
00111        i != __ball_ifs.end();
00112        ++i) {
00113     blackboard->close(i->second);
00114   }
00115
00116   // close all WI opponent interfaces
00117   for (LockMap<string, UidTimeObjPosMap>::iterator i = __opponent_ifs.begin();
00118        i != __opponent_ifs.end();
00119        ++i) {
00120     for (UidTimeObjPosMap::iterator j = i->second.begin();
00121          j != i->second.end();
00122          ++j) {
00123       blackboard->close(j->second.second);
00124     }
00125   }
00126
00127   blackboard->close(__gamestate_if);
00128   delete __worldinfo_transceiver;
00129 }
00130
00131
00132 void
00133 WorldModelNetworkThread::loop()
00134 {
00135   __worldinfo_transceiver->flush_sequence_numbers(__cfg_flush_time_sec);
00136   __worldinfo_transceiver->recv(false, __cfg_max_msgs_per_recv);
00137   usleep( __cfg_sleep_time_msec * 1000 );
00138   // check for dead ones
00139   std::map<std::string, fawkes::Time>::iterator lsi = __last_seen.begin();
00140   Time now;
00141   __last_seen.lock();
00142   while (lsi != __last_seen.end()) {
00143     if (now - &lsi->second > 3.0) {
00144       logger->log_info("WorldModelNetworkThread", "Expiring host %s", lsi->first.c_str());
00145       // this is is as dead as the chair I'm sitting on
00146       __pose_ifs.lock();
00147       if (__pose_ifs.find(lsi->first) != __pose_ifs.end()) {
00148         blackboard->close(__pose_ifs[lsi->first]);
00149         __pose_ifs.erase(lsi->first);
00150       }
00151       __pose_ifs.unlock();
00152       __ball_ifs.lock();
00153       if (__ball_ifs.find(lsi->first) != __ball_ifs.end()) {
00154         blackboard->close(__ball_ifs[lsi->first]);
00155         __ball_ifs.erase(lsi->first);
00156       }
00157       __ball_ifs.unlock();
00158       __opponent_ifs.lock();
00159       if (__opponent_ifs.find(lsi->first) != __opponent_ifs.end()) {
00160         std::map<unsigned int, std::pair<Time, ObjectPositionInterface *> >::iterator i;
00161         for (i = __opponent_ifs[lsi->first].begin(); i != __opponent_ifs[lsi->first].end(); ++i) {
00162           blackboard->close(i->second.second);
00163         }
00164         __opponent_ifs.erase(lsi->first);
00165       }
00166       __opponent_ifs.unlock();
00167       std::map<std::string, fawkes::Time>::iterator tmp = lsi;
00168       ++lsi;
00169       __last_seen.erase(tmp);
00170     } else {
00171       ++lsi;
00172     }
00173   }
00174   __last_seen.unlock();
00175
00176   __opponent_ifs.lock();
00177   std::map<std::string, UidTimeObjPosMap>::iterator o = __opponent_ifs.begin();
00178   while (o != __opponent_ifs.end()) {
00179     UidTimeObjPosMap::iterator top = o->second.begin();
00180     while (top != o->second.end()) {
00181       if (now - &(top->second.first) > 3.0) {
00182         logger->log_info("WorldModelNetworkThread", "Expiring Opponent %s:%u", o->first.c_str(), top->first);
00183         blackboard->close(top->second.second);
00184         UidTimeObjPosMap::iterator tmp = top;
00185         ++top;
00186         o->second.erase(tmp);
00187       } else {
00188         ++top;
00189       }
00190     }
00191     if (o->second.empty()) {
00192       std::map<std::string, UidTimeObjPosMap>::iterator tmp = o;
00193       ++o;
00194       __opponent_ifs.erase(tmp);
00195     } else {
00196       ++o;
00197     }
00198   }
00199   __opponent_ifs.unlock();
00200
00201 }
00202
00203 
00204 /** Access the WI transceiver.
00205  * @return pointer to the WI transceiver
00206  */
00207 WorldInfoTransceiver*
00208 WorldModelNetworkThread::get_transceiver()
00209 {
00210   return __worldinfo_transceiver;
00211 }
00212
00213
00214 void
00215 WorldModelNetworkThread::pose_rcvd(const char *from_host,
00216                                    float x, float y, float theta,
00217                                    float *covariance)
00218 {
00219   __pose_ifs.lock();
00220   if (__pose_ifs.find(from_host) == __pose_ifs.end()) {
00221     try {
00222       std::string id = std::string("WI RoboPos ") + from_host;
00223       __pose_ifs[from_host] = blackboard->open_for_writing<ObjectPositionInterface>(id.c_str());
00224     } catch (Exception &e) {
00225       logger->log_warn("WorldModelNetworkThread", "Failed to create ObjectPositionInterface "
00226                        "for pose of %s, exception follows", from_host);
00227       logger->log_warn("WorldModelNetworkThread", e);
00228       return;
00229     }
00230   }
00231
00232   // Pose is our aliveness indicator
00233   __last_seen.lock();
00234   __last_seen[from_host].stamp();
00235   __last_seen.unlock();
00236
00237   ObjectPositionInterface *iface = __pose_ifs[from_host];
00238   iface->set_world_x(x);
00239   iface->set_world_y(y);
00240   iface->set_world_z(theta);
00241   iface->set_world_xyz_covariance(covariance);
00242   iface->write();
00243   __pose_ifs.unlock();
00244 }
00245
00246
00247 void
00248 WorldModelNetworkThread::velocity_rcvd(const char *from_host, float vel_x,
00249                                        float vel_y, float vel_theta, float *covariance)
00250 {
00251   // TODO
00252 }
00253
00254
00255 void
00256 WorldModelNetworkThread::ball_pos_rcvd(const char *from_host,
00257                                        bool visible, int visibility_history,
00258                                        float dist, float bearing, float slope,
00259                                        float *covariance)
00260 {
00261   __ball_ifs.lock();
00262   if (__ball_ifs.find(from_host) == __ball_ifs.end()) {
00263     try {
00264       std::string id = std::string("WI BPos ") + from_host;
00265       __ball_ifs[from_host] = blackboard->open_for_writing<ObjectPositionInterface>(id.c_str());
00266     } catch (Exception &e) {
00267       logger->log_warn("WorldModelNetworkThread", "Failed to create ObjectPositionInterface "
00268                        "for ball pos of %s, exception follows", from_host);
00269       logger->log_warn("WorldModelNetworkThread", e);
00270       return;
00271     }
00272   }
00273
00274   ObjectPositionInterface *iface = __ball_ifs[from_host];
00275   iface->set_flags( iface->flags() |
00276                     ObjectPositionInterface::TYPE_BALL |
00277                     ObjectPositionInterface::FLAG_HAS_RELATIVE_POLAR |
00278                     ObjectPositionInterface::FLAG_HAS_COVARIANCES );
00279   iface->set_visible(visible);
00280   iface->set_visibility_history(visibility_history);
00281   iface->set_distance(dist);
00282   iface->set_bearing(bearing);
00283   iface->set_slope(slope);
00284   iface->set_dbs_covariance(covariance);
00285   iface->write();
00286   __ball_ifs.unlock();
00287 }
00288
00289
00290 void
00291 WorldModelNetworkThread::global_ball_pos_rcvd(const char *from_host,
00292                                               bool visible, int visibility_history,
00293                                               float x, float y, float z,
00294                                               float *covariance)
00295 {
00296   __ball_ifs.lock();
00297   if (__ball_ifs.find(from_host) == __ball_ifs.end()) {
00298     try {
00299       std::string id = std::string("WI BPos ") + from_host;
00300       __ball_ifs[from_host] = blackboard->open_for_writing<ObjectPositionInterface>(id.c_str());
00301     } catch (Exception &e) {
00302       logger->log_warn("WorldModelNetworkThread", "Failed to create ObjectPositionInterface "
00303                        "for ball pos of %s, exception follows", from_host);
00304       logger->log_warn("WorldModelNetworkThread", e);
00305       return;
00306     }
00307   }
00308
00309   ObjectPositionInterface *iface = __ball_ifs[from_host];
00310   iface->set_flags( iface->flags() |
00311                     ObjectPositionInterface::TYPE_BALL |
00312                     ObjectPositionInterface::FLAG_HAS_WORLD |
00313                     ObjectPositionInterface::FLAG_HAS_Z_AS_ORI |
00314                     ObjectPositionInterface::FLAG_HAS_COVARIANCES );
00315   iface->set_visible(visible);
00316   iface->set_visibility_history(visibility_history);
00317   iface->set_world_x(x);
00318   iface->set_world_y(y);
00319   iface->set_world_z(z);
00320   iface->set_world_xyz_covariance(covariance);
00321   iface->write();
00322   __ball_ifs.unlock();
00323 }
00324
00325
00326 void
00327 WorldModelNetworkThread::ball_velocity_rcvd(const char *from_host,
00328                                             float vel_x, float vel_y, float vel_z,
00329                                             float *covariance)
00330 {
00331   // TODO
00332 }
00333
00334
00335 void
00336 WorldModelNetworkThread::global_ball_velocity_rcvd(const char *from_host,
00337                                                    float vel_x, float vel_y, float vel_z,
00338                                                    float *covariance)
00339 {
00340   // TODO
00341 }
00342
00343
00344 void
00345 WorldModelNetworkThread::opponent_pose_rcvd(const char *from_host,
00346                                             unsigned int uid,
00347                                             float distance, float bearing,
00348                                             float *covariance)
00349 {
00350   __opponent_ifs.lock();
00351   std::map<std::string, std::map<unsigned int, std::pair<Time, ObjectPositionInterface *> > >::iterator f;
00352
00353   bool iface_exists = true;
00354   if ( ((f = __opponent_ifs.find(from_host)) == __opponent_ifs.end()) ||
00355        (f->second.find(uid) == f->second.end()) ) {
00356
00357     char *tmp;
00358     if (asprintf(&tmp, "WI Opp %u %s", ++__opponent_id, from_host) != -1) {
00359       try {
00360         std::string id = tmp;
00361         free(tmp);
00362         logger->log_debug("WorldModelNetworkThread", "Opening new interface for %s:%u", from_host, uid);
00363         __opponent_ifs[from_host][uid] = make_pair(Time(), blackboard->open_for_writing<ObjectPositionInterface>(id.c_str()));
00364       } catch (Exception &e) {
00365         logger->log_warn("WorldModelNetworkThread", "Failed to create ObjectPositionInterface "
00366                          "for opponent %s:%u, exception follows", from_host, uid);
00367         logger->log_warn("WorldModelNetworkThread", e);
00368         iface_exists = false;
00369       }
00370     } else {
00371       logger->log_error("WorldModelNetworkThread", "Could not create interface ID string, out of memory during asprintf().");
00372       iface_exists = false;
00373     }
00374   }
00375
00376   if (iface_exists) {
00377     logger->log_debug("WorldModelNetworkThread", "Setting opponent %s:%u", from_host, uid);
00378     ObjectPositionInterface *iface = __opponent_ifs[from_host][uid].second;
00379     iface->set_distance(distance);
00380     iface->set_bearing(bearing);
00381     iface->set_dbs_covariance(covariance);
00382     iface->write();
00383
00384     __opponent_ifs[from_host][uid].first.stamp();
00385   } else {
00386     logger->log_warn("WorldModelNetworkThread", "Opponent pose interface does not exist, ignoring");
00387   }
00388   __opponent_ifs.unlock();
00389 }
00390
00391
00392 void
00393 WorldModelNetworkThread::opponent_disapp_rcvd(const char *from_host, unsigned int uid)
00394 {
00395   __opponent_ifs.lock();
00396   std::map<std::string, std::map<unsigned int, std::pair<Time, ObjectPositionInterface *> > >::iterator f;
00397   if ( ((f = __opponent_ifs.find(from_host)) != __opponent_ifs.end()) &&
00398        (f->second.find(uid) != f->second.end()) ) {
00399     blackboard->close(f->second[uid].second);
00400     f->second.erase(uid);
00401   }
00402   __opponent_ifs.unlock();
00403 }
00404
00405
00406 void
00407 WorldModelNetworkThread::gamestate_rcvd(const char *from_host,
00408                                         unsigned int game_state,
00409                                         fawkes::worldinfo_gamestate_team_t state_team,
00410                                         unsigned int score_cyan, unsigned int score_magenta,
00411                                         fawkes::worldinfo_gamestate_team_t our_team,
00412                                         fawkes::worldinfo_gamestate_goalcolor_t our_goal_color,
00413                                         fawkes::worldinfo_gamestate_half_t half)
00414 {
00415   logger->log_debug("WorldModelNetworkThread", "Received Gamestate %i from %s, state team %i, score %u:%u, our team: %i, our goal: %i, half: %i",
00416                     game_state, from_host, state_team, score_magenta, our_team, our_goal_color, half);
00417   switch (game_state) {
00418     case GS_FROZEN:
00419       __gamestate_if->set_game_state(GameStateInterface::GS_FROZEN);       break;
00420     case GS_PLAY:
00421       __gamestate_if->set_game_state(GameStateInterface::GS_PLAY);         break;
00422     case GS_KICK_OFF:
00423       __gamestate_if->set_game_state(GameStateInterface::GS_KICK_OFF);     break;
00424     case GS_DROP_BALL:
00425       __gamestate_if->set_game_state(GameStateInterface::GS_DROP_BALL);    break;
00426     case GS_PENALTY:
00427       __gamestate_if->set_game_state(GameStateInterface::GS_PENALTY);      break;
00428     case GS_CORNER_KICK:
00429       __gamestate_if->set_game_state(GameStateInterface::GS_CORNER_KICK);  break;
00430     case GS_THROW_IN:
00431       __gamestate_if->set_game_state(GameStateInterface::GS_THROW_IN);     break;
00432     case GS_FREE_KICK:
00433       __gamestate_if->set_game_state(GameStateInterface::GS_FREE_KICK);    break;
00434     case GS_GOAL_KICK:
00435       __gamestate_if->set_game_state(GameStateInterface::GS_GOAL_KICK);    break;
00436     case GS_HALF_TIME:
00437       __gamestate_if->set_game_state(GameStateInterface::GS_HALF_TIME);    break;
00438   }
00439
00440   switch (state_team) {
00441     case TEAM_NONE:
00442       __gamestate_if->set_state_team(GameStateInterface::TEAM_NONE);       break;
00443     case TEAM_CYAN:
00444       __gamestate_if->set_state_team(GameStateInterface::TEAM_CYAN);       break;
00445     case TEAM_MAGENTA:
00446       __gamestate_if->set_state_team(GameStateInterface::TEAM_MAGENTA);    break;
00447     case TEAM_BOTH:
00448       __gamestate_if->set_state_team(GameStateInterface::TEAM_BOTH);       break;
00449   }
00450
00451   switch (our_team) {
00452     case TEAM_NONE:
00453       __gamestate_if->set_our_team(GameStateInterface::TEAM_NONE);         break;
00454     case TEAM_CYAN:
00455       __gamestate_if->set_our_team(GameStateInterface::TEAM_CYAN);         break;
00456     case TEAM_MAGENTA:
00457       __gamestate_if->set_our_team(GameStateInterface::TEAM_MAGENTA);      break;
00458     case TEAM_BOTH:
00459       __gamestate_if->set_our_team(GameStateInterface::TEAM_BOTH);         break;
00460   }
00461
00462   switch (our_goal_color) {
00463     case GOAL_BLUE:
00464       __gamestate_if->set_our_goal_color(GameStateInterface::GOAL_BLUE);   break;
00465     case GOAL_YELLOW:
00466       __gamestate_if->set_our_goal_color(GameStateInterface::GOAL_YELLOW); break;
00467   }
00468
00469   switch (half) {
00470     case HALF_FIRST:
00471       __gamestate_if->set_half(GameStateInterface::HALF_FIRST);            break;
00472     case HALF_SECOND:
00473       __gamestate_if->set_half(GameStateInterface::HALF_SECOND);           break;
00474   }
00475
00476   __gamestate_if->set_score_cyan(score_cyan);
00477   __gamestate_if->set_score_magenta(score_magenta);
00478
00479   __gamestate_if->write();
00480 }
00481
00482
00483 void
00484 WorldModelNetworkThread::penalty_rcvd(const char *from_host,
00485                                       unsigned int player, unsigned int penalty,
00486                                       unsigned int seconds_remaining)
00487 {
00488   // TBD
00489 }
00490