fake_gps.cpp
Go to the documentation of this file.
1 
11 /*
12  * Copyright 2015 Christoph Tobler.
13  * Copyright 2017 Nuno Marques.
14  * Copyright 2019 Amilcar Lucas.
15  *
16  * This file is part of the mavros package and subject to the license terms
17  * in the top-level LICENSE file of the mavros repository.
18  * https://github.com/mavlink/mavros/tree/master/LICENSE.md
19  */
20 
21 #include <mavros/mavros_plugin.h>
22 #include <mavros/setpoint_mixin.h>
24 #include <GeographicLib/Geocentric.hpp>
25 #include <GeographicLib/Geoid.hpp>
26 
27 #include <geometry_msgs/PoseStamped.h>
28 #include <geometry_msgs/PoseWithCovarianceStamped.h>
29 #include <geometry_msgs/TransformStamped.h>
30 
31 // the number of GPS leap seconds
32 #define GPS_LEAPSECONDS_MILLIS 18000ULL
33 
34 #define MSEC_PER_WEEK (7ULL * 86400ULL * 1000ULL)
35 #define UNIX_OFFSET_MSEC (17000ULL * 86400ULL + 52ULL * 10ULL * MSEC_PER_WEEK - GPS_LEAPSECONDS_MILLIS)
36 
37 namespace mavros {
38 namespace extra_plugins {
39 using mavlink::common::GPS_FIX_TYPE;
40 using mavlink::common::GPS_INPUT_IGNORE_FLAGS;
41 
51  private plugin::TF2ListenerMixin<FakeGPSPlugin> {
52 public:
53  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
54 
56  fp_nh("~fake_gps"),
57  gps_rate(5.0),
58  // WGS-84 ellipsoid (a - equatorial radius, f - flattening of ellipsoid)
59  earth(GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f()),
60  use_mocap(true),
61  use_vision(false),
62  use_hil_gps(true),
63  mocap_transform(true),
64  mocap_withcovariance(false),
65  tf_listen(false),
66  eph(2.0),
67  epv(2.0),
68  horiz_accuracy(0.0f),
69  vert_accuracy(0.0f),
70  speed_accuracy(0.0f),
71  gps_id(0),
73  fix_type(GPS_FIX_TYPE::NO_GPS),
74  tf_rate(10.0),
75  map_origin(0.0, 0.0, 0.0)
76  { }
77 
78  void initialize(UAS &uas_) override
79  {
81 
82  double _gps_rate;
83  double origin_lat, origin_lon, origin_alt;
84 
85  last_pos_time = ros::Time(0.0);
86 
87  // general params
88  fp_nh.param<int>("gps_id", gps_id, 0);
89  int ft_i;
90  fp_nh.param<int>("fix_type", ft_i, utils::enum_value(GPS_FIX_TYPE::NO_GPS));
91  fix_type = static_cast<GPS_FIX_TYPE>(ft_i);
92  fp_nh.param("gps_rate", _gps_rate, 5.0); // GPS data rate of 5hz
93  gps_rate = _gps_rate;
94  fp_nh.param("eph", eph, 2.0);
95  fp_nh.param("epv", epv, 2.0);
96  fp_nh.param<float>("horiz_accuracy", horiz_accuracy, 0.0f);
97  fp_nh.param<float>("vert_accuracy", vert_accuracy, 0.0f);
98  fp_nh.param<float>("speed_accuracy", speed_accuracy, 0.0f);
99  fp_nh.param<int>("satellites_visible", satellites_visible, 5);
100 
101  // default origin/starting point: Zürich geodetic coordinates
102  fp_nh.param("geo_origin/lat", origin_lat, 47.3667); // [degrees]
103  fp_nh.param("geo_origin/lon", origin_lon, 8.5500); // [degrees]
104  fp_nh.param("geo_origin/alt", origin_alt, 408.0); // [meters - height over the WGS-84 ellipsoid]
105 
106  // init map origin with geodetic coordinates
107  map_origin = {origin_lat, origin_lon, origin_alt};
108 
109  try {
114  earth.Forward(map_origin.x(), map_origin.y(), map_origin.z(),
115  ecef_origin.x(), ecef_origin.y(), ecef_origin.z());
116  }
117  catch (const std::exception& e) {
118  ROS_INFO_STREAM("FGPS: Caught exception: " << e.what() << std::endl);
119  }
120 
121  // source set params
122  fp_nh.param("use_mocap", use_mocap, true); // listen to MoCap source
123  fp_nh.param("mocap_transform", mocap_transform, true); // listen to MoCap source (TransformStamped if true; PoseStamped if false)
124  fp_nh.param("mocap_withcovariance", mocap_withcovariance, false); // ~mocap/pose uses PoseWithCovarianceStamped Message
125 
126  fp_nh.param("tf/listen", tf_listen, false); // listen to TF source
127  fp_nh.param("use_vision", use_vision, false); // listen to Vision source
128  fp_nh.param("use_hil_gps", use_hil_gps, true); // send HIL_GPS MAVLink messages if true,
129  // send GPS_INPUT mavlink messages if false
130 
131  // tf params
132  fp_nh.param<std::string>("tf/frame_id", tf_frame_id, "map");
133  fp_nh.param<std::string>("tf/child_frame_id", tf_child_frame_id, "fix");
134  fp_nh.param("tf/rate_limit", tf_rate, 10.0);
135 
136  if (use_mocap) {
137  if (mocap_transform) { // MoCap data in TransformStamped msg
138  mocap_tf_sub = fp_nh.subscribe("mocap/tf", 10, &FakeGPSPlugin::mocap_tf_cb, this);
139  }
140  else if (mocap_withcovariance) {// MoCap data in PoseWithCovarianceStamped msg
141  mocap_pose_cov_sub = fp_nh.subscribe("mocap/pose_cov", 10, &FakeGPSPlugin::mocap_pose_cov_cb, this);
142  }
143  else { // MoCap data in PoseStamped msg
144  mocap_pose_sub = fp_nh.subscribe("mocap/pose", 10, &FakeGPSPlugin::mocap_pose_cb, this);
145  }
146  }
147  else if (use_vision) { // Vision data in PoseStamped msg
149  }
150  else if (tf_listen) { // Pose aquired from TF Listener
151  ROS_INFO_STREAM_NAMED("fake_gps", "Listen to transform " << tf_frame_id
152  << " -> " << tf_child_frame_id);
153  tf2_start("FakeGPSVisionTF", &FakeGPSPlugin::transform_cb);
154  }
155  else {
156  ROS_ERROR_NAMED("fake_gps", "No pose source!");
157  }
158  }
159 
161  {
162  return { /* Rx disabled */ };
163  }
164 
165 private:
166  friend class TF2ListenerMixin;
168 
171 
172  // Constructor for a ellipsoid
173  GeographicLib::Geocentric earth;
174 
179 
180  bool use_mocap;
181  bool use_vision;
182  bool use_hil_gps;
185  bool tf_listen;
186 
187  double eph, epv;
191  int gps_id;
193  GPS_FIX_TYPE fix_type;
194 
195  double tf_rate;
196  std::string tf_frame_id;
197  std::string tf_child_frame_id;
199 
200  Eigen::Vector3d map_origin;
201  Eigen::Vector3d ecef_origin;
202  Eigen::Vector3d old_ecef;
203  double old_stamp;
204 
205  /* -*- mid-level helpers and low-level send -*- */
206 
210  void send_fake_gps(const ros::Time &stamp, const Eigen::Vector3d &ecef_offset) {
211  // Throttle incoming messages to 5hz
212  if ((ros::Time::now() - last_pos_time) < ros::Duration(gps_rate)) {
213  return;
214  }
215  last_pos_time = ros::Time::now();
216 
217  Eigen::Vector3d geodetic;
218  Eigen::Vector3d current_ecef(ecef_origin.x() + ecef_offset.x(),
219  ecef_origin.y() + ecef_offset.y(),
220  ecef_origin.z() + ecef_offset.z());
221 
222  try {
223  earth.Reverse(current_ecef.x(), current_ecef.y(), current_ecef.z(),
224  geodetic.x(), geodetic.y(), geodetic.z());
225  }
226  catch (const std::exception& e) {
227  ROS_INFO_STREAM("FGPS: Caught exception: " << e.what() << std::endl);
228  }
229 
230  Eigen::Vector3d vel = (old_ecef - current_ecef) / (stamp.toSec() - old_stamp); // [m/s]
231 
232  // store old values
233  old_stamp = stamp.toSec();
234  old_ecef = current_ecef;
235 
236  if (use_hil_gps) {
243  mavlink::common::msg::HIL_GPS hil_gps {};
244 
245  vel *= 1e2; // [cm/s]
246 
247  // compute course over ground
248  double cog;
249  if (vel.x() == 0 && vel.y() == 0) {
250  cog = 0;
251  }
252  else if (vel.x() >= 0 && vel.y() < 0) {
253  cog = M_PI * 5 / 2 - atan2(vel.x(), vel.y());
254  }
255  else {
256  cog = M_PI / 2 - atan2(vel.x(), vel.y());
257  }
258 
259  // Fill in and send message
260  hil_gps.time_usec = stamp.toNSec() / 1000; // [useconds]
261  hil_gps.lat = geodetic.x() * 1e7; // [degrees * 1e7]
262  hil_gps.lon = geodetic.y() * 1e7; // [degrees * 1e7]
263  hil_gps.alt = (geodetic.z() + GeographicLib::Geoid::ELLIPSOIDTOGEOID *
264  (*m_uas->egm96_5)(geodetic.x(), geodetic.y())) * 1e3; // [meters * 1e3]
265  hil_gps.vel = vel.block<2, 1>(0, 0).norm(); // [cm/s]
266  hil_gps.vn = vel.x(); // [cm/s]
267  hil_gps.ve = vel.y(); // [cm/s]
268  hil_gps.vd = vel.z(); // [cm/s]
269  hil_gps.cog = cog * 1e2; // [degrees * 1e2]
270  hil_gps.eph = eph * 1e2; // [cm]
271  hil_gps.epv = epv * 1e2; // [cm]
272  hil_gps.fix_type = utils::enum_value(fix_type);;
273  hil_gps.satellites_visible = satellites_visible;
274 
275  UAS_FCU(m_uas)->send_message_ignore_drop(hil_gps);
276  }
277  else {
282  mavlink::common::msg::GPS_INPUT gps_input {};
283 
284  // Fill in and send message
285  gps_input.time_usec = stamp.toNSec() / 1000; // [useconds]
286  gps_input.gps_id = gps_id; //
287  gps_input.ignore_flags = 0;
288  if (speed_accuracy == 0.0f)
289  gps_input.ignore_flags |= utils::enum_value(GPS_INPUT_IGNORE_FLAGS::FLAG_SPEED_ACCURACY);
290  if (eph == 0.0f)
291  gps_input.ignore_flags |= utils::enum_value(GPS_INPUT_IGNORE_FLAGS::FLAG_HDOP);
292  if (epv == 0.0f)
293  gps_input.ignore_flags |= utils::enum_value(GPS_INPUT_IGNORE_FLAGS::FLAG_VDOP);
294  if (fabs(vel.x()) <= 0.01f && fabs(vel.y()) <= 0.01f)
295  gps_input.ignore_flags |= utils::enum_value(GPS_INPUT_IGNORE_FLAGS::FLAG_VEL_HORIZ);
296  if (fabs(vel.z()) <= 0.01f)
297  gps_input.ignore_flags |= utils::enum_value(GPS_INPUT_IGNORE_FLAGS::FLAG_VEL_VERT);
298  int64_t tdiff = (gps_input.time_usec / 1000) - UNIX_OFFSET_MSEC;
299  gps_input.time_week = tdiff / MSEC_PER_WEEK;
300  gps_input.time_week_ms = tdiff - (gps_input.time_week * MSEC_PER_WEEK);
301  gps_input.speed_accuracy = speed_accuracy; // [m/s] TODO how can this be dynamicaly calculated ???
302  gps_input.horiz_accuracy = horiz_accuracy; // [m] will either use the static parameter value, or the dynamic covariance from function mocap_pose_cov_cb() bellow
303  gps_input.vert_accuracy = vert_accuracy;// [m] will either use the static parameter value, or the dynamic covariance from function mocap_pose_cov_cb() bellow
304  gps_input.lat = geodetic.x() * 1e7; // [degrees * 1e7]
305  gps_input.lon = geodetic.y() * 1e7; // [degrees * 1e7]
306  gps_input.alt = (geodetic.z() + GeographicLib::Geoid::ELLIPSOIDTOGEOID *
307  (*m_uas->egm96_5)(geodetic.x(), geodetic.y())); // [meters]
308  gps_input.vn = vel.x(); // [m/s]
309  gps_input.ve = vel.y(); // [m/s]
310  gps_input.vd = vel.z(); // [m/s]
311  gps_input.hdop = eph; // [m]
312  gps_input.vdop = epv; // [m]
313  gps_input.fix_type = utils::enum_value(fix_type);;
314  gps_input.satellites_visible = satellites_visible;
315 
316  UAS_FCU(m_uas)->send_message_ignore_drop(gps_input);
317  }
318  }
319 
320  /* -*- callbacks -*- */
322  {
323  Eigen::Affine3d pos_enu;
324  tf::transformMsgToEigen(trans->transform, pos_enu);
325 
326  send_fake_gps(trans->header.stamp, ftf::transform_frame_enu_ecef(Eigen::Vector3d(pos_enu.translation()), map_origin));
327  }
328 
330  {
331  Eigen::Affine3d pos_enu;
332  tf::poseMsgToEigen(req->pose.pose, pos_enu);
333  horiz_accuracy = (req->pose.covariance[0] + req->pose.covariance[7]) / 2.0f;
334  vert_accuracy = req->pose.covariance[14];
335 
336  send_fake_gps(req->header.stamp, ftf::transform_frame_enu_ecef(Eigen::Vector3d(pos_enu.translation()), map_origin));
337  }
338 
340  {
341  Eigen::Affine3d pos_enu;
342  tf::poseMsgToEigen(req->pose, pos_enu);
343 
344  send_fake_gps(req->header.stamp, ftf::transform_frame_enu_ecef(Eigen::Vector3d(pos_enu.translation()), map_origin));
345  }
346 
348  {
349  Eigen::Affine3d pos_enu;
350  tf::poseMsgToEigen(req->pose, pos_enu);
351 
352  send_fake_gps(req->header.stamp, ftf::transform_frame_enu_ecef(Eigen::Vector3d(pos_enu.translation()), map_origin));
353  }
354 
355  void transform_cb(const geometry_msgs::TransformStamped &trans)
356  {
357  Eigen::Affine3d pos_enu;
358 
359  tf::transformMsgToEigen(trans.transform, pos_enu);
360 
361  send_fake_gps(trans.header.stamp, ftf::transform_frame_enu_ecef(Eigen::Vector3d(pos_enu.translation()), map_origin));
362  }
363 };
364 } // namespace extra_plugins
365 } // namespace mavros
366 
void mocap_pose_cb(const geometry_msgs::PoseStamped::ConstPtr &req)
Definition: fake_gps.cpp:339
std::shared_ptr< MAVConnInterface const > ConstPtr
GeographicLib::Geocentric earth
Definition: fake_gps.cpp:173
void mocap_tf_cb(const geometry_msgs::TransformStamped::ConstPtr &trans)
Definition: fake_gps.cpp:321
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
void send_fake_gps(const ros::Time &stamp, const Eigen::Vector3d &ecef_offset)
Send fake GPS coordinates through HIL_GPS or GPS_INPUT Mavlink msg.
Definition: fake_gps.cpp:210
bool use_hil_gps
set use of use_hil_gps MAVLink messages
Definition: fake_gps.cpp:182
void initialize(UAS &uas_) override
Definition: fake_gps.cpp:78
void tf2_start(const char *_thd_name, void(FakeGPSPlugin::*cbp)(const geometry_msgs::TransformStamped &))
#define ROS_INFO_STREAM_NAMED(name, args)
bool mocap_transform
set use of mocap data (TransformStamped msg)
Definition: fake_gps.cpp:183
Eigen::Vector3d map_origin
geodetic origin [lla]
Definition: fake_gps.cpp:200
Subscriptions get_subscriptions() override
Definition: fake_gps.cpp:160
#define MSEC_PER_WEEK
Definition: fake_gps.cpp:34
bool param(const std::string &param_name, T &param_val, const T &default_val) const
EIGEN_MAKE_ALIGNED_OPERATOR_NEW FakeGPSPlugin()
Definition: fake_gps.cpp:55
std::shared_ptr< GeographicLib::Geoid > egm96_5
void mocap_pose_cov_cb(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr &req)
Definition: fake_gps.cpp:329
#define UAS_FCU(uasobjptr)
double old_stamp
previous stamp [s]
Definition: fake_gps.cpp:203
uint64_t toNSec() const
void transform_cb(const geometry_msgs::TransformStamped &trans)
Definition: fake_gps.cpp:355
T transform_frame_enu_ecef(const T &in, const T &map_origin)
Eigen::Vector3d old_ecef
previous geocentric position [m]
Definition: fake_gps.cpp:202
bool tf_listen
set use of TF Listener data
Definition: fake_gps.cpp:185
void transformMsgToEigen(const geometry_msgs::Transform &m, Eigen::Affine3d &e)
#define ROS_INFO_STREAM(args)
std::vector< HandlerInfo > Subscriptions
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
Eigen::Vector3d ecef_origin
geocentric origin [m]
Definition: fake_gps.cpp:201
#define ROS_ERROR_NAMED(name,...)
static Time now()
void vision_cb(const geometry_msgs::PoseStamped::ConstPtr &req)
Definition: fake_gps.cpp:347
void initialize(UAS &uas_) override
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
bool mocap_withcovariance
~mocap/pose uses PoseWithCovarianceStamped Message
Definition: fake_gps.cpp:184
bool use_vision
set use of vision data
Definition: fake_gps.cpp:181
#define UNIX_OFFSET_MSEC
Definition: fake_gps.cpp:35
constexpr std::underlying_type< _T >::type enum_value(_T e)
bool use_mocap
set use of mocap data (PoseStamped msg)
Definition: fake_gps.cpp:180


mavros_extras
Author(s): Vladimir Ermakov , Amilcar Lucas
autogenerated on Tue Jun 1 2021 02:36:36