scoring_plugin.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
18 #include <gazebo/common/Assert.hh>
19 #include <gazebo/common/Console.hh>
20 #include <gazebo/physics/Joint.hh>
21 #include <gazebo/physics/Model.hh>
23 
26  : WorldPlugin(), gzNode(new gazebo::transport::Node()) {
27 }
28 
29 void ScoringPlugin::Load(gazebo::physics::WorldPtr _world,
30  sdf::ElementPtr _sdf)
31 {
32  GZ_ASSERT(_world, "ScoringPlugin::Load(): NULL world pointer");
33  GZ_ASSERT(_sdf, "ScoringPlugin::Load(): NULL _sdf pointer");
34 
35  this->world = _world;
36  this->sdf = _sdf;
37 
38  // SDF.
39  if (!this->ParseSDFParameters())
40  {
41  gzerr << "Scoring disabled" << std::endl;
42  return;
43  }
44 
45  this->readyTime.Set(this->initialStateDuration);
46  this->runningTime = this->readyTime + this->readyStateDuration;
47  this->finishTime = this->runningTime + this->runningStateDuration;
48 
49  // Prepopulate the task msg.
50  this->taskMsg.name = this->taskName;
51  this->taskMsg.ready_time.fromSec(this->readyTime.Double());
52  this->taskMsg.running_time.fromSec(this->runningTime.Double());
53  this->UpdateTaskMessage();
54 
55  // Initialize ROS transport.
56  this->rosNode.reset(new ros::NodeHandle());
57  this->taskPub = this->rosNode->advertise<vrx_gazebo::Task>
58  (this->taskInfoTopic, 100);
59  this->contactPub = this->rosNode->advertise<vrx_gazebo::Contact>
60  (this->contactDebugTopic, 100);
61 
62  this->updateConnection = gazebo::event::Events::ConnectWorldUpdateBegin(
63  std::bind(&ScoringPlugin::Update, this));
64 
65  gzNode->Init();
66 #if GAZEBO_MAJOR_VERSION >= 8
67  std::string worldName = this->world->Name();
68 #else
69  std::string worldName = this->world->GetName();
70 #endif
71  std::string collisionTopic =
72  std::string("/gazebo/") + worldName + std::string("/physics/contacts");
73  collisionSub = gzNode->Subscribe(collisionTopic,
75 
76  if (char* env_dbg = std::getenv("VRX_DEBUG"))
77  {
78  if (std::string(env_dbg) == "false")
79  this->debug = false;
80  }
81  else
82  {
83  gzwarn << "VRX_DEBUG enviornment variable not set, defaulting to true"
84  << std::endl;
85  }
86  this->serverControlPub =
87  this->gzNode->Advertise<gazebo::msgs::ServerControl>
88  ("/gazebo/server/control");
89 }
90 
92 double ScoringPlugin::Score() const
93 {
94  return this->score;
95 }
96 
98 void ScoringPlugin::SetScore(double _newScore)
99 {
100  if (this->TaskState() == "running")
101  this->score = _newScore;
102 }
103 
105 std::string ScoringPlugin::TaskName() const
106 {
107  return this->taskName;
108 }
109 
111 std::string ScoringPlugin::TaskState() const
112 {
113  return this->taskState;
114 }
115 
117 gazebo::common::Time ScoringPlugin::ElapsedTime() const
118 {
119  return this->elapsedTime;
120 }
121 
123 gazebo::common::Time ScoringPlugin::RemainingTime() const
124 {
125  return this->remainingTime;
126 }
127 
130 {
131  if (this->taskState == "finished")
132  return;
133 
134  this->taskState = "finished";
135  this->OnFinished();
136 }
137 
140 {
141  // The vehicle might not be ready yet, let's try to get it.
142  #if GAZEBO_MAJOR_VERSION >= 8
143  if (!this->vehicleModel)
144  this->vehicleModel = this->world->ModelByName(this->vehicleName);
145  #else
146  if (!this->vehicleModel)
147  this->vehicleModel = this->world->GetModel(this->vehicleName);
148  #endif
149 
150  this->UpdateTime();
151  this->UpdateTaskState();
152  this->PublishStats();
153 }
154 
157 {
158  #if GAZEBO_MAJOR_VERSION >= 8
159  this->currentTime = this->world->SimTime();
160  #else
161  this->currentTime = this->world->GetSimTime();
162  #endif
163 
164  if (this->taskState == "running")
165  {
166  this->elapsedTime = this->currentTime - this->runningTime;
167  this->remainingTime = this->finishTime - this->currentTime;
168  this->timedOut = this->remainingTime <= gazebo::common::Time::Zero;
169  }
170 }
171 
174 {
175  if (this->taskState == "initial" &&
176  this->currentTime >= this->readyTime)
177  {
178  this->taskState = "ready";
179  this->ReleaseVehicle();
180  this->OnReady();
181  return;
182  }
183 
184  if (this->taskState == "ready" &&
185  this->currentTime >= this->runningTime)
186  {
187  this->taskState = "running";
188  this->OnRunning();
189  return;
190  }
191 
192  if (this->taskState == "running" && this->timedOut)
193  {
194  this->taskState = "finished";
195  this->OnFinished();
196  return;
197  }
198 }
199 
202 {
203  this->taskMsg.state = this->taskState;
204  this->taskMsg.elapsed_time.fromSec(this->elapsedTime.Double());
205  this->taskMsg.remaining_time.fromSec(this->remainingTime.Double());
206  this->taskMsg.timed_out = this->timedOut;
207  this->taskMsg.score = this->score;
208 }
209 
212 {
213  this->UpdateTaskMessage();
214 
215  // We publish stats at 1Hz.
216  if (this->currentTime - this->lastStatsSent >= gazebo::common::Time(1, 0))
217  {
218  this->taskPub.publish(this->taskMsg);
219  this->lastStatsSent = this->currentTime;
220  }
221 }
222 
225 {
226  if (!this->vehicleModel || this->lockJointNames.empty())
227  return;
228 
229  for (auto jointName : this->lockJointNames)
230  {
231  auto joint = this->vehicleModel->GetJoint(jointName);
232  if (joint)
233  joint->Detach();
234  else
235  gzerr << "Unable to release [" << jointName << "]" << std::endl;
236  }
237 
238  this->lockJointNames.clear();
239 
240  gzmsg << "Vehicle released" << std::endl;
241 }
242 
245 {
246  gzmsg << "OnReady" << std::endl;
247 }
248 
251 {
252  gzmsg << "OnRunning" << std::endl;
253 }
254 
257 {
258  gzmsg << ros::Time::now() << " OnFinished" << std::endl;
259  // If a timeoutScore was specified, use it.
260  if (this->timedOut && this->timeoutScore > 0.0)
261  {
262  this->score = this->timeoutScore;
263  }
264  this->UpdateTaskMessage();
265  this->taskPub.publish(this->taskMsg);
266  this->Exit();
267 }
268 
271 {
272 }
273 
275 void ScoringPlugin::OnCollisionMsg(ConstContactsPtr &_contacts) {
276  // loop though collisions, if any include the wamv, increment collision
277  // counter
278  for (unsigned int i = 0; i < _contacts->contact_size(); ++i) {
279  std::string wamvCollisionStr1 = _contacts->contact(i).collision1();
280  std::string wamvCollisionStr2 = _contacts->contact(i).collision2();
281  std::string wamvCollisionSubStr1 =
282  wamvCollisionStr1.substr(0, wamvCollisionStr1.find("lump"));
283  std::string wamvCollisionSubStr2 =
284  wamvCollisionStr2.substr(0, wamvCollisionStr2.find("lump"));
285 
286  bool isWamvHit =
287  wamvCollisionSubStr1 == "wamv::base_link::base_link_fixed_joint_" ||
288  wamvCollisionSubStr2 == "wamv::base_link::base_link_fixed_joint_";
289  bool isHitBufferPassed = this->currentTime - this->lastCollisionTime >
290  gazebo::common::Time(CollisionBuffer, 0);
291 
292  // publish a Contact MSG
293  if (isWamvHit && this->debug) {
294  this->contactMsg.header.stamp = ros::Time::now();
295  this->contactMsg.collision1 = _contacts->contact(i).collision1();
296  this->contactMsg.collision2 = _contacts->contact(i).collision2();
297  this->contactPub.publish(this->contactMsg);
298  }
299 
300  if (isWamvHit && isHitBufferPassed) {
301  this->collisionCounter++;
302  gzmsg << "[" << this->collisionCounter
303  << "] New collision counted between ["
304  << _contacts->contact(i).collision1() << "] and ["
305  << _contacts->contact(i).collision2() << "]" << std::endl;
306  // Uncomment to get details of collisions
307  // gzdbg << _contacts->contact(i).DebugString() << std::endl;
308 #if GAZEBO_MAJOR_VERSION >= 8
309  this->lastCollisionTime = this->world->SimTime();
310 #else
311  this->lastCollisionTime = this->world->GetSimTime();
312 #endif
313  this->collisionList.push_back(
314  _contacts->contact(i).collision1() +
315  std::string(" || ") + _contacts->contact(i).collision2());
316  this->collisionTimestamps.push_back(this->currentTime);
317  this->OnCollision();
318  return;
319  }
320  }
321 }
322 
325 {
326  // This is a required element.
327  if (!this->sdf->HasElement("vehicle"))
328  {
329  gzerr << "Unable to find <vehicle> element in SDF." << std::endl;
330  return false;
331  }
332  this->vehicleName = this->sdf->Get<std::string>("vehicle");
333 
334  // This is a required element.
335  if (!this->sdf->HasElement("task_name"))
336  {
337  gzerr << "Unable to find <task_name> element in SDF." << std::endl;
338  return false;
339  }
340  this->taskName = this->sdf->Get<std::string>("task_name");
341 
342  // This is an optional element.
343  if (this->sdf->HasElement("task_info_topic"))
344  this->taskInfoTopic = this->sdf->Get<std::string>("task_info_topic");
345 
346  // This is an optional element.
347  if (this->sdf->HasElement("contact_debug_topic"))
348  this->contactDebugTopic = this->sdf->Get<std::string>
349  ("contact_debug_topic");
350 
351  // This is an optional element.
352  if (this->sdf->HasElement("initial_state_duration"))
353  {
354  double value = this->sdf->Get<double>("initial_state_duration");
355  if (value < 0)
356  {
357  gzerr << "<initial_state_duration> value should not be negative."
358  << std::endl;
359  return false;
360  }
361  this->initialStateDuration = value;
362  }
363 
364  // This is an optional element.
365  if (this->sdf->HasElement("ready_state_duration"))
366  {
367  double value = this->sdf->Get<double>("ready_state_duration");
368  if (value < 0)
369  {
370  gzerr << "<ready_state_duration> value should not be negative."
371  << std::endl;
372  return false;
373  }
374 
375  this->readyStateDuration = value;
376  }
377 
378  // This is an optional element.
379  if (this->sdf->HasElement("running_state_duration"))
380  {
381  double value = this->sdf->Get<double>("running_state_duration");
382  if (value < 0)
383  {
384  gzerr << "<running_state_duration> value should not be negative."
385  << std::endl;
386  return false;
387  }
388  this->runningStateDuration = value;
389  }
390 
391  // This is an optional element.
392  if (this->sdf->HasElement("collision_buffer"))
393  {
394  this->CollisionBuffer = this->sdf->Get<float>("collision_buffer");
395  }
396 
397  return this->ParseJoints();
398 }
399 
402 {
403  // Optional element.
404  if (this->sdf->HasElement("release_joints"))
405  {
406  auto releaseJointsElem = this->sdf->GetElement("release_joints");
407 
408  // We need at least one joint.
409  if (!releaseJointsElem->HasElement("joint"))
410  {
411  gzerr << "Unable to find <joint> element in SDF." << std::endl;
412  return false;
413  }
414 
415  auto jointElem = releaseJointsElem->GetElement("joint");
416 
417  // Parse a new joint to be released.
418  while (jointElem)
419  {
420  // The joint's name.
421  if (!jointElem->HasElement("name"))
422  {
423  gzerr << "Unable to find <name> element in SDF." << std::endl;
424  return false;
425  }
426 
427  const std::string jointName = jointElem->Get<std::string>("name");
428  this->lockJointNames.push_back(jointName);
429 
430  // Parse the next joint.
431  jointElem = jointElem->GetNextElement("joint");
432  }
433  }
434 
435  return true;
436 }
437 
439 {
440  if (char* env = std::getenv("VRX_EXIT_ON_COMPLETION"))
441  {
442  if (std::string(env) == "true")
443  {
444  // shutdown gazebo
445  gazebo::msgs::ServerControl msg;
446  msg.set_stop(true);
447  this->serverControlPub->Publish(msg);
448  // shutdown gazebo
449  if (ros::ok())
450  ros::shutdown();
451  }
452  }
453  else
454  {
455  gzerr << "VRX_EXIT_ON_COMPLETION not set"
456  << " will not shutdown on ScoringPlugin::Exit()"
457  << std::endl;
458  ROS_ERROR_STREAM("VRX_EXIT_ON_COMPLETION not set, will" <<
459  "not shutdown on ScoringPlugin::Exit()");
460  }
461  return;
462 }
463 
464 void ScoringPlugin::SetTimeoutScore(double _timeoutScore)
465 {
466  this->timeoutScore = _timeoutScore;
467 }
468 
470 {
471  return this->timeoutScore;
472 }
473 
475 {
476  return this->runningStateDuration;
477 }
msg
void UpdateTime()
Update all time-related variables.
std::string TaskName() const
Get the task name.
gazebo::common::Time lastCollisionTime
Last collision time.
double Score() const
Get the current score.
void publish(const boost::shared_ptr< M > &message) const
void SetTimeoutScore(double _timeoutScore)
Set the score in case of timeout.
virtual void ReleaseVehicle()
Tries to release the vehicle in case is locked.
std::vector< std::string > lockJointNames
The name of the joints to be dettached during ReleaseVehicle().
float CollisionBuffer
Collision buffer.
std::string contactDebugTopic
Topic where debug collision is published.
gazebo::common::Time currentTime
Current time (simulation).
bool debug
Bool flag for debug.
void UpdateTaskMessage()
Update the task stats message.
std::vector< gazebo::common::Time > collisionTimestamps
Collisions timestamps.
std::string TaskState() const
Get the task state.
gazebo::common::Time remainingTime
Remaining time since the start of the task (running state).
double timeoutScore
Score in case of timeout - added for Navigation task.
void Load(gazebo::physics::WorldPtr _world, sdf::ElementPtr _sdf)
double runningStateDuration
Duration (seconds) of the running state (max task time).
void Exit()
Shutdown Gazebo and ROS.
void Finish()
Finish the current task. This will set the "finished" flag in the task message to true...
ros::Publisher taskPub
Publisher for the task state.
virtual void OnRunning()
Callback executed when the task state transition into "running".
void UpdateTaskState()
Update the state of the current task.
std::vector< std::string > collisionList
Collision list.
gazebo::common::Time ElapsedTime() const
Elapsed time in the running state.
bool ParseSDFParameters()
Parse all SDF parameters.
std::string taskState
The task state.
gazebo::common::Time elapsedTime
void PublishStats()
Publish the task stats over a ROS topic.
gazebo::transport::NodePtr gzNode
gazebo node pointer
std::unique_ptr< ros::NodeHandle > rosNode
ROS node handle.
vrx_gazebo::Contact contactMsg
ROS Contact Msg.
void Update()
Callback executed at every world update.
ROSCPP_DECL bool ok()
vrx_gazebo::Task taskMsg
The next task message to be published.
gazebo::common::Time runningTime
Absolute time specifying the start of the running state.
gazebo::common::Time readyTime
Absolute time specifying the start of the ready state.
gazebo::physics::WorldPtr world
A world pointer.
gazebo::common::Time finishTime
Absolute time specifying the start of the finish state.
gazebo::physics::ModelPtr vehicleModel
Pointer to the vehicle to score.
double initialStateDuration
Duration (seconds) of the initial state.
gazebo::common::Time lastStatsSent
Time at which the last message was sent.
double GetTimeoutScore()
Get the timeoutScore.
gazebo::event::ConnectionPtr updateConnection
Pointer to the update event connection.
gazebo::common::Time RemainingTime() const
Remaining time in the running state.
gazebo::transport::SubscriberPtr collisionSub
Collision detection node subscriber.
void OnCollisionMsg(ConstContactsPtr &_contacts)
Callback function when collision occurs in the world.
static Time now()
ROSCPP_DECL void shutdown()
double readyStateDuration
Duration (seconds) of the ready state.
std::string taskName
The name of the task.
std::string taskInfoTopic
Topic where the task stats are published.
virtual void OnFinished()
Callback executed when the task state transition into "finished".
bool timedOut
Whether the current task has timed out or not.
#define ROS_ERROR_STREAM(args)
ros::Publisher contactPub
Publisher for the collision.
ScoringPlugin()
Class constructor.
bool ParseJoints()
Parse the joints section of the SDF block.
gazebo::transport::PublisherPtr serverControlPub
gazebo server control publisher
int collisionCounter
Collisions counter.
void SetScore(double _newScore)
Set the score.
virtual void OnReady()
Callback executed when the task state transition into "ready".
std::string vehicleName
The name of the vehicle to score.
virtual void OnCollision()
Callback executed when a collision is detected for the WAMV.
double GetRunningStateDuration()
Get running duration.
double score
The score.


vrx_gazebo
Author(s): Brian Bingham , Carlos Aguero
autogenerated on Thu May 7 2020 03:54:56