ROS2 robot_localization包的使用教程

1、引言

Robot_localization是一个ROS的包,基于卡尔曼滤波,对多种传感器进行数据融合,进而完成机器人的定位。如果你有相关应用场景,那么该包可以大大降低工作量与工作难度。该包的使用不是那么复杂,但网上相关的资料却较少。如下链接,是一个基于ROS1的教程,较为清晰直接的介绍了该包的具体作用与如何使用。然而在我的工作中,采用的是ROS2,因此我将该教程的代码移植到了ROS2中,同时希望可以帮助更多的人。因此该文章主要是移植后的ROS2代码,具体的教程请参考链接。

教程链接

2、准备工作

Github源码链接
在Github上,根据使用的ROS版本,下载相应的源码,并放在自己工作目录的src文件夹下,并进行编译。
第一次大概率由于没有安装相关的包,而编译报错,根据相应错误提示,安装相关的包即可。
完成编译后,即可以进行教程代码的编写。

3、移植ROS2后的教程代码

代码目录如下,源码按顺序给出
在这里插入图片描述

//odometry.hpp
#ifndef __robot_localization_demo__odometry__
#define __robot_localization_demo__odometry__

#include <random>
#include "rclcpp/rclcpp.hpp"
#include "turtlesim/msg/pose.hpp"
#include <geometry_msgs/msg/twist_with_covariance_stamped.hpp>

class TurtleOdometry: public rclcpp::Node  {
public:
    TurtleOdometry( double frequency, double error_vx_systematic, double error_vx_random,
        double error_wz_systematic, double error_wz_random, bool visualize=false);
    ~TurtleOdometry();
    void spin();
private:
    double frequency_;
    std::default_random_engine random_generator_;
    std::normal_distribution<double> random_distribution_vx_;
    std::normal_distribution<double> random_distribution_wz_;
    unsigned frame_sequence_;
    bool visualize_;
    std::string visualization_turtle_name_;

    rclcpp::callback_group::CallbackGroup::SharedPtr client_cb_group_;
    rclcpp::callback_group::CallbackGroup::SharedPtr other_cb_group_;

    rclcpp::Subscription<turtlesim::msg::Pose>::SharedPtr turtle_pose_subscriber_;
    rclcpp::Publisher<geometry_msgs::msg::TwistWithCovarianceStamped>::SharedPtr turtle_twist_publisher_;
    rclcpp::Time cached_pose_timestamp_;
    turtlesim::msg::Pose cached_pose_;
    void turtlePoseCallback(const turtlesim::msg::Pose::SharedPtr message);
    inline bool isVisualizationRequested() { return visualize_; };
    inline bool isVisualizationTurtleAvailable() { return visualization_turtle_name_ != ""; };
    void spawnAndConfigureVisualizationTurtle(const turtlesim::msg::Pose & initial_pose);
    void moveVisualizationTurtle(const turtlesim::msg::Pose & measurement);
    rclcpp::TimerBase::SharedPtr timer_;
};

#endif
//positioning_system.hpp
#ifndef __robot_localization_demo__positioning_system__
#define __robot_localization_demo__positioning_system__


#include <random>
#include "rclcpp/rclcpp.hpp"
#include "turtlesim/msg/pose.hpp"
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"



class TurtlePositioningSystem: public rclcpp::Node {
public:
    TurtlePositioningSystem(double frequency, double error_x_systematic,
          double error_x_random, double error_y_systematic, double error_y_random, double error_yaw_systematic,
          double error_yaw_random, bool visualize=false);
    ~TurtlePositioningSystem();
    void spin();
private:
    double frequency_;
    std::default_random_engine random_generator_;
    std::normal_distribution<double> random_distribution_x_;
    std::normal_distribution<double> random_distribution_y_;
    std::normal_distribution<double> random_distribution_yaw_;
    unsigned frame_sequence_;
    bool visualize_;
    std::string visualization_turtle_name_;

    rclcpp::callback_group::CallbackGroup::SharedPtr client_cb_group_;
    rclcpp::callback_group::CallbackGroup::SharedPtr other_cb_group_;

