VINS_MONO视觉导航算法【三】ROS基础知识介绍

文章目录

    • 其他文章
    • 说明
    • ROS
      • launch文件
        • 基本概念
          • 定义
          • 用途
        • 文件结构
          • 根标签
          • 常用标签
            • \<node>
            • \<param>
            • \<rosparam>
            • \<remap>
            • \<include>
            • \<arg>
            • \<group>
        • 示例
          • 基本示例
          • 嵌套示例
        • 使用方法
          • 启动 *.launch 文件
          • 传递参数
        • 总结
      • ROS topic
        • Topic 的基本概念
        • Topic 的工作原理
        • 常用命令
        • 示例
        • 总结
      • ROS常用命令
        • rosrun
        • roslaunch
        • rosbag
          • 主要功能
        • roscore
        • rosnode
        • rostopic
        • rosservice
        • rosparam
        • rqt
        • ros::spin()
          • 功能
          • 使用场景
          • 示例
            • 解释
            • 替代方案
          • 总结
        • ros::NodeHandle
          • 主要功能
          • 示例代码
          • 详细解释
          • advertise
            • 语法和参数
            • 参数说明
            • 示例
          • subscribe
            • 语法和参数
            • 参数说明
            • 示例代码
            • 详细解释
            • 成员函数作为回调函数
            • 详细解释
        • ros::Publisher
          • 主要功能
          • 创建和使用 ros::Publisher
          • 示例代码
          • 详细解释
          • 其他常用方法
      • RViz
        • RViz 的主要特点
        • RViz 的使用
          • 启动 RViz
          • 加载配置文件
          • 示例中的 RViz 配置
        • 总结
      • EVO
        • EVO的主要功能
        • 使用EVO进行性能测试的基本步骤
        • 示例命令
        • 结论

其他文章

  1. VINS_MONO视觉导航算法【一】基础知识介绍
  2. VINS_MONO视觉导航算法【二】论文讲解+GPU实现调研
  3. VINS_MONO视觉导航算法【三】ROS基础知识介绍
  4. VINS_MONO视觉导航算法【四】VINS_Mono代码解释

说明

这是第三篇,这一部分介绍一些ROS的基础概念,方便后面理解VINS_Mono代码。

ROS

launch文件

*.launch 文件是 ROS(Robot Operating System)中的一种 XML 文件,用于描述和配置多个节点、参数以及其他 ROS 系统组件。通过 *.launch 文件,可以一次性启动多个节点,并设置各种参数,从而简化了复杂系统的启动和配置过程。下面是关于 *.launch 文件的详细解释:

基本概念
定义

.launch 文件: 是一种 XML 文件,用于描述和配置 ROS 系统中的节点、参数、话题、服务等。

roslaunch 命令: 用于启动 *.launch 文件中定义的节点和配置。

用途

启动多个节点: 可以同时启动多个节点,而不需要在多个终端中分别运行 rosrun 命令。

设置参数: 可以在启动文件中设置节点的参数,这些参数会被加载到参数服务器中。

命名空间管理: 可以使用命名空间来组织和隔离节点,避免命名冲突。

重映射话题和服务: 可以在启动文件中重映射话题和服务的名称,使节点之间的通信更加灵活。

嵌套启动文件: 可以在一个启动文件中包含其他启动文件,实现模块化配置。

文件结构
根标签

: 是 *.launch 文件的根标签,所有其他标签都必须包含在这个标签内。

常用标签
<node>

描述: 用于启动一个 ROS 节点。在 *.launch 文件中,节点通过 标签来定义。每个节点代表一个独立的 ROS 进程,可以执行特定的任务,如传感器数据处理、导航算法等。

常用属性:

pkg: 节点所在的功能包名称。

type: 节点的可执行文件名称。

name: 节点启动时的名称。

args: 传递给节点的命令行参数。

output: 控制节点的日志输出,可以是 “screen”(输出到终端)或 “log”(输出到日志文件)。

respawn: 如果节点退出,是否自动重启,可以是 “true” 或 “false”。

required: 如果节点退出,是否终止其他节点,可以是 “true” 或 “false”。

ns: 节点的命名空间。

示例:

<node pkg="my_robot" type="navigation_node" name="nav_node" output="screen">

  <param name="target_location" value="room_1" >

  <remap from="odom" to="base_odom" >

</node>
  • pkg=“my_robot”: 节点所在的包名是 my_robot。
  • type=“navigation_node”: 节点的可执行文件名是 navigation_node。
  • name=“nav_node”: 节点启动时的名称是 nav_node。
  • output=“screen”: 节点的日志输出到终端。
  • : 设置节点的参数。
  • : 重映射话题。
<param>

描述: 用于设置参数服务器中的参数。

常用属性:

name: 参数的名称。

value: 参数的值。

