Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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
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
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
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
00253 std::map<std::string, ariac::Kit> kits;
00254
00255 sdf::ElementPtr kitElem = goalElem->GetElement("kit");
00256 while (kitElem)
00257 {
00258
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
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
00278 sdf::ElementPtr objectElem = kitElem->GetElement("object");
00279 while (objectElem)
00280 {
00281
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
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
00302 ariac::KitObject obj = {type, pose};
00303 kit.objects.push_back(obj);
00304
00305 objectElem = objectElem->GetNextElement("object");
00306 }
00307
00308
00309 kits[kitType] = kit;
00310
00311 kitElem = kitElem->GetNextElement("kit");
00312 }
00313
00314
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
00323 std::sort(this->dataPtr->goalsToAnnounce.begin(), this->dataPtr->goalsToAnnounce.end());
00324
00325
00326
00327
00328
00329
00330
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
00339 this->dataPtr->goalPub = this->dataPtr->rosnode->advertise<
00340 osrf_gear::Goal>(goalsTopic, 1000, true);
00341
00342
00343 this->dataPtr->gazeboTaskStatePub = this->dataPtr->rosnode->advertise<
00344 std_msgs::String>(gazeboTaskStateTopic, 1000);
00345
00346
00347 this->dataPtr->gazeboTaskScorePub = this->dataPtr->rosnode->advertise<
00348 std_msgs::Float32>(gazeboTaskScoreTopic, 1000);
00349
00350
00351 this->dataPtr->teamStartServiceServer =
00352 this->dataPtr->rosnode->advertiseService(teamStartServiceName,
00353 &ROSAriacTaskManagerPlugin::HandleStartService, this);
00354
00355
00356 this->dataPtr->submitTrayServiceServer =
00357 this->dataPtr->rosnode->advertiseService(submitTrayServiceName,
00358 &ROSAriacTaskManagerPlugin::HandleSubmitTrayService, this);
00359
00360
00361 this->dataPtr->conveyorControlClient =
00362 this->dataPtr->rosnode->serviceClient<osrf_gear::ConveyorBeltControl>(
00363 conveyorControlTopic);
00364
00365
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
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
00402 this->ProcessGoalsToAnnounce();
00403
00404
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
00418 this->dataPtr->timeSpentOnCurrentGoal = this->dataPtr->goalsInProgress.top().timeTaken;
00419
00420
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
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
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
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
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
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
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
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
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
00583 auto goal = this->dataPtr->goalsInProgress.top();
00584 ROS_INFO_STREAM("Restoring order: " << goal.goalID);
00585 this->AssignGoal(goal);
00586 }
00587 }