    rclcpp::Subscription<turtlesim::msg::Pose>::SharedPtr turtle_pose_subscriber_;
    rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr turtle_pose_publisher_;
    rclcpp::Time cached_pose_timestamp_;
    turtlesim::msg::Pose cached_pose_;
    void turtlePoseCallback(const turtlesim::msg::Pose::SharedPtr message);
    inline bool isVisualizationRequested() { return visualize_; };
    inline bool isVisualizationTurtleAvailable() { return visualization_turtle_name_ != ""; };
    void spawnAndConfigureVisualizationTurtle(const turtlesim::msg::Pose & initial_pose);
    void moveVisualizationTurtle(const turtlesim::msg::Pose & measurement);


    rclcpp::TimerBase::SharedPtr timer_;
};

#endif
#robot_localization_demo.launch.py
from launch import LaunchDescription
from ament_index_python.packages import get_package_share_directory
import os
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package         = 'turtlesim',
            node_executable = 'turtlesim_node',
            node_name       = 'turtlesim',
        ),
        # Node(
        #     package         = 'turtlesim',
        #     node_executable = 'turtle_teleop_key',
        #     node_name       = 'teleop',
        #     output='screen',
        # ),
        Node(
            package         = 'robot_localization_demo',
            node_executable = 'positioning_system_node',
            node_name       = 'turtle1_positioning_system_node',
            output='screen',
            arguments=["-f","1.","-x","0.2","-y","0.2","-t","0.2","-v"],
            #prefix = ['gdbserver localhost:3000'],
        ),
        Node(
            package         = 'robot_localization_demo',
            node_executable = 'odometry_node',
            node_name       = 'turtle1_odometry_node',
            output='screen',
            arguments=["-f","20.","-x","0.05","-X","0.","-t","0.","-T","0.02","-v"],
            #prefix = ['gdbserver localhost:3000'],
        ),
        Node(
            package         = 'robot_localization',
            node_executable = 'ekf_node',
            name       = 'robot_localization_ekf_node_odom',
            output='screen',
            parameters=[os.path.join(get_package_share_directory("robot_localization_demo"), 'params', 'node_odom.yaml')],
            remappings=[
               ('/odometry/filtered', '/odometry/filtered_twist'),
            ]
        ),
        Node(
            package         = 'robot_localization',
            node_executable = 'ekf_node',
            name       = 'robot_localization_ekf_node_map',
            output='screen',
            parameters=[os.path.join(get_package_share_directory("robot_localization_demo"), 'params', 'node_map.yaml')],
            remappings=[
                ('/odometry/filtered', 'odometry/filtered_map'),
            ]
        ),
        Node(
            package         = 'robot_localization_demo',
            node_executable = 'transformation_visualization_node',
            output='screen',
        ),       

    ])
#node_map.yaml
### ekf config file ###
ekf_filter_node:
    ros__parameters:
        frequency: 30.0
        sensor_timeout: 0.1
        two_d_mode: true
        transform_time_offset: 0.0
        transform_timeout: 0.0
        print_diagnostics: true
        debug: false
        debug_out_file: /path/to/debug/file.txt
        publish_tf: true
        publish_acceleration: false
        map_frame: map              
        odom_frame: odom            
        base_link_frame: base_link  
        world_frame: map           

        twist0: /turtle1/sensors/twist
        twist0_config: [false, false, false,
                       false, false, false,
                       true, true, false,
                       false, false, true,
                       false, false, false]

        pose0: /turtle1/sensors/pose
        pose0_config: [true, true, false,
                false, false, true,
                false, false, false,
                false, false, true,
                false, false, false]
#node_odom.yaml
### ekf config file ###
ekf_filter_node:
    ros__parameters:
        frequency: 30.0
        sensor_timeout: 0.1
        two_d_mode: true
        transform_time_offset: 0.0
        transform_timeout: 0.0
        print_diagnostics: true
        debug: false
        publish_tf: true
        publish_acceleration: false
        map_frame: map              
        odom_frame: odom            
        base_link_frame: base_link  
        world_frame: odom           
        twist0: /turtle1/sensors/twist
        twist0_config: [false, false, false,
                       false, false, false,
                       true, true, false,
                       false, false, true,
                       false, false, false]
        twist0_differential: false
//odometry.cpp

#include "turtlesim/srv/spawn.hpp"
#include "turtlesim/srv/set_pen.hpp"
#include "turtlesim/srv/teleport_relative.hpp"
#include "odometry.hpp"
#include "rclcpp/rclcpp.hpp"
#include <chrono>

using std::placeholders::_1;
using namespace std::chrono_literals;