type: 参数的类型,可以是 “string”, “int”, “float”, “bool”, “yaml” 等。

textfile: 从文本文件中读取参数值。

binfile: 从二进制文件中读取参数值。

command: 通过命令行命令生成参数值。

<rosparam>

描述: 用于从 YAML 文件中加载参数到参数服务器,或从参数服务器中删除参数。

常用属性:

command: 操作类型,可以是 “load”, “dump”, “delete”。

file: YAML 文件的路径。

param: 参数的名称。

<remap>

描述: 用于重映射话题或服务的名称。

常用属性:

from: 原始名称。

to: 新名称。

<include>

描述: 用于包含其他启动文件。

常用属性:

file: 要包含的启动文件的路径。

<arg>

描述: 用于定义启动文件中的变量。

常用属性:

name: 变量的名称。

default: 变量的默认值。

value: 变量的值(如果在命令行中指定了值,则使用命令行中的值)。

<group>

描述: 用于将一组节点或配置项组织在一起。

常用属性:

ns: 组的命名空间。

if: 条件属性,如果条件为真,则执行组内的内容。

unless: 条件属性,如果条件为假,则执行组内的内容。

示例
基本示例
<launch>

  <!-- 定义一个参数 -->

  <param name="max_velocity" value="1.0" >

  <!-- 启动一个节点 -->

  <node pkg="my_robot" type="navigation_node" name="nav_node" output="screen">
  
    <!-- 设置节点的参数 -->

    <param name="target_location" value="room_1" >

    <!-- 重映射话题 -->

    <remap from="odom" to="base_odom" >
  
  </node>

  <!-- 包含另一个启动文件 -->

  <include file="$(find my_robot)/launch/sensors.launch" >

</launch>
嵌套示例
<launch>

  <!-- 定义一个变量 -->

  <arg name="use_sim_time" default="false" >

  <!-- 使用变量 -->

  <param name="use_sim_time" value="$(arg use_sim_time)" >

  <!-- 启动一个节点组 -->

  <group ns="robot1">

    <node pkg="my\_robot" type="navigation\_node" name="nav\_node" output="screen">
    
      <param name="target\_location" value="room\_1" />
    
    </node>

    <node pkg="my_robot" type="navigation_node" name="nav_node" output="screen">

      <param name="target_location" value="room_1" >

    </node>
    
  </group>

  <!-- 启动另一个节点组 -->

  <group ns="robot2" if="$(arg use_sim_time)">

    <node pkg="my\_robot" type="navigation\_node" name="nav\_node" output="screen">
    
      <param name="target\_location" value="room\_2" />
    
    </node>

  </group>

</launch>
使用方法
启动 *.launch 文件
roslaunch package_name launch_file_name.launch

package_name: 节点所在的功能包名称。

launch_file_name: 启动文件的名称。
传递参数
roslaunch package_name launch_file_name.launch arg_name:=arg_value

arg_name: 变量的名称。

arg_value: 变量的值。
总结

*.launch 文件是 ROS 中非常重要的配置文件,通过它可以方便地管理和启动多个节点,设置参数,重映射话题和服务,以及嵌套其他启动文件。合理使用 *.launch 文件可以大大提高开发效率,简化复杂系统的启动和配置过程。

ROS topic

在 ROS(Robot Operating System)中,topic 是一种通信机制,用于节点之间的异步消息传递。通过 topic,多个节点可以发布和订阅消息,实现数据的共享和交换。以下是关于 ROS topic 的详细解释:

Topic 的基本概念

发布者(Publisher):

发布者是向特定 topic 发送消息的节点。一个发布者可以向多个 topic 发布消息,但通常情况下,一个发布者只向一个 topic 发布消息。

订阅者(Subscriber):

订阅者是从特定 topic 接收消息的节点。一个订阅者可以订阅多个 topic,但通常情况下,一个订阅者只订阅一个 topic。

消息(Message):

消息是发布者和订阅者之间传递的数据单元。每条消息都有一个特定的数据结构,这个结构由 ROS 消息类型(如 std_msgs/String、sensor_msgs/Image 等)定义。

Topic 的工作原理

注册:

当一个节点启动时,它会向 ROS 主节点(master node)注册自己作为一个发布者或订阅者,并指定它所发布的或订阅的 topic。

发现:

主节点维护一个所有注册节点的列表,并将这些信息提供给其他节点。当一个订阅者节点启动时,它会向主节点查询是否有发布者节点正在发布它感兴趣的 topic。如果有,主节点会将发布者的地址提供给订阅者。

连接:

订阅者节点会直接与发布者节点建立 TCP/IP 连接,以便接收消息。这种连接是点对点的,不经过主节点。

消息传递:

发布者节点通过已建立的连接将消息发送给订阅者节点。订阅者节点接收到消息后,可以对其进行处理。

常用命令
列出所有活动 topic: 

