1919#include < eigen_conversions/eigen_msg.h>
2020
2121#include < geometry_msgs/PoseStamped.h>
22+ #include < geographic_msgs/GeoPointStamped.h>
2223
2324#include < mavros_msgs/SetMavFrame.h>
2425#include < mavros_msgs/GlobalPositionTarget.h>
26+ #include < mavros_msgs/PositionTarget.h>
2527
2628#include < GeographicLib/Geocentric.hpp>
2729// #include <GeographicLib/Geoid.hpp>
@@ -32,7 +34,7 @@ using mavlink::common::MAV_FRAME;
3234/* *
3335 * @brief Setpoint position plugin
3436 *
35- * Send setpoint positions to FCU controller.
37+ * Send and receive setpoint positions from FCU controller.
3638 */
3739class SetpointPositionPlugin : public plugin ::PluginBase,
3840 private plugin::SetPositionTargetLocalNEDMixin<SetpointPositionPlugin>,
@@ -44,7 +46,8 @@ class SetpointPositionPlugin : public plugin::PluginBase,
4446 sp_nh (" ~setpoint_position" ),
4547 spg_nh(" ~" ),
4648 tf_rate(50.0 ),
47- tf_listen(false )
49+ tf_listen(false ),
50+ is_map_init(false )
4851 { }
4952
5053 void initialize (UAS &uas_)
@@ -71,6 +74,9 @@ class SetpointPositionPlugin : public plugin::PluginBase,
7174 gps_sub = spg_nh.subscribe (" global_position/global" , 10 , &SetpointPositionPlugin::gps_cb, this );
7275 // Subscribe for current local ENU pose.
7376 local_sub = spg_nh.subscribe (" local_position/pose" , 10 , &SetpointPositionPlugin::local_cb, this );
77+
78+ // subscriber for global origin (aka map origin)
79+ gp_origin_sub = spg_nh.subscribe (" global_position/gp_origin" , 10 , &SetpointPositionPlugin::gp_origin_cb, this );
7480 }
7581 mav_frame_srv = sp_nh.advertiseService (" mav_frame" , &SetpointPositionPlugin::set_mav_frame_cb, this );
7682
@@ -81,11 +87,16 @@ class SetpointPositionPlugin : public plugin::PluginBase,
8187 } else {
8288 mav_frame = utils::mav_frame_from_str (mav_frame_str);
8389 }
90+
91+ // publish targets received from FCU
92+ setpointg_pub = sp_nh.advertise <geometry_msgs::PoseStamped>(" cmd_pos" , 10 );
8493 }
8594
8695 Subscriptions get_subscriptions ()
8796 {
88- return { /* Rx disabled */ };
97+ return {
98+ make_handler (&SetpointPositionPlugin::handle_set_position_target_global_int),
99+ };
89100 }
90101
91102private:
@@ -98,19 +109,24 @@ class SetpointPositionPlugin : public plugin::PluginBase,
98109 ros::Subscriber setpointg_sub; // !< GPS setpoint
99110 ros::Subscriber gps_sub; // !< current GPS
100111 ros::Subscriber local_sub; // !< current local ENU
112+ ros::Subscriber gp_origin_sub; // !< global origin LLA
101113 ros::ServiceServer mav_frame_srv;
114+ ros::Publisher setpointg_pub; // !< global position target from FCU
102115
103116 /* Stores current gps state. */
104117 // sensor_msgs::NavSatFix current_gps_msg;
105118 Eigen::Vector3d current_gps; // !< geodetic coordinates LLA
106119 Eigen::Vector3d current_local_pos; // !< Current local position in ENU
120+ Eigen::Vector3d map_origin {}; // !< oigin of map frame [lla]
121+ Eigen::Vector3d ecef_origin {}; // !< geocentric origin [m]
107122 uint32_t old_gps_stamp = 0 ; // !< old time gps time stamp in [ms], to check if new gps msg is received
108123
109124 std::string tf_frame_id;
110125 std::string tf_child_frame_id;
111126
112127 bool tf_listen;
113128 double tf_rate;
129+ bool is_map_init;
114130
115131 MAV_FRAME mav_frame;
116132
@@ -250,6 +266,27 @@ class SetpointPositionPlugin : public plugin::PluginBase,
250266 current_local_pos = ftf::to_eigen (msg->pose .position );
251267 }
252268
269+ /* *
270+ * global origin in LLA
271+ */
272+ void gp_origin_cb (const geographic_msgs::GeoPointStamped::ConstPtr &msg)
273+ {
274+ ecef_origin = {msg->position .latitude , msg->position .longitude , msg->position .altitude };
275+ /* *
276+ * @brief Conversion from ECEF (Earth-Centered, Earth-Fixed) to geodetic coordinates (LLA)
277+ */
278+ GeographicLib::Geocentric earth (GeographicLib::Constants::WGS84_a (), GeographicLib::Constants::WGS84_f ());
279+ try {
280+ earth.Reverse (ecef_origin.x (), ecef_origin.y (), ecef_origin.z (),
281+ map_origin.x (), map_origin.y (), map_origin.z ());
282+ }
283+ catch (const std::exception& e) {
284+ ROS_WARN_STREAM (" setpoint: Caught exception: " << e.what () << std::endl);
285+ return ;
286+ }
287+ is_map_init = true ;
288+ }
289+
253290 bool set_mav_frame_cb (mavros_msgs::SetMavFrame::Request &req, mavros_msgs::SetMavFrame::Response &res)
254291 {
255292 mav_frame = static_cast <MAV_FRAME>(req.mav_frame );
@@ -258,6 +295,52 @@ class SetpointPositionPlugin : public plugin::PluginBase,
258295 res.success = true ;
259296 return true ;
260297 }
298+
299+ /* -*- rx handler -*- */
300+
301+ /* *
302+ * @brief handle SET_POSITION_TARGET_GLOBAL_INT mavlink msg
303+ * handles and publishes position target received from FCU
304+ */
305+ void handle_set_position_target_global_int (const mavlink::mavlink_message_t *msg, mavlink::common::msg::SET_POSITION_TARGET_GLOBAL_INT &position_target)
306+ {
307+ /* check if type_mask field ignores position*/
308+ if (position_target.type_mask & (mavros_msgs::GlobalPositionTarget::IGNORE_LATITUDE | mavros_msgs::GlobalPositionTarget::IGNORE_LONGITUDE) > 0 ) {
309+ ROS_WARN_NAMED (" setpoint" , " lat and/or lon ignored" );
310+ return ;
311+ }
312+
313+ /* check origin has been set */
314+ if (!is_map_init) {
315+ ROS_WARN_NAMED (" setpoint" , " SetPositionTargetGlobal failed because no origin" );
316+ }
317+
318+ /* convert lat/lon target to ECEF */
319+ Eigen::Vector3d pos_target_ecef {}; // !< local ECEF coordinates on map frame [m]
320+ GeographicLib::Geocentric earth (GeographicLib::Constants::WGS84_a (), GeographicLib::Constants::WGS84_f ());
321+ try {
322+ earth.Forward (position_target.lat_int / 1E7 , position_target.lon_int / 1E7 , position_target.alt / 1E3 ,
323+ pos_target_ecef.x (), pos_target_ecef.y (), pos_target_ecef.z ());
324+ }
325+ catch (const std::exception& e) {
326+ ROS_WARN_STREAM (" setpoint: Caught exception: " << e.what () << std::endl);
327+ return ;
328+ }
329+
330+ /* create position target PoseStamped message */
331+ auto pose = boost::make_shared<geometry_msgs::PoseStamped>();
332+ pose->header = m_uas->synchronized_header (" map" , position_target.time_boot_ms );
333+ pose->pose .orientation .w = 1 ; // unit quaternion with no rotation
334+
335+ /* convert ECEF target to ENU */
336+ const Eigen::Vector3d local_ecef = pos_target_ecef - ecef_origin;
337+ tf::pointEigenToMsg (ftf::transform_frame_ecef_enu (local_ecef, map_origin), pose->pose .position );
338+ pose->pose .position .z = 0 ; // force z-axis to zero
339+
340+ /* publish target */
341+ setpointg_pub.publish (pose);
342+ }
343+
261344};
262345} // namespace std_plugins
263346} // namespace mavros
0 commit comments