ROSAriacTaskManagerPlugin.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 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 <algorithm>
00019 #include <limits>
00020 #include <mutex>
00021 #include <ostream>
00022 #include <string>
00023 #include <vector>
00024 #include <gazebo/common/Assert.hh>
00025 #include <gazebo/common/Console.hh>
00026 #include <gazebo/common/Events.hh>
00027 #include <gazebo/math/Pose.hh>
00028 #include <gazebo/msgs/gz_string.pb.h>
00029 #include <gazebo/physics/PhysicsTypes.hh>
00030 #include <gazebo/physics/World.hh>
00031 #include <gazebo/transport/transport.hh>
00032 #include <ros/ros.h>
00033 #include <sdf/sdf.hh>
00034 #include <std_msgs/Float32.h>
00035 #include <std_msgs/String.h>
00036 #include <std_srvs/Trigger.h>
00037 
00038 
00039 #include "osrf_gear/ARIAC.hh"
00040 #include "osrf_gear/ROSAriacTaskManagerPlugin.hh"
00041 #include "osrf_gear/AriacScorer.h"
00042 #include <osrf_gear/ConveyorBeltControl.h>
00043 #include <osrf_gear/ConveyorBeltState.h>
00044 #include "osrf_gear/Goal.h"
00045 #include "osrf_gear/Kit.h"
00046 #include "osrf_gear/KitObject.h"
00047 #include "osrf_gear/VacuumGripperState.h"
00048 
00049 namespace gazebo
00050 {
00053   struct ROSAriacTaskManagerPluginPrivate
00054   {
00056     public: physics::WorldPtr world;
00057 
00059     public: sdf::ElementPtr sdf;
00060 
00062     public: std::vector<ariac::Goal> goalsToAnnounce;
00063 
00066     public: std::stack<ariac::Goal> goalsInProgress;
00067 
00069     public: AriacScorer ariacScorer;
00070 
00072     public: ariac::GameScore currentGameScore;
00073 
00075     public: std::unique_ptr<ros::NodeHandle> rosnode;
00076 
00078     public: ros::Publisher goalPub;
00079 
00081     public: ros::Subscriber trayInfoSub;
00082 
00084     public: ros::Subscriber gripperStateSub;
00085 
00087     public: ros::Publisher gazeboTaskStatePub;
00088 
00090     public: ros::Publisher gazeboTaskScorePub;
00091 
00093     public: ros::ServiceServer teamStartServiceServer;
00094 
00096     public: ros::ServiceServer submitTrayServiceServer;
00097 
00099     public: transport::NodePtr node;
00100 
00102     public: transport::PublisherPtr populatePub;
00103 
00105     public: ros::ServiceClient conveyorControlClient;
00106 
00108     public: event::ConnectionPtr connection;
00109 
00111     public: common::Time lastUpdateTime;
00112 
00114     public: common::Time gameStartTime;
00115 
00117     public: double timeSpentOnCurrentGoal;
00118 
00120     public: std::string currentState = "init";
00121 
00123     public: std::mutex mutex;
00124   };
00125 }
00126 
00127 using namespace gazebo;
00128 
00129 GZ_REGISTER_WORLD_PLUGIN(ROSAriacTaskManagerPlugin)
00130 
00131 
00132 static void fillGoalMsg(const ariac::Goal &_goal,
00133                         osrf_gear::Goal &_msgGoal)
00134 {
00135   _msgGoal.goal_id.data = _goal.goalID;
00136   for (const auto item : _goal.kits)
00137   {
00138     osrf_gear::Kit msgKit;
00139     msgKit.kit_type.data = item.first;
00140     for (const auto &obj : item.second.objects)
00141     {
00142       osrf_gear::KitObject msgObj;
00143       msgObj.type = obj.type;
00144       msgObj.pose.position.x = obj.pose.pos.x;
00145       msgObj.pose.position.y = obj.pose.pos.y;
00146       msgObj.pose.position.z = obj.pose.pos.z;
00147       msgObj.pose.orientation.x = obj.pose.rot.x;
00148       msgObj.pose.orientation.y = obj.pose.rot.y;
00149       msgObj.pose.orientation.z = obj.pose.rot.z;
00150       msgObj.pose.orientation.w = obj.pose.rot.w;
00151 
00152       // Add the object to the kit.
00153       msgKit.objects.push_back(msgObj);
00154     }
00155     _msgGoal.kits.push_back(msgKit);
00156   }
00157 }
00158 
00160 ROSAriacTaskManagerPlugin::ROSAriacTaskManagerPlugin()
00161   : dataPtr(new ROSAriacTaskManagerPluginPrivate)
00162 {
00163 }
00164 
00166 ROSAriacTaskManagerPlugin::~ROSAriacTaskManagerPlugin()
00167 {
00168   this->dataPtr->rosnode->shutdown();
00169 }
00170 
00172 void ROSAriacTaskManagerPlugin::Load(physics::WorldPtr _world,
00173   sdf::ElementPtr _sdf)
00174 {
00175   GZ_ASSERT(_world, "ROSAriacTaskManagerPlugin world pointer is NULL");
00176   GZ_ASSERT(_sdf, "ROSAriacTaskManagerPlugin sdf pointer is NULL");
00177   this->dataPtr->world = _world;
00178   this->dataPtr->sdf = _sdf;
00179 
00180   std::string robotNamespace = "";
00181   if (_sdf->HasElement("robot_namespace"))
00182   {
00183     robotNamespace = _sdf->GetElement(
00184       "robot_namespace")->Get<std::string>() + "/";
00185   }
00186 
00187   std::string teamStartServiceName = "start";
00188   if (_sdf->HasElement("team_start_service_name"))
00189     teamStartServiceName = _sdf->Get<std::string>("team_start_service_name");
00190 
00191   std::string gazeboTaskStateTopic = "competition_state";
00192   if (_sdf->HasElement("gazebo_task_state_topic"))
00193     gazeboTaskStateTopic = _sdf->Get<std::string>("gazebo_task_state_topic");
00194 
00195   std::string gazeboTaskScoreTopic = "current_score";
00196   if (_sdf->HasElement("gazebo_task_score_topic"))
00197     gazeboTaskScoreTopic = _sdf->Get<std::string>("gazebo_task_score_topic");
00198 
00199   std::string conveyorControlTopic = "conveyor/control";
00200   if (_sdf->HasElement("conveyor_control_topic"))
00201     conveyorControlTopic = _sdf->Get<std::string>("conveyor_control_topic");
00202 
00203   std::string populationActivateTopic = "populate_belt";
00204   if (_sdf->HasElement("population_activate_topic"))
00205     populationActivateTopic = _sdf->Get<std::string>("population_activate_topic");
00206 
00207   std::string goalsTopic = "orders";
00208   if (_sdf->HasElement("goals_topic"))
00209     goalsTopic = _sdf->Get<std::string>("goals_topic");
00210 
00211   std::string submitTrayServiceName = "submit_tray";
00212   if (_sdf->HasElement("submit_tray_service_name"))
00213     submitTrayServiceName = _sdf->Get<std::string>("submit_tray_service_name");
00214 
00215 
00216   // Parse the goals.
00217   sdf::ElementPtr goalElem = NULL;
00218   if (_sdf->HasElement("goal"))
00219   {
00220     goalElem = _sdf->GetElement("goal");
00221   }
00222 
00223   unsigned int goalCount = 0;
00224   while (goalElem)
00225   {
00226     // Parse the start time.
00227     if (!goalElem->HasElement("start_time"))
00228     {
00229       gzerr << "Unable to find <start_time> element in <goal>. Ignoring" << std::endl;
00230       goalElem = goalElem->GetNextElement("goal");
00231       continue;
00232     }
00233     sdf::ElementPtr startTimeElement = goalElem->GetElement("start_time");
00234     double startTime = startTimeElement->Get<double>();
00235 
00236     // Parse the allowed completion time.
00237     double allowedTime = std::numeric_limits<double>::infinity();
00238     if (goalElem->HasElement("allowed_time"))
00239     {
00240       sdf::ElementPtr allowedTimeElement = goalElem->GetElement("allowed_time");
00241       allowedTime = allowedTimeElement->Get<double>();
00242     }
00243 
00244     // Parse the kits.
00245     if (!goalElem->HasElement("kit"))
00246     {
00247       gzerr << "Unable to find <kit> element in <goal>. Ignoring" << std::endl;
00248       goalElem = goalElem->GetNextElement("goal");
00249       continue;
00250     }
00251 
00252     // Store all kits for a goal.
00253     std::map<std::string, ariac::Kit> kits;
00254 
00255     sdf::ElementPtr kitElem = goalElem->GetElement("kit");
00256     while (kitElem)
00257     {
00258       // Check the validity of the kit.
00259       if (!kitElem->HasElement("object"))
00260       {
00261         gzerr << "Unable to find <object> element in <kit>. Ignoring"
00262               << std::endl;
00263         kitElem = kitElem->GetNextElement("kit");
00264         continue;
00265       }
00266 
00267       ariac::Kit kit;
00268 
00269       // Parse the kit type.
00270       ariac::KitType_t kitType;
00271       if (kitElem->HasElement("kit_type"))
00272       {
00273         kitType = kitElem->Get<std::string>("kit_type");
00274       }
00275       kit.kitType = kitType;
00276 
00277       // Parse the objects inside the kit.
00278       sdf::ElementPtr objectElem = kitElem->GetElement("object");
00279       while (objectElem)
00280       {
00281         // Parse the object type.
00282         if (!objectElem->HasElement("type"))
00283         {
00284           gzerr << "Unable to find <type> in object.\n";
00285           objectElem = objectElem->GetNextElement("object");
00286           continue;
00287         }
00288         sdf::ElementPtr typeElement = objectElem->GetElement("type");
00289         std::string type = typeElement->Get<std::string>();
00290 
00291         // Parse the object pose (optional).
00292         if (!objectElem->HasElement("pose"))
00293         {
00294           gzerr << "Unable to find <pose> in object.\n";
00295           objectElem = objectElem->GetNextElement("object");
00296           continue;
00297         }
00298         sdf::ElementPtr poseElement = objectElem->GetElement("pose");
00299         math::Pose pose = poseElement->Get<math::Pose>();
00300 
00301         // Add the object to the kit.
00302         ariac::KitObject obj = {type, pose};
00303         kit.objects.push_back(obj);
00304 
00305         objectElem = objectElem->GetNextElement("object");
00306       }
00307 
00308       // Add a new kit to the collection of kits.
00309       kits[kitType] = kit;
00310 
00311       kitElem = kitElem->GetNextElement("kit");
00312     }
00313 
00314     // Add a new goal.
00315     ariac::GoalID_t goalID = "goal_" + std::to_string(goalCount++);
00316     ariac::Goal goal = {goalID, startTime, allowedTime, kits, 0.0};
00317     this->dataPtr->goalsToAnnounce.push_back(goal);
00318 
00319     goalElem = goalElem->GetNextElement("goal");
00320   }
00321 
00322   // Sort the goals by their start times.
00323   std::sort(this->dataPtr->goalsToAnnounce.begin(), this->dataPtr->goalsToAnnounce.end());
00324 
00325   // Debug output.
00326   // gzdbg << "Goals:" << std::endl;
00327   // for (auto goal : this->dataPtr->goalsToAnnounce)
00328   //   gzdbg << goal << std::endl;
00329 
00330   // Initialize ROS
00331   this->dataPtr->rosnode.reset(new ros::NodeHandle(robotNamespace));
00332 
00333   if(ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Info))
00334   {
00335     ros::console::notifyLoggerLevelsChanged();
00336   }
00337 
00338   // Publisher for announcing new goals.
00339   this->dataPtr->goalPub = this->dataPtr->rosnode->advertise<
00340     osrf_gear::Goal>(goalsTopic, 1000, true);  // latched=true
00341 
00342   // Publisher for announcing new state of Gazebo's task.
00343   this->dataPtr->gazeboTaskStatePub = this->dataPtr->rosnode->advertise<
00344     std_msgs::String>(gazeboTaskStateTopic, 1000);
00345 
00346   // Publisher for announcing the score of the game.
00347   this->dataPtr->gazeboTaskScorePub = this->dataPtr->rosnode->advertise<
00348     std_msgs::Float32>(gazeboTaskScoreTopic, 1000);
00349 
00350   // Service for starting the competition.
00351   this->dataPtr->teamStartServiceServer =
00352     this->dataPtr->rosnode->advertiseService(teamStartServiceName,
00353       &ROSAriacTaskManagerPlugin::HandleStartService, this);
00354 
00355   // Service for submitting trays for inspection.
00356   this->dataPtr->submitTrayServiceServer =
00357     this->dataPtr->rosnode->advertiseService(submitTrayServiceName,
00358       &ROSAriacTaskManagerPlugin::HandleSubmitTrayService, this);
00359 
00360   // Client for the conveyor control commands.
00361   this->dataPtr->conveyorControlClient =
00362     this->dataPtr->rosnode->serviceClient<osrf_gear::ConveyorBeltControl>(
00363       conveyorControlTopic);
00364 
00365   // Initialize Gazebo transport.
00366   this->dataPtr->node = transport::NodePtr(new transport::Node());
00367   this->dataPtr->node->Init();
00368   this->dataPtr->populatePub =
00369     this->dataPtr->node->Advertise<msgs::GzString>(populationActivateTopic);
00370 
00371   // Initialize the game scorer.
00372   this->dataPtr->trayInfoSub = this->dataPtr->rosnode->subscribe(
00373     "/ariac/trays", 10, &AriacScorer::OnTrayInfoReceived, &this->dataPtr->ariacScorer);
00374   this->dataPtr->gripperStateSub = this->dataPtr->rosnode->subscribe(
00375     "/ariac/gripper/state", 10, &AriacScorer::OnGripperStateReceived,
00376     &this->dataPtr->ariacScorer);
00377 
00378   this->dataPtr->gameStartTime = this->dataPtr->world->GetSimTime();
00379 
00380   this->dataPtr->connection = event::Events::ConnectWorldUpdateEnd(
00381     boost::bind(&ROSAriacTaskManagerPlugin::OnUpdate, this));
00382 }
00383 
00385 void ROSAriacTaskManagerPlugin::OnUpdate()
00386 {
00387   std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
00388   auto currentSimTime = this->dataPtr->world->GetSimTime();
00389 
00390   double elapsedTime = (currentSimTime - this->dataPtr->lastUpdateTime).Double();
00391   if (this->dataPtr->currentState == "ready")
00392   {
00393     this->dataPtr->gameStartTime = currentSimTime;
00394     this->dataPtr->currentState = "go";
00395 
00396     this->ControlConveyorBelt(0.2);
00397     this->PopulateConveyorBelt();
00398   }
00399   else if (this->dataPtr->currentState == "go")
00400   {
00401     // Update the goal manager.
00402     this->ProcessGoalsToAnnounce();
00403 
00404     // Update the score.
00405     this->dataPtr->ariacScorer.Update(elapsedTime);
00406     auto gameScore = this->dataPtr->ariacScorer.GetGameScore();
00407     if (gameScore.total() != this->dataPtr->currentGameScore.total())
00408     {
00409       ROS_DEBUG_STREAM("Current game score: " << gameScore.total());
00410       this->dataPtr->currentGameScore = gameScore;
00411     }
00412 
00413     if (!this->dataPtr->goalsInProgress.empty())
00414     {
00415       this->dataPtr->goalsInProgress.top().timeTaken += elapsedTime;
00416       auto goalID = this->dataPtr->goalsInProgress.top().goalID;
00417       // TODO: timing should probably be managed by the scorer but we want to use sim time
00418       this->dataPtr->timeSpentOnCurrentGoal = this->dataPtr->goalsInProgress.top().timeTaken;
00419 
00420       // Check for completed goals.
00421       bool goalCompleted = this->dataPtr->ariacScorer.IsCurrentGoalComplete();
00422       if (goalCompleted)
00423       {
00424         ROS_INFO_STREAM("Order complete: " << goalID);
00425         this->StopCurrentGoal();
00426       }
00427       else
00428       {
00429         // Check if the time limit for the current goal has been exceeded.
00430         if (this->dataPtr->timeSpentOnCurrentGoal > this->dataPtr->goalsInProgress.top().allowedTime)
00431         {
00432           ROS_INFO_STREAM("Order timed out: " << goalID);
00433           this->StopCurrentGoal();
00434         }
00435       }
00436     }
00437 
00438     if (this->dataPtr->goalsInProgress.empty() && this->dataPtr->goalsToAnnounce.empty())
00439     {
00440       this->dataPtr->currentGameScore.totalProcessTime =
00441         (currentSimTime - this->dataPtr->gameStartTime).Double();
00442       this->dataPtr->currentState = "end_game";
00443     }
00444   }
00445   else if (this->dataPtr->currentState == "end_game")
00446   {
00447     ROS_INFO_STREAM("No more orders to process. Final score: " << this->dataPtr->currentGameScore.total());
00448     ROS_INFO_STREAM("Score breakdown:\n" << this->dataPtr->currentGameScore);
00449     this->dataPtr->currentState = "done";
00450   }
00451 
00452   // TODO: Publish at a lower frequency.
00453   std_msgs::Float32 scoreMsg;
00454   scoreMsg.data = this->dataPtr->currentGameScore.total();
00455   this->dataPtr->gazeboTaskScorePub.publish(scoreMsg);
00456 
00457   std_msgs::String stateMsg;
00458   stateMsg.data = this->dataPtr->currentState;
00459   this->dataPtr->gazeboTaskStatePub.publish(stateMsg);
00460 
00461   this->dataPtr->lastUpdateTime = currentSimTime;
00462 }
00463 
00465 void ROSAriacTaskManagerPlugin::ProcessGoalsToAnnounce()
00466 {
00467   if (this->dataPtr->goalsToAnnounce.empty())
00468     return;
00469 
00470   // Check whether announce a new goal from the list.
00471   auto elapsed = this->dataPtr->world->GetSimTime() - this->dataPtr->gameStartTime;
00472   if (elapsed.Double() >= this->dataPtr->goalsToAnnounce.front().startTime)
00473   {
00474     auto goal = this->dataPtr->goalsToAnnounce.front();
00475 
00476     // Move goal to the 'in process' stack
00477     this->dataPtr->goalsInProgress.push(ariac::Goal(goal));
00478     this->dataPtr->goalsToAnnounce.erase(this->dataPtr->goalsToAnnounce.begin());
00479 
00480     this->AssignGoal(goal);
00481   }
00482 }
00483 
00485 bool ROSAriacTaskManagerPlugin::HandleStartService(
00486   std_srvs::Trigger::Request & req,
00487   std_srvs::Trigger::Response & res)
00488 {
00489   (void)req;
00490   std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
00491 
00492   if (this->dataPtr->currentState == "init") {
00493     this->dataPtr->currentState = "ready";
00494     res.success = true;
00495     res.message = "competition started successfully!";
00496     return true;
00497   }
00498   res.success = false;
00499   res.message = "cannot start if not in 'init' state";
00500   return true;
00501 }
00502 
00504 bool ROSAriacTaskManagerPlugin::HandleSubmitTrayService(
00505   osrf_gear::SubmitTray::Request & req,
00506   osrf_gear::SubmitTray::Response & res)
00507 {
00508   std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
00509 
00510   if (this->dataPtr->currentState != "go") {
00511     ROS_ERROR("Competition is not running so trays cannot be submitted.");
00512     return false;
00513   }
00514 
00515   ariac::KitTray kitTray;
00516   if (!this->dataPtr->ariacScorer.GetTrayById(req.tray_id.data, kitTray))
00517   {
00518     res.success = false;
00519     return true;
00520   }
00521   kitTray.currentKit.kitType = req.kit_type.data;
00522   res.success = true;
00523   res.inspection_result = this->dataPtr->ariacScorer.SubmitTray(kitTray).total();
00524   return true;
00525 }
00526 
00528 void ROSAriacTaskManagerPlugin::ControlConveyorBelt(double velocity)
00529 {
00530 
00531   if (!this->dataPtr->conveyorControlClient.exists())
00532   {
00533     this->dataPtr->conveyorControlClient.waitForExistence();
00534   }
00535 
00536   // Make a service call to set the velocity of the belt
00537   osrf_gear::ConveyorBeltState controlMsg;
00538   controlMsg.velocity = velocity;
00539   osrf_gear::ConveyorBeltControl srv;
00540   srv.request.state = controlMsg;
00541   this->dataPtr->conveyorControlClient.call(srv);
00542   if (!srv.response.success) {
00543     ROS_ERROR_STREAM("Failed to control conveyor");
00544   }
00545 }
00546 
00548 void ROSAriacTaskManagerPlugin::PopulateConveyorBelt()
00549 {
00550   // Publish a message on the activation_plugin of the PopulationPlugin.
00551   gazebo::msgs::GzString msg;
00552   msg.set_data("restart");
00553   this->dataPtr->populatePub->Publish(msg);
00554 }
00555 
00557 void ROSAriacTaskManagerPlugin::AssignGoal(const ariac::Goal & goal)
00558 {
00559     // Publish the goal to ROS topic
00560     ROS_INFO_STREAM("Announcing order: " << goal.goalID);
00561     osrf_gear::Goal goalMsg;
00562     fillGoalMsg(goal, goalMsg);
00563     this->dataPtr->goalPub.publish(goalMsg);
00564 
00565     // Assign the scorer the goal to monitor
00566     gzdbg << "Assigning order: " << goal << std::endl;
00567     this->dataPtr->ariacScorer.AssignGoal(goal);
00568 }
00569 
00571 void ROSAriacTaskManagerPlugin::StopCurrentGoal()
00572 {
00573   if (this->dataPtr->goalsInProgress.size())
00574   {
00575     ROS_INFO_STREAM("Stopping order: " << this->dataPtr->goalsInProgress.top().goalID);
00576     this->dataPtr->goalsInProgress.pop();
00577     this->dataPtr->ariacScorer.UnassignCurrentGoal(this->dataPtr->timeSpentOnCurrentGoal);
00578   }
00579 
00580   if (this->dataPtr->goalsInProgress.size())
00581   {
00582     // Assign the previous goal to the scorer
00583     auto goal = this->dataPtr->goalsInProgress.top();
00584     ROS_INFO_STREAM("Restoring order: " << goal.goalID);
00585     this->AssignGoal(goal);
00586   }
00587 }


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