rostopic list

查看某个 topic 的消息类型: 

rostopic type /topic_name

查看某个 topic 的消息内容: 

rostopic echo /topic_name

发布消息到某个 topic: 

rostopic pub /topic_name std_msgs/String "data: 'Hello, World!'"

查看某个 topic 的频率: 

rostopic hz /topic_name
示例

假设有一个发布者节点发布 /chatter topic 的字符串消息,一个订阅者节点订阅该 topic 并打印接收到的消息。

发布者节点代码示例(Python)

#!/usr/bin/env python

import rospy

from std_msgs.msg import String

def talker():

    pub = rospy.Publisher('chatter', String, queue_size=10)
    
    rospy.init_node('talker', anonymous=True)
    
    rate = rospy.Rate(1)  # 1 Hz
    
    while not rospy.is_shutdown():
    
        hello_str = "Hello, World! %s" % rospy.get_time()
    
        rospy.loginfo(hello_str)
    
        pub.publish(hello_str)
    
        rate.sleep()

pub = rospy.Publisher('chatter', String, queue_size=10)

rospy.init_node('talker', anonymous=True)

rate = rospy.Rate(1)  # 1 Hz

while not rospy.is_shutdown():

    hello_str = "Hello, World! %s" % rospy.get_time()

    rospy.loginfo(hello_str)

    pub.publish(hello_str)

    rate.sleep()
    
    if name == 'main':

    try:
    
        talker()
    
    except rospy.ROSInterruptException:
    
        pass


订阅者节点代码示例(Python)

#!/usr/bin/env python

import rospy

from std_msgs.msg import String

def callback(data):

    rospy.loginfo(rospy.get_caller_id() + " I heard %s", data.data)

def listener():

    rospy.init_node('listener', anonymous=True)
    
    rospy.Subscriber("chatter", String, callback)
    
    rospy.spin()

if name == 'main':

    listener()


总结

ROS topic 是一种轻量级、高效的通信机制,适用于节点之间的异步消息传递。通过发布者和订阅者的模式,ROS topic 实现了数据的解耦和灵活的通信架构。熟悉如何使用 topic 和相关的命令行工具,可以帮助开发者更好地管理和调试 ROS 系统。

ROS常用命令

rosrun

描述: 用于启动单个 ROS 节点。

语法:

rosrun package_name executable_name

示例:

rosrun my_robot navigation_node

用途: 主要用于调试和测试单个节点。

roslaunch

描述: 用于启动 *.launch 文件,可以同时启动多个节点,并设置参数、重映射话题等。

语法:

roslaunch package_name launch_file_name.launch

示例:

roslaunch my_robot navigation.launch

用途: 适用于启动复杂的系统,包含多个节点和参数配置。

rosbag

rosbag 是 ROS(Robot Operating System)中一个非常重要的命令行工具,用于记录和回放ROS话题消息。它主要用于数据采集、测试和回放,帮助开发者收集和分析机器人在实际运行中的数据。

主要功能

记录数据:

使用 rosbag record 命令可以记录指定的话题数据到一个文件中。

例如,记录所有话题的数据:

rosbag record -a

记录特定话题的数据:

rosbag record /topic1 /topic2

回放数据:

使用 rosbag play 命令可以回放记录的数据文件。

例如,回放一个数据文件:

rosbag play my_bag_file.bag

控制回放速度:

rosbag play my_bag_file.bag --rate=0.5 # 慢速回放

查看数据:

使用 rosbag info 命令可以查看数据文件的信息,包括话题列表、消息数量等。

例如,查看数据文件的信息:

rosbag info my_bag_file.bag

转换数据:

使用 rosbag filter 命令可以过滤和转换数据文件。

例如,过滤出特定话题的消息:

rosbag filter input.bag output.bag “topic == ‘/topic1’”

roscore

启动 ROS 核心节点,它是所有 ROS 节点通信的基础。

例如:

roscore

rosnode

查看和管理 ROS 节点。

例如,列出所有活动节点:

rosnode list

查看节点的信息:

rosnode info /node_name

rostopic

查看和管理 ROS 话题。

例如,列出所有活动话题:

rostopic list

查看某个话题的消息类型:

rostopic type /topic_name

发布消息到某个话题:

rostopic pub /topic_name std_msgs/String “data: ‘Hello, World!’”

查看某个话题的消息内容:

rostopic echo /topic_name

rosservice

查看和管理 ROS 服务。

例如,列出所有活动服务:

rosservice list

查看某个服务的服务类型:

rosservice type /service_name

调用某个服务:

rosservice call /service_name “request_data”

rosparam

查看和管理 ROS 参数服务器上的参数。

例如,列出所有参数:

rosparam list

设置参数:

rosparam set /param_name value

获取参数:

rosparam get /param_name

rqt

ROS 的图形用户界面工具,提供了多种插件用于可视化和调试ROS系统。