TurtleOdometry::TurtleOdometry( double frequency,
    double error_vx_systematic, double error_vx_random, double error_wz_systematic, double error_wz_random, bool visualize):
  Node("odometry_node"),
  frequency_{frequency},
  random_generator_{},
  random_distribution_vx_{error_vx_systematic, error_vx_random},
  random_distribution_wz_{error_wz_systematic, error_wz_random},
  frame_sequence_{0},
  visualize_{visualize},
  visualization_turtle_name_{""}
{
  client_cb_group_ = this->create_callback_group(rclcpp::callback_group::CallbackGroupType::MutuallyExclusive);
  other_cb_group_ = this->create_callback_group(rclcpp::callback_group::CallbackGroupType::MutuallyExclusive);
  other_cb_group_ = this->create_callback_group(rclcpp::callback_group::CallbackGroupType::MutuallyExclusive);
  auto sub_opt = rclcpp::SubscriptionOptions();
  sub_opt.callback_group = other_cb_group_;
  turtle_pose_subscriber_ = this->create_subscription<turtlesim::msg::Pose>(
      "turtle1/pose", 16, std::bind(&TurtleOdometry::turtlePoseCallback, this, _1),sub_opt);
  turtle_twist_publisher_ = this->create_publisher<geometry_msgs::msg::TwistWithCovarianceStamped>("turtle1/sensors/twist", 16);
  timer_ = this->create_wall_timer(
  std::chrono::milliseconds((int)(1000/frequency_)), std::bind(&TurtleOdometry::spin, this),other_cb_group_);
}


TurtleOdometry::~TurtleOdometry() {
  ;
}


void TurtleOdometry::spin() {
    // Distort real twist to get a 'measurement'.
    auto measurement = cached_pose_;
    measurement.linear_velocity *= (1. + random_distribution_vx_(random_generator_));
    measurement.angular_velocity += measurement.linear_velocity * random_distribution_wz_(random_generator_);
    // Publish measurement.
    geometry_msgs::msg::TwistWithCovarianceStamped current_twist;
    //current_twist.header.seq = ++ frame_sequence_;
    current_twist.header.stamp = this->get_clock()->now();
    current_twist.header.frame_id = "base_link";
    current_twist.twist.twist.linear.x = measurement.linear_velocity;
    current_twist.twist.twist.linear.y = 0.;
    current_twist.twist.twist.linear.z = 0.;
    current_twist.twist.twist.angular.x = 0.;
    current_twist.twist.twist.angular.y = 0.;
    current_twist.twist.twist.angular.z = measurement.angular_velocity;
    current_twist.twist.covariance = std::array<double, 36>({
        std::pow(random_distribution_vx_.mean() + random_distribution_vx_.stddev(), 2), 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., std::pow(measurement.linear_velocity * (random_distribution_wz_.mean() + random_distribution_wz_.stddev()), 2)});
    turtle_twist_publisher_->publish(current_twist);
    if(isVisualizationRequested() && isVisualizationTurtleAvailable()) {
      moveVisualizationTurtle(measurement);
    }
}


void TurtleOdometry::turtlePoseCallback(const turtlesim::msg::Pose::SharedPtr message) {
  cached_pose_timestamp_ = this->get_clock()->now();
  cached_pose_ = *message;
  // If this is the first message, initialize the visualization turtle.
  if(isVisualizationRequested() && !isVisualizationTurtleAvailable()) {
    spawnAndConfigureVisualizationTurtle(*message);
  }
}


