wayfinding_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 <geographic_msgs/GeoPoseStamped.h>
19 #include <geographic_msgs/GeoPath.h>
20 #include <std_msgs/Float64.h>
21 #include <std_msgs/Float64MultiArray.h>
22 #include <std_msgs/String.h>
23 #include <cmath>
24 #include <gazebo/common/Console.hh>
25 #include <gazebo/common/SphericalCoordinates.hh>
26 #include <ignition/math/Quaternion.hh>
27 #include <ignition/math/Vector3.hh>
28 #include <gazebo/physics/Model.hh>
29 
32 
35  : waypointMarkers("waypoint_marker")
36 {
37  gzmsg << "Wayfinding scoring plugin loaded" << std::endl;
38  this->timer.Stop();
39  this->timer.Reset();
40 }
41 
43 void WayfindingScoringPlugin::Load(gazebo::physics::WorldPtr _world,
44  sdf::ElementPtr _sdf)
45 {
46  ScoringPlugin::Load(_world, _sdf);
47  this->sdf = _sdf;
48  gzmsg << "Task [" << this->TaskName() << "]" << std::endl;
49 
50  // A waypoints element is required.
51  if (!this->sdf->HasElement("waypoints"))
52  {
53  gzerr << "Unable to find <waypoints> element in SDF." << std::endl;
54  return;
55  }
56  auto waypointsElem = this->sdf->GetElement("waypoints");
57 
58  // We need at least one waypoint
59  if (!waypointsElem->HasElement("waypoint"))
60  {
61  gzerr << "Unable to find <waypoint> element in SDF." << std::endl;
62  return;
63  }
64  auto waypointElem = waypointsElem->GetElement("waypoint");
65 
66  while (waypointElem)
67  {
68  ignition::math::Vector3d latlonyaw =
69  waypointElem->Get<ignition::math::Vector3d>("pose");
70 
71  // Convert lat/lon to local
72  // snippet from UUV Simulator SphericalCoordinatesROSInterfacePlugin.cc
73  ignition::math::Vector3d scVec(latlonyaw.X(), latlonyaw.Y(), 0.0);
74 
75 #if GAZEBO_MAJOR_VERSION >= 8
76  ignition::math::Vector3d cartVec =
77  _world->SphericalCoords()->LocalFromSpherical(scVec);
78 #else
79  ignition::math::Vector3d cartVec =
80  _world->GetSphericalCoordinates()->LocalFromSpherical(scVec);
81 #endif
82 
83  cartVec.Z() = latlonyaw.Z();
84 
85  // Set up relevant vectors
86  this->sphericalWaypoints.push_back(latlonyaw);
87  this->localWaypoints.push_back(cartVec);
88 
89  // Print some debugging messages
90  gzmsg << "Waypoint, Spherical: Lat = " << latlonyaw.X()
91  << " Lon = " << latlonyaw.Y() << std::endl;
92  gzmsg << "Waypoint, Local: X = " << cartVec.X()
93  << " Y = " << cartVec.Y() << " Yaw = " << cartVec.Z() << std::endl;
94 
95  waypointElem = waypointElem->GetNextElement("waypoint");
96  }
97 
98  // Setup ROS node and publisher
99  this->rosNode.reset(new ros::NodeHandle());
100  this->waypointsPub =
101  this->rosNode->advertise<geographic_msgs::GeoPath>(
102  this->waypointsTopic, 10, true);
103 
104  this->minErrorsPub =
105  this->rosNode->advertise<std_msgs::Float64MultiArray>(
106  this->minErrorsTopic, 100);
107 
108  this->meanErrorPub =
109  this->rosNode->advertise<std_msgs::Float64>(
110  this->meanErrorTopic, 100);
111 
112  this->updateConnection = gazebo::event::Events::ConnectWorldUpdateBegin(
113  std::bind(&WayfindingScoringPlugin::Update, this));
114 
115  // Publish waypoint markers
116  if (_sdf->HasElement("markers"))
117  {
118  this->waypointMarkers.Load(_sdf->GetElement("markers"));
119  if (this->waypointMarkers.IsAvailable())
120  {
121  int markerId = 0;
122  for (const auto waypoint : this->localWaypoints)
123  {
124  if (!this->waypointMarkers.DrawMarker(markerId, waypoint.X(),
125  waypoint.Y(), waypoint.Z(), std::to_string(markerId)))
126  {
127  gzerr << "Error creating visual marker" << std::endl;
128  }
129  markerId++;
130  }
131  }
132  else
133  {
134  gzwarn << "Cannot display gazebo markers (Gazebo version < 8)"
135  << std::endl;
136  }
137  }
138 }
139 
142 {
143  // The vehicle might not be ready yet, let's try to get it.
144  if (!this->vehicleModel)
145  {
146  #if GAZEBO_MAJOR_VERSION >= 8
147  this->vehicleModel = this->world->ModelByName(this->vehicleName);
148  #else
149  this->vehicleModel = this->world->GetModel(this->vehicleName);
150  #endif
151  if (!this->vehicleModel)
152  return;
153  }
154 
155  // Nothing to do if the task is not in "running" state.
156  if (this->ScoringPlugin::TaskState() != "running")
157  return;
158 
159  std_msgs::Float64MultiArray minErrorsMsg;
160  std_msgs::Float64 meanErrorMsg;
161 
162  #if GAZEBO_MAJOR_VERSION >= 8
163  const auto robotPose = this->vehicleModel->WorldPose();
164  #else
165  const auto robotPose = this->vehicleModel->GetWorldPose().Ign();
166  #endif
167  double currentHeading = robotPose.Rot().Euler().Z();
168 
169  double currentTotalError = 0;
170 
171  for (unsigned i = 0; i < this->localWaypoints.size(); ++i)
172  {
173  const ignition::math::Vector3d wp = this->localWaypoints[i];
174  double dx = wp.X() - robotPose.Pos().X();
175  double dy = wp.Y() - robotPose.Pos().Y();
176  double dhdg = abs(wp.Z() - currentHeading);
177  double headError = 1 - abs(dhdg - M_PI)/M_PI;
178 
179  double poseError = sqrt(pow(dx, 2) + pow(dy, 2)) + headError;
180 
181  // If this is the first time through, minError == poseError
182  if (i == this->minErrors.size())
183  {
184  this->minErrors.push_back(poseError);
185  }
186 
187  // If poseError is smaller than the minimum, update the minimum
188  if (poseError < this->minErrors.at(i))
189  {
190  this->minErrors.at(i) = poseError;
191  }
192 
193  // add current minimum to current total error
194  currentTotalError += this->minErrors.at(i);
195  }
196 
197  this->meanError = currentTotalError / this->localWaypoints.size();
198 
199  // Set up multi array dimensions
200  minErrorsMsg.layout.dim.push_back(std_msgs::MultiArrayDimension());
201  minErrorsMsg.layout.dim[0].label = "minimum errors";
202  minErrorsMsg.layout.dim[0].size = this->localWaypoints.size();
203  minErrorsMsg.layout.dim[0].stride = this->localWaypoints.size();
204 
205  minErrorsMsg.data = this->minErrors;
206  meanErrorMsg.data = this->meanError;
207 
208  // Publish at 1 Hz.
209  if (this->timer.GetElapsed() >= gazebo::common::Time(1.0))
210  {
211  this->minErrorsPub.publish(minErrorsMsg);
212  this->meanErrorPub.publish(meanErrorMsg);
213  this->timer.Reset();
214  this->timer.Start();
215  }
216 
217  this->ScoringPlugin::SetScore(this->meanError);
218 }
219 
222 {
223  gzmsg << "Publishing Waypoints" << std::endl;
224  geographic_msgs::GeoPoseStamped wp_msg;
225  geographic_msgs::GeoPath path_msg;
226 
227  path_msg.header.stamp = ros::Time::now();
228 
229  for (auto wp : this->sphericalWaypoints)
230  {
231  wp_msg.pose.position.latitude = wp.X();
232  wp_msg.pose.position.longitude = wp.Y();
233  wp_msg.pose.position.altitude = 0.0;
234 
235  const ignition::math::Quaternion<double> orientation(0.0, 0.0, wp.Z());
236 
237  wp_msg.pose.orientation.x = orientation.X();
238  wp_msg.pose.orientation.y = orientation.Y();
239  wp_msg.pose.orientation.z = orientation.Z();
240  wp_msg.pose.orientation.w = orientation.W();
241 
242  wp_msg.header.stamp = ros::Time::now();
243  path_msg.poses.push_back(wp_msg);
244  }
245  this->waypointsPub.publish(path_msg);
246 }
247 
250 {
251  gzmsg << "OnReady" << std::endl;
252  this->PublishWaypoints();
253 }
254 
255 
258 {
259  gzmsg << "OnRunning" << std::endl;
260  this->timer.Start();
261 }
262 
263 // Register plugin with gazebo
gazebo::event::ConnectionPtr updateConnection
Pointer to the update event connection.
double meanError
Current average minimum error for all waypoints.
std::string TaskName() const
Get the task name.
void PublishWaypoints()
Publish the waypoints through which the vehicle must navigate.
void publish(const boost::shared_ptr< M > &message) const
GZ_REGISTER_WORLD_PLUGIN(UsvWindPlugin)
bool IsAvailable()
Returns if markers are available for current system.
std::vector< double > minErrors
Vector containing current minimum 2D pose error achieved for each waypoint so far.
void OnReady() override
Callback executed when the task state transition into "ready".
std::string TaskState() const
Get the task state.
ros::Publisher meanErrorPub
Publisher for the current rms error.
std::unique_ptr< ros::NodeHandle > rosNode
ROS node handle.
void Load(gazebo::physics::WorldPtr _world, sdf::ElementPtr _sdf)
std::string minErrorsTopic
Topic where the current minimum pose error distance for each waypoint is published.
void Load(gazebo::physics::WorldPtr _world, sdf::ElementPtr _sdf)
ros::Publisher waypointsPub
Publisher for the goal.
std::string waypointsTopic
Topic where the list of waypoints is published.
void Update()
Callback executed at every world update.
ros::Publisher minErrorsPub
Publisher for the combined 2D pose error.
std::vector< ignition::math::Vector3d > localWaypoints
Vector containing waypoints as 3D vectors of doubles representing X Y yaw, where X and Y are local (G...
void Load(sdf::ElementPtr _sdf)
Load marker parameters from SDF.
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
gazebo::physics::WorldPtr world
A world pointer.
std::vector< ignition::math::Vector3d > sphericalWaypoints
Vector containing waypoints as 3D vectors of doubles representing Lattitude Longitude yaw...
gazebo::physics::ModelPtr vehicleModel
Pointer to the vehicle to score.
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
WaypointMarkers waypointMarkers
Waypoint visualization markers.
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
bool DrawMarker(int _marker_id, double _x, double _y, double _yaw, std::string _text="")
Draw waypoint marker in Gazebo.
static Time now()
std::string meanErrorTopic
Topic where the current average minimum error is published.
gazebo::common::Timer timer
Timer used to calculate the elapsed time docked in the bay.
A plugin for computing the score of the wayfinding navigation task. This plugin derives from the gene...
void SetScore(double _newScore)
Set the score.
void OnRunning() override
Callback executed when the task state transition into "running".
std::string vehicleName
The name of the vehicle to score.


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