例如,启动 rqt:

rqt

ros::spin()

ros::spin(); 是 ROS(Robot Operating System)中的一个函数调用,用于启动一个循环,不断处理接收到的消息和服务请求。这是 ROS 节点的标准入口点之一,通常用于节点的主循环中。以下是详细的解释:

功能

消息处理:

ros::spin(); 会进入一个无限循环,监听并处理订阅的 topic 上的消息。

它会调用所有已注册的回调函数,处理接收到的消息。

服务请求处理:

如果节点提供了服务(services),ros::spin(); 也会处理这些服务请求。

定时器处理:

如果节点中有定时器(timers),ros::spin(); 也会处理定时器的回调。

使用场景

单线程节点:对于大多数简单的 ROS 节点,使用 ros::spin(); 是最常见的方式。它会阻塞当前线程,直到节点被关闭。

多线程节点:如果需要更细粒度的控制,可以使用 ros::spinOnce(); 结合自定义的循环来实现多线程处理。

示例

以下是一个简单的 ROS 节点示例,展示了如何使用 ros::spin();:

#include <ros/ros.h>

#include <sensor_msgs/Image.h>

// 回调函数,处理接收到的图像消息

void imageCallback(const sensor_msgs::ImageConstPtr& msg)

{

    // 处理图像消息
    
    ROS_INFO("Received an image with timestamp: %f", msg->header.stamp.toSec());

}

int main(int argc, char **argv)

{

    // 初始化 ROS 节点
    
    ros::init(argc, argv, "image_subscriber");
    
    // 创建节点句柄
    
    ros::NodeHandle nh;
    
    // 订阅图像话题
    
    ros::Subscriber sub = nh.subscribe("camera/image_raw", 1, imageCallback);
    
    // 进入消息处理循环
    
    ros::spin();
    
    return 0;

}


解释

初始化节点:

ros::init(argc, argv, “image_subscriber”); 初始化 ROS 节点,节点名称为 image_subscriber。

创建节点句柄:

ros::NodeHandle nh; 创建一个节点句柄,用于订阅话题、发布消息等。

订阅话题:

ros::Subscriber sub = nh.subscribe(“camera/image_raw”, 1, imageCallback); 订阅名为 camera/image_raw 的话题,并指定回调函数 imageCallback 处理接收到的消息。

进入消息处理循环:

ros::spin(); 进入消息处理循环,监听并处理订阅的话题上的消息。

替代方案

ros::spinOnce();:

如果需要在主循环中进行其他操作,可以使用 ros::spinOnce(); 结合自定义的循环。

示例:

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

    ros::init(argc, argv, "image_subscriber");
    
    ros::NodeHandle nh;
    
    ros::Subscriber sub = nh.subscribe("camera/image_raw", 1, imageCallback);
    
    while (ros::ok())
    
    {
    
        // 处理一次消息
    
        ros::spinOnce();
    
        // 其他操作
    
        // ...
    
        // 控制循环频率
    
        ros::Rate loop_rate(10); // 10 Hz
    
        loop_rate.sleep();
    
    }
    
    return 0;

ros::init(argc, argv, "image_subscriber");

ros::NodeHandle nh;

ros::Subscriber sub = nh.subscribe("camera/image_raw", 1, imageCallback);

while (ros::ok())

{

    // 处理一次消息

    ros::spinOnce();

    // 其他操作

    // ...

    // 控制循环频率

    ros::Rate loop_rate(10); // 10 Hz

    loop_rate.sleep();

}

return 0;

}

在这个示例中,ros::spinOnce(); 会在每次循环中处理一次消息,然后执行其他操作,最后通过 ros::Rate 控制循环频率。

总结

ros::spin(); 是一个简单而强大的函数,适用于大多数单线程的 ROS 节点。它会持续监听并处理消息,直到节点被关闭。如果你需要更细粒度的控制,可以考虑使用 ros::spinOnce(); 结合自定义的循环。

ros::NodeHandle

ros::NodeHandle 是ROS(Robot Operating System)中的一个核心类,用于管理ROS节点的各种资源,包括创建发布者(publishers)、订阅者(subscribers)、服务客户端和服务服务器等。ros::NodeHandle 对象是每个ROS节点的主要入口点,提供了许多方法来与ROS系统进行交互。

主要功能

创建发布者:

使用 advertise<>() 方法创建发布者,用于发布消息到特定的话题。

创建订阅者:

使用 subscribe<>() 方法创建订阅者,用于订阅特定话题的消息。

创建服务客户端:

使用 serviceClient<>() 方法创建服务客户端,用于调用服务。

创建服务服务器:

使用 advertiseService<>() 方法创建服务服务器,用于处理服务请求。

获取参数:

使用 getParam()、param() 等方法获取节点的参数。

设置参数:

