当前位置: 首页 > news >正文

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

相关文章:

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

文章目录 其他文章说明ROSlaunch文件基本概念定义用途 文件结构根标签常用标签\<node>\<param>\<rosparam>\<remap>\<include>\<arg>\<group> 示例基本示例嵌套示例 使用方法启动 *.launch 文件传递参数 总结 ROS topicTopic 的基本…...

Python 3 教程第13篇(集合)

Python3 集合 集合&#xff08;set&#xff09;是一个无序的不重复元素序列。 集合中的元素不会重复&#xff0c;并且可以进行交集、并集、差集等常见的集合操作。 可以使用大括号 { } 创建集合&#xff0c;元素之间用逗号 , 分隔&#xff0c; 或者也可以使用 set() 函数创建集…...

cesium 3dtile ClippingPlanes 多边形挖洞ClippingPlaneCollection

原理就是3dtiles里面的属性clippingPlanes 采用ClippingPlaneCollection&#xff0c;构成多边形来挖洞。 其次就是xyz法向量挖洞 clippingPlanes: new this.ffCesium.Cesium.ClippingPlaneCollection({unionClippingRegions: true, // true 表示多个切割面能合并为一个有效的…...

开发者如何使用GCC提升开发效率GUI操作

看此篇前请先阅读https://blog.csdn.net/qq_20330595/article/details/144139026?spm1001.2014.3001.5502 先上效果图 找到对应的环境版本 配置环境 目录结构 CtrlShiftP c_cpp_properties.json {"configurations": [{"name": "Win32","i…...

什么是隐式类型转换?

隐式类型转换&#xff08;Implicit Type Conversion&#xff09;是指编译器在没有明确要求的情况下&#xff0c;自动地将一种类型的值转换为另一种类型。C 语言支持隐式类型转换&#xff0c;这通常发生在表达式运算或函数调用中&#xff0c;以确保操作数或参数的类型兼容性。 隐…...

