global_position.cpp
Go to the documentation of this file.
1 
10 /*
11  * Copyright 2014,2017 Nuno Marques.
12  * Copyright 2015,2016 Vladimir Ermakov.
13  *
14  * This file is part of the mavros package and subject to the license terms
15  * in the top-level LICENSE file of the mavros repository.
16  * https://github.com/mavlink/mavros/tree/master/LICENSE.md
17  */
18 
19 #include <angles/angles.h>
20 #include <mavros/mavros_plugin.h>
22 #include <GeographicLib/Geocentric.hpp>
23 
24 #include <std_msgs/Float64.h>
25 #include <std_msgs/UInt32.h>
26 #include <nav_msgs/Odometry.h>
27 #include <sensor_msgs/NavSatFix.h>
28 #include <sensor_msgs/NavSatStatus.h>
29 #include <geometry_msgs/PoseStamped.h>
30 #include <geometry_msgs/TwistStamped.h>
31 #include <geometry_msgs/TransformStamped.h>
32 #include <geographic_msgs/GeoPointStamped.h>
33 
34 #include <mavros_msgs/HomePosition.h>
35 
36 namespace mavros {
37 namespace std_plugins {
46 public:
47  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
48 
50  gp_nh("~global_position"),
51  tf_send(false),
52  use_relative_alt(true),
53  is_map_init(false),
54  rot_cov(99999.0)
55  { }
56 
57  void initialize(UAS &uas_) override
58  {
59  PluginBase::initialize(uas_);
60 
61  // general params
62  gp_nh.param<std::string>("frame_id", frame_id, "map");
63  gp_nh.param<std::string>("child_frame_id", child_frame_id, "base_link");
64  gp_nh.param("rot_covariance", rot_cov, 99999.0);
65  gp_nh.param("gps_uere", gps_uere, 1.0);
66  gp_nh.param("use_relative_alt", use_relative_alt, true);
67  // tf subsection
68  gp_nh.param("tf/send", tf_send, false);
69  gp_nh.param<std::string>("tf/frame_id", tf_frame_id, "map");
70  gp_nh.param<std::string>("tf/global_frame_id", tf_global_frame_id, "earth"); // The global_origin should be represented as "earth" coordinate frame (ECEF) (REP 105)
71  gp_nh.param<std::string>("tf/child_frame_id", tf_child_frame_id, "base_link");
72 
74 
75  // gps data
76  raw_fix_pub = gp_nh.advertise<sensor_msgs::NavSatFix>("raw/fix", 10);
77  raw_vel_pub = gp_nh.advertise<geometry_msgs::TwistStamped>("raw/gps_vel", 10);
78  raw_sat_pub = gp_nh.advertise<std_msgs::UInt32>("raw/satellites", 10);
79 
80  // fused global position
81  gp_fix_pub = gp_nh.advertise<sensor_msgs::NavSatFix>("global", 10);
82  gp_odom_pub = gp_nh.advertise<nav_msgs::Odometry>("local", 10);
83  gp_rel_alt_pub = gp_nh.advertise<std_msgs::Float64>("rel_alt", 10);
84  gp_hdg_pub = gp_nh.advertise<std_msgs::Float64>("compass_hdg", 10);
85 
86  // global origin
87  gp_global_origin_pub = gp_nh.advertise<geographic_msgs::GeoPointStamped>("gp_origin", 10, true);
89 
90  // home position subscriber to set "map" origin
91  // TODO use UAS
93 
94  // offset from local position to the global origin ("earth")
95  gp_global_offset_pub = gp_nh.advertise<geometry_msgs::PoseStamped>("gp_lp_offset", 10);
96  }
97 
99  {
100  return {
102  // GPS_STATUS: there no corresponding ROS message, and it is not supported by APM
106  };
107  }
108 
109 private:
111 
121 
124 
125  std::string frame_id;
126  std::string child_frame_id;
127  std::string tf_frame_id;
128  std::string tf_global_frame_id;
129  std::string tf_child_frame_id;
130 
131  bool tf_send;
134 
135  double rot_cov;
136  double gps_uere;
137 
138  Eigen::Vector3d map_origin {};
139  Eigen::Vector3d ecef_origin {};
140  Eigen::Vector3d local_ecef {};
141 
142  template<typename MsgT>
143  inline void fill_lla(MsgT &msg, sensor_msgs::NavSatFix::Ptr fix)
144  {
145  fix->latitude = msg.lat / 1E7; // deg
146  fix->longitude = msg.lon / 1E7; // deg
147  fix->altitude = msg.alt / 1E3 + m_uas->geoid_to_ellipsoid_height(fix); // in meters
148  }
149 
151  {
152  fix->position_covariance.fill(0.0);
153  fix->position_covariance[0] = -1.0;
154  fix->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
155  }
156 
157  /* -*- message handlers -*- */
158 
159  void handle_gps_raw_int(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GPS_RAW_INT &raw_gps)
160  {
161  auto fix = boost::make_shared<sensor_msgs::NavSatFix>();
162 
163  fix->header = m_uas->synchronized_header(child_frame_id, raw_gps.time_usec);
164 
165  fix->status.service = sensor_msgs::NavSatStatus::SERVICE_GPS;
166  if (raw_gps.fix_type > 2)
167  fix->status.status = sensor_msgs::NavSatStatus::STATUS_FIX;
168  else {
169  ROS_WARN_THROTTLE_NAMED(30, "global_position", "GP: No GPS fix");
170  fix->status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
171  }
172 
173  fill_lla(raw_gps, fix);
174 
175  float eph = (raw_gps.eph != UINT16_MAX) ? raw_gps.eph / 1E2F : NAN;
176  float epv = (raw_gps.epv != UINT16_MAX) ? raw_gps.epv / 1E2F : NAN;
177 
178  ftf::EigenMapCovariance3d gps_cov(fix->position_covariance.data());
179 
180  // With mavlink v2.0 use accuracies reported by sensor
181  if (msg->magic == MAVLINK_STX &&
182  raw_gps.h_acc > 0 && raw_gps.v_acc > 0) {
183  gps_cov.diagonal() << std::pow(raw_gps.h_acc / 1E3, 2), std::pow(raw_gps.h_acc / 1E3, 2), std::pow(raw_gps.v_acc / 1E3, 2);
184  fix->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
185  }
186  // With mavlink v1.0 approximate accuracies by DOP
187  else if (!std::isnan(eph) && !std::isnan(epv)) {
188  gps_cov.diagonal() << std::pow(eph * gps_uere, 2), std::pow(eph * gps_uere, 2), std::pow(epv * gps_uere, 2);
189  fix->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED;
190  }
191  else {
192  fill_unknown_cov(fix);
193  }
194 
195  // store & publish
196  m_uas->update_gps_fix_epts(fix, eph, epv, raw_gps.fix_type, raw_gps.satellites_visible);
197  raw_fix_pub.publish(fix);
198 
199  if (raw_gps.vel != UINT16_MAX &&
200  raw_gps.cog != UINT16_MAX) {
201  double speed = raw_gps.vel / 1E2; // m/s
202  double course = angles::from_degrees(raw_gps.cog / 1E2); // rad
203 
204  auto vel = boost::make_shared<geometry_msgs::TwistStamped>();
205 
206  vel->header.stamp = fix->header.stamp;
207  vel->header.frame_id = frame_id;
208 
209  // From nmea_navsat_driver
210  vel->twist.linear.x = speed * std::sin(course);
211  vel->twist.linear.y = speed * std::cos(course);
212 
213  raw_vel_pub.publish(vel);
214  }
215 
216  // publish satellite count
217  auto sat_cnt = boost::make_shared<std_msgs::UInt32>();
218  sat_cnt->data = raw_gps.satellites_visible;
219  raw_sat_pub.publish(sat_cnt);
220  }
221 
222  void handle_gps_global_origin(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GPS_GLOBAL_ORIGIN &glob_orig)
223  {
224  auto g_origin = boost::make_shared<geographic_msgs::GeoPointStamped>();
225  // auto header = m_uas->synchronized_header(frame_id, glob_orig.time_boot_ms); #TODO: requires Mavlink msg update
226 
227  g_origin->header.frame_id = tf_global_frame_id;
228  g_origin->header.stamp = ros::Time::now();
229 
230  g_origin->position.latitude = glob_orig.latitude / 1E7;
231  g_origin->position.longitude = glob_orig.longitude / 1E7;
232  g_origin->position.altitude = glob_orig.altitude / 1E3 + m_uas->geoid_to_ellipsoid_height(&g_origin->position); // convert height amsl to height above the ellipsoid
233 
234  try {
239  GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(),
240  GeographicLib::Constants::WGS84_f());
241 
242  earth.Forward(g_origin->position.latitude, g_origin->position.longitude, g_origin->position.altitude,
243  g_origin->position.latitude, g_origin->position.longitude, g_origin->position.altitude);
244 
245  gp_global_origin_pub.publish(g_origin);
246  }
247  catch (const std::exception& e) {
248  ROS_INFO_STREAM("GP: Caught exception: " << e.what() << std::endl);
249  }
250  }
251 
254  void handle_global_position_int(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GLOBAL_POSITION_INT &gpos)
255  {
256  auto odom = boost::make_shared<nav_msgs::Odometry>();
257  auto fix = boost::make_shared<sensor_msgs::NavSatFix>();
258  auto relative_alt = boost::make_shared<std_msgs::Float64>();
259  auto compass_heading = boost::make_shared<std_msgs::Float64>();
260 
261  auto header = m_uas->synchronized_header(child_frame_id, gpos.time_boot_ms);
262 
263  // Global position fix
264  fix->header = header;
265 
266  fill_lla(gpos, fix);
267 
268  // fill GPS status fields using GPS_RAW data
269  auto raw_fix = m_uas->get_gps_fix();
270  if (raw_fix) {
271  fix->status.service = raw_fix->status.service;
272  fix->status.status = raw_fix->status.status;
273  fix->position_covariance = raw_fix->position_covariance;
274  fix->position_covariance_type = raw_fix->position_covariance_type;
275  }
276  else {
277  // no GPS_RAW_INT -> fix status unknown
278  fix->status.service = sensor_msgs::NavSatStatus::SERVICE_GPS;
279  fix->status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
280 
281  // we don't know covariance
282  fill_unknown_cov(fix);
283  }
284 
285  relative_alt->data = gpos.relative_alt / 1E3; // in meters
286  compass_heading->data = (gpos.hdg != UINT16_MAX) ? gpos.hdg / 1E2 : NAN; // in degrees
287 
301  odom->header.stamp = header.stamp;
302  odom->header.frame_id = frame_id;
303  odom->child_frame_id = child_frame_id;
304 
305  // Linear velocity
306  tf::vectorEigenToMsg(Eigen::Vector3d(gpos.vy, gpos.vx, gpos.vz) / 1E2,
307  odom->twist.twist.linear);
308 
309  // Velocity covariance unknown
310  ftf::EigenMapCovariance6d vel_cov_out(odom->twist.covariance.data());
311  vel_cov_out.fill(0.0);
312  vel_cov_out(0) = -1.0;
313 
314  // Current fix in ECEF
315  Eigen::Vector3d map_point;
316 
317  try {
325  GeographicLib::Geocentric map(GeographicLib::Constants::WGS84_a(),
326  GeographicLib::Constants::WGS84_f());
327 
335  // Current fix to ECEF
336  map.Forward(fix->latitude, fix->longitude, fix->altitude,
337  map_point.x(), map_point.y(), map_point.z());
338 
339  // Set the current fix as the "map" origin if it's not set
340  if (!is_map_init && fix->status.status >= sensor_msgs::NavSatStatus::STATUS_FIX) {
341  map_origin.x() = fix->latitude;
342  map_origin.y() = fix->longitude;
343  map_origin.z() = fix->altitude;
344 
345  ecef_origin = map_point; // Local position is zero
346  is_map_init = true;
347  }
348  }
349  catch (const std::exception& e) {
350  ROS_INFO_STREAM("GP: Caught exception: " << e.what() << std::endl);
351  }
352 
353  // Compute the local coordinates in ECEF
354  local_ecef = map_point - ecef_origin;
355  // Compute the local coordinates in ENU
356  tf::pointEigenToMsg(ftf::transform_frame_ecef_enu(local_ecef, map_origin), odom->pose.pose.position);
357 
362  if (use_relative_alt)
363  odom->pose.pose.position.z = relative_alt->data;
364 
365  odom->pose.pose.orientation = m_uas->get_attitude_orientation_enu();
366 
367  // Use ENU covariance to build XYZRPY covariance
368  ftf::EigenMapConstCovariance3d gps_cov(fix->position_covariance.data());
369  ftf::EigenMapCovariance6d pos_cov_out(odom->pose.covariance.data());
370  pos_cov_out.setZero();
371  pos_cov_out.block<3, 3>(0, 0) = gps_cov;
372  pos_cov_out.block<3, 3>(3, 3).diagonal() <<
373  rot_cov,
374  rot_cov,
375  rot_cov;
376 
377  // publish
378  gp_fix_pub.publish(fix);
379  gp_odom_pub.publish(odom);
380  gp_rel_alt_pub.publish(relative_alt);
381  gp_hdg_pub.publish(compass_heading);
382 
383  // TF
384  if (tf_send) {
385  geometry_msgs::TransformStamped transform;
386 
387  transform.header.stamp = odom->header.stamp;
388  transform.header.frame_id = tf_frame_id;
389  transform.child_frame_id = tf_child_frame_id;
390 
391  // setRotation()
392  transform.transform.rotation = odom->pose.pose.orientation;
393 
394  // setOrigin()
395  transform.transform.translation.x = odom->pose.pose.position.x;
396  transform.transform.translation.y = odom->pose.pose.position.y;
397  transform.transform.translation.z = odom->pose.pose.position.z;
398 
399  m_uas->tf2_broadcaster.sendTransform(transform);
400  }
401  }
402 
403  void handle_lpned_system_global_offset(const mavlink::mavlink_message_t *msg, mavlink::common::msg::LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET &offset)
404  {
405  auto global_offset = boost::make_shared<geometry_msgs::PoseStamped>();
406  global_offset->header = m_uas->synchronized_header(tf_global_frame_id, offset.time_boot_ms);
407 
408  auto enu_position = ftf::transform_frame_ned_enu(Eigen::Vector3d(offset.x, offset.y, offset.z));
409  auto enu_baselink_orientation = ftf::transform_orientation_aircraft_baselink(
411  ftf::quaternion_from_rpy(offset.roll, offset.pitch, offset.yaw)));
412 
413  tf::pointEigenToMsg(enu_position, global_offset->pose.position);
414  tf::quaternionEigenToMsg(enu_baselink_orientation, global_offset->pose.orientation);
415 
416  gp_global_offset_pub.publish(global_offset);
417 
418  // TF
419  if (tf_send) {
420  geometry_msgs::TransformStamped transform;
421 
422  transform.header.stamp = global_offset->header.stamp;
423  transform.header.frame_id = tf_global_frame_id;
424  transform.child_frame_id = tf_frame_id;
425 
426  // setRotation()
427  transform.transform.rotation = global_offset->pose.orientation;
428 
429  // setOrigin()
430  transform.transform.translation.x = global_offset->pose.position.x;
431  transform.transform.translation.y = global_offset->pose.position.y;
432  transform.transform.translation.z = global_offset->pose.position.z;
433 
434  m_uas->tf2_broadcaster.sendTransform(transform);
435  }
436  }
437 
438  /* -*- diagnostics -*- */
440  {
441  int fix_type, satellites_visible;
442  float eph, epv;
443 
444  m_uas->get_gps_epts(eph, epv, fix_type, satellites_visible);
445 
446  if (satellites_visible <= 0)
447  stat.summary(2, "No satellites");
448  else if (fix_type < 2)
449  stat.summary(1, "No fix");
450  else if (fix_type == 2)
451  stat.summary(0, "2D fix");
452  else if (fix_type >= 3)
453  stat.summary(0, "3D fix");
454 
455  stat.addf("Satellites visible", "%zd", satellites_visible);
456  stat.addf("Fix type", "%d", fix_type);
457 
458  if (!std::isnan(eph))
459  stat.addf("EPH (m)", "%.2f", eph);
460  else
461  stat.add("EPH (m)", "Unknown");
462 
463  if (!std::isnan(epv))
464  stat.addf("EPV (m)", "%.2f", epv);
465  else
466  stat.add("EPV (m)", "Unknown");
467  }
468 
469  /* -*- callbacks -*- */
470 
472  {
473  map_origin.x() = req->geo.latitude;
474  map_origin.y() = req->geo.longitude;
475  map_origin.z() = req->geo.altitude;
476 
477  try {
481  GeographicLib::Geocentric map(GeographicLib::Constants::WGS84_a(),
482  GeographicLib::Constants::WGS84_f());
483 
484  // map_origin to ECEF
485  map.Forward(map_origin.x(), map_origin.y(), map_origin.z(),
486  ecef_origin.x(), ecef_origin.y(), ecef_origin.z());
487  }
488  catch (const std::exception& e) {
489  ROS_INFO_STREAM("GP: Caught exception: " << e.what() << std::endl);
490  }
491 
492  is_map_init = true;
493  }
494 
496  {
497  mavlink::common::msg::SET_GPS_GLOBAL_ORIGIN gpo = {};
498 
499  Eigen::Vector3d global_position;
500 
501  gpo.target_system = m_uas->get_tgt_system();
502  // gpo.time_boot_ms = stamp.toNSec() / 1000; #TODO: requires Mavlink msg update
503 
504  gpo.latitude = req->position.latitude * 1E7;
505  gpo.longitude = req->position.longitude * 1E7;
506  gpo.altitude = (req->position.altitude + m_uas->ellipsoid_to_geoid_height(&req->position)) * 1E3;
507 
508  UAS_FCU(m_uas)->send_message_ignore_drop(gpo);
509  }
510 };
511 } // namespace std_plugins
512 } // namespace mavros
513 
std::string frame_id
origin frame for topic headers
MAVROS Plugin base class.
Definition: mavros_plugin.h:36
Eigen::Vector3d ecef_origin
geocentric origin of map frame [m]
std::shared_ptr< MAVConnInterface const > ConstPtr
std_msgs::Header synchronized_header(const std::string &frame_id, const T time_stamp)
Create message header from time_boot_ms or time_usec stamps and frame_id.
Definition: mavros_uas.h:375
void fill_lla(MsgT &msg, sensor_msgs::NavSatFix::Ptr fix)
double ellipsoid_to_geoid_height(T lla)
Conversion from height above ellipsoid (WGS-84) to height above geoid (AMSL)
Definition: mavros_uas.h:263
#define ROS_WARN_THROTTLE_NAMED(period, name,...)
geometry_msgs::Quaternion get_attitude_orientation_enu()
Get Attitude orientation quaternion.
Definition: uas_data.cpp:165
void summary(unsigned char lvl, const std::string s)
void quaternionEigenToMsg(const Eigen::Quaterniond &e, geometry_msgs::Quaternion &m)
void handle_lpned_system_global_offset(const mavlink::mavlink_message_t *msg, mavlink::common::msg::LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET &offset)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void fill_unknown_cov(sensor_msgs::NavSatFix::Ptr fix)
MAVROS Plugin base.
std::string tf_global_frame_id
global origin for TF
void handle_global_position_int(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GLOBAL_POSITION_INT &gpos)
HandlerInfo make_handler(const mavlink::msgid_t id, void(_C::*fn)(const mavlink::mavlink_message_t *msg, const mavconn::Framing framing))
Definition: mavros_plugin.h:87
Eigen::Map< Eigen::Matrix< double, 6, 6, Eigen::RowMajor > > EigenMapCovariance6d
Eigen::Map for Covariance6d.
Definition: frame_tf.h:50
Eigen::Map< const Eigen::Matrix< double, 3, 3, Eigen::RowMajor > > EigenMapConstCovariance3d
Definition: frame_tf.h:47
#define UAS_DIAG(uasobjptr)
helper accessor to diagnostic updater
Definition: mavros_uas.h:48
void set_gp_origin_cb(const geographic_msgs::GeoPointStamped::ConstPtr &req)
void addf(const std::string &key, const char *format,...)
void gps_diag_run(diagnostic_updater::DiagnosticStatusWrapper &stat)
tf2_ros::TransformBroadcaster tf2_broadcaster
Definition: mavros_uas.h:275
Eigen::Vector3d local_ecef
local ECEF coordinates on map frame [m]
PluginBase()
Plugin constructor Should not do anything before initialize()
Definition: mavros_plugin.h:74
void home_position_cb(const mavros_msgs::HomePosition::ConstPtr &req)
uint8_t get_tgt_system()
Return communication target system.
Definition: mavros_uas.h:159
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
UAS for plugins.
Definition: mavros_uas.h:67
static double from_degrees(double degrees)
void vectorEigenToMsg(const Eigen::Vector3d &e, geometry_msgs::Vector3 &m)
#define UAS_FCU(uasobjptr)
helper accessor to FCU link interface
Definition: mavros_uas.h:42
std::string tf_child_frame_id
frame for TF and Pose
T transform_frame_ned_enu(const T &in)
Transform data expressed in NED to ENU frame.
Definition: frame_tf.h:215
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void handle_gps_global_origin(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GPS_GLOBAL_ORIGIN &glob_orig)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW GlobalPositionPlugin()
void sendTransform(const geometry_msgs::TransformStamped &transform)
Eigen::Map< Eigen::Matrix< double, 3, 3, Eigen::RowMajor > > EigenMapCovariance3d
Eigen::Map for Covariance3d.
Definition: frame_tf.h:46
void pointEigenToMsg(const Eigen::Vector3d &e, geometry_msgs::Point &m)
Eigen::Quaterniond quaternion_from_rpy(const Eigen::Vector3d &rpy)
Convert euler angles to quaternion.
void initialize(UAS &uas_) override
Plugin initializer.
std::string child_frame_id
body-fixed frame for topic headers
#define ROS_INFO_STREAM(args)
Subscriptions get_subscriptions() override
Return vector of MAVLink message subscriptions (handlers)
std::vector< HandlerInfo > Subscriptions
Subscriptions vector.
Definition: mavros_plugin.h:47
sensor_msgs::NavSatFix::Ptr get_gps_fix()
Retunrs last GPS RAW message.
Definition: uas_data.cpp:245
T transform_frame_ecef_enu(const T &in, const T &map_origin)
Transform data expressed in ECEF frame to ENU frame.
Definition: frame_tf.h:254
T transform_orientation_ned_enu(const T &in)
Transform from attitude represented WRT NED frame to attitude represented WRT ENU frame...
Definition: frame_tf.h:160
static Time now()
void handle_gps_raw_int(const mavlink::mavlink_message_t *msg, mavlink::common::msg::GPS_RAW_INT &raw_gps)
Eigen::Vector3d map_origin
geodetic origin of map frame [lla]
const std::string header
void add(const std::string &key, const T &val)
T transform_orientation_aircraft_baselink(const T &in)
Transform from attitude represented WRT aircraft frame to attitude represented WRT base_link frame...
Definition: frame_tf.h:178
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void update_gps_fix_epts(sensor_msgs::NavSatFix::Ptr &fix, float eph, float epv, int fix_type, int satellites_visible)
Store GPS RAW data.
Definition: uas_data.cpp:220
double geoid_to_ellipsoid_height(T lla)
Conversion from height above geoid (AMSL) to height above ellipsoid (WGS-84)
Definition: mavros_uas.h:250
void get_gps_epts(float &eph, float &epv, int &fix_type, int &satellites_visible)
Returns EPH, EPV, Fix type and satellites visible.
Definition: uas_data.cpp:234
std::shared_ptr< MAVConnInterface > Ptr


mavros
Author(s): Vladimir Ermakov
autogenerated on Tue Jun 13 2023 02:17:50