使用 setParam() 方法设置节点的参数。

私有命名空间:

使用 ros::NodeHandle nh("~") 创建一个私有命名空间的节点句柄,用于访问节点私有的参数。

示例代码

以下是一个简单的示例,展示了如何使用 ros::NodeHandle 创建发布者和订阅者:

#include <ros/ros.h>

#include <std_msgs/String.h>

// 回调函数,处理接收到的消息

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO("I heard: [%s]", msg->data.c_str());

}

int main(int argc, char **argv)

{

    // 初始化ROS节点
    
    ros::init(argc, argv, "example_node");
    
    // 创建ROS节点句柄
    
    ros::NodeHandle nh;
    
    // 创建发布者,发布字符串消息到 "chatter" 话题
    
    ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);
    
    // 创建订阅者,订阅 "chatter" 话题的字符串消息
    
    ros::Subscriber chatter_sub = nh.subscribe("chatter", 1000, chatterCallback);
    
    // 主循环
    
    ros::Rate loop_rate(10);  // 10 Hz
    
    int count = 0;
    
    while (ros::ok())
    
    {
    
        // 创建消息
    
        std_msgs::String msg;
    
        std::stringstream ss;
    
        ss << "hello world " << count;
    
        msg.data = ss.str();
    
        // 发布消息
    
        chatter_pub.publish(msg);
    
        // 处理ROS回调函数
    
        ros::spinOnce();
    
        // 控制主循环的频率
    
        loop_rate.sleep();
    
        ++count;
    
    }
    
    return 0;

}
详细解释

初始化ROS节点:

ros::init(argc, argv, “example_node”);

初始化ROS节点,传递命令行参数和节点名称。

创建ROS节点句柄:

ros::NodeHandle nh;

创建一个 ros::NodeHandle 对象,用于管理节点的资源。

创建发布者:

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>(“chatter”, 1000);

使用 advertise<>() 方法创建一个发布者,发布 std_msgs::String 类型的消息到 chatter 话题,队列大小为1000。

创建订阅者:

ros::Subscriber chatter_sub = nh.subscribe(“chatter”, 1000, chatterCallback);

使用 subscribe<>() 方法创建一个订阅者,订阅 chatter 话题的 std_msgs::String 类型的消息,并指定回调函数 chatterCallback。

回调函数:

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO("I heard: [%s]", msg->data.c_str());

}

回调函数 chatterCallback 处理接收到的消息,并打印消息内容。

主循环:

ros::Rate loop_rate(10);  // 10 Hz

int count = 0;

while (ros::ok())

{

    // 创建消息
    
    std_msgs::String msg;
    
    std::stringstream ss;
    
    ss << "hello world " << count;
    
    msg.data = ss.str();
    
    // 发布消息
    
    chatter_pub.publish(msg);
    
    // 处理ROS回调函数
    
    ros::spinOnce();
    
    // 控制主循环的频率
    
    loop_rate.sleep();
    
    ++count;

}

主循环中创建消息并发布,处理ROS回调函数,并控制主循环的频率。

advertise

在ROS(Robot Operating System)中,n.advertise<>() 是一个用于创建发布者(publisher)的方法。这个方法属于 ros::NodeHandle 类,用于声明一个节点将要发布某个话题的消息。

语法和参数

ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);

参数说明

topic (const std::string& topic):

话题名称,用于标识发布的消息流。例如 “imu_propagate”。

queue_size (uint32_t queue_size):

消息队列的大小。这是发布者内部用于缓冲消息的队列大小。如果消息生成速度快于消息传输速度,队列可以暂时存储多余的消息,防止消息丢失。

latch (bool latch = false):

是否启用消息缓存(可选参数,默认为 false)。如果设置为 true,则最后一条消息会被缓存,新订阅者订阅时会立即收到这条消息,而不需要等待新的消息发布。

示例

ros::Publisher pub_latest_odometry = n.advertise<nav_msgs::Odometry>(“imu_propagate”, 1000);

详细解释

创建发布者对象:

n 是一个 ros::NodeHandle 对象,用于管理ROS节点的各种资源。

advertise<>() 方法创建一个发布者对象,并将其赋值给 pub_latest_odometry 变量。

指定消息类型:

<nav_msgs::Odometry> 是模板参数,指定了发布者将要发布的消息类型。在这个例子中,消息类型是 nav_msgs::Odometry。

指定话题名称:

“imu_propagate” 是话题名称,表示发布的消息将通过这个话题进行传输。

指定队列大小:

1000 是消息队列的大小,表示发布者内部可以缓存最多1000条消息。

subscribe

subscribe<>() 方法是ROS(Robot Operating System)中 ros::NodeHandle 类的一个重要方法,用于创建订阅者(subscriber)。通过订阅者,节点可以接收来自特定话题的消息。订阅者会在每次接收到新消息时调用指定的回调函数。