void TurtleOdometry::spawnAndConfigureVisualizationTurtle(const turtlesim::msg::Pose & initial_pose) {
  if(isVisualizationRequested() && !isVisualizationTurtleAvailable()) {
    // Spawn a new turtle and store its name.
    auto client = this->create_client<turtlesim::srv::Spawn>("spawn",rmw_qos_profile_services_default,client_cb_group_);
    client->wait_for_service();
    turtlesim::srv::Spawn::Request::SharedPtr spawn_visualization_turtle = std::make_shared<turtlesim::srv::Spawn::Request>();
    spawn_visualization_turtle->x = initial_pose.x;
    spawn_visualization_turtle->y = initial_pose.y;
    spawn_visualization_turtle->theta = initial_pose.theta;
    auto result_future = client->async_send_request(spawn_visualization_turtle);
    result_future.wait();
    auto result = result_future.get();
    visualization_turtle_name_=result->name;
    // Set pen color to red.
    turtlesim::srv::SetPen::Request::SharedPtr configure_visualization_turtle  = std::make_shared<turtlesim::srv::SetPen::Request>();
    configure_visualization_turtle->r = 255;
    configure_visualization_turtle->g = 0;
    configure_visualization_turtle->b = 0;
    configure_visualization_turtle->width = 1;
    configure_visualization_turtle->off = 0;
    auto client_configure = this->create_client<turtlesim::srv::SetPen>(visualization_turtle_name_ + "/set_pen",rmw_qos_profile_services_default,client_cb_group_);
    auto set_pen_result_future = client_configure->async_send_request(configure_visualization_turtle);
    set_pen_result_future.wait();
    // Log message.
    RCLCPP_INFO(this->get_logger(),"Relative position measurement (odometry) visualized by '%s' with a red pen.", visualization_turtle_name_.c_str());
  }
}


void TurtleOdometry::moveVisualizationTurtle(const turtlesim::msg::Pose & measurement) {
  if(isVisualizationRequested() && isVisualizationTurtleAvailable()) {
    // Move visualization turtle to the 'measured' position.
    turtlesim::srv::TeleportRelative::Request::SharedPtr visualize_current_twist =std::make_shared<turtlesim::srv::TeleportRelative::Request>();
    visualize_current_twist->linear = measurement.linear_velocity / frequency_;
    visualize_current_twist->angular = measurement.angular_velocity / frequency_;
    auto client = this->create_client<turtlesim::srv::TeleportRelative>(
        visualization_turtle_name_ + "/teleport_relative",rmw_qos_profile_services_default,client_cb_group_);
    client->async_send_request(visualize_current_twist);
  }
}

//odometry_node.cpp
#include <boost/program_options.hpp>
#include "rclcpp/rclcpp.hpp"
#include "odometry.hpp"

int main(int argc, char * argv[]) {

  double frequency;
  double error_vx_systematic;
  double error_vx_random;
  double error_wz_systematic;
  double error_wz_random;

  namespace po = boost::program_options;
  po::options_description description("Recognised options");
  description.add_options()
      ("help,h", "print help message")
      ("frequency,f", po::value<double>(&frequency)->default_value(1.), "set measurement frequency (Hz)")
      ("error-vx-systematic,X", po::value<double>(&error_vx_systematic)->default_value(0.), "set systematic error on X velocity")
      ("error-vx-random,x", po::value<double>(&error_vx_random)->default_value(0.), "set random error on X velocity")
      ("error-wz-systematic,T", po::value<double>(&error_wz_systematic)->default_value(0.), "set systematic error on angular velocity")
      ("error-wz-random,t", po::value<double>(&error_wz_random)->default_value(0.), "set random error on angular velocity")
      ("visualize,v", "visualize positioning system measurement");
  po::variables_map variables_map;
  po::store(po::parse_command_line(argc, argv, description), variables_map);
  po::notify(variables_map);

  if (variables_map.count("help")) {
    std::cout << description << std::endl;
    return EXIT_FAILURE;
  }

  rclcpp::init(argc, argv);

  auto node = std::make_shared<TurtleOdometry>(frequency,
      error_vx_systematic, error_vx_random, error_wz_systematic, error_wz_random,
      (variables_map.count("visualize")? true: false));
  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(node);
  executor.spin();
  rclcpp::shutdown();

  return EXIT_SUCCESS;
}

//positioning_system.cpp
#include "positioning_system.hpp"
#include "turtlesim/srv/spawn.hpp"
#include "turtlesim/srv/set_pen.hpp"
#include "turtlesim/srv/teleport_absolute.hpp"
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
#include <chrono>
#include <tf2/LinearMath/Quaternion.h>
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"

using std::placeholders::_1;
using namespace std::chrono_literals;


