AriacScorer.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012-2016 Open Source Robotics Foundation
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *
00016 */
00017 
00018 #include <string>
00019 
00020 #include <gazebo/math/Pose.hh>
00021 #include <gazebo/math/Vector3.hh>
00022 #include <gazebo/math/Quaternion.hh>
00023 
00024 #include "osrf_gear/AriacScorer.h"
00025 
00027 AriacScorer::AriacScorer()
00028 {
00029 }
00030 
00032 AriacScorer::~AriacScorer()
00033 {
00034 }
00035 
00037 ariac::GameScore AriacScorer::GetGameScore()
00038 {
00039   return this->gameScore;
00040 }
00041 
00043 ariac::GoalScore AriacScorer::GetCurrentGoalScore()
00044 {
00045   return *this->goalScore;
00046 }
00047 
00049 void AriacScorer::Update(double timeStep)
00050 {
00051   if (this->isPartTravelling)
00052   {
00053     this->gameScore.partTravelTime += timeStep;
00054   }
00055 
00056   boost::mutex::scoped_lock kitTraysLock(this->kitTraysMutex);
00057 
00058   if (this->newGoalReceived)
00059   {
00060     this->AssignGoal(this->newGoal);
00061   }
00062 
00063   // During the competition, this environment variable will be set.
00064   auto v = std::getenv("ARIAC_COMPETITION");
00065   if (!v)
00066   {
00067     // Check score of trays in progress.
00068     if (this->newGoalReceived || this->newTrayInfoReceived)
00069     {
00070       this->ScoreCurrentState();
00071     }
00072   }
00073 
00074   this->newGoalReceived = false;
00075   this->newTrayInfoReceived = false;
00076 }
00077 
00079 bool AriacScorer::IsCurrentGoalComplete()
00080 {
00081   return this->goalScore->isComplete();
00082 }
00083 
00085 void AriacScorer::ScoreCurrentState()
00086 {
00087   for (const auto & item : this->kitTrays)
00088   {
00089     auto trayID = item.first;
00090     auto tray = item.second;
00091     if (tray.currentKit.kitType != "")
00092     {
00093       auto trayScore = ScoreTray(tray);
00094       ROS_INFO_STREAM("Score from tray '" << trayID <<
00095         "' with kit type '" << tray.currentKit.kitType << "': " << trayScore.total());
00096     }
00097     else
00098     {
00099       for (const auto & item : this->currentGoal.kits)
00100       {
00101         auto kit = item.second;
00102         auto goalKitType = kit.kitType;
00103         tray.currentKit.kitType = goalKitType;
00104         auto trayScore = ScoreTray(tray);
00105         ROS_INFO_STREAM("Score from tray '" << trayID
00106           << "' if it were to have kit type '" << goalKitType << "': "
00107           << trayScore.total());
00108       }
00109     }
00110   }
00111 }
00112 
00114 bool AriacScorer::GetTrayById(const ariac::TrayID_t & trayID, ariac::KitTray & kitTray)
00115 {
00116   auto it = this->kitTrays.find(trayID);
00117   if (it == this->kitTrays.end())
00118   {
00119     ROS_DEBUG_STREAM("No known tray with ID: " << trayID);
00120     return false;
00121   }
00122   kitTray = it->second;
00123   return true;
00124 }
00125 
00127 ariac::TrayScore AriacScorer::SubmitTray(const ariac::KitTray & tray)
00128 {
00129   auto trayScore = ScoreTray(tray);
00130   ROS_DEBUG_STREAM("Score from tray '" << tray.trayID << "': " << trayScore.total());
00131   this->goalScore->trayScores[tray.trayID] = trayScore;
00132   return trayScore;
00133 }
00134 
00136 ariac::TrayScore AriacScorer::ScoreTray(const ariac::KitTray & tray)
00137 {
00138   ariac::Kit kit = tray.currentKit;
00139   ariac::KitType_t kitType = tray.currentKit.kitType;
00140   ariac::TrayScore score;
00141   if (this->currentGoal.kits.find(kitType) == this->currentGoal.kits.end())
00142   {
00143     ROS_DEBUG_STREAM("No known kit type: " << kitType);
00144     return score;
00145   }
00146   ariac::Kit assignedKit = this->currentGoal.kits[kitType];
00147   auto numAssignedObjects = assignedKit.objects.size();
00148   ROS_DEBUG_STREAM("Comparing the " << numAssignedObjects <<
00149     " assigned objects with the current " <<
00150     kit.objects.size() << " objects");
00151 
00152   // Count the number of each type of assigned object
00153   std::map<std::string, unsigned int> assignedObjectTypeCount, currentObjectTypeCount;
00154   for (const auto & obj : assignedKit.objects)
00155   {
00156     if (assignedObjectTypeCount.find(obj.type) == assignedObjectTypeCount.end())
00157     {
00158       assignedObjectTypeCount[obj.type] = 0;
00159     }
00160     assignedObjectTypeCount[obj.type] += 1;
00161   }
00162 
00163   ROS_DEBUG_STREAM("Checking object counts");
00164 
00165   bool assignedObjectsMissing = false;
00166   for (auto & value : assignedObjectTypeCount)
00167   {
00168     auto assignedObjectType = value.first;
00169     auto assignedObjectCount = value.second;
00170     auto currentObjectCount =
00171       std::count_if(kit.objects.begin(), kit.objects.end(),
00172         [assignedObjectType](ariac::KitObject k) {return k.type == assignedObjectType;});
00173     ROS_DEBUG_STREAM("Found " << currentObjectCount <<
00174       " objects of type '" << assignedObjectType << "'");
00175     score.partPresence +=
00176       std::min(long(assignedObjectCount), currentObjectCount) * scoringParameters.objectPresence;
00177     if (currentObjectCount < assignedObjectCount)
00178     {
00179       assignedObjectsMissing = true;
00180     }
00181   }
00182   if (!assignedObjectsMissing)
00183   {
00184     ROS_DEBUG_STREAM("All objects on tray");
00185     score.allPartsBonus += scoringParameters.allObjectsBonusFactor * numAssignedObjects;
00186   }
00187 
00188   ROS_DEBUG_STREAM("Checking object poses");
00189   // Keep track of which assigned objects have already been 'matched' to one on the tray.
00190   // This is to prevent multiple objects being close to a single target pose both scoring points.
00191   std::vector<ariac::KitObject> remainingAssignedObjects(assignedKit.objects);
00192 
00193   for (const auto & currentObject : kit.objects)
00194   {
00195     for (auto it = remainingAssignedObjects.begin(); it != remainingAssignedObjects.end(); ++it)
00196     {
00197       // Only check poses of parts of the same type
00198       auto assignedObject = *it;
00199       if (assignedObject.type != currentObject.type)
00200         continue;
00201 
00202       // Check the position of the object (ignoring orientation)
00203       ROS_DEBUG_STREAM("Comparing pose '" << currentObject.pose <<
00204         "' with the assigned pose '" << assignedObject.pose << "'");
00205       gazebo::math::Vector3 posnDiff = assignedObject.pose.CoordPositionSub(currentObject.pose);
00206       posnDiff.z = 0;
00207       if (posnDiff.GetLength() > scoringParameters.distanceThresh)
00208         continue;
00209       ROS_DEBUG_STREAM("Object of type '" << currentObject.type <<
00210         "' in the correct position");
00211       score.partPose += scoringParameters.objectPosition;
00212 
00213       // Check the orientation of the object.
00214       gazebo::math::Quaternion objOrientation = currentObject.pose.rot;
00215       gazebo::math::Quaternion goalOrientation = assignedObject.pose.rot;
00216 
00217       // Filter objects that aren't in the appropriate orientation (loosely).
00218       // If the quaternions represent the same orientation, q1 = +-q2 => q1.dot(q2) = +-1
00219       double orientationDiff = objOrientation.Dot(goalOrientation);
00220       // TODO: this value can probably be derived using relationships between
00221       // euler angles and quaternions.
00222       double quaternionDiffThresh = 0.05;
00223       if (std::abs(orientationDiff) < (1.0 - quaternionDiffThresh))
00224         continue;
00225 
00226       // Now filter the poses based on a threshold set in radians (more user-friendly).
00227       double yawDiff = objOrientation.GetYaw() - goalOrientation.GetYaw();
00228       if (std::abs(yawDiff) > scoringParameters.orientationThresh)
00229         continue;
00230 
00231       ROS_DEBUG_STREAM("Object of type '" << currentObject.type <<
00232         "' in the correct orientation");
00233       score.partPose += scoringParameters.objectOrientation;
00234 
00235       // Once a match is found, don't permit it to be matched again
00236       remainingAssignedObjects.erase(it);
00237       break;
00238     }
00239   }
00240 
00241   // Check if all assigned objects have been matched to one on the tray
00242   if (remainingAssignedObjects.empty())
00243   {
00244     score.isComplete = true;
00245   }
00246 
00247   return score;
00248 }
00249 
00251 void AriacScorer::OnTrayInfoReceived(const osrf_gear::KitTray::ConstPtr & trayMsg)
00252 {
00253   boost::mutex::scoped_lock kitTraysLock(this->kitTraysMutex);
00254 
00255   // Get the ID of the tray that the message is from.
00256   std::string trayID = trayMsg->tray.data;
00257 
00258   if (this->kitTrays.find(trayID) == this->kitTrays.end())
00259   {
00260     // This is the first time we've heard from this tray: initialize it.
00261     this->kitTrays[trayID] = ariac::KitTray(trayID);
00262   }
00263 
00264   // Update the state of the tray.
00265   // TODO: this should be moved outside of the callback
00266   // Do this even if the tray isn't part of the current goal because maybe it
00267   // will be part of future goals.
00268   this->newTrayInfoReceived = true;
00269   ariac::Kit kitState;
00270   FillKitFromMsg(trayMsg->kit, kitState);
00271   this->kitTrays[trayID].UpdateKitState(kitState);
00272 }
00273 
00275 void AriacScorer::OnGoalReceived(const osrf_gear::Goal::ConstPtr & goalMsg)
00276 {
00277   ROS_DEBUG("Received a goal");
00278   this->newGoalReceived = true;
00279 
00280   ariac::Goal goal;
00281   goal.goalID = goalMsg->goal_id.data;
00282   for (const auto & kitMsg : goalMsg->kits)
00283   {
00284     ariac::KitType_t kitType = kitMsg.kit_type.data;
00285     ariac::Kit assignedKit;
00286     FillKitFromMsg(kitMsg, assignedKit);
00287     goal.kits[kitType] = assignedKit;
00288   }
00289   this->newGoal = goal;
00290 }
00291 
00293 void AriacScorer::AssignGoal(const ariac::Goal & goal)
00294 {
00295   ariac::GoalID_t goalID = goal.goalID;
00296   if (this->gameScore.goalScores.find(goalID) == this->gameScore.goalScores.end())
00297   {
00298     // This is a previously unseen goal: start scoring from scratch
00299     this->gameScore.goalScores[goalID] = ariac::GoalScore();
00300     this->gameScore.goalScores[goalID].goalID = goalID;
00301   }
00302   this->goalScore = &this->gameScore.goalScores[goalID];
00303 
00304   this->currentGoal = goal;
00305 }
00306 
00308 ariac::GoalScore AriacScorer::UnassignCurrentGoal(double timeTaken)
00309 {
00310   auto goalScore = *this->goalScore;
00311   goalScore.timeTaken = timeTaken;
00312   this->currentGoal.kits.clear();
00313   return goalScore;
00314 }
00315 
00317 void AriacScorer::FillKitFromMsg(const osrf_gear::Kit &kitMsg, ariac::Kit &kit)
00318 {
00319   kit.objects.clear();
00320   for (const auto & objMsg : kitMsg.objects)
00321   {
00322     ariac::KitObject obj;
00323     obj.type = ariac::DetermineModelType(objMsg.type);
00324     geometry_msgs::Point p = objMsg.pose.position;
00325     geometry_msgs::Quaternion o = objMsg.pose.orientation;
00326     gazebo::math::Vector3 objPosition(p.x, p.y, p.z);
00327     gazebo::math::Quaternion objOrientation(o.w, o.x, o.y, o.z);
00328     obj.pose = gazebo::math::Pose(objPosition, objOrientation);
00329     kit.objects.push_back(obj);
00330   }
00331 }
00332 
00334 void AriacScorer::OnGripperStateReceived(const osrf_gear::VacuumGripperState &stateMsg)
00335 {
00336   this->isPartTravelling = stateMsg.enabled && stateMsg.attached;
00337 }


osrf_gear
Author(s):
autogenerated on Mon Sep 5 2016 03:41:33