语法和参数

subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(M const&), const boost::shared_ptr& obj, const TransportHints& transport_hints = TransportHints());

参数说明

topic (const std::string& topic):

话题名称,用于标识订阅的消息流。例如 “chatter”。

queue_size (uint32_t queue_size):

消息队列的大小。这是订阅者内部用于缓冲接收到的消息的队列大小。如果消息生成速度快于消息处理速度,队列可以暂时存储多余的消息,防止消息丢失。

fp (void(*fp)(M const&)):

回调函数指针,用于处理接收到的消息。M 是消息类型,例如 std_msgs::String。

obj (const boost::shared_ptr& obj):

回调函数所属的对象。如果你的回调函数是类的成员函数,需要传递一个指向该对象的智能指针。

transport_hints (const TransportHints& transport_hints = TransportHints()):

传输提示(可选参数),用于指定传输方式,例如TCP或UDP。默认情况下,使用系统的默认传输方式。

示例代码

以下是一个完整的示例,展示了如何使用 subscribe<>() 创建订阅者并处理接收到的消息。

示例代码

#include <ros/ros.h>

#include <std_msgs/String.h>

// 回调函数,处理接收到的消息

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO("I heard: [%s]", msg->data.c_str());

}

int main(int argc, char **argv)

{

    // 初始化ROS节点
    
    ros::init(argc, argv, "example_subscriber");
    
    // 创建ROS节点句柄
    
    ros::NodeHandle nh;
    
    // 创建订阅者,订阅 "chatter" 话题的字符串消息
    
    ros::Subscriber sub = nh.subscribe("chatter", 1000, chatterCallback);
    
    // 主循环
    
    ros::spin();
    
    return 0;

}
详细解释

初始化ROS节点:

ros::init(argc, argv, “example_subscriber”);

初始化ROS节点,传递命令行参数和节点名称。

创建ROS节点句柄:

ros::NodeHandle nh;

创建一个 ros::NodeHandle 对象,用于管理节点的资源。

创建订阅者:

ros::Subscriber sub = nh.subscribe(“chatter”, 1000, chatterCallback);

使用 subscribe<>() 方法创建一个订阅者,订阅 chatter 话题的 std_msgs::String 类型的消息,队列大小为1000,并指定回调函数 chatterCallback。

回调函数:

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO("I heard: [%s]", msg->data.c_str());

}

回调函数 chatterCallback 处理接收到的消息,并打印消息内容。

主循环:

ros::spin();

使用 ros::spin() 进入主循环,处理所有的回调函数。ros::spin() 会一直阻塞,直到节点关闭。

成员函数作为回调函数

如果你的回调函数是类的成员函数,需要传递一个指向该对象的智能指针。以下是一个示例:

示例代码

#include <ros/ros.h>

#include <std_msgs/String.h>

class ExampleSubscriber

{

public:

    // 构造函数
    
    ExampleSubscriber()
    
    {
    
        // 创建ROS节点句柄
    
        ros::NodeHandle nh;
    
        // 创建订阅者,订阅 "chatter" 话题的字符串消息
    
        sub = nh.subscribe("chatter", 1000, &ExampleSubscriber::chatterCallback, this);
    
    }
    
    // 回调函数,处理接收到的消息
    
    void chatterCallback(const std_msgs::String::ConstPtr& msg)
    
    {
    
        ROS_INFO("I heard: [%s]", msg->data.c_str());
    
    }

private:

    ros::Subscriber sub;

};

int main(int argc, char **argv)

{

    // 初始化ROS节点
    
    ros::init(argc, argv, "example_subscriber");
    
    // 创建订阅者对象
    
    ExampleSubscriber example_subscriber;
    
    // 主循环
    
    ros::spin();
    
    return 0;

}
详细解释

构造函数:

ExampleSubscriber()

{

    // 创建ROS节点句柄
    
    ros::NodeHandle nh;
    
    // 创建订阅者,订阅 "chatter" 话题的字符串消息
    
    sub = nh.subscribe("chatter", 1000, &ExampleSubscriber::chatterCallback, this);

}

在构造函数中创建ROS节点句柄,并使用 subscribe<>() 方法创建订阅者,订阅 chatter 话题的 std_msgs::String 类型的消息,队列大小为1000,并指定成员函数 chatterCallback 作为回调函数,同时传递 this 指针。

成员函数作为回调函数:

void chatterCallback(const std_msgs::String::ConstPtr& msg)

{

    ROS_INFO("I heard: [%s]", msg->data.c_str());

}

成员函数 chatterCallback 处理接收到的消息,并打印消息内容。

ros::Publisher

ros::Publisher 是ROS(Robot Operating System)中的一个类,用于发布消息到特定的话题。通过 ros::Publisher,你可以将数据发送到其他节点订阅的同一个话题,从而实现节点之间的通信。

