Program Listing for File plugin_base.hpp

Return to documentation for file (include/as2_state_estimator/plugin_base.hpp)

/*!*******************************************************************************************
 *  \file       plugin_base.hpp
 *  \brief      An state estimation plugin base for AeroStack2
 *  \authors    Miguel Fernández Cortizas
 *              David Pérez Saura
 *              Rafael Pérez Seguí
 *              Pedro Arias Pérez
 *
 *  \copyright  Copyright (c) 2022 Universidad Politécnica de Madrid
 *              All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ********************************************************************************/

#ifndef __STATE_ESTIMATOR_PLUGIN_BASE_HPP__
#define __STATE_ESTIMATOR_PLUGIN_BASE_HPP__

#include <tf2_ros/buffer.h>
#include <tf2_ros/buffer_interface.h>
#include <tf2_ros/static_transform_broadcaster.h>
#include <tf2_ros/transform_broadcaster.h>
#include <as2_core/node.hpp>
#include <as2_core/utils/tf_utils.hpp>
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <geometry_msgs/msg/twist_stamped.hpp>
#include <nav_msgs/msg/odometry.hpp>
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/subscription_base.hpp>

#include <as2_core/names/topics.hpp>

namespace as2_state_estimator_plugin_base {
class StateEstimatorBase {
protected:
  as2::Node* node_ptr_;

private:
  std::string earth_frame_id_;
  std::string base_frame_id_;
  std::string odom_frame_id_;
  std::string map_frame_id_;
  tf2::Transform earth_to_map_ = tf2::Transform::getIdentity();
  tf2::Transform map_to_odom_  = tf2::Transform::getIdentity();
  tf2::Transform odom_to_base_ = tf2::Transform::getIdentity();

public:
  StateEstimatorBase(){};
  void setup(as2::Node* node,
             std::shared_ptr<tf2_ros::Buffer> tf_buffer,
             std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster,
             std::shared_ptr<tf2_ros::StaticTransformBroadcaster> static_tf_broadcaster) {
    node_ptr_              = node;
    tf_buffer_             = tf_buffer;
    tf_broadcaster_        = tf_broadcaster;
    static_tf_broadcaster_ = static_tf_broadcaster;

    twist_pub_ = node_ptr_->create_publisher<geometry_msgs::msg::TwistStamped>(
        as2_names::topics::self_localization::twist, as2_names::topics::self_localization::qos);
    pose_pub_ = node_ptr_->create_publisher<geometry_msgs::msg::PoseStamped>(
        as2_names::topics::self_localization::pose, as2_names::topics::self_localization::qos);

    // node_ptr_->declare_parameter<std::string>("base_frame", "base_link");
    // node_ptr_->declare_parameter<std::string>("global_ref_frame", "earth");
    // node_ptr_->declare_parameter<std::string>("odom_frame", "odom");
    // node_ptr_->declare_parameter<std::string>("map_frame", "map");

    node_ptr_->get_parameter("base_frame", base_frame_id_);
    node_ptr_->get_parameter("global_ref_frame", earth_frame_id_);
    node_ptr_->get_parameter("odom_frame", odom_frame_id_);
    node_ptr_->get_parameter("map_frame", map_frame_id_);

    base_frame_id_ = as2::tf::generateTfName(node_ptr_, base_frame_id_);
    odom_frame_id_ = as2::tf::generateTfName(node_ptr_, odom_frame_id_);
    map_frame_id_  = as2::tf::generateTfName(node_ptr_, map_frame_id_);
    // !! WATCHOUT : earth_frame_id_ is not generated because it is a global frame

    on_setup();
  };
  virtual void on_setup() = 0;
  virtual bool get_earth_to_map_transform(geometry_msgs::msg::TransformStamped& transform) {
    RCLCPP_WARN(node_ptr_->get_logger(),
                "get_earth_to_map_transform not implemented using default identity transform");
    transform = as2::tf::getTransformation(get_earth_frame(), get_map_frame(), 0, 0, 0, 0, 0, 0);
    return true;
  };

private:
  std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
  std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
  std::shared_ptr<tf2_ros::StaticTransformBroadcaster> static_tf_broadcaster_;
  rclcpp::Publisher<geometry_msgs::msg::TwistStamped>::SharedPtr twist_pub_;
  rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr pose_pub_;

  void check_standard_transform(const geometry_msgs::msg::TransformStamped& transform) {
    if (transform.header.frame_id == get_earth_frame() &&
        transform.child_frame_id == get_map_frame()) {
      earth_to_map_ = tf2::Transform(
          tf2::Quaternion(transform.transform.rotation.x, transform.transform.rotation.y,
                          transform.transform.rotation.z, transform.transform.rotation.w),
          tf2::Vector3(transform.transform.translation.x, transform.transform.translation.y,
                       transform.transform.translation.z));
    }
  }

protected:
  inline void publish_transform(const geometry_msgs::msg::TransformStamped& transform) {
    tf_broadcaster_->sendTransform(transform);
  }
  inline void publish_static_transform(const geometry_msgs::msg::TransformStamped& transform) {
    static_tf_broadcaster_->sendTransform(transform);
  }

  inline void publish_twist(const geometry_msgs::msg::TwistStamped& twist) {
    twist_pub_->publish(twist);
  }
  inline void publish_pose(const geometry_msgs::msg::PoseStamped& pose) {
    pose_pub_->publish(pose);
  }

  inline const std::string& get_earth_frame() const { return earth_frame_id_; }
  inline const std::string& get_map_frame() const { return map_frame_id_; }
  inline const std::string& get_odom_frame() const { return odom_frame_id_; }
  inline const std::string& get_base_frame() const { return base_frame_id_; }

  tf2::Transform odom_to_baselink;
  tf2::Transform earth_to_map;
  tf2::Transform earth_to_baselink;

  bool static_transforms_published_ = false;
  rclcpp::TimerBase::SharedPtr static_transforms_timer_;

  bool get_earth_to_map_transform(tf2::Transform& earth_to_map) {
    geometry_msgs::msg::TransformStamped transform;
    if (get_earth_to_map_transform(transform)) {
      tf2::fromMsg(transform.transform, earth_to_map);
      return true;
    }
    return false;
  }

  bool convert_earth_to_baselink_2_odom_to_baselink_transform(
      const tf2::Transform& earth_to_baselink,
      tf2::Transform& odom_to_baselink,
      const tf2::Transform& earth_to_map,
      const tf2::Transform& map_to_odom = tf2::Transform::getIdentity()) {
    odom_to_baselink = map_to_odom.inverse() * earth_to_map.inverse() * earth_to_baselink;
    return true;
  }

  bool convert_odom_to_baselink_2_earth_to_baselink_transform(
      const tf2::Transform& odom_to_baselink,
      tf2::Transform& earth_to_baselink,
      const tf2::Transform& earth_to_map,
      const tf2::Transform& map_to_odom = tf2::Transform::getIdentity()) {
    earth_to_baselink = earth_to_map * map_to_odom * odom_to_baselink;
    return true;
  }
};
}  // namespace as2_state_estimator_plugin_base

#endif