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.launchpackage_name: 节点所在的功能包名称。launch_file_name: 启动文件的名称。
传递参数
roslaunch package_name launch_file_name.launch arg_name:=arg_valuearg_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 pythonimport rospyfrom std_msgs.msg import Stringdef talker():pub = rospy.Publisher('chatter', String, queue_size=10)rospy.init_node('talker', anonymous=True)rate = rospy.Rate(1)  # 1 Hzwhile 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 Hzwhile 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 pythonimport rospyfrom std_msgs.msg import Stringdef 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 Hzloop_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 Hzloop_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 Hzint 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 Hzint 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 Hzint 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 Hzint 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.mzph.cn/diannao/63035.shtml

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

相关文章

MySql:理解数据库

目录 一、什么是数据库 第一层理解 第二层理解 第三层理解 二、Linux下的数据库 三、基本认识 登录数据库时&#xff0c; mysql -u root -h 127.0.0.1 -P 3306 -p -h指定MySql服务器所在主机&#xff0c;若在本地则为回环地址。-P表示目标主机上MySql服务端口号 一般简单…

BERT模型的输出格式探究以及提取出BERT 模型的CLS表示,last_hidden_state[:, 0, :]用于提取每个句子的CLS向量表示

说在前面 最近使用自己的数据集对bert-base-uncased进行了二次预训练&#xff0c;只使用了MLM任务&#xff0c;发现在加载训练好的模型进行输出CLS表示用于下游任务时&#xff0c;同一个句子的输出CLS表示都不一样&#xff0c;并且控制台输出以下警告信息。说是没有这些权重。…

高级java每日一道面试题-2024年12月03日-JVM篇-什么是Stop The World? 什么是OopMap? 什么是安全点?

如果有遗漏,评论区告诉我进行补充 面试官: 什么是Stop The World? 什么是OopMap? 什么是安全点? 我回答: 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;Stop The World、OopMap 和 安全点 是与垃圾回收&#xff08;GC&#xff09;和性能优化密切相关的概念。理…

PROTEUS资源导引

本专栏讲述51、32单片机的仿真设计&#xff0c;且所有文章资源共享&#xff0c;如需哪篇文章&#xff0c;可按ctrlF键搜索查询&#xff0c;点击进入即可。 -----------------------------------------------------------目录------------------------------------------------…

Vue框架开发一个简单的购物车(Vue.js)

让我们利用所学知识来开发一个简单的购物车 &#xff08;记得暴露属性和方法&#xff01;&#xff01;&#xff01;&#xff09; 首先来看一下最基本的一个html框架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

系统加固-Linux不允许用户使用密码登录,只能使用密钥登录

一、密码登录的安全隐患 传统的密码登录方式&#xff0c;尽管简单直接&#xff0c;却存在诸多安全隐患。首先&#xff0c;密码本身容易被猜测或通过暴力破解手段获得。特别是当用户设置了过于简单或常见的密码时&#xff0c;系统面临的安全风险将显著增加。其次&#xff0c;密…

大数据实验E5HBase:安装配置,shell 命令和Java API使用

实验目的 熟悉HBase操作常用的shell 命令和Java API使用&#xff1b; 实验要求 掌握HBase的基本操作命令和函数接口的使用&#xff1b; 实验平台 操作系统&#xff1a;Linux&#xff08;建议Ubuntu16.04或者CentOS 7 以上&#xff09;&#xff1b;Hadoop版本&#xff1a;3…

【Vivado】xdc约束文件编写

随手记录一下项目中学到的约束文件编写技巧。 时序约束 创建生成时钟 参考链接&#xff1a; Vivado Design Suite Tcl Command Reference Guide (UG835) Vivado Design Suite User Guide: Using Constraints (UG903) 通过Clocking Wizard IP创建的时钟&#xff08;MMCM或…

Electron + Vue 简单实现窗口程序(Windows)从零到一

前言 想做一个桌面应用程序&#xff0c;一直没有找到简单快速可上手的框架。刚好有点前端的底子&#xff0c;就发现了Electron。关于Electron的介绍&#xff0c;请移步 https://www.electronjs.org/ 查阅。 简单来说&#xff0c;引用官网的话&#xff0c;Electron是一个使用 …

spring boot整合ArtemisMQ进行手动消息确认