主要功能

发布消息:

使用 publish() 方法将消息发布到指定的话题。

检查是否有订阅者:

使用 getNumSubscribers() 方法检查当前话题是否有订阅者。

获取话题名称:

使用 getTopic() 方法获取当前发布者的话题名称。

创建和使用 ros::Publisher

创建发布者

创建发布者通常通过 ros::NodeHandle 的 advertise<>() 方法完成。以下是创建发布者的步骤:

初始化ROS节点:

ros::init(argc, argv, “example_node”);

创建ROS节点句柄:

ros::NodeHandle nh;

创建发布者:

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>(“chatter”, 1000);

发布消息

使用 publish() 方法发布消息:

std_msgs::String msg;

msg.data = “Hello, World!”;

chatter_pub.publish(msg);

示例代码

以下是一个完整的示例,展示了如何创建和使用 ros::Publisher:

#include <ros/ros.h>

#include <std_msgs/String.h>

int main(int argc, char **argv)

{

    // 初始化ROS节点
    
    ros::init(argc, argv, "example_publisher");
    
    // 创建ROS节点句柄
    
    ros::NodeHandle nh;
    
    // 创建发布者,发布字符串消息到 "chatter" 话题
    
    ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("chatter", 1000);
    
    // 主循环
    
    ros::Rate loop_rate(10);  // 10 Hz
    
    int count = 0;
    
    while (ros::ok())
    
    {
    
        // 创建消息
    
        std_msgs::String msg;
    
        std::stringstream ss;
    
        ss << "hello world " << count;
    
        msg.data = ss.str();
    
        // 发布消息
    
        chatter_pub.publish(msg);
    
        // 输出发布信息
    
        ROS_INFO("Published: %s", msg.data.c_str());
    
        // 处理ROS回调函数
    
        ros::spinOnce();
    
        // 控制主循环的频率
    
        loop_rate.sleep();
    
        ++count;
    
    }
    
    return 0;

}

详细解释

初始化ROS节点:

ros::init(argc, argv, “example_publisher”);

初始化ROS节点,传递命令行参数和节点名称。

创建ROS节点句柄:

ros::NodeHandle nh;

创建一个 ros::NodeHandle 对象,用于管理节点的资源。

创建发布者:

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>(“chatter”, 1000);

使用 advertise<>() 方法创建一个发布者,发布 std_msgs::String 类型的消息到 chatter 话题,队列大小为1000。

主循环:

ros::Rate loop_rate(10);  // 10 Hz

int count = 0;

while (ros::ok())

{

    // 创建消息
    
    std_msgs::String msg;
    
    std::stringstream ss;
    
    ss << "hello world " << count;
    
    msg.data = ss.str();
    
    // 发布消息
    
    chatter_pub.publish(msg);
    
    // 输出发布信息
    
    ROS_INFO("Published: %s", msg.data.c_str());
    
    // 处理ROS回调函数
    
    ros::spinOnce();
    
    // 控制主循环的频率
    
    loop_rate.sleep();
    
    ++count;

}

在主循环中,创建消息并发布,输出发布信息,处理ROS回调函数,并控制主循环的频率。

其他常用方法

检查是否有订阅者:

int num_subscribers = chatter_pub.getNumSubscribers();

if (num_subscribers > 0)

{

    ROS_INFO("There are %d subscribers to the topic.", num_subscribers);

}

获取话题名称:

std::string topic_name = chatter_pub.getTopic();

ROS_INFO(“Topic name: %s”, topic_name.c_str());

RViz

RViz (Robot Visualization)是 Robot Operating System (ROS) 中的一款强大的三维可视化工具,广泛用于机器人系统的开发和调试。它可以帮助开发者以图形化的方式查看和分析机器人模型、传感器数据、环境地图等多种类型的数据。通过 RViz,用户可以直观地了解机器人的状态和行为,从而提高开发和调试的效率。

RViz 的主要特点

可视化机器人模型:

RViz 可以加载和显示机器人的三维模型,并根据实际的关节状态进行动态更新。这使得用户能够直观地了解机器人的外观和姿态。12

显示传感器数据:

RViz 可以接收和显示来自机器人传感器(如激光雷达、摄像头、IMU 等)的数据。用户可以实时查看和分析传感器数据,帮助理解机器人周围的环境。16

生成导航地图:

RViz 可以通过接收来自 SLAM(Simultaneous Localization and Mapping)或其他建图算法的数据,生成并显示机器人所在环境的二维或三维地图。16

调试运动规划:

RViz 可以显示机器人的路径规划结果,并提供交互式界面来调试和优化运动规划算法。用户可以可视化虚拟路径、障碍物和碰撞检测等信息。16

可定制性:

RViz 提供了丰富的配置选项,允许用户按照自己的需求自定义界面布局、可视化对象和颜色风格等。用户可以根据实际情况进行个性化设置,以满足特定的可视化需求。16

