wm_thread.cpp

00001
00002 /***************************************************************************
00003  *  wm_thread.cpp - Fawkes WorldModel Plugin Thread
00004  *
00005  *  Created: Fri Jun 29 11:56:48 2007 (on flight to RoboCup 2007, Atlanta)
00006  *  Copyright  2006-2008  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 "wm_thread.h"
00024 #include "net_thread.h"
00025
00026 #include "fusers/single_copy.h"
00027 #include "fusers/multi_copy.h"
00028 #include "fusers/objpos_average.h"
00029
00030 #include <netcomm/worldinfo/transceiver.h>
00031 #include <utils/system/pathparser.h>
00032 #include <geometry/hom_point.h>
00033 #include <geometry/hom_vector.h>
00034
00035 #include <interfaces/GameStateInterface.h>
00036 #include <interfaces/ObjectPositionInterface.h>
00037
00038 #include <cmath>
00039 #include <cstring>
00040
00041 using namespace std;
00042 using namespace fawkes;
00043 
00044 /** @class WorldModelThread <plugins/worldmodel/wm_thread.h>
00045  * Main thread of worldmodel plugin.
00046  * @author Tim Niemueller
00047  * @author Daniel Beck
00048  */
00049 
00050 /** Constructor.
00051  * @param net_thread pointer to a WorldModelNetworkThread
00052  */
00053 WorldModelThread::WorldModelThread(WorldModelNetworkThread* net_thread)
00054   : Thread("WorldModelThread", Thread::OPMODE_WAITFORWAKEUP),
00055     BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_WORLDSTATE)
00056 {
00057   __net_thread = net_thread;
00058
00059   __wi_send_enabled = false;
00060   __wi_send_interval = 20;
00061   __wi_send_counter  =  1;
00062
00063   __wi_send_pose    = NULL;
00064   __wi_send_ball    = NULL;
00065
00066
00067   __wi_send_interval = 15;
00068   __wi_send_counter  =  1;
00069 }
00070
00071 
00072 /** Destructor. */
00073 WorldModelThread::~WorldModelThread()
00074 {
00075 }
00076
00077 void
00078 WorldModelThread::init()
00079 {
00080   try {
00081     __cfg_confspace = config->get_string("/worldmodel/confspace");
00082
00083     logger->log_debug("WorldModelThread", "Config space: %s", __cfg_confspace.c_str());
00084
00085     std::string prefix = "/worldmodel/interfaces/" + __cfg_confspace + "/";
00086     std::list<std::string> combos;
00087     // Read interfaces
00088     Configuration::ValueIterator *vi = config->search(prefix.c_str());
00089     while (vi->next()) {
00090       if (strcmp(vi->type(), "string") == 0) {
00091         PathParser pp(vi->path());
00092         if ( pp.size() > 1 ) {
00093           combos.push_back(pp[pp.size() - 2]);
00094         }
00095       }
00096     }
00097     combos.sort();
00098     combos.unique();
00099
00100     for (std::list<std::string>::iterator i = combos.begin(); i != combos.end(); ++i) {
00101       std::string type    = config->get_string((prefix + *i + "/type").c_str());
00102       std::string from_id = config->get_string((prefix + *i + "/from_id").c_str());
00103       std::string to_id   = config->get_string((prefix + *i + "/to_id").c_str());
00104       std::string method  = config->get_string((prefix + *i + "/method").c_str());
00105
00106       if (method == "copy") {
00107         if (from_id.find_first_of("*?[") == std::string::npos) {
00108           logger->log_debug(name(), "Instantiating SingleCopyFuser for %s -> %s (type: %s)",
00109                             from_id.c_str(), to_id.c_str(), type.c_str());
00110           WorldModelSingleCopyFuser *fuser = new WorldModelSingleCopyFuser(blackboard, type.c_str(),
00111                                                                            from_id.c_str(), to_id.c_str());
00112           __fusers.push_back(fuser);
00113         } else {
00114           logger->log_debug(name(), "Instantiating MultiCopyFuser for %s -> %s (type: %s)",
00115                             from_id.c_str(), to_id.c_str(), type.c_str());
00116           WorldModelMultiCopyFuser *fuser = new WorldModelMultiCopyFuser(blackboard, type.c_str(),
00117                                                                          from_id.c_str(), to_id.c_str());
00118           __fusers.push_back(fuser);
00119         }
00120       } else if (method == "average") {
00121         // sanity checks
00122         if (type != "ObjectPositionInterface") {
00123           throw Exception("Can only average interfaces of type ObjectPositionInterface");
00124         }
00125         logger->log_debug(name(), "Instantiating ObjPosAverageFuser for %s -> %s (type: %s)",
00126                           from_id.c_str(), to_id.c_str(), type.c_str());
00127         WorldModelObjPosAverageFuser *fuser = new WorldModelObjPosAverageFuser(logger, blackboard,
00128                                                                                from_id.c_str(), to_id.c_str());
00129           __fusers.push_back(fuser);
00130
00131       } else {
00132         throw Exception("Unknown fuse method '%s', for interface %s -> %s (type %s)",
00133                         method.c_str(), from_id.c_str(), to_id.c_str(), type.c_str());
00134       }
00135     }
00136
00137   } catch (Exception &e) {
00138     e.print_trace();
00139   }
00140
00141   __wi_send_enabled = false;
00142   try {
00143     std::string prefix = "/worldmodel/wi_send/" + __cfg_confspace + "/";
00144     __wi_send_enabled = config->get_bool((prefix + "enable_send").c_str());
00145
00146     if (__wi_send_enabled) {
00147       logger->log_debug(name(), "Sending worldinfo messages enabled");
00148
00149       std::string pose_id = config->get_string((prefix + "pose_id").c_str());
00150       std::string ball_id = config->get_string((prefix + "ball_id").c_str());
00151
00152       logger->log_debug(name(), "Obtaining pose worldinfo data from interface %s.",
00153                         pose_id.c_str());
00154       logger->log_debug(name(), "Obtaining ball worldinfo data from interface %s.",
00155                         ball_id.c_str());
00156
00157       __wi_send_pose      = blackboard->open_for_reading<ObjectPositionInterface>(pose_id.c_str());
00158       __wi_send_ball      = blackboard->open_for_reading<ObjectPositionInterface>(ball_id.c_str());
00159
00160     } else {
00161       logger->log_debug(name(), "Sending worldinfo messages disabled");
00162     }
00163
00164   } catch (Exception& e) {
00165     if ( __wi_send_enabled) {
00166       throw;
00167     } else {
00168       logger->log_debug(name(), "Sending worldinfo messages disabled (enable not set)");
00169     }
00170   }
00171
00172 }
00173
00174 
00175 /** Clean up when init failed.
00176  * You may only call this from init(). Never ever call it from anywhere
00177  * else!
00178  */
00179 void
00180 WorldModelThread::init_failure_cleanup()
00181 {
00182 }
00183
00184
00185 void
00186 WorldModelThread::finalize()
00187 {
00188   for (__fit = __fusers.begin(); __fit != __fusers.end(); ++__fit) {
00189     delete *__fit;
00190   }
00191   __fusers.clear();
00192
00193   if (__wi_send_enabled) {
00194     try {
00195       blackboard->close(__wi_send_pose);
00196       blackboard->close(__wi_send_ball);
00197     } catch (Exception& e) {
00198       e.print_trace();
00199     }
00200   }
00201 }
00202
00203
00204 void
00205 WorldModelThread::loop()
00206 {
00207   for (__fit = __fusers.begin(); __fit != __fusers.end(); ++__fit) {
00208     (*__fit)->fuse();
00209   }
00210
00211   // only send every __wi_send_interval loop
00212   if ( 0 != (__wi_send_counter % __wi_send_interval) ) {
00213     ++__wi_send_counter;
00214     return;
00215   }
00216
00217   __wi_send_counter = 1;
00218
00219   WorldInfoTransceiver* transceiver = __net_thread->get_transceiver();
00220
00221   if (__wi_send_enabled) {
00222     __wi_send_pose->read();
00223     __wi_send_ball->read();
00224
00225     bool do_send = false;
00226
00227     // pose
00228     HomPoint pos;
00229     pos.x( __wi_send_pose->world_x() );
00230     pos.y( __wi_send_pose->world_y() );
00231     float yaw = __wi_send_pose->world_z();
00232     if (__wi_send_pose->has_writer()) {
00233       do_send = true;
00234       transceiver->set_pose(pos.x(), pos.y(), yaw,
00235                             __wi_send_pose->world_xyz_covariance() /* TODO */);
00236       transceiver->set_velocity(__wi_send_pose->world_x_velocity(),
00237                                 __wi_send_pose->world_y_velocity(),
00238                                 __wi_send_pose->world_z_velocity(),
00239                                 __wi_send_pose->world_xyz_velocity_covariance());
00240
00241       // ball
00242       if (__wi_send_ball->has_writer() && __wi_send_ball->is_valid()) {
00243         if (__wi_send_ball->flags() & ObjectPositionInterface::FLAG_HAS_WORLD) {
00244           transceiver->set_glob_ball_pos(__wi_send_ball->world_x(),
00245                                          __wi_send_ball->world_y(),
00246                                          __wi_send_ball->world_z(),
00247                                          __wi_send_ball->world_xyz_covariance() );
00248         } else {
00249           // compute global ball position
00250           HomVector relative_ball;
00251           relative_ball.x( __wi_send_ball->relative_x() );
00252           relative_ball.y( __wi_send_ball->relative_y() );
00253           relative_ball.rotate_z( yaw );
00254           HomPoint global_ball = pos + relative_ball;
00255
00256           transceiver->set_glob_ball_pos(global_ball.x(), global_ball.y(), 0.0,
00257                                          __wi_send_ball->dbs_covariance() /* TODO */);
00258         }
00259         transceiver->set_glob_ball_visible(__wi_send_ball->is_visible(),
00260                                            __wi_send_ball->visibility_history());
00261
00262         // TODO
00263 //      transceiver->set_glob_ball_velocity(__wi_send_ball->relative_x_velocity(),
00264 //                                          __wi_send_ball->relative_y_velocity(),
00265 //                                          __wi_send_ball->relative_z_velocity(),
00266 //                                          __wi_send_ball->relative_xyz_velocity_covariance());
00267       }
00268     }
00269
00270     if (do_send) {
00271       transceiver->send();
00272     }
00273   }
00274 }