|
14 | 14 | #include <mrs_msgs/UavState.h>
|
15 | 15 | #include <mrs_msgs/Float64Stamped.h>
|
16 | 16 | #include <mrs_msgs/HwApiAltitude.h>
|
| 17 | +#include <mrs_msgs/RtkGps.h> |
17 | 18 |
|
18 | 19 | #include <tf2_ros/transform_broadcaster.h>
|
19 | 20 | #include <tf2_ros/static_transform_broadcaster.h>
|
@@ -129,6 +130,11 @@ class TransformManager : public nodelet::Nodelet {
|
129 | 130 | void callbackGnss(const sensor_msgs::NavSatFix::ConstPtr msg);
|
130 | 131 | std::atomic<bool> got_utm_offset_ = false;
|
131 | 132 |
|
| 133 | + mrs_lib::SubscribeHandler<mrs_msgs::RtkGps> sh_rtk_gps_; |
| 134 | + void callbackRtkGps(const mrs_msgs::RtkGps::ConstPtr msg); |
| 135 | + |
| 136 | + std::optional<geometry_msgs::Pose> transformRtkToFcu(const geometry_msgs::PoseStamped& pose_in) const; |
| 137 | + |
132 | 138 | void publishFcuUntiltedTf(const geometry_msgs::QuaternionStampedConstPtr& msg);
|
133 | 139 | };
|
134 | 140 | /*//}*/
|
@@ -279,6 +285,9 @@ void TransformManager::onInit() {
|
279 | 285 |
|
280 | 286 | /*//}*/
|
281 | 287 |
|
| 288 | + param_loader.loadParam(yaml_prefix + "rtk_antenna/frame_id", ch_->frames.rtk_antenna); |
| 289 | + ch_->frames.ns_rtk_antenna = ch_->uav_name + "/" + ch_->frames.rtk_antenna; |
| 290 | + |
282 | 291 | param_loader.loadParam("mrs_uav_managers/estimation_manager/state_estimators", estimator_names_);
|
283 | 292 | param_loader.loadParam(yaml_prefix + "tf_sources", tf_source_names_);
|
284 | 293 |
|
@@ -396,7 +405,11 @@ void TransformManager::onInit() {
|
396 | 405 | sh_hw_api_orientation_ =
|
397 | 406 | mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped>(shopts, "orientation_in", &TransformManager::callbackHwApiOrientation, this);
|
398 | 407 |
|
399 |
| - sh_gnss_ = mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>(shopts, "gnss_in", &TransformManager::callbackGnss, this); |
| 408 | + if (utm_source_name_ == "rtk" || utm_source_name_ == "rtk_garmin") { |
| 409 | + sh_rtk_gps_ = mrs_lib::SubscribeHandler<mrs_msgs::RtkGps>(shopts, "rtk_gps_in", &TransformManager::callbackRtkGps, this); |
| 410 | + } else { |
| 411 | + sh_gnss_ = mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>(shopts, "gnss_in", &TransformManager::callbackGnss, this); |
| 412 | + } |
400 | 413 | /*//}*/
|
401 | 414 |
|
402 | 415 | if (!param_loader.loadedSuccessfully()) {
|
@@ -708,38 +721,122 @@ void TransformManager::callbackGnss(const sensor_msgs::NavSatFix::ConstPtr msg)
|
708 | 721 | return;
|
709 | 722 | }
|
710 | 723 |
|
| 724 | + if (got_utm_offset_) { |
| 725 | + return; |
| 726 | + } |
| 727 | + |
711 | 728 | mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackGnss", ch_->scope_timer.logger, ch_->scope_timer.enabled);
|
712 | 729 |
|
713 |
| - if (!got_utm_offset_) { |
| 730 | + double out_x; |
| 731 | + double out_y; |
| 732 | + |
| 733 | + mrs_lib::UTM(msg->latitude, msg->longitude, &out_x, &out_y); |
714 | 734 |
|
715 |
| - double out_x; |
716 |
| - double out_y; |
| 735 | + if (!std::isfinite(out_x)) { |
| 736 | + ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_x\"!!!", getPrintName().c_str()); |
| 737 | + return; |
| 738 | + } |
717 | 739 |
|
718 |
| - mrs_lib::UTM(msg->latitude, msg->longitude, &out_x, &out_y); |
| 740 | + if (!std::isfinite(out_y)) { |
| 741 | + ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_y\"!!!", getPrintName().c_str()); |
| 742 | + return; |
| 743 | + } |
719 | 744 |
|
720 |
| - if (!std::isfinite(out_x)) { |
721 |
| - ROS_ERROR_THROTTLE(1.0, "[Odometry]: NaN detected in UTM variable \"out_x\"!!!"); |
722 |
| - return; |
723 |
| - } |
| 745 | + geometry_msgs::Point utm_origin; |
| 746 | + utm_origin.x = out_x; |
| 747 | + utm_origin.y = out_y; |
| 748 | + utm_origin.z = msg->altitude; |
724 | 749 |
|
725 |
| - if (!std::isfinite(out_y)) { |
726 |
| - ROS_ERROR_THROTTLE(1.0, "[Odometry]: NaN detected in UTM variable \"out_y\"!!!"); |
727 |
| - return; |
728 |
| - } |
| 750 | + ROS_INFO("[%s]: utm_origin position calculated as: x: %.2f, y: %.2f, z: %.2f from GNSS", getPrintName().c_str(), utm_origin.x, utm_origin.y, utm_origin.z); |
| 751 | + |
| 752 | + for (size_t i = 0; i < tf_sources_.size(); i++) { |
| 753 | + tf_sources_[i]->setUtmOrigin(utm_origin); |
| 754 | + tf_sources_[i]->setWorldOrigin(world_origin_); |
| 755 | + } |
| 756 | + got_utm_offset_ = true; |
| 757 | +} |
| 758 | +/*//}*/ |
729 | 759 |
|
730 |
| - geometry_msgs::Point utm_origin; |
731 |
| - utm_origin.x = out_x; |
732 |
| - utm_origin.y = out_y; |
733 |
| - utm_origin.z = msg->altitude; |
| 760 | +/*//{ callbackRtkGps() */ |
| 761 | +void TransformManager::callbackRtkGps(const mrs_msgs::RtkGps::ConstPtr msg) { |
734 | 762 |
|
735 |
| - ROS_INFO("[%s]: utm_origin position calculated as: x: %.2f, y: %.2f, z: %.2f", getPrintName().c_str(), utm_origin.x, utm_origin.y, utm_origin.z); |
| 763 | + if (!is_initialized_) { |
| 764 | + return; |
| 765 | + } |
736 | 766 |
|
737 |
| - for (size_t i = 0; i < tf_sources_.size(); i++) { |
738 |
| - tf_sources_[i]->setUtmOrigin(utm_origin); |
739 |
| - tf_sources_[i]->setWorldOrigin(world_origin_); |
740 |
| - } |
741 |
| - got_utm_offset_ = true; |
| 767 | + if (got_utm_offset_) { |
| 768 | + return; |
| 769 | + } |
| 770 | + |
| 771 | + mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackRtkGps", ch_->scope_timer.logger, ch_->scope_timer.enabled); |
| 772 | + |
| 773 | + double out_x; |
| 774 | + double out_y; |
| 775 | + |
| 776 | + geometry_msgs::PoseStamped rtk_pos; |
| 777 | + |
| 778 | + if (!std::isfinite(msg->gps.latitude)) { |
| 779 | + ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->latitude\"!!!", getPrintName().c_str()); |
| 780 | + return; |
| 781 | + } |
| 782 | + |
| 783 | + if (!std::isfinite(msg->gps.longitude)) { |
| 784 | + ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->longitude\"!!!", getPrintName().c_str()); |
| 785 | + return; |
742 | 786 | }
|
| 787 | + |
| 788 | + if (!std::isfinite(msg->gps.altitude)) { |
| 789 | + ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->altitude\"!!!", getPrintName().c_str()); |
| 790 | + return; |
| 791 | + } |
| 792 | + |
| 793 | + if (msg->fix_type.fix_type != mrs_msgs::RtkFixType::RTK_FIX) { |
| 794 | + ROS_INFO_THROTTLE(1.0, "[%s] %s RTK FIX", getPrintName().c_str(), Support::waiting_for_string.c_str()); |
| 795 | + return; |
| 796 | + } |
| 797 | + |
| 798 | + rtk_pos.header = msg->header; |
| 799 | + mrs_lib::UTM(msg->gps.latitude, msg->gps.longitude, &rtk_pos.pose.position.x, &rtk_pos.pose.position.y); |
| 800 | + rtk_pos.pose.position.z = msg->gps.altitude; |
| 801 | + rtk_pos.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0); |
| 802 | + |
| 803 | + rtk_pos.pose.position.x -= ch_->world_origin.x; |
| 804 | + rtk_pos.pose.position.y -= ch_->world_origin.y; |
| 805 | + |
| 806 | + |
| 807 | + // transform the RTK position from antenna to FCU |
| 808 | + auto res = transformRtkToFcu(rtk_pos); |
| 809 | + if (res) { |
| 810 | + rtk_pos.pose = res.value(); |
| 811 | + } else { |
| 812 | + ROS_ERROR_THROTTLE(1.0, "[%s]: transform to fcu failed", getPrintName().c_str()); |
| 813 | + return; |
| 814 | + } |
| 815 | + |
| 816 | + mrs_lib::UTM(msg->gps.latitude, msg->gps.longitude, &out_x, &out_y); |
| 817 | + |
| 818 | + if (!std::isfinite(out_x)) { |
| 819 | + ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_x\"!!!", getPrintName().c_str()); |
| 820 | + return; |
| 821 | + } |
| 822 | + |
| 823 | + if (!std::isfinite(out_y)) { |
| 824 | + ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_y\"!!!", getPrintName().c_str()); |
| 825 | + return; |
| 826 | + } |
| 827 | + |
| 828 | + geometry_msgs::Point utm_origin; |
| 829 | + utm_origin.x = out_x; |
| 830 | + utm_origin.y = out_y; |
| 831 | + utm_origin.z = msg->gps.altitude; |
| 832 | + |
| 833 | + ROS_INFO("[%s]: utm_origin position calculated as: x: %.2f, y: %.2f, z: %.2f from RTK msg", getPrintName().c_str(), utm_origin.x, utm_origin.y, utm_origin.z); |
| 834 | + |
| 835 | + for (size_t i = 0; i < tf_sources_.size(); i++) { |
| 836 | + tf_sources_[i]->setUtmOrigin(utm_origin); |
| 837 | + tf_sources_[i]->setWorldOrigin(world_origin_); |
| 838 | + } |
| 839 | + got_utm_offset_ = true; |
743 | 840 | }
|
744 | 841 | /*//}*/
|
745 | 842 |
|
@@ -786,6 +883,49 @@ void TransformManager::publishFcuUntiltedTf(const geometry_msgs::QuaternionStamp
|
786 | 883 | }
|
787 | 884 | /*//}*/
|
788 | 885 |
|
| 886 | +/*//{ transformRtkToFcu() */ |
| 887 | +std::optional<geometry_msgs::Pose> TransformManager::transformRtkToFcu(const geometry_msgs::PoseStamped& pose_in) const { |
| 888 | + |
| 889 | + geometry_msgs::PoseStamped pose_tmp = pose_in; |
| 890 | + |
| 891 | + // inject current orientation into rtk pose |
| 892 | + auto res1 = ch_->transformer->getTransform(ch_->frames.ns_fcu_untilted, ch_->frames.ns_fcu, ros::Time::now()); |
| 893 | + if (res1) { |
| 894 | + pose_tmp.pose.orientation = res1.value().transform.rotation; |
| 895 | + } else { |
| 896 | + ROS_ERROR_THROTTLE(1.0, "[%s]: Could not obtain transform from %s to %s.", getPrintName().c_str(), |
| 897 | + ch_->frames.ns_fcu_untilted.c_str(), ch_->frames.ns_fcu.c_str()); |
| 898 | + return {}; |
| 899 | + } |
| 900 | + |
| 901 | + // invert tf |
| 902 | + tf2::Transform tf_utm_to_antenna = Support::tf2FromPose(pose_tmp.pose); |
| 903 | + geometry_msgs::PoseStamped utm_in_antenna; |
| 904 | + utm_in_antenna.pose = Support::poseFromTf2(tf_utm_to_antenna.inverse()); |
| 905 | + utm_in_antenna.header.stamp = pose_in.header.stamp; |
| 906 | + utm_in_antenna.header.frame_id = ch_->frames.ns_rtk_antenna; |
| 907 | + |
| 908 | + // transform to fcu |
| 909 | + geometry_msgs::PoseStamped utm_in_fcu; |
| 910 | + utm_in_fcu.header.frame_id = ch_->frames.ns_fcu; |
| 911 | + utm_in_fcu.header.stamp = pose_in.header.stamp; |
| 912 | + auto res2 = ch_->transformer->transformSingle(utm_in_antenna, ch_->frames.ns_fcu); |
| 913 | + |
| 914 | + if (res2) { |
| 915 | + utm_in_fcu = res2.value(); |
| 916 | + } else { |
| 917 | + ROS_ERROR_THROTTLE(1.0, "[%s]: Could not transform RTK pose from %s to %s.", getPrintName().c_str(), utm_in_antenna.header.frame_id.c_str(), ch_->frames.ns_fcu.c_str()); |
| 918 | + return {}; |
| 919 | + } |
| 920 | + |
| 921 | + // invert tf |
| 922 | + tf2::Transform tf_fcu_to_utm = Support::tf2FromPose(utm_in_fcu.pose); |
| 923 | + geometry_msgs::Pose fcu_in_utm = Support::poseFromTf2(tf_fcu_to_utm.inverse()); |
| 924 | + |
| 925 | + return fcu_in_utm; |
| 926 | +} |
| 927 | +/*//}*/ |
| 928 | + |
789 | 929 | /*//{ getName() */
|
790 | 930 | std::string TransformManager::getName() const {
|
791 | 931 | return name_;
|
|
0 commit comments