1.4.5 里程计案例(C++)

1.源文件

功能包cpp00_odom的src目录下,新建C++文件odom2path.cpp,并编辑文件,输入如下内容:

/*
    需求:订阅机器人的里程计数据,生成并发布机器人的运行轨迹。
    流程:
        1.包含头文件;
        2.初始化ROS2客户端;
        3.自定义节点类;
          3-1.创建订阅方,订阅里程计消息;
          3-2.创建发布方,发布轨迹信息。
        4.调用spin函数,并传入节点对象指针;
        5.资源释放。
*/
// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include "nav_msgs/msg/path.hpp"
#include "geometry_msgs/msg/pose_stamped.hpp"
#include "geometry_msgs/msg/pose.hpp"

using namespace std::placeholders;
// 3.自定义节点类;
class Odom2Path: public rclcpp::Node{
public:
    Odom2Path():Node("odom2path_node_cpp"){
        // 将原点添加进路径
        append_last_pose();
        // 3-1.创建订阅方,订阅里程计消息;
        odom_sub_ = this->create_subscription<nav_msgs::msg::Odometry>("/odom",10,std::bind(&Odom2Path::odom_cb,this,_1));
        // 3-2.创建发布方,发布轨迹信息。
        path_pub_ = this->create_publisher<nav_msgs::msg::Path>("/path",10);

    }
private:
    rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr odom_sub_;
    rclcpp::Publisher<nav_msgs::msg::Path>::SharedPtr path_pub_;
    std::vector<geometry_msgs::msg::PoseStamped> poses; // 用于保存路径中的途经点的集合
    geometry_msgs::msg::Pose last_pose; // 集合中最后一个途经点的位姿信息

    void odom_cb(const nav_msgs::msg::Odometry::SharedPtr odom){
        // 获取当前位姿信息
        auto current_pose = odom->pose.pose;
        // 计算与上一位姿之间的直线距离
        double distance = get_distance(current_pose);
        // 如果符合条件(直线距离大于40cm),就组织新的轨迹信息
        if (distance >= 0.4)
        {
            last_pose = current_pose;
            append_last_pose(); // 将当前途经点添加进集合
        }
        // 周期性发布轨迹信息,无论是否添加了新的途经点数据
        publish_path();

    }
    // 将点添加进数组
    void append_last_pose(){
        // 组织PoseStamped数据
        auto ps = geometry_msgs::msg::PoseStamped();
        ps.header.stamp = this->now();
        ps.header.frame_id = "odom";
        ps.pose = last_pose;
        // 追加进集合
        poses.push_back(ps);
    }
    // 发布路径
    void publish_path(){

        // 组织Path数据
        auto path_msg = nav_msgs::msg::Path();
        path_msg.header.stamp = this->now();
        path_msg.header.frame_id = "odom";
        path_msg.poses = poses;
        // 发布
        path_pub_->publish(path_msg);
    }
    // 获取当前位姿与集合中最后一个途经点的直线距离
    double get_distance(const geometry_msgs::msg::Pose& current_pose){
        double dx = current_pose.position.x - last_pose.position.x;
        double dy = current_pose.position.y - last_pose.position.y;
        double distance =  sqrt(pow(dx,2) + pow(dy,2));
        return distance;
    }
};

int main(int argc, char const *argv[])
{
    // 2.初始化ROS2客户端;
    rclcpp::init(argc,argv);
    // 4.调用spain函数,并传入节点对象指针;
    rclcpp::spin(std::make_shared<Odom2Path>());
    // 5.资源释放。
    rclcpp::shutdown();
    return 0;
}

2.编辑配置文件

1.packages.xml

在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:

<depend>rclcpp</depend>
<depend>nav_msgs</depend>
<depend>geometry_msgs</depend>
2.CMakeLists.txt

CMakeLists.txt 中核心配置如下:

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(nav_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)



add_executable(odom2path src/odom2path.cpp)

ament_target_dependencies(
  sim_laser
  "rclcpp"
  "nav_msgs"
  "geometry_msgs"
)

install(TARGETS odom2path
  DESTINATION lib/${PROJECT_NAME})

3.编译

终端中进入当前工作空间,编译功能包:

colcon build --packages-select cpp00_odom

4.执行

请先按照之前介绍,启动机器人底盘以及键盘控制节点。

然后在当前工作空间下,启动终端,并输入如下指令:

. install/setup.bash
ros2 run cpp00_odom odom2path

5.使用rviz2查看结果

新建终端,输入如下指令:

rviz2

rviz2启动后,将参考坐标系设置为odom,添加Path插件并将话题设置为/path。当键盘控制机器人运动时,在rviz2中就会显示机器人的运动轨迹,其运行结果与演示案例类似。

results matching ""

    No results matching ""