Project: engagement_recognition License: BSD Dependencies:
Used by:
None |
engagement_recognition/src/recognition/rnode/rnode.cppGo to the documentation of this file.00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2010, Worcester Polytechnic Institute 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Worcester Polytechnic Institute. nor the names 00018 * of its contributors may be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 // @author Brett Ponsler (bponsler (at) wpi (dot) edu) 00035 #include "rnode.h" 00036 00037 // Include additional functions that may be useful 00038 #include "../actors/actor_manager.h" 00039 #include "../lib/engagement_macros.h" 00040 #include "../lib/engagement_params.h" 00041 #include "../objects/engagement_objects.h" 00042 00043 // Include the engagement handler which is used for each Actor 00044 #include "../handlers/engagement_handler.h" 00045 00046 // Include the RecognizerFactory and the EventFactory 00047 #include "../recognizers/recognizer_factory.h" 00048 #include "../events/event_factory.h" 00049 00050 // Include all the subscription callback methods 00051 #include "callbacks/performing.h" 00052 #include "callbacks/recognition.h" 00053 #include "callbacks/vision.h" 00054 00055 // Include the file logger 00056 #include "../logger/file_logger.h" 00057 00058 RNode::~RNode() 00059 { 00060 // Deconstruct the robot 00061 ActorManager::destroy(); 00062 Robot::destroy(); 00063 00064 // Delete the master thread 00065 if (this->master_thread_) 00066 free(master_thread_); 00067 } 00068 00069 RNode::RNode() : 00070 EventSink(), master_thread_(NULL), old_threads_() 00071 { 00072 // Create the logger for this class 00073 this->setLogger(EngagementParams::getRecogTag()); 00074 FileLogger::setDirectory(EngagementParams::getLogDirectory()); 00075 00076 // Set the default RNode values here 00077 this->shared_gaze_start_ = UNDEFINED_TIME; 00078 this->shared_gaze_ = Duration(); 00079 00080 // Subscribe and advertise all the incoming and outgoing messages 00081 this->subscribe(); 00082 this->advertise(); 00083 } 00084 00085 RNode::RNode(EventSink *parent) : 00086 EventSink(parent) 00087 { 00088 // Create the logger for this class 00089 this->setLogger(EngagementParams::getRecogTag()); 00090 FileLogger::setDirectory(EngagementParams::getLogDirectory()); 00091 00092 // Set the default RNode values here 00093 this->shared_gaze_start_ = UNDEFINED_TIME; 00094 this->shared_gaze_ = Duration(); 00095 00096 // Subscribe and advertise all the incoming and outgoing messages 00097 this->subscribe(); 00098 this->advertise(); 00099 } 00100 00101 void RNode::subscribe() 00102 { 00103 // Create the node handles for vision and collaboration 00104 ros::NodeHandle *vision_handle = EngagementParams::getVisionHandle(); 00105 ros::NodeHandle *performing_handle = EngagementParams::getPerformingHandle(); 00106 00107 // Subscribe using the control handle 00108 performing_look_sub_ = RNODE_SUBSCRIBE(performing_handle, 00109 PERFORMING_LOOK_TOPIC, 00110 &RNode::performingLookCallback); 00111 performing_point_sub_ = RNODE_SUBSCRIBE(performing_handle, 00112 PERFORMING_POINT_TOPIC, 00113 &RNode::performingPointCallback); 00114 performing_shake_sub_ = RNODE_SUBSCRIBE(performing_handle, 00115 PERFORMING_SHAKE_TOPIC, 00116 &RNode::performingShakeCallback); 00117 performing_nod_sub_ = RNODE_SUBSCRIBE(performing_handle, 00118 PERFORMING_NOD_TOPIC, 00119 &RNode::performingNodCallback); 00120 performing_ext_action_sub_ = RNODE_SUBSCRIBE(performing_handle, 00121 PERFORMING_EXTENDED_ACTION_TOPIC, 00122 &RNode::performingExtendedActionCallback); 00123 performing_utterance_sub_ = RNODE_SUBSCRIBE(performing_handle, 00124 PERFORMING_UTTERANCE_TOPIC, 00125 &RNode::performingUtteranceCallback); 00126 00127 // Subscribe using the vision handle 00128 vision_face_sub_ = RNODE_SUBSCRIBE(vision_handle, 00129 VISION_FACE_TOPIC, 00130 &RNode::visionFaceCallback); 00131 } 00132 00133 void RNode::advertise() 00134 { 00135 // Grab the NodeHandles for external messages 00136 ros::NodeHandle *recog_handle = EngagementParams::getRecogHandle(); 00137 ros::NodeHandle *robot_handle = EngagementParams::getRecogRobotHandle(); 00138 ros::NodeHandle *human_handle = EngagementParams::getRecogHumanHandle(); 00139 00140 // Advertise all the services 00141 recog_statistics_srv_ = RNODE_SERVICE(recog_handle, 00142 RECOG_STATISTICS_TOPIC, 00143 &RNode::recogStatisticsService); 00144 recog_dir_gaze_srv_ = RNODE_SERVICE(robot_handle, 00145 RECOG_DIRECTED_GAZE_TOPIC, 00146 &RNode::recogDirGazeService); 00147 recog_mf_gaze_srv_ = RNODE_SERVICE(robot_handle, 00148 RECOG_MUTUAL_FACIAL_GAZE_TOPIC, 00149 &RNode::recogMFGazeService); 00150 recog_adjacency_pair_srv_ = RNODE_SERVICE(robot_handle, 00151 RECOG_ADJACENCY_PAIR_TOPIC, 00152 &RNode::recogAdjacencyPairService); 00153 00154 // Create all the publishers for outgoing messages dealing with the human 00155 status_pub_ = RNODE_ADVERTISE(human_handle, ActorIDStatus, 00156 engagement::RECOG_STATUS_TOPIC); 00157 } 00158 00159 void RNode::startSharedGaze() 00160 { 00161 // If the shared gaze is already started, end the shared gaze, 00162 // before starting a new one 00163 if (this->shared_gaze_start_ != UNDEFINED_TIME) 00164 this->endSharedGaze(); 00165 00166 // The shared gaze has started 00167 this->shared_gaze_start_ = CURRENT_TIME; 00168 00169 this->debug(9, "Shared gaze started."); 00170 } 00171 00172 void RNode::endSharedGaze() 00173 { 00174 // Ensure that the start time is not undefined 00175 if (this->shared_gaze_start_ != UNDEFINED_TIME) 00176 { 00177 // The shared gaze has ended 00178 // Calculate the duration of shared gaze 00179 unsigned long duration = CURRENT_TIME - this->shared_gaze_start_; 00180 00181 // Add the shared gaze duration to the overall duration 00182 this->shared_gaze_.event(duration); 00183 00184 // Reset the shared gaze duration 00185 this->shared_gaze_start_ = UNDEFINED_TIME; 00186 00187 this->debug(9, "Shared gaze completed [%ld].", duration); 00188 } 00189 } 00190 00191 void RNode::relayToActors(std::string topic, ros::Message *message) 00192 { 00193 ActorManager::relayToActors(topic, message); 00194 } 00195 00196 void RNode::castEvent(Event event) 00197 { 00198 // Grab the additional data from the event 00199 std::vector<std::string> event_additional = event.getAdditional(); 00200 00201 // Determine which type of event we received 00202 if (EventFactory::isCompleted(event)) 00203 { 00204 // Make sure we have all the information 00205 if (event_additional.size() == 8) 00206 { 00207 // Grab the information from the event 00208 std::string type = event_additional.at(0); 00209 std::string initiator = event_additional.at(1); 00210 std::string actor_id = event_additional.at(2); 00211 std::string str_start = event_additional.at(3); 00212 std::string str_delay = event_additional.at(4); 00213 std::string str_duration = event_additional.at(5); 00214 std::string str_success = event_additional.at(6); 00215 std::string str_data = event_additional.at(7); 00216 00217 // Attempt to find the actor 00218 Actor *actor = this->findActor(actor_id); 00219 00220 // Ensure that this actor exists 00221 if (!actor) 00222 { 00223 this->warn("Actor [%s] does not exist.", actor_id.c_str()); 00224 this->error("Rejecting connection event event."); 00225 return; 00226 } 00227 00228 // Determine the success and duration of the connection event 00229 bool success = (str_success == EventFactory::getSuccessName() ? true 00230 : false); 00231 00232 // Publish the connection event message on the connection event topic 00233 this->green("CONNECTION EVENT: [%s %s %s %s %s %s %s %s]", 00234 type.c_str(), initiator.c_str(), actor_id.c_str(), 00235 str_start.c_str(), str_delay.c_str(), 00236 str_duration.c_str(), str_success.c_str(), 00237 str_data.c_str()); 00238 00239 // Check the engaged status of this actor 00240 if (!actor->getEngaged()) 00241 { 00242 // If the actor was not engaged, we need to send an engaged message 00243 // Create the Actor message 00244 engagement_msgs::ActorIDStatus actor_msg; 00245 00246 // The message relates to this actor, and it is true for engaged 00247 actor_msg.actor.id = actor_id; 00248 actor_msg.status.value = bml_msgs::Flag::TRUE; 00249 00250 // Publish the engaged message externally and internally 00251 this->status_pub_.publish(actor_msg); 00252 this->relayToActors(engagement::RECOGNITION_NAMESPACE + "/" + 00253 engagement::HUMAN_NAMESPACE + "/" + 00254 engagement::RECOG_STATUS_TOPIC, &actor_msg); 00255 00256 // Set the actor's engaged status to true 00257 actor->setEngaged(true); 00258 } 00259 00260 // If it failed, we need to update the wait for the recognizer 00261 if (success == false) 00262 { 00263 // Grab the type of the connection event 00264 std::string ce_type = event_additional.at(0) + " Event Failed."; 00265 00266 // Print out that the specific event failed 00267 this->info(ce_type.c_str()); 00268 } 00269 } 00270 else 00271 this->warn("CONNECTION EVENT: expected 7 pieces of data, got %d", 00272 event_additional.size()); 00273 } 00274 else if (EventFactory::isSuccess(event)) 00275 { 00276 // Make sure the event contains the type of event that succeeded 00277 if (event_additional.size() > 0) 00278 { 00279 // Grab the type of the connection event 00280 std::string ce_type = event_additional.at(0) + " Event Succeeded."; 00281 00282 // Print out that the specific event succeeded 00283 this->info(ce_type.c_str()); 00284 } 00285 else 00286 this->error("Received [null] event type."); 00287 } 00288 } 00289 00290 bool RNode::compareAdditional(std::vector<std::string> additional, 00291 std::string compare) 00292 { 00293 // RNode has no additional data to compare currently 00294 return false; 00295 } 00296 00297 bool RNode::foundActor(std::string id) 00298 { 00299 // Try to locate the object 00300 Actor *found_actor = this->findActor(id); 00301 00302 // If the object already exists we cannot add it. 00303 if (found_actor != NULL) 00304 { 00305 this->warn("Cannot add actor '%s'. It already exists!", id.c_str()); 00306 00307 return false; 00308 } 00309 00310 // Create a new actor using the id 00311 Actor *actor = ActorManager::createActor(id); 00312 00313 // Create a new engagement handler, with the actor, the robot and the RNode 00314 EngagementHandler *ehandler = new EngagementHandler(id, (EventSink*)this); 00315 00316 // Set the actor's engagement handler 00317 actor->setHandler(ehandler); 00318 00319 this->debug(9, "Added actor [%s].", actor->getID().c_str()); 00320 00321 // Set the start time of the logger to the current time to keep 00322 // track of the start of the interaction 00323 EngagementParams::setStartTime(CURRENT_TIME); 00324 00325 return true; 00326 } 00327 00328 bool RNode::lostActor(std::string id) 00329 { 00330 // Try to find the actor in the hash table 00331 Actor *act = this->findActor(id); 00332 00333 // Make sure the actor exists 00334 if (act != NULL) 00335 { 00336 ActorManager::removeActor(id); 00337 00338 // The object has not been updated recently enough, get rid of it 00339 this->debug(9, "Deleted actor '%s'.", id.c_str()); 00340 00341 return true; 00342 } 00343 00344 return false; 00345 } 00346 00347 Actor* RNode::findActor(std::string id) 00348 { 00349 return ActorManager::findActor(id); 00350 } 00351 00352 void *RNode::spin(void *param) 00353 { 00354 // Assign a sleep rate 00355 ros::Rate sleep_rate(10); 00356 00357 pthread_t myself = pthread_self(); 00358 00359 // Now, so long as we're the master we need to spin 00360 while (pthread_equal(**((pthread_t**)param), myself) != 0) 00361 { 00362 // We need to spin one time 00363 ros::spinOnce(); 00364 00365 // Sleep for the given rate 00366 sleep_rate.sleep(); 00367 } 00368 00369 // Exit this thread now that we're no longer the master 00370 pthread_exit((void*)true); 00371 00372 return (void*)true; 00373 } 00374 00375 void RNode::spawnThread() 00376 { 00377 // Add the thread to the list of old threads 00378 if (this->master_thread_ != NULL) 00379 this->old_threads_.push_back(this->master_thread_); 00380 00381 // Create memory for the new thread 00382 pthread_t *new_thread = (pthread_t*)calloc(1, sizeof(pthread_t)); 00383 00384 // Store the new thread as the master thread 00385 this->master_thread_ = new_thread; 00386 00387 int status = -1; 00388 // Call the spin function with the new thread 00389 while (status != 0) 00390 { 00391 status = pthread_create(new_thread, NULL, &RNode::spin, 00392 (void*)&this->master_thread_); 00393 } 00394 } 00395 00396 bool RNode::masterExists() 00397 { 00398 // Return true if the master thread exists, false otherwise 00399 return (this->master_thread_ != NULL); 00400 } 00401 00402 void RNode::updateOldThreads() 00403 { 00404 // Traverse through all the old threads 00405 for (unsigned c = 0; c < this->old_threads_.size(); c++) 00406 { 00407 bool remove = false; 00408 pthread_t *thread = this->old_threads_.at(c); 00409 00410 // Determine if the thread exists or not 00411 if (thread == NULL) 00412 remove = true; 00413 else if (pthread_tryjoin_np(*(thread), NULL) == 0) 00414 remove = true; 00415 00416 // Remove the old thread from the list 00417 if (remove) 00418 { 00419 // Free the thread if it exists 00420 if (thread != NULL) 00421 free(thread); 00422 00423 this->old_threads_.erase(this->old_threads_.begin() + c); 00424 c--; 00425 } 00426 } 00427 } |