TurtlePositioningSystem::TurtlePositioningSystem(double frequency, double error_x_systematic,
        double error_x_random, double error_y_systematic, double error_y_random, double error_yaw_systematic,
        double error_yaw_random, bool visualize):
  Node("positioning_node"),
  frequency_{frequency},
  random_generator_{},
  random_distribution_x_{error_x_systematic, error_x_random},
  random_distribution_y_{error_y_systematic, error_y_random},
  random_distribution_yaw_{error_yaw_systematic, error_yaw_random},
  frame_sequence_{0},
  visualize_{visualize},
  visualization_turtle_name_{""}
{
  client_cb_group_ = this->create_callback_group(rclcpp::callback_group::CallbackGroupType::MutuallyExclusive);
  other_cb_group_ = this->create_callback_group(rclcpp::callback_group::CallbackGroupType::MutuallyExclusive);
  auto sub_opt = rclcpp::SubscriptionOptions();
  sub_opt.callback_group = other_cb_group_;
  turtle_pose_subscriber_ = this->create_subscription<turtlesim::msg::Pose>(
  "turtle1/pose", 16, std::bind(&TurtlePositioningSystem::turtlePoseCallback, this, _1),sub_opt);
  turtle_pose_publisher_ = this->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("turtle1/sensors/pose", 16);
  timer_ = this->create_wall_timer(
  std::chrono::milliseconds((int)(1000/frequency_)), std::bind(&TurtlePositioningSystem::spin, this),other_cb_group_);
}


  TurtlePositioningSystem::~TurtlePositioningSystem() {
    ;
  }


  void TurtlePositioningSystem::spin() {
      // Distort real pose to get a 'measurement'.
      auto measurement = cached_pose_;
      measurement.x += random_distribution_x_(random_generator_);
      measurement.y += random_distribution_y_(random_generator_);
      measurement.theta += random_distribution_yaw_(random_generator_);
      // Publish measurement.
      geometry_msgs::msg::PoseWithCovarianceStamped current_pose;
      //current_pose.header.seq = ++ frame_sequence_;
      current_pose.header.stamp = this->get_clock()->now();
      current_pose.header.frame_id = "map";
      current_pose.pose.pose.position.x = measurement.x;
      current_pose.pose.pose.position.y = measurement.y;
      current_pose.pose.pose.position.z = 0.;
      tf2::Quaternion quat;
      quat.setRPY(0., 0., measurement.theta);
      current_pose.pose.pose.orientation = tf2::toMsg(quat);
      current_pose.pose.covariance = std::array<double, 36>({
          std::pow(random_distribution_x_.mean() + random_distribution_x_.stddev(), 2), 0., 0., 0., 0., 0.,
          0., std::pow(random_distribution_y_.mean() + random_distribution_y_.stddev(), 2), 0., 0., 0., 0.,
          0., 0., 0., 0., 0., 0.,
          0., 0., 0., 0., 0., 0.,
          0., 0., 0., 0., 0., 0.,
          0., 0., 0., 0., 0., std::pow(random_distribution_yaw_.mean() + random_distribution_yaw_.stddev(), 2)});
      turtle_pose_publisher_->publish(current_pose);
      if(isVisualizationRequested() && isVisualizationTurtleAvailable()) {
        moveVisualizationTurtle(measurement);
      }
    }


  void TurtlePositioningSystem::turtlePoseCallback(const turtlesim::msg::Pose::SharedPtr message) {
    cached_pose_timestamp_ =this->get_clock()->now();
    cached_pose_ = *message;
    // If this is the first message, initialize the visualization turtle.
    if(isVisualizationRequested() && !isVisualizationTurtleAvailable()) {
      spawnAndConfigureVisualizationTurtle(*message);
    }
  }


  void TurtlePositioningSystem::spawnAndConfigureVisualizationTurtle(const turtlesim::msg::Pose & initial_pose) {
    if(isVisualizationRequested() && !isVisualizationTurtleAvailable()) {
      // Spawn a new turtle and store its name.
      auto client = this->create_client<turtlesim::srv::Spawn>("spawn",rmw_qos_profile_services_default,client_cb_group_);
      client->wait_for_service();
      turtlesim::srv::Spawn::Request::SharedPtr spawn_visualization_turtle = std::make_shared<turtlesim::srv::Spawn::Request>();

      spawn_visualization_turtle->x = initial_pose.x;
      spawn_visualization_turtle->y = initial_pose.y;
      spawn_visualization_turtle->theta = initial_pose.theta;
      // auto set_turtle_name = [&](rclcpp::Client<turtlesim::srv::Spawn>::SharedFuture inner_future){
      //   auto result = inner_future.get();
      //   visualization_turtle_name_=result->name;
      auto result_future = client->async_send_request(spawn_visualization_turtle);
      result_future.wait();
      auto result = result_future.get();
      visualization_turtle_name_=result->name;
      // Set pen color to blue.
      turtlesim::srv::SetPen::Request::SharedPtr configure_visualization_turtle = std::make_shared<turtlesim::srv::SetPen::Request>();
      configure_visualization_turtle->r = 0;
      configure_visualization_turtle->g = 0;
      configure_visualization_turtle->b = 255;
      configure_visualization_turtle->width = 1;
      configure_visualization_turtle->off = 0;
      auto client_configure = this->create_client<turtlesim::srv::SetPen>(visualization_turtle_name_ + "/set_pen",rmw_qos_profile_services_default,client_cb_group_);
      auto set_pen_result_future = client_configure->async_send_request(configure_visualization_turtle);
      set_pen_result_future.wait();
      // Log message.
      RCLCPP_INFO(this->get_logger(),"Relative position measurement (odometry) visualized by '%s' with a blue pen.", visualization_turtle_name_.c_str()); 
    }
  }


  void TurtlePositioningSystem::moveVisualizationTurtle(const turtlesim::msg::Pose & measurement) {
    if(isVisualizationRequested() && isVisualizationTurtleAvailable()) {
      // Move visualization turtle to the 'measured' position.
      turtlesim::srv::TeleportAbsolute::Request::SharedPtr visualize_current_pose = std::make_shared<turtlesim::srv::TeleportAbsolute::Request>();
      visualize_current_pose->x = measurement.x;
      visualize_current_pose->y = measurement.y;
      visualize_current_pose->theta = measurement.theta;
      auto client = this->create_client<turtlesim::srv::TeleportAbsolute>(
        visualization_turtle_name_ + "/teleport_absolute",rmw_qos_profile_services_default,client_cb_group_);
      client->async_send_request(visualize_current_pose);
    }
  }