RViz 的使用
启动 RViz

RViz 可以通过命令行启动,通常需要先启动 ROS 核心节点 roscore,然后再启动 RViz。启动命令如下:

roscore

rosrun rviz rviz

加载配置文件

RViz 支持加载配置文件,这些文件包含了 RViz 的初始设置,如显示的内容、参数配置等。配置文件通常以 .rviz 为扩展名。在启动 RViz 时,可以通过 -d 参数指定配置文件的路径:

rosrun rviz rviz -d path/to/config_file.rviz

示例中的 RViz 配置

在你提供的 *.launch 文件中,RViz 的启动配置如下:

<launch>

    <node name="rvizvisualisation" pkg="rviz" type="rviz" output="log" args="-d $(find vins_estimator)/../config/vins_rviz_config.rviz" >

</launch>

解释

标签: 用于定义一个 ROS 节点。

name=“rvizvisualisation”: 节点的名称为 rvizvisualisation。

pkg=“rviz”: 节点所在的包名是 rviz。

type=“rviz”: 节点的可执行文件名是 rviz。

output=“log”: 节点的日志输出到日志文件。

args="-d $(find vins_estimator)/…/config/vins_rviz_config.rviz": 传递给节点的命令行参数,用于指定 RViz 配置文件的路径。

$(find vins_estimator): 这是一个 ROS 变量,用于查找 vins_estimator 包的路径。

/…/config/vins_rviz_config.rviz: 从 vins_estimator 包的路径向上一级目录,然后进入 config 文件夹,找到 vins_rviz_config.rviz 配置文件。

总结

RViz 是 ROS 中一个非常强大的三维可视化工具,通过它可以直观地查看和分析机器人系统的各种数据。通过 *.launch 文件,可以方便地启动 RViz 并加载预设的配置文件,从而快速进入开发和调试状态。在你的示例中,rvizvisualisation 节点启动时会加载 vins_rviz_config.rviz 配置文件,确保 RViz 以预设的显示效果启动。17

EVO

EVO(Evaluation of Visual Odometry / SLAM)是一款开源软件工具,专门用于评估视觉里程计(Visual Odometry, VO)和同时定位与地图构建(Simultaneous Localization and Mapping, SLAM)系统的性能。EVO 提供了一套完整的评估框架,包括数据处理、结果可视化以及多种评价指标计算等功能,适用于研究人员和工程师对不同VO/SLAM算法的性能进行比较和分析。

EVO的主要功能

多格式支持:

EVO 支持多种数据格式,包括但不限于 TUM RGB-D 数据集格式、Kitti 数据集格式、Euroc MAV 数据集格式等,这使得它能够兼容不同的实验数据源。

丰富的评价指标:

EVO 提供了多种评价指标,如绝对轨迹误差(ATE)、相对位姿误差(RPE)等,这些指标能够从不同角度评估VO/SLAM系统的精度和稳定性。

灵活的结果可视化:

EVO 具有强大的结果可视化功能,可以生成轨迹对比图、误差分布图等多种图表,帮助用户直观地理解评估结果。

命令行接口和Python API:

EVO 不仅提供了命令行工具,还提供了Python API,这使得用户可以在脚本中集成EVO的功能,实现自动化评估流程。

易于扩展:

EVO 的设计考虑到了灵活性和可扩展性,用户可以根据需要添加新的数据格式支持或自定义评估指标。

使用EVO进行性能测试的基本步骤

准备数据:

准备好待评估的VO/SLAM系统的输出数据,通常是估计的轨迹文件,格式应符合所选数据集的标准。

获取真值数据:

获取相应的真值数据(ground truth),这些数据通常来自高精度的测量设备或数据集本身提供的真值轨迹。

运行EVO工具:

使用EVO的命令行工具或Python API,将估计的轨迹与真值轨迹进行比较,计算评价指标。

分析结果:

分析EVO生成的报告和图表,评估VO/SLAM系统的性能。

示例命令

以下是一个使用EVO命令行工具评估ATE的例子:

evo_ape tum groundtruth.txt trajectory.txt --plot --plot_mode=xy --save_plot plot.png

evo_ape:调用EVO的绝对轨迹误差评估模块。

tum:指定数据格式为TUM格式。

groundtruth.txt:真值轨迹文件。

trajectory.txt:待评估系统输出的估计轨迹文件。

–plot:生成轨迹对比图。

–plot_mode=xy:指定绘制模式为二维平面图。

–save_plot plot.png:将生成的图表保存为图片文件。

结论

EVO 是一个功能全面且灵活的评估工具,对于从事VO/SLAM研究和开发的人员来说,是非常有用的工具。通过EVO,可以轻松地评估和比较不同算法的性能,从而推动相关技术的发展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值