Project: engagement_recognition License: BSD Dependencies:
Used by:
None |
engagement_recognition/src/recognition/recognizers/recognizer.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 "recognizer.h" 00036 00037 #include "../logger/file_logger.h" 00038 #include "../events/event_factory.h" 00039 #include "../lib/engagement_params.h" 00040 #include "../lib/engagement_macros.h" 00041 #include "../actors/actor_manager.h" 00042 00043 Recognizer::~Recognizer() 00044 { 00045 // Delete this state 00046 if (this->state_) 00047 delete this->state_; 00048 00049 // Delete the semaphores 00050 delete this->state_semaphore_; 00051 delete this->semaphore_; 00052 } 00053 00054 Recognizer::Recognizer() : 00055 EventSink() 00056 { 00057 // Have no state 00058 this->state_ = NULL; 00059 00060 // Set the start and end time to undefined 00061 this->start_time_ = UNDEFINED_TIME; 00062 this->end_time_ = UNDEFINED_TIME; 00063 00064 // Set the start and end delay to undefined 00065 this->start_delay_ = UNDEFINED_TIME; 00066 this->end_delay_ = UNDEFINED_TIME; 00067 00068 // Start the max timeout at -1 00069 this->max_delay_ = -1; 00070 00071 // Have no succeeded yet 00072 this->succeeded_ = false; 00073 00074 // Has not been initiated yet 00075 this->initiator_ = initiator::NO_INIT; 00076 00077 // No type identifier given 00078 this->type_ = ""; 00079 00080 // Do not have an actor yet 00081 this->actor_ = ""; 00082 00083 // Create the semaphores 00084 this->semaphore_ = new Semaphore(1); 00085 this->semaphore_ = new Semaphore(0); 00086 } 00087 00088 Recognizer::Recognizer(std::string type, EventSink *sink) : 00089 EventSink(sink) 00090 { 00091 // Have no state 00092 this->state_ = NULL; 00093 00094 // Set the start and end time to undefined 00095 this->start_time_ = UNDEFINED_TIME; 00096 this->end_time_ = UNDEFINED_TIME; 00097 00098 // Set the start and end delay to undefined 00099 this->start_delay_ = UNDEFINED_TIME; 00100 this->end_delay_ = UNDEFINED_TIME; 00101 00102 // Start the max timeout at -1 00103 this->max_delay_ = -1; 00104 00105 // Have no succeeded yet 00106 this->succeeded_ = false; 00107 00108 // Has not been initated yet 00109 this->initiator_ = initiator::NO_INIT; 00110 00111 // Use the given type 00112 this->type_ = type; 00113 00114 // Do not have an actor yet 00115 this->actor_ = ""; 00116 00117 // Create the semaphores 00118 this->state_semaphore_ = new Semaphore(1); 00119 this->semaphore_ = new Semaphore(0); 00120 } 00121 00122 Recognizer::Recognizer(State *state, std::string type, std::string actor, 00123 EventSink *sink) : 00124 EventSink(sink) 00125 { 00126 // Begin in the start state 00127 this->state_ = state; 00128 00129 // Set the start and end time to undefined 00130 this->start_time_ = UNDEFINED_TIME; 00131 this->end_time_ = UNDEFINED_TIME; 00132 00133 // Set the start and end delay to undefined 00134 this->start_delay_ = UNDEFINED_TIME; 00135 this->end_delay_ = UNDEFINED_TIME; 00136 00137 // Start the max timeout at -1 00138 this->max_delay_ = -1; 00139 00140 // Have not succeeded yet 00141 this->succeeded_ = false; 00142 00143 // Has not been initated yet 00144 this->initiator_ = initiator::NO_INIT; 00145 00146 // Use the given type 00147 this->type_ = type; 00148 00149 // Use the given actor 00150 this->actor_ = actor; 00151 00152 // Create the semaphores 00153 this->state_semaphore_ = new Semaphore(1); 00154 this->semaphore_ = new Semaphore(0); 00155 } 00156 00157 void Recognizer::received(std::string topic, ros::Message *message) 00158 { 00159 // Create an empty event, which will help us determine 00160 // whether an event was created and needs to be handled 00161 this->state_semaphore_->wait(); 00162 Event event = this->state_->received(topic, message); 00163 this->state_semaphore_->post(); 00164 00165 // Make sure the event exists, and then use it to transition 00166 if (event.getName().length() != 0) 00167 this->transition(event); 00168 } 00169 00170 void Recognizer::callService(boost::barrier *barrier) 00171 { 00172 // Set the status to cycling 00173 this->status_.setCycle(); 00174 00175 // Block, until the even completes 00176 this->block(); 00177 00178 // Tell the thread barrier we're done processing 00179 if (barrier) 00180 barrier->wait(); 00181 } 00182 00183 void Recognizer::castEvent(Event event) 00184 { 00185 // Call the transition method which will be 00186 // implemented by concrete recognizers 00187 this->transition(event); 00188 } 00189 00190 void Recognizer::setState(factory::StateType type) 00191 { 00192 // Cast ourselves into an EventSink 00193 EventSink *sink = (EventSink*)this; 00194 00195 // Create the new state 00196 State *new_state = StateFactory::createState(type, this->actor_, sink); 00197 00198 // Grab the state temporarily and the name 00199 this->state_semaphore_->wait(); 00200 State *temp = this->state_; 00201 const char *temp_name = (temp != NULL ? this->state_->getName() : ""); 00202 this->state_semaphore_->post(); 00203 00204 // Display output based on whether we're currently in a state or not 00205 if (temp != NULL) 00206 { 00207 // Determine if the new state exists 00208 if (new_state) 00209 { 00210 this->debug(5, "\033[96mrecognizer: [%s] -> [%s].\033[0m", 00211 temp_name, new_state->getName()); 00212 } 00213 else 00214 { 00215 this->error("\033[96mrecognizer: -> Invalid state change.\033[0m"); 00216 } 00217 } 00218 else if (new_state) 00219 { 00220 this->debug(5, "\033[96mrecognizer: -> [%s].\033[0m", 00221 new_state->getName()); 00222 } 00223 00224 // Only change states if it was a valid transition 00225 if (new_state) 00226 { 00227 // Make sure to block with the semaphore 00228 this->state_semaphore_->wait(); 00229 00230 // Free the memory for the current state prior to switching states 00231 if (this->state_) 00232 delete this->state_; 00233 00234 // Set the state to the new state 00235 this->state_ = new_state; 00236 00237 this->state_semaphore_->post(); 00238 } 00239 } 00240 00241 void Recognizer::setStartState() 00242 { 00243 // Get the start state type based on what type of recognizer this is 00244 factory::StateType type = StateFactory::getStartState(this->type_); 00245 00246 // Make sure the type was found, and set the state to the new start state 00247 if (type != factory::INVALID_STATE) 00248 this->setState(type); 00249 } 00250 00251 const char *Recognizer::getStateName() 00252 { 00253 this->state_semaphore_->wait(); 00254 const char *name = this->state_->getName(); 00255 this->state_semaphore_->post(); 00256 00257 return name; 00258 } 00259 00260 bool Recognizer::compareAdditional(std::vector<std::string> additional, 00261 std::string compare) 00262 { 00263 //NOTE: Same means that the additional contains the objects 00264 // different means that the additional does not contain the objects 00265 00266 // Make sure there are additional objects 00267 if (additional.size() > 0) 00268 { 00269 // Traverse through all of the additional objects 00270 for (unsigned d = 0; d < additional.size(); d++) 00271 { 00272 // Determine if the objects are the same 00273 if (this->getObject() == additional.at(d)) 00274 { 00275 // If we're looking for the same, then true, if different then false 00276 if (compare == EventSink::CONTAINS) 00277 return true; 00278 } 00279 } 00280 00281 // The object was not found in the list 00282 if (compare == EventSink::CONTAINS) 00283 return false; 00284 00285 this->warn("Received an unrecognized comparison request '%s'.", 00286 compare.c_str()); 00287 } 00288 00289 return false; 00290 } 00291 00292 void Recognizer::succeed(Action action) 00293 { 00294 this->succeeded_ = true; 00295 00296 // Make sure we have a parent event sink 00297 if (this->parent_) 00298 { 00299 // Create the additional information, with the type of this recognizer 00300 std::vector<std::string> additional = std::vector<std::string>(); 00301 additional.push_back(this->type_); 00302 00303 // Unblock with the succeeded case 00304 this->unblock(ServiceResponse::succeeded(), action); 00305 00306 // Cast the success or failure event upward using the additional data 00307 this->parent_->castEvent(EventFactory::success(additional)); 00308 } 00309 } 00310 00311 void Recognizer::initialize(initiator::Initiator initiator) 00312 { 00313 // Set the start time for this recognizer 00314 this->start_time_ = CURRENT_TIME; 00315 00316 // Store the initiator 00317 this->initiator_ = initiator; 00318 00319 // Make sure the actor field has been set 00320 if (this->actor_ == "") 00321 this->warn("[%s] recognizer: actor field has not been set.", 00322 this->type_.c_str()); 00323 } 00324 00325 void Recognizer::complete(bool success) 00326 { 00327 // Set the success and end time for this connection event 00328 this->succeeded_ = success; 00329 this->end_time_ = CURRENT_TIME; 00330 00331 // If this is a failed event, we need to unblock the mutex 00332 if (!success) 00333 { 00334 // Unblock with the failed case, and no action 00335 this->unblock(ServiceResponse::failed(), Action::noAction()); 00336 } 00337 00338 // Convert the start time to a string stream 00339 std::stringstream start; 00340 start << this->start_time_; 00341 00342 // Convert the duration into a string stream 00343 std::stringstream duration; 00344 00345 // Select the duration based on if it undefined or not 00346 if (this->start_time_!= UNDEFINED_TIME && 00347 this->end_time_ != UNDEFINED_TIME) 00348 { 00349 // Calculate the duration and add it to the stringstream 00350 unsigned long total_duration = (this->end_time_ - this->start_time_); 00351 00352 duration << total_duration; 00353 } 00354 else 00355 duration << 0; 00356 00357 // Convert the delay into a string stream 00358 std::stringstream delay; 00359 00360 // Select the delay time based on if it undefined or not 00361 if (this->start_delay_ != UNDEFINED_TIME && 00362 this->end_delay_ != UNDEFINED_TIME) 00363 { 00364 // Calculate the delay and add it to the stringstream 00365 unsigned long total_delay = (this->end_delay_ - this->start_delay_); 00366 00367 delay << total_delay; 00368 } 00369 else 00370 delay << 0; 00371 00372 // Grab the name of the file to log to from the param server 00373 std::string log_file = EngagementParams::getLogFile(); 00374 00375 // Print out the completion of the event to the CSV file as: 00376 // start time, type, delay, duration, initiator, success 00377 FileLogger::log(log_file.c_str(), "%ld,%s,%s,%s,%s,%s,%s\n", 00378 this->start_time_ - EngagementParams::getStartTime(), 00379 this->type_.c_str(), 00380 delay.str().c_str(), 00381 duration.str().c_str(), 00382 (this->initiator_ == initiator::ROBOT ? "ROBOT" 00383 : this->actor_.c_str()), 00384 (this->succeeded_ ? "SUCCESS" : "FAILURE"), 00385 this->getObject().c_str()); 00386 00387 // Add the information to the vector for additional data 00388 std::vector<std::string> additional = std::vector<std::string>(); 00389 additional.push_back(this->type_); 00390 additional.push_back((this->initiator_ == initiator::ROBOT ? "ROBOT" 00391 : "HUMAN")); 00392 additional.push_back(this->actor_); 00393 additional.push_back(start.str()); 00394 additional.push_back(delay.str()); 00395 additional.push_back(duration.str()); 00396 additional.push_back((this->succeeded_ ? "SUCCESS" : "FAILURE")); 00397 additional.push_back(this->getObject()); 00398 00399 // Make sure we have a parent event sink and then 00400 // cast the success or failure event upward using the additional data 00401 if (this->parent_ != NULL) 00402 this->parent_->castEvent(EventFactory::completed(additional)); 00403 00404 // Reset all the values and times 00405 this->succeeded_ = false; 00406 this->initiator_ = initiator::NO_INIT; 00407 this->start_time_ = UNDEFINED_TIME; 00408 this->end_time_ = UNDEFINED_TIME; 00409 this->start_delay_ = UNDEFINED_TIME; 00410 this->end_delay_ = UNDEFINED_TIME; 00411 } 00412 00413 void Recognizer::setActor(std::string actor) 00414 { 00415 if (actor == "") 00416 this->warn("Setting [%s] recognizer to an empty actor.", 00417 this->type_.c_str()); 00418 this->actor_ = actor; 00419 } 00420 00421 Actor *Recognizer::getActor() 00422 { 00423 return ActorManager::findActor(this->actor_); 00424 } 00425 00426 std::string Recognizer::getObject() 00427 { 00428 return std::string(""); 00429 } 00430 00431 ServiceResponse Recognizer::getStatus() 00432 { 00433 return this->status_; 00434 } 00435 00436 double Recognizer::getMaxDelayParam(ros::NodeHandle *handle, double def) 00437 { 00438 // Only load the parameter if it has not been loaded yet 00439 if (this->max_delay_ == -1) 00440 { 00441 // Make sure the handle exists, and try to grab the parameter 00442 // use a default of -1 00443 if (handle) 00444 handle->param(engagement::MAX_DELAY_PARAM, this->max_delay_, def); 00445 else 00446 this->max_delay_ = def; 00447 00448 return this->max_delay_; 00449 } 00450 00451 return def; 00452 } 00453 00454 void Recognizer::setAction(Action action) 00455 { 00456 this->action_ = action; 00457 } 00458 00459 Action Recognizer::getAction() 00460 { 00461 return this->action_; 00462 } 00463 00464 void Recognizer::block() 00465 { 00466 // Wait on the semaphore until it reaches a value of zero 00467 while (this->semaphore_->getValue() > 0) 00468 this->semaphore_->wait(); 00469 00470 // Block until we are finished cycling 00471 do 00472 { 00473 double delay = this->max_delay_; 00474 this->debug(15, "Service semaphore blocking."); 00475 00476 // If degraded, select a random timeout between 0 and 2*normal timeout 00477 if (EngagementParams::isDegraded()) 00478 { 00479 if (rand() % 2 == 0) 00480 delay = .01; 00481 else 00482 delay = 2 * this->max_delay_; 00483 00484 this->cyan("Degraded selected timeout of [%lf]", delay); 00485 } 00486 00487 // Block the semaphore for the given amount of time, if the 00488 // wait fails (ends due to duration) then it failed 00489 if (!this->semaphore_->timedWait(delay)) 00490 { 00491 int verb = (EngagementParams::isDegraded() ? 5 : 15); 00492 this->debug(verb, "Semaphore timed out and unblocked itself."); 00493 00494 // Set the status to failed 00495 this->status_.setFailed(); 00496 00497 // Set this state to the start state 00498 this->setStartState(); 00499 00500 // Complete the recognizer with the false case 00501 this->complete(false); 00502 } 00503 00504 this->debug(15, "Service semaphore unblocked."); 00505 } 00506 while (this->status_.isCycle()); 00507 00508 this->debug(15, "Service semaphore unblocked completely."); 00509 } 00510 00511 void Recognizer::unblock(ServiceResponse status, Action action) 00512 { 00513 // The recognizer cannot unblock itself if it's degraded 00514 if (EngagementParams::isDegraded()) 00515 return; 00516 00517 // Set our status and action to the given values 00518 this->status_ = status; 00519 this->action_ = action; 00520 00521 // Only post if the semaphore is blocking 00522 if (this->semaphore_->getValue() <= 0) 00523 { 00524 this->debug(15, "Posting the service semaphore."); 00525 this->semaphore_->post(); 00526 } 00527 } |