//positioning_system_node.cpp
#include <boost/program_options.hpp>
#include "rclcpp/rclcpp.hpp"
#include "positioning_system.hpp"

int main(int argc, char * argv[]) {

    double frequency;
    double error_x_systematic;
    double error_x_random;
    double error_y_systematic;
    double error_y_random;
    double error_yaw_systematic;
    double error_yaw_random;

    namespace po = boost::program_options;
    po::options_description description("Recognised options");
    description.add_options()
        ("help,h", "print help message")
        ("frequency,f", po::value<double>(&frequency)->default_value(1.), "set measurement frequency (Hz)")
        ("error-x-systematic,X", po::value<double>(&error_x_systematic)->default_value(0.), "set systematic error on X")
        ("error-x-random,x", po::value<double>(&error_x_random)->default_value(0.), "set random error on X")
        ("error-y-systematic,Y", po::value<double>(&error_y_systematic)->default_value(0.), "set systematic error on Y")
        ("error-y-random,y", po::value<double>(&error_y_random)->default_value(0.), "set random error on Y")
        ("error-yaw-systematic,T", po::value<double>(&error_yaw_systematic)->default_value(0.), "set systematic error on yaw")
        ("error-yaw-random,t", po::value<double>(&error_yaw_random)->default_value(0.), "set random error on yaw")
        ("visualize,v", "visualize positioning system measurement");
    po::variables_map variables_map;
    po::store(po::parse_command_line(argc, argv, description), variables_map);
    po::notify(variables_map);

    if (variables_map.count("help")) {
    std::cout << description << std::endl;
    return EXIT_FAILURE;
    }

    rclcpp::init(argc, argv);
    auto node = std::make_shared<TurtlePositioningSystem> (frequency,
    error_x_systematic, error_x_random, error_y_systematic, error_y_random,
    error_yaw_systematic, error_yaw_random, (variables_map.count("visualize")? true: false));
    rclcpp::executors::MultiThreadedExecutor executor;
    executor.add_node(node);
    executor.spin();
    rclcpp::shutdown();

    return EXIT_SUCCESS;
}
//transformation_visualization_node.cpp
#include "rclcpp/rclcpp.hpp"
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <tf2_ros/transform_listener.h>
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "turtlesim/srv/spawn.hpp"
#include "turtlesim/srv/set_pen.hpp"
#include "turtlesim/srv/teleport_absolute.hpp"
#include <chrono>
using namespace std::chrono_literals;