1、SpringBoot整合ArtemisMQ进行手动消息确认使用的是&#xff1a; factory.setSessionTransacted(false); factory.setSessionAcknowledgeMode(ActiveMQJMSConstants.INDIVIDUAL_ACKNOWLEDGE); 2、SpringBoot整合ActiveMQ进行手动消息确认使用的是&#xff1a; factory.setSe…

健康养生生活

在快节奏的现代生活中&#xff0c;健康养生愈发成为人们关注的焦点。它不仅是一种生活方式&#xff0c;更是对生命质量的珍视与呵护。 健康养生&#xff0c;饮食为先。合理的膳食结构是维持身体健康的基石。我们应确保每餐营养均衡&#xff0c;增加蔬菜、水果、全谷物以及优质蛋…

开源模型应用落地-安全合规篇-用户输入价值观判断(三)

一、前言 在深度合规功能中,对用户输入内容的价值观判断具有重要意义。这一功能不仅仅是对信息合法性和合规性的简单审核,更是对信息背后隐含的伦理道德和社会责任的深刻洞察。通过对价值观的判断,系统能够识别可能引发不当影响或冲突的内容,从而为用户提供更安全、更和谐的…

如何避免数据丢失:服务器恢复与预防策略

在当今数字时代&#xff0c;数据对于个人和企业来说都至关重要。数据丢失可能会导致严重的财务损失、业务中断甚至法律责任。因此&#xff0c;采取措施防止数据丢失至关重要。本文将讨论服务器数据丢失的常见原因以及如何防止数据丢失的有效策略。 服务器数据丢失的常见原因 服…

LeetCode Hot100 11~20

目录 子串11. 滑动窗口最大值12. 最小覆盖子串 数组13. 最大子数组和14. 合并区间15. 翻转数组16. 除数字自身以外的乘积17. 缺失的第一个正数 矩阵18. 矩阵置零19. 螺旋矩阵20 旋转图像90度 子串 11. 滑动窗口最大值 本题使用deque来维护一个单调队列 注意删除元素和添加元素…

网站访问统计A/B测试与数据分析

在网站运营中&#xff0c;访问统计和数据分析是优化用户体验和提高转化率的关键工具。A/B测试作为一种数据驱动的方法&#xff0c;能够帮助网站运营者验证设计和内容的有效性。A/B测试的基本原理是同时展示两个不同的版本&#xff08;A和B&#xff09;&#xff0c;通过比较它们…

Spring MVC:深入理解与应用实践

前言 Spring MVC是Spring框架提供的一个用于构建Web应用程序的Model-View-Controller&#xff08;MVC&#xff09;实现。它通过分离业务逻辑、数据、显示来组织代码&#xff0c;使得Web应用程序的开发变得更加简洁和高效。本文将从概述、功能点、背景、业务点、底层原理等多个…

C学习:移位幻影之左移一个负数,会发生什么?

C学习&#xff1a;移位幻影之左移一个负数&#xff0c;会发生什么&#xff1f; 问题背景无符号数移位问题有符号数移位操作使低位置零问题 问题背景 C语言中&#xff0c;移位是个简单的问题&#xff0c;但又是个高风险的问题。 简单在于&#xff0c;大部分场景都可以理解为乘或…

芯驰X9SP与汽车麦克风-打造无缝驾驶体验

当今汽车技术的进步不仅提升了驾驶体验&#xff0c;还改变了我们与车辆互动的方式。汽车麦克风作为车内语音控制系统的重要组成部分&#xff0c;正逐渐成为现代汽车的标配。 技术原理 汽车麦克风主要依赖于声音传感技术&#xff0c;通常包括电容式麦克风和动圈式麦克风。这些…

tomcat的Mysql链接字符串问题

tomcat配置mysql链接需要改server.xml或content.xml。 但是server.xml或content.xml中mysql的配置看起来很古怪: url"jdbc:mysql://10.21.0.6:3306/hrdatabase?characterEncodinggbk&amp;autoReconnecttrue" 而使用springboot开发java应用&#xff0c;使用ya…

界面控件Syncfusion Essential Studio®现在已完全支持 .NET 9

Syncfusion Essential Studio现在完全支持 .NET 9&#xff0c;可最新版本2024 Volume 3 版本中使用&#xff01;通过此更新&#xff0c;Blazor、.NET MAUI、WPF、WinForms、WinUI和ASP.NET Core 平台中的 Syncfusion 组件以及文档处理库已准备好让您利用 .NET 9 中的最新功能。…