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

news2024/12/26 19:30:31

文章目录

    • 其他文章
    • 说明
    • 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,可以轻松地评估和比较不同算法的性能,从而推动相关技术的发展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2254131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Matlab三点雨流计数法的载荷时间历程分析与循环疲劳评估

随着工程领域中机械设备和结构系统的复杂性不断增加&#xff0c;疲劳分析成为评估其可靠性与使用寿命的关键环节。载荷时间历程数据在疲劳分析中扮演着重要角色&#xff0c;而雨流计数法作为经典的循环计数方法&#xff0c;能够有效地从载荷时间历程中提取疲劳载荷循环信息。本…

帝可得-策略管理

策略管理 需求说明 策略管理主要涉及到二个功能模块&#xff0c;业务流程如下&#xff1a; 新增策略: 允许管理员定义新的策略&#xff0c;包括策略的具体内容和参数&#xff08;如折扣率&#xff09;策略分配: 将策略分配给一个或多个售货机。 #mermaid-svg-PSQOJMLJqVGn3W…

【数据结构】手搓链表

一、定义 typedef struct node_s {int _data;struct node_s *_next; } node_t;typedef struct list_s {node_t *_head;node_t *_tail; } list_t;节点结构体&#xff08;node_s&#xff09;&#xff1a; int _data;存储节点中的数据struct node_s *_next;&#xff1a;指向 node…

嵌入式 C 编程必备(7):const 关键字 —— 打造稳定的常量空间

目录 一、const关键字的基本含义与用法 1.1. 修饰基本数据类型 1.2. 修饰指针 1.3. 修饰数组 1.4. 修饰结构体 二、const关键字在嵌入式编程中的优势 2.1. 提升代码可读性 2.2. 增强代码安全性 2.3. 优化内存使用 2.4. 促进模块化设计 2.5. 支持静态分析和测试 三、…

Day28 买卖股票的最佳时机 跳跃游戏 跳跃游戏 II K 次取反后最大化的数组和