int main(int argc, char* argv[]) {
    rclcpp::init(argc, argv);

  std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("transformation_visualization_node");

  tf2_ros::Buffer tf_buffer(node->get_clock());
  tf2_ros::TransformListener tf_listener(tf_buffer);

  // Spawn a new turtle and store its name.
    auto client = node->create_client<turtlesim::srv::Spawn>("spawn");
    while (!client->wait_for_service(std::chrono::seconds(1))) {
    if (!rclcpp::ok()) {
        RCLCPP_ERROR(node->get_logger(), "client interrupted while waiting for service to appear.");
        return 1;
    }
    RCLCPP_INFO(node->get_logger(), "waiting for service to appear...");
    }

  turtlesim::srv::Spawn::Request::SharedPtr spawn_visualization_turtle = std::make_shared<turtlesim::srv::Spawn::Request>();
  spawn_visualization_turtle->x = 0;
  spawn_visualization_turtle->y = 0;
  spawn_visualization_turtle->theta = 0;
  auto result_future = client->async_send_request(spawn_visualization_turtle);
    if (rclcpp::spin_until_future_complete(node, result_future) !=
    rclcpp::executor::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "service call failed :(");
    //client->remove_pending_request(result_future);
    return 1;
  }
  auto result = result_future.get();
  auto visualization_turtle_name = result->name;
  // Set pen color to light blue.
  turtlesim::srv::SetPen::Request::SharedPtr configure_visualization_turtle = std::make_shared<turtlesim::srv::SetPen::Request>();
  configure_visualization_turtle->r = 0;
  configure_visualization_turtle->g = 255;
  configure_visualization_turtle->b = 0;
  configure_visualization_turtle->width = 3;
  configure_visualization_turtle->off = 0;
  auto client_configure = node->create_client<turtlesim::srv::SetPen>( visualization_turtle_name + "/set_pen");
  auto result_future_setpen = client_configure->async_send_request(configure_visualization_turtle);
    if (rclcpp::spin_until_future_complete(node, result_future_setpen) !=
    rclcpp::executor::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "service call failed :(");
    //client->remove_pending_request(result_future);
    return 1;
  }
  // Log message.
  RCLCPP_INFO(node->get_logger(),"Absolute position estimate visualized by '%s' using a green pen.", visualization_turtle_name.c_str());

  // Visualize the estimated position of the turtle in the map frame.
  rclcpp::Rate a(10);
  while(rclcpp::ok()) {
    // Get base_link to map transformation.
    geometry_msgs::msg::TransformStamped base_link_to_map_transform;
    try {
      base_link_to_map_transform = tf_buffer.lookupTransform("map", "base_link", tf2::TimePointZero);
    }
    catch (tf2::TransformException &ex) {
      RCLCPP_INFO(node->get_logger(),"tf2_ros::Buffer::lookupTransform failed: %s", ex.what());
      rclcpp::sleep_for(1s);
      continue;
    }
    // Move visualization turtle to the estimated position.
    geometry_msgs::msg::PoseStamped pose_base_link, pose_map;
    pose_base_link.header.stamp = node->get_clock()->now();
    pose_base_link.header.frame_id = "base_link";
    pose_base_link.pose.position.x = 0.;
    pose_base_link.pose.position.y = 0.;
    pose_base_link.pose.position.z = 0.;
    pose_base_link.pose.orientation.x = 0.;
    pose_base_link.pose.orientation.y = 0.;
    pose_base_link.pose.orientation.z = 0.;
    pose_base_link.pose.orientation.w = 1.;
    tf2::doTransform(pose_base_link, pose_map, base_link_to_map_transform);
    turtlesim::srv::TeleportAbsolute::Request::SharedPtr visualize_current_pose = std::make_shared<turtlesim::srv::TeleportAbsolute::Request>();
    visualize_current_pose->x = pose_map.pose.position.x;
    visualize_current_pose->y = pose_map.pose.position.y;
    tf2::Quaternion quaternion(pose_map.pose.orientation.x, pose_map.pose.orientation.y, pose_map.pose.orientation.z, pose_map.pose.orientation.w);
    visualize_current_pose->theta = quaternion.getAngle();
    auto client_visual =node->create_client<turtlesim::srv::TeleportAbsolute>(visualization_turtle_name + "/teleport_absolute");
    auto result_future_visual =client_visual->async_send_request(visualize_current_pose);
        if (rclcpp::spin_until_future_complete(node, result_future_visual) !=
    rclcpp::executor::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "service call failed :(");
    //client->remove_pending_request(result_future);
    return 1;
  }
    // Sleep until the next update.
    a.sleep();
  }

  return EXIT_SUCCESS;
}

#CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(robot_localization_demo)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

set(CMAKE_PREFIX_PATH ../../install)
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(tf2_ros REQUIRED) 
find_package(geometry_msgs REQUIRED)
find_package(turtlesim REQUIRED)
find_package(tf2 REQUIRED)
find_package(tf2_geometry_msgs REQUIRED)
find_package(robot_localization REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

find_package(Boost REQUIRED COMPONENTS program_options)
include_directories(${Boost_INCLUDE_DIRS})

add_executable(odometry_node src/odometry_node.cpp src/odometry.cpp)
target_include_directories(odometry_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

  ament_target_dependencies(
    odometry_node   
    rclcpp
    geometry_msgs
    turtlesim
    tf2
    tf2_ros
  )  
  target_link_libraries(odometry_node
  Boost::program_options
)   

add_executable(positioning_system_node src/positioning_system_node.cpp src/positioning_system.cpp)
target_include_directories(positioning_system_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

  ament_target_dependencies(
    positioning_system_node   
    rclcpp
    geometry_msgs
    turtlesim
    tf2
    tf2_ros
  )    
  target_link_libraries(positioning_system_node
  Boost::program_options
)   
add_executable(transformation_visualization_node src/transformation_visualization_node.cpp)
target_include_directories(transformation_visualization_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

  ament_target_dependencies(
    transformation_visualization_node   
    rclcpp
    geometry_msgs
    turtlesim
    tf2
    tf2_ros
    tf2_geometry_msgs
  )    

install(TARGETS odometry_node positioning_system_node transformation_visualization_node
  DESTINATION lib/${PROJECT_NAME})

install(DIRECTORY
  params
  launch
  DESTINATION share/${PROJECT_NAME}
  USE_SOURCE_PERMISSIONS
)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

///package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>robot_localization_demo</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="a@todo.todo">a</maintainer>
  <license>TODO: License declaration</license>

  <depend>geometry_msgs</depend>
  <depend>robot_localization</depend>
  <depend>rclcpp</depend>
  <depend>tf2</depend>
  <depend>tf2_ros</depend>
  <depend>turtlesim</depend>
  <depend>RL</depend>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


4、编译使用

将教程代码进行编译,随后launch运行,并在单独的窗口运行小乌龟控制节点,即可开始测试。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
要使用ROS功能robot_localization,您需要按照以下步骤操作: 1. 安装robot_localization功能 在终端中执行以下命令,安装robot_localization功能: ``` sudo apt-get install ros-<distro>-robot-localization ``` 其中,`<distro>`是您正在使用的ROS发行版的名称。例如,如果您使用的是ROS Kinetic,那么命令应该是: ``` sudo apt-get install ros-kinetic-robot-localization ``` 2. 配置参数文件 在使用robot_localization功能之前,您需要配置一个参数文件来定义您的传感器和估计器的设置。您可以使用以下命令将默认参数文件复制到您的工作空间中: ``` cp /opt/ros/<distro>/share/robot_localization/params/ekf_template.yaml <workspace>/src/<package>/config/ekf.yaml ``` 请注意将`<distro>`替换为您正在使用的ROS发行版的名称,并将`<workspace>`替换为您的工作空间的路径,`<package>`替换为您要使用robot_localization功能ROS软件的名称。 然后,您需要编辑`<workspace>/src/<package>/config/ekf.yaml`文件,根据您的传感器和估计器的设置进行配置。 3. 启动节点 在终端中执行以下命令,启动robot_localization节点: ``` roslaunch <package> <launch_file>.launch ``` 请注意将`<package>`替换为您要使用robot_localization功能ROS软件的名称,`<launch_file>`替换为您要启动的launch文件的名称。 4. 查看输出 启动节点后,robot_localization将开始接收传感器数据,并使用您的配置进行状态估计。您可以使用以下命令查看robot_localization节点的输出: ``` rostopic echo /odometry/filtered ``` 请注意将`/odometry/filtered`替换为您在参数文件中配置的输出话题。 这些是使用robot_localization功能的基本步骤。您可以在ROS Wiki上找到更多详细的信息和示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值