爬虫专栏第三篇:Python 实战:运用 requests 突破京东商品评论获取难题(含 cookie 处理与编码设置技巧

简介&#xff1a;本文以京东商品评论为例&#xff0c;详细介绍了使用requests库获取网页数据的过程&#xff0c;包括从打开商品评价页面、抓包分析找到评论接口&#xff0c;到处理cookie参数、解决cookie字符串解析问题&#xff0c;以及设置正确的编码以成功获取评论数据&#…...

HCIE:详解OSPF,从基础到高级特性再到深入研究

目录 前言 一、OSPF协议基本原理 简介 基本原理 OSPF路由器类型 OSPF网络类型 OSPF报文类型和封装 OSPF邻居的建立的维护 DR和BDR的选举 伪节点 LSDB的更新 OSPF的配置 二、OSPF的高级特性 虚连接&#xff08;Virtual-Link&#xff09; OSPF的LSA和路由选择 OSPF…...

第六十六条:谨慎使用本地方法

其实在java中有很多都是采用C或C语言实现的比如native这种的本地方法&#xff0c;感兴趣的可以找源代码看看。 Java Native Interface (JNI) 允许Java应用程序可以调用本地方法&#xff08;native method&#xff09;&#xff0c;所谓本地方法是指使用本地程序设计语言&#xf…...

neo4j如何存储关于liquidity structure的层次和关联结构

在 Neo4j 中存储关于流动性结构&#xff08;liquidity structure&#xff09;的层次和关联结构非常适合&#xff0c;因为 Neo4j 是一个基于图的数据库&#xff0c;能够自然地建模和存储复杂的关系和层次结构。下面是如何在 Neo4j 中设计和实现这样的数据模型的详细步骤和示例。…...

45 基于单片机的信号选择与温度变化

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DS18B20检测温度&#xff0c;通过三种LED灯代表不同状态。 采用DAC0832显示信号脉冲&#xff0c;通过8位数码管显示温度。 信号脉冲可以根据两个按键分别调整为正弦…...

2、Three.js初步认识场景Scene、相机Camera、渲染器Renderer三要素

三要素之间关系&#xff1a; 有了虚拟场景Scene&#xff0c;相机录像Camera&#xff0c;在相机小屏幕上看到的Renderer Scene当前空间 Mesh人在场景 Camera相机录像 Renderer显示器上 首先先描述下Scene&#xff1a; 这个场景为三要素之一&#xff0c;一切需要展示的东西都需…...

Java基础面试题06:hashCode()和equals()方法的重要性体现在什么地方?

前言 Java中的hashCode()和equals()方法看似是干同一件事&#xff0c;但它们的使用场景和作用却大有不同。为了让程序更高效、更准确地运行&#xff0c;我们需要对这两者有深入的了解&#xff0c;并掌握它们的重写规则。 hashCode()和equals()的基础知识 什么是hashCode&…...

Matlab Simulink HDL Coder开发流程(一)— 创建HDL兼容的Simulink模型

创建HDL兼容的Simulink模型 一、使用Balnk DUT模板二、从HDL Coder库中选择模块三、为DUT开发算法/功能四、为设计创建Testbench五、仿真验证设计功能六、Simulink模型生成HDL代码 这个例子说明了如何创建一个用于生成HDL代码的Simulink模型。要创建兼容HDL代码生成的MATLAB算法…...

C#基础之方法

文章目录 1 方法1.1 定义方法1.2 参数传递1.2.1 按值传递参数1.2.2 按引用传递参数1.2.3 按输出传递参数1.2.4 可变参数 params1.2.5 具名参数1.2.6 可选参数 1.3 匿名方法1.3.1 Lambda 表达式1.3.1.1 定义1.3.1.2 常用类型1.3.1.3 Lambda 表达式与 LINQ1.3.1.4 Lambda 表达式的…...

Pytest框架学习19--参数化2

1、数据源是yaml 安装yaml&#xff0c;使用safe_load方法读取文件&#xff0c;解析出数据 pip install PyYAML # test_data.yaml test_case_1:a: 2b: 3expected_result: 5test_case_2:a: -1b: 10expected_result: 9test_case_3:a: 0b: 0expected_result: 0# test_code.pyimpor…...

VSCode中“Run Code”运行程序时,终端出现中文乱码解决方法

问题描述 在VSCode中“Run Code”运行程序时&#xff0c;终端输出结果出现中文乱码现象&#xff1a; 解决方法 1. 检查系统cmd的默认编码 查看Windows终端当前编码方式的命令&#xff1a; chcp输出结果是一段数字代码&#xff0c;如936&#xff0c;这说明当前的cmd编码方式…...

HarmonyOS 5.0应用开发——列表(List)

【高心星出品】 文章目录 列表&#xff08;List&#xff09;列表介绍列表布局设置主轴方向设置交叉轴方向 列表填充分组列表填充 滚动条位置设置滚动位置滚到监听 列表项侧滑 列表&#xff08;List&#xff09; 列表介绍 列表作为一种容器&#xff0c;会自动按其滚动方向排列…...

C++设计模式外观模式(Facade)

什么是桥接模式&#xff1f; 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它的核心目的是解耦抽象部分和实现部分&#xff0c;让它们可以独立变化。在简单的描述中&#xff0c;桥接模式可以让你在不修改原有代码的情况下&#xff0c;分别…...

《Python基础》之Numpy库

目录 简介 一、创建数组 1、根据列表创建数组 2、创建全0数组 3、创建全1数组 4、创建单位矩阵 5、创建随机数数组 二、查看数组的属性 三、 数组的操作 1、索引和切片 2、变形 3、拼接 &#xff08;1&#xff09;、vstack() 纵向拼接 &#xff08;2&#xff09;、hs…...

Python异步编程与API调用:提高效率与性能的实践指南

引言 在当今的软件开发领域&#xff0c;异步编程已成为提高应用程序性能和响应能力的关键技术。特别是在处理I/O密集型任务&#xff0c;如API调用时&#xff0c;异步编程能够显著提升效率。本文将通过一个具体的示例——使用Python的asyncio和aiohttp库来异步调用API&#xff…...

Zookeeper3.4.14集群安装

Zookeeper3.4.14三节点集群安装 为保证集群高可用&#xff0c;Zookeeper 集群的节点数最好是奇数&#xff0c;最少有三个节点&#xff0c;所以这里搭建一个三个节点的集群。(在一个节点模拟三节点&#xff0c;真实的三节点把ip替换一下即可&#xff0c;按照hadoop案件把网络打…...

电机驱动MCU介绍

电机驱动MCU是一种专为电机控制设计的微控制器单元&#xff0c;它集成了先进的控制算法和高性能的功率输出能力。 电机驱动MCU采用高性能的处理器核心&#xff0c;具有快速的运算速度和丰富的外设接口。它内置了专业的电机控制算法&#xff0c;包括PID控制、FOC&#xff08;Fi…...

Python 面向对象编程详解

Python 面向对象编程详解 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来设计软件。在 Python 中&#xff0c;面向对象编程非常强大&#xff0c;允许开发者通过类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;来模…...

网络技术-不使用K8S情况下哪些方法可搭建服务链编排

在不使用Kubernetes&#xff08;k8s&#xff09;&#xff08;或不使用Docker环境技术的&#xff09;情况下&#xff0c;搭建服务链编排环境需要依赖其他服务编排和容器化技术&#xff0c;或者采用传统的虚拟机和服务管理方法。以下是一些可能的解决方案&#xff1a; 一、使用其…...

JVM_总结详解

1、CPU和内存的交互 了解jvm内存模型前&#xff0c;了解下cpu和计算机内存的交互情况。【因为Java虚拟机内存模型定义的访问操作与计算机十分相似】 有篇很棒的文章&#xff0c;从cpu讲到内存模型:[什么是java内存模型&#xff1f;] 在计算机中&#xff0c;cpu和内存的交互最…...

go语言 Pool实现资源池管理数据库连接资源或其他常用需要共享的资源

go Pool Pool用于展示如何使用有缓冲的通道实现资源池&#xff0c;来管理可以在任意数量的goroutine之间共享及独立使用的资源。这种模式在需要共享一组静态资源的情况&#xff08;如共享数据库连接或者内存缓冲区&#xff09;下非 常有用。如果goroutine需要从池里得到这些资…...

初级数据结构——邻接表

目录 前言一、定义与结构二、特点与性质三、构建方式四、操作与应用五、代码模版六、经典例题[1.——LCP 07. 传递信息](https://leetcode.cn/problems/chuan-di-xin-xi/description/)代码题解 [2.——547. 省份数量](https://leetcode.cn/problems/number-of-provinces/)代码题…...

思维导图+实现一个登录窗口界面

QQ2024122-205851 import sys from PyQt6.QtGui import QIcon, QPixmap, QMovie from PyQt6.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton, QLabel, QVBoxLayout# 封装我的窗口类 class LoginWidget(QWidget):# 构造函数def __init__(self):# 初始化父类su…...

多级缓存设计实践

缓存是什么&#xff1f; 缓存技术是一种用于加速数据访问的优化策略。它通过将频繁访问的数据存储在高速存储介质&#xff08;如内存&#xff09;中&#xff0c;减少对慢速存储设备&#xff08;如硬盘或远程服务器&#xff09;的访问次数&#xff0c;从而提升系统的响应速度和…...

ElasticSearch学习笔记一

目录 1.ElasticSearch-Head如何启动 2.ElasticSearch-Head创建索引 2.1创建索引时的“分片数”和“副本数”是什么意思&#xff1f; 类比 1&#xff1a;图书馆的书架与备份 类比 2&#xff1a;快递分拣中心与包裹副本 总结 ​编辑 2.2如何查看现有索引的分片数和备份数 …...

A058-基于Spring Boot的餐饮管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看项目链接获取⬇️&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600个选题ex…...

代码设计:设计模式:应对变化

文章目录 概述1.拆分代码2.解耦3.扩展总结概述 代码的设计模式主要为了应对变化 三种代码设计中应对变化的方式 1.拆分代码 2.解耦 3.扩展 1.拆分代码 减小变化对代码的影响 需要拆分代码的几种情况 1.类或方法的代码量巨大,导致代码可读性降低 2.存在复杂的代码,如…...

《Vue 路由导航:打造流畅的单页应用一》

一、Vue Router 简介 Vue Router 是什么&#xff1f; Vue Router 是 Vue.js 官方提供的路由管理器&#xff0c;用于构建单页面应用并实现页面间导航。它基于 Vue 的组件系统构建&#xff0c;通过配置路由将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面…...

【xshell连接失败】

xshell用pem连接失败 Warning: Identity file ”open_api_test.ssh not accessible: No such file or directory. Warning: Identity file open_api_test2.pem not accessible: No such file or directory. Permission denied (publickey,gssapi-keyex,gssapi-with-mic). 搞了半…...

说说Elasticsearch拼写纠错是如何实现的?

大家好&#xff0c;我是锋哥。今天分享关于【说说Elasticsearch拼写纠错是如何实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说Elasticsearch拼写纠错是如何实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Elasticsearch 中&…...

实例讲解MATLAB绘图坐标轴标签旋转

在进行绘图时需要在图片上添加上做标轴的标签&#xff0c;但是当数据量比较多时&#xff0c;例如一天24小时的数据&#xff0c;这时把每个小时显示在左边轴的标签上&#xff0c;文字内容放不下&#xff0c;因此需要将坐标轴标签旋转一定的角度&#xff0c;这样可以更好在图形上…...

Win10+Ubuntu20.04双系统重装Ubuntu22.04单系统

从去年 8 月美化 Ubuntu 系统后一直存在内核错误问题&#xff0c;但因为大部分功能还能正常使用&#xff0c;只是在 apt 时报错&#xff0c;所以一直逃避不想重装&#xff0c;直到最近 12 月新的开始&#xff0c;恰好设置的界面打不开得重装 gnome &#xff0c;所以下定决心重装…...

eBPF:现代Linux的强大内核扩展技术

eBPF&#xff1a;现代Linux的强大内核扩展技术 eBPF&#xff08;Extended Berkeley Packet Filter&#xff09;是一项变革性的技术&#xff0c;它为Linux内核提供了一个灵活的、可编程的方式来处理数据包过滤、网络监控、安全性和系统性能分析等多种任务。 1. eBPF简介 1.1 …...

深度学习-52-AI应用实战之基于Yolo8的目标检测自动标注

文章目录 1 YOLOv81.1 YOLOV8的不同版本1.2 可检测类别1.3 数据说明1.4 网络结构1.5 算法核心步骤2 目标检测的基本原理2.1 安装yolov8(cpu版本)2.2 图片检测2.3 视频检测2.4 自动标注2.5 保存标注结果3 参考附录1 YOLOv8 YOLOv8是一种前沿的计算机视觉技术,它基于先前YOLO版…...

人工智能工作流程概述:从数据到智能决策

目录 一、引言 二、人工智能工作流程概述 &#xff08;一&#xff09;数据收集 &#xff08;二&#xff09;数据预处理 &#xff08;三&#xff09;模型选择与设计 &#xff08;四&#xff09;模型训练 &#xff08;五&#xff09;模型评估 &#xff08;六&#xff09;模…...

Jenkins升级到最新版本后无法启动

1. 场景还原 最近在web界面将jenkins升级到最新版本后&#xff0c;后台无法启动jenkins服务&#xff0c;服务状态如下&#xff1a; 运行jenkins命令提示invalid Java version jenkins --version jenkins: invalid Java version: java version "1.8.0_202" Java(TM)…...

.net core MVC入门(三)——Product页面添加

文章目录 项目地址一、Product数据库准备 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、Product数据库准备 添加Product的EF上下文 public DbSet<Category> Categories { get; set; …...

【Java基础】笔记

List和ArrayList区别 public class Arrays_BugDemo {public static void main(String[] args){/** List 是一个固定大小的列表&#xff0c;虽然可以进行查询操作&#xff0c;但不支持添加、删除或修改元素。* 如果需要一个可以动态修改的列表&#xff0c;可以使用 ArrayList 进…...

Docker 进阶指南:常用命令、最佳实践与资源管理

Docker 进阶指南&#xff1a;常用命令、最佳实践与资源管理 Docker 作为一种轻量级的容器化技术&#xff0c;已经成为现代软件开发和部署不可或缺的工具。本文将为您深入介绍 Docker 的常用命令、最佳实践以及如何有效管理容器资源&#xff0c;帮助您更好地在 Ubuntu 22.04 或…...

C++编写静态库

1、新建项目创建静态库staticLib1. demoStaticLib.h #pragma once class ArrayTool { public:int Max(const int* lpHead, const int nLength);int Sum(const int* lpHead, const int nLength); }; demoStaticLib.cpp #include "pch.h" #include "demoStati…...

oracle数据库日常操作

1、执行SQL语句后不显示PL/SQL procedure successfully completed set feedback off; 2、显示实例名称 echo "set sqlprompt \"_user_connect_identifier> \"" >> $ORACLE_HOME/sqlplus/admin/glogin.sql 3、客户端尝试连接到服务器时发生超时 …...

行驶证 OCR 识别API接口的影响因素

一、影响因素 (一)证件质量与图像质量 行驶证的质量对OCR 识别 API 界面的效果有重要影响。清晰的文件可以使识别系统准确地捕获文本信息&#xff0c;而模糊的文本可能会导致识别错误。而且不同地区、不同年份的行驶证在字体、排版、格式等方面可能存在差异&#xff0c;甚至可…...

什么是TCP/IP和UDP

TCP/IP和UDP都是网络协议&#xff0c;用于不同计算机或设备之间的通信。它们的作用是定义数据如何在网络上传输&#xff0c;但它们在传输方式、可靠性和效率上有显著的区别。 1. TCP/IP TCP/IP&#xff08;传输控制协议/互联网协议&#xff0c;Transmission Control Protocol…...

1074 Reversing Linked List (25)

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K3, then you must output 3→2→1→6→5→4; if K4, you must output 4→3→2→1→5→6. Input Specif…...

layui table 纵向滚动条导致单元格表头表体错位问题

我用的时layui2.6.8版本 历史项目维护&#xff0c;bug给我让我做了&#xff0c;本来利用前端手段强解决&#xff0c;后来发现很多table 找了解决办法 打开layui-v2.6.8/lay/modules/table.js 如果打开后时压缩的代码 直接搜索 e.find(".layui-table-patch") …...