贪心算法 part02 122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 求最大利润 将每天的正利润加和 public int maxProfit(int[] prices) {int totalPrices 0;for(int i0;i<prices.length;i){if(i<prices.length-1&&prices[i1]>prices[…

【专题】计算机网络之运输层(传输层)

1. 运输层协议概述 1.1 进程之间的通信 (1) 运输层的作用 运输层提供进程间的逻辑通信。 运输层的屏蔽作用&#xff1a; 运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;&#xff0c;使应用进程看见的就是好像在两个运…

Ansible 运维工具

安装 apt install ansible /etc/ansible/hosts , 指定密码或密钥访问分组机器 [k8s_masters] master0.c0.k8s.sb[k8s_nodes] node0.c0.k8s.sb node1.c0.k8s.sb[k8s:children] k8s_masters k8s_nodes[k8s_masters:vars] ansible_ssh_usersbadmin ansible_ssh_pass"***&q…

matlab 中的 bug

在matlab中绘图&#xff0c;设置 axe 的背景颜色 axes_in3.Color #00235B ;打印的时候 print(figure_handle1,-dpng,-r300,"merge_yt_ey") ;此时保存的图片无法识别背景颜色 原因在于 matlab 中的 InverseHardcopy 将 InvertHardcopy 设置成 off 则可以解决这个问…

利用Python爬虫快速获取淘宝/天猫SKU详细信息数据

引言 在当今的电商环境中&#xff0c;获取商品的详细信息对于市场分析和竞争策略至关重要。阿里作为中国最大的电商平台&#xff0c;拥有海量的商品数据。本文将介绍如何利用Python编写爬虫程序&#xff0c;快速获取商品的SKU详细信息数据&#xff0c;并提供相应的代码示例。 …

R语言机器学习论文(二):数据准备

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据一、数据描述二、数据预处理(一)修改元素名称(二)剔除无关变量(三)缺失值检查(四)重复值检查(五)异常值检查三、描述性统计(一)连续变量数据情…

基于图像变化检测的毁伤效果评估——学习笔记

前言 闲的无聊&#xff0c;看看论文。 基本评估步骤 第一步&#xff1a;图像预处理。通过图像配准、不同波段提取、图像校正、图像滤波等手段&#xff0c;统一图像格式&#xff08;文中统一为灰度图&#xff09;&#xff0c;得到待检测图像&#xff1b; 第二步&#xff1a;…

A1228 php+Mysql旅游供需平台的设计与实现 导游接单 旅游订单 旅游分享网站 thinkphp框架 源码 配置 文档 全套资料

旅游供需平台 1.项目描述2. 开发背景与意义3.项目功能4.界面展示5.源码获取 1.项目描述 随着社会经济的快速发展&#xff0c;生活水平的提高&#xff0c;人们对旅游的需求日益增强&#xff0c;因此&#xff0c;为给用户提供一个便利的查看导游信息&#xff0c;进行导游招募的平…

青海摇摇了3天,技术退步明显.......

最近快手上的青海摇招聘活动非常火热&#xff0c;我已经在思考是否备战张诗尧的秋招活动。开个玩笑正片开始&#xff1a; 先说一下自己的情况&#xff0c;大专生&#xff0c;20年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c…

工业—使用Flink处理Kafka中的数据_ProduceRecord2

使用 Flink 消费 Kafka 中 ProduceRecord 主题的数据,统计在已经检验的产品中,各设备每 5 分钟 生产产品总数,将结果存入HBase 中的 gyflinkresult:Produce5minAgg 表, rowkey“

Python爬虫——猫眼电影

用python中requests库爬取猫眼电影信息并保存到csv文件中 猫眼专业版 爬取界面 效果预览 代码 import requests import jsonurl1https://piaofang.maoyan.com/dashboard-ajax?orderType0&uuid1938bd58ddac8-02c2bbe3b009ed-4c657b58-144000-1938bd58ddac8&timeStamp…

ArcGIS求取多个点距离线要素的最近距离以及距离倒数

本文介绍在ArcMap软件中&#xff0c;对于点要素中的每一个点&#xff0c;求取其距离最近的道路的距离、距离倒数的方法。 首先&#xff0c;看一下本文的需求。现在已知一个点要素&#xff0c;其中含有多个点&#xff0c;假设每一个点表示城市中的一家商店&#xff1b;同时&…

SpringBoot开发——Spring Boot3.4 强大的结构化日志记录

文章目录 1. 简介2. 实战案例2.1 环境依赖2.2 快速入门2.3 输出到文件2.4 添加附加字段2.5 自定义日志格式总结1. 简介 日志记录是应用故障排除中早已确立的部分,也是可观测性的三大支柱之一,另外两个是指标和追踪。在生产环境中,没有人喜欢盲目行事,而当故障发生时,开发…

多级IIR滤波效果(BIQUAD),system verilog验证

MATLAB生成IIR系数 采用率1k&#xff0c;截止频率30hz&#xff0c;Matlab生成6阶对应的biquad3级系数 Verilog测试代码 // fs1khz,fc30hz initial beginreal Sig_Orig, Noise_white, Mix_sig;real fs 1000;Int T 1; //周期int N T*fs; //1s的采样点数// 数组声明…

MySQL索引(三):选错索引

优化器选择索引的目的&#xff0c;是找到一个最优的执行方案&#xff0c;并用最小的代价去执行语句。 思考 假设有表结构&#xff1a; -- T表结构&#xff1a; CREATE TABLE t (id int(11) NOT NULL,a int(11) DEFAULT NULL,b int(11) DEFAULT NULL,PRIMARY KEY (id),KEY a (…

区块链学习笔记(2)--区块链的交易模型part1

模型基础 区块链的tx分为两种模型&#xff0c;分别是比特币为代表的UTXO&#xff08;Unspent Transaction Output&#xff09;模型&#xff0c;和以太坊为代表的Account模型。前者适用于货币记账&#xff0c;后者适用于链上应用。 UTXO模型 类似于现金的交易模型 一个tx包含…