ROS话题(Topic)通信:通信模型、Hello World与拓展

文章目录

  • 一、话题通讯模型
  • 二、Topic Hello World
    • 2.1 创建并初始化功能包
    • 2.2 确定Topic名称及消息格式
    • 2.3 实现发布者与订阅者(C++版)
    • 2.4 实现发布者与订阅者(Python版)
    • 2.5 关于Topic Hello World的注意
  • 拓展1:devel下其他文件与目录的作用
  • 拓展2:build 目录下各文件与目录的作用

话题通信适用于不断更新数据、少逻辑处理的传输相关的应用场景。

一、话题通讯模型

话题是一种单向通讯方式,它通过发布和订阅的方式传递消息,该模型涉及到三个角色:

  • Master (管理者)
  • Publisher(发布者)
  • Subscriber(订阅者)

Master 负责保管 PublisherSubscriber 的注册信息,并匹配话题相同的 PublisherSubscriber ,帮助 他们建立连接,连接建立后,Publisher 可以发布消息,且发布的消息会被 Subscriber 订阅。

在这里插入图片描述

话题模型通讯流程:

  • 0)advertise:发布者注册

​ 发布者(Publisher)向管理者(Master)注册信息,包括RPC地址和Topic名字。Master会将发布者的注册信息加入到注册表中,并查询是否有该话题的订阅者。

  • 1)subscribe:订阅者注册

​ 订阅者(Subscriber)向管理者(Master)注册信息,包括Topic名字。Master会将订阅者(Subscriber)的注册信息加入到注册表中,并查询是否有该话题的发布者。

  • 2)Master匹配信息:牵线搭桥

​ 管理者(Master)通过查询注册表发现有匹配的发布者(Publisher)和订阅者(Subscriber),则向订阅者(Subscriber)发送发布者的RPC地址信息。

  • 3)connect:订阅者请求连接发布者

​ 订阅者根据发布者的RPC地址,请求连接发布者(Publisher),并传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。

  • 4)发布者确认请求

    发布者(Publisher)收到请求后,通过RPC向订阅者确认连接信息,并发送自身的 TCP/UDP 地址信息。

  • 5)建立连接

​ 订阅者根据发布者的TCP/UDP地址信息与订阅者建立TCP/UDP连接。

  • 6)发送消息

​ 连接建立后,发布者开始向订阅者发布话题消息数据。

Note:

  1. 上述实现流程中,前五步使用 RPC 协议,最后两步使用 TCP/UDP 协议,默认TCP。
  2. 发布者 与 订阅者 的启动无先后顺序要求。
  3. 发布者 与 订阅者 都可以有多个。
  4. 发布者 与 订阅者 连接建立后,不再需要 ROS Master。即便关闭 ROS Master,发布者 与 订阅者 照常通信。不过不会再有新的发布者 与 订阅者加入。

二、Topic Hello World

万物始于Hello World,同样,使用Hello World介绍Topic的简单使用。

使用Topic传输数据时,需要注意以下几点:

  • Topic名称
  • 消息格式
  • 发布者实现
  • 订阅者实现

接下来实现一个简单的 Topic 话题通信,发布者发布 Hello Word n (n代表递增数列)字符串,订阅者接收到后输出到屏幕。

2.1 创建并初始化功能包

(这一步不是必须,这里只是为了方便清晰的说明,也可以使用已有的包,在包里新增节点等方法)

首先创建 topic_hello_world 包,命令如下:

catkin_creat_pkg topic_hello_world std_msgs roscpp rospy

创建后,文件结构如下:

在这里插入图片描述

2.2 确定Topic名称及消息格式

Topic名称:/hello_world_topic

消息格式:std_msgs::String

消息文件路径:/opt/ros/noetic/share/std_msgs/msg/String.msg

消息文件内容:

string data

2.3 实现发布者与订阅者(C++版)

在创建的 topic_hello_world 包路径下有一个 src 目录,在这里存储C++源码,我们创建 topic_hello_world_pub.cpp 以实现发布者,编辑内容如下:

/*实现流程:1.包含头文件2.初始化 ROS 节点:命名(唯一)3.实例化 ROS 句柄4.实例化 发布者 对象5.组织被发布的数据,并编写逻辑发布数据
*/
// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h" // std_msgs包自带的普通文本的消息类型
#include <sstream>int main(int argc, char **argv)
{// 以下任意一句: 设置编码,解决ROS LOG打印中文乱码的问题// 但 rostopic echo 中文乱码的问题无法解决// setlocale(LC_ALL, ""); setlocale(LC_CTYPE, "zh_CN.utf8");// 2.初始化 ROS 节点: 命名(唯一)// 参数1和参数2 后期为节点传值会使用// 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 拓扑网络中唯一ros::init(argc, argv, "publisher");// 3.实例化 ROS 句柄// 该类封装了 ROS 中的一些常用功能ros::NodeHandle nh;// 4.实例化 发布者 对象,向ROS Master注册发布者// 泛型 std_msgs::String: 发布的消息类型// 参数1: 要发布到的话题名称// 参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)ros::Publisher pub = nh.advertise<std_msgs::String>("/hello_world_topic", 10);// 延时1s等待publisher在ROS Master注册成功后,再发布消息。// ros::Duration(1.0).sleep();// 目的同上,为了确保发布者注册成功再发布消息// 等待直到发布者成功注册到 ROS Master,并有订阅者订阅while (pub.getNumSubscribers() == 0){if (!ros::ok()){// 如果节点被关闭,退出程序return 0;}ROS_INFO_ONCE("Waiting for subscribers to connect...");ros::Duration(1.0).sleep(); // 等待一秒钟}// 5.组织被发布的数据,并编写逻辑发布数据std_msgs::String msg;std::string msg_front = "Hello World "; // 消息前缀int count = 0;                          // 消息计数器// 运行loop的频率(1Hz: 一秒1次)ros::Rate r(1);// 让节点一直运行while (ros::ok()){// 拼接字符串与编号,并组装消息数据msg.data = msg_front + std::to_string(count);// 发布消息pub.publish(msg);// 打印发送的消息ROS_INFO("发送的消息: %s", msg.data.c_str());// 根据前面制定的发布频率自动休眠 休眠时间 = 1/频率 s;r.sleep();// 循环结束前,让 count 自增count++;}return 0;
}

创建 topic_hello_world_sub.cpp 以实现订阅者,编辑内容如下:

/*实现流程:1.包含头文件2.初始化 ROS 节点:命名(唯一)3.实例化 ROS 句柄4.实例化 订阅者 对象5.处理订阅的消息(回调函数)6.设置循环调用回调函数
*/// 1.包含头文件
#include "ros/ros.h"
#include "std_msgs/String.h"// 5.处理订阅的消息(回调函数)
// topic回调函数,处理订阅的消息
void topicCallback(const std_msgs::String::ConstPtr &msg_p)
{ROS_INFO("收到的消息: %s", msg_p->data.c_str());
}int main(int argc, char **argv)
{// 以下任意一句: 设置编码,解决ROS LOG打印中文乱码的问题// 但 rostopic echo 中文乱码的问题无法解决// setlocale(LC_ALL, ""); setlocale(LC_CTYPE, "zh_CN.utf8");// 2.初始化 ROS 节点:命名(唯一)ros::init(argc, argv, "subscriber");// 3.实例化 ROS 句柄ros::NodeHandle nh;// 4.实例化 订阅者 对象ros::Subscriber sub = nh.subscribe<std_msgs::String>("/hello_world_topic", 10, topicCallback);// 6.设置循环调用回调函数ros::spin(); // 循环读取接收的数据,并调用回调函数处理return 0;
}

修改 CMakeLists.txt ,只需添加如下内容:

add_executable(${PROJECT_NAME}_pub src/topic_hello_world_pub.cpp)
add_executable(${PROJECT_NAME}_sub src/topic_hello_world_sub.cpp)target_link_libraries(${PROJECT_NAME}_pub${catkin_LIBRARIES}
)target_link_libraries(${PROJECT_NAME}_sub${catkin_LIBRARIES}
)

编译运行

进入工作空间执行 catkin_make 命令编译工程,编译成功后,使用如下命令依次启动发布者和订阅者。

1. 启动ros master
roscore
2. 启动发布者
./devel/lib/topic_hello_world/topic_hello_world_pub
3. 启动订阅者
./devel/lib/topic_hello_world/topic_hello_world_sub

结果如下:

在这里插入图片描述

目前为止,Topic Hello World 已经成功了。

2.4 实现发布者与订阅者(Python版)

在创建的 topic_hello_world 包路径下 src 目录的同级,创建一个 scripts 目录,在这里存储脚本(如python脚本),我们创建 topic_hello_world_pub.py 以实现发布者,编辑内容如下:

#! /usr/bin python
"""实现流程:1.导包 2.初始化 ROS 节点:命名(唯一)3.实例化 发布者 对象4.组织被发布的数据,并编写逻辑发布数据
"""
# 1.导包
import rospy
from std_msgs.msg import Stringdef main():# 2.初始化 ROS 节点:命名(唯一)rospy.init_node("publisher")# 3.实例化 发布者 对象pub = rospy.Publisher("/hello_world_topic", String, queue_size=10)# rospy.sleep(1)while pub.get_num_connections() == 0:if rospy.is_shutdown():returnrospy.loginfo_once("Waiting for subscribers to connect...")rospy.sleep(1)# 4.组织要发布的数据,并编写逻辑发布数据msg = String()  # 创建 msg 对象msg_front = "Hello World "count = 0  # 计数器# 设置循环频率rate = rospy.Rate(1)while not rospy.is_shutdown():# 拼接字符串msg.data = msg_front + str(count)pub.publish(msg)rate.sleep()rospy.loginfo("发送的消息: %s", msg.data)count += 1if __name__ == "__main__":main()

scrips中创建 topic_hello_world_sub.py 以实现订阅者,编辑内容如下:

#! /usr/bin python
"""实现流程:1.导包 2.初始化 ROS 节点:命名(唯一)3.实例化 订阅者 对象4.处理订阅的消息(回调函数)5.设置循环调用回调函数
"""
# 1.导包
import rospy
from std_msgs.msg import String# 4.处理订阅的消息(回调函数)
def topicCallback(msg):rospy.loginfo("收到的消息: %s", msg.data)def main():# 2.初始化 ROS 节点:命名(唯一)rospy.init_node("subscriber")# 3.实例化 订阅者 对象sub = rospy.Subscriber("/hello_world_topic", String, topicCallback, queue_size=10)# 5.设置循环调用回调函数rospy.spin()if __name__ == "__main__":main()

修改 CMakeLists.txt ,只需添加如下内容:

catkin_install_python(PROGRAMSscripts/topic_hello_world_pub.pyscripts/topic_hello_world_sub.pyDESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

编译运行

进入工作空间执行 catkin_make 命令编译工程,编译成功后,使用如下命令依次启动发布者和订阅者。

1. 启动ros master(如果已启动,无需再启动)
roscore
2. 启动发布者
python ./devel/lib/topic_hello_world/topic_hello_world_pub.py
3. 启动订阅者
python ./devel/lib/topic_hello_world/topic_hello_world_pub.py

结果如下:

在这里插入图片描述

2.5 关于Topic Hello World的注意

启动发布者与订阅者时建议用如下命令:(上述命令只是给初学者的):

启动发布者
rosrun topic_hello_world topic_hello_world_pub (C++版)
rosrun topic_hello_world topic_hello_world_pub.py (Python版)
启动订阅者
rosrun topic_hello_world topic_hello_world_sub (C++版)
rosrun topic_hello_world topic_hello_world_sub.py (Python版)

其中,rosrun 是执行ROS可执行文件的命令,topic_hello_world是功能包的名称,topic_hello_world_pub是该功能包下可执行文件(如节点)的名称。

如果你遇到如下错误:

在这里插入图片描述

那么可能你没有把工作空间的路径加到终端环境变量中,听起看来是不是很晕,不要急,catkin 为我们提供了一个脚本可以做这件事,它位于工作空间下的 devel 目录中,有如下三个脚本:

setup.bash 
setup.zsh
setup.sh

其中,

  • setup.sh:是一个Shell脚本,用于设置ROS软件包的环境变量。当你使用source devel/setup.sh命令时,它会将当前工作空间的路径添加到ROS_PACKAGE_PATH中,并设置其他与ROS运行时相关的环境变量,如:将当前工作空间的 bin, lib, includeshare 文件夹添加到终端环境的 PATH, LD_LIBRARY_PATH, CMAKE_PREFIX_PATHPYTHONPATH 变量中。这样,在执行 ROS 命令和使用 ROS 相关库时,终端将能够找到和访问这些文件夹中的内容。
  • setup.bash:一个Bash脚本,用于设置ROS软件包的环境变量。他调用了 setup.sh
  • setup.zsh:是一个Zsh脚本,类似于setup.bash,用于设置ROS软件包的环境变量。他调用了 setup.sh

根据你使用的shell类型运行相应的脚本,我们一般把脚本加到终端配置文件中,以bash为例:

  1. 编辑~/.bashrc文件,将source <setup.bash_abs_path>添加到文件中,一般添加到末尾,其中<setup.bash_path>代表setup.bash文件的绝对路径。
  2. 执行 source ~/.bashrc 使修改生效。

至此,再执行 rosrun topic_hello_world topic_hello_world_pub 就不会报错了。

拓展1:devel下其他文件与目录的作用

在这里插入图片描述

  1. cmake.lock: 一个用于记录构建过程中的锁文件。它包含有关构建状态和依赖项的信息,用于锁定CMake的缓存信息。当CMake在构建过程中遇到相同的输入时,它会使用这个文件来避免重复编译。
  2. lib: 包含编译生成的库文件。ROS软件包中的节点或其他模块编译后生成的库文件通常会存放在这个目录下。
  3. local_setup.zsh: 一个Zsh脚本,用于设置当前终端会话的环境变量,使其能够识别和运行与ROS相关的程序和软件包。
  4. _setup_util.py: 一个Python脚本,用于设置ROS软件包的环境变量。这个脚本被setup.sh调用。
  5. env.sh: 一个用于设置环境变量的脚本。当你希望手动设置ROS软件包的环境变量时,可以使用这个脚本。
  6. local_setup.bash: 一个Bash脚本,用于设置当前终端会话的环境变量,使其能够识别和运行与ROS相关的程序和软件包。
  7. include: 包含头文件。在编译时,一些头文件可能会被拷贝到这个目录下,以便在其他ROS软件包中使用。
  8. local_setup.sh: 一个Shell脚本,用于设置当前终端会话的环境变量,使其能够识别和运行与ROS相关的程序和软件包。
  9. share: 包含共享的数据文件、配置文件和其他资源。这些资源可以被其他软件包或节点访问和使用。可能包含ROS软件包的配置文件、启动文件、参数设置等共享资源。

拓展2:build 目录下各文件与目录的作用

  1. atomic_configure: 包含构建配置的原子配置文件,用于确保配置的原子性。这个文件可能包含一些构建系统的配置信息。
  2. bin: 包含构建生成的可执行文件。ROS软件包中的节点或其他二进制文件通常会存放在这个目录下。
  3. catkin: 包含Catkin构建系统的一些生成文件和配置信息。
  4. catkin_generated: 包含由Catkin工具生成的文件。这个目录包含一些与Catkin相关的中间文件和构建信息。
  5. CATKIN_IGNORE: 一个标记文件,用于指示Catkin在构建过程中忽略此目录。这对于排除特定目录或文件不参与构建是很有用的。
  6. gtest: Google Test(gtest)的相关文件和构建信息。gtest是一个用于C++单元测试的测试框架。
  7. test_results: 包含测试运行的结果。当运行catkin_make run_tests时,测试框架会将测试结果输出到这个目录。
  8. catkin_make.cache: 一个Catkin缓存文件,包含构建系统的一些缓存信息,以提高构建效率。
  9. CMakeCache.txt: 由CMake生成,包含有关CMake配置的缓存信息。这个文件记录了CMake变量的当前值,以及一些配置选项。
  10. Makefile: 由CMake生成,用于执行实际的编译和构建操作。
  11. CMakeFiles: 包含由CMake生成的中间文件。这些文件包括用于构建过程中生成的临时对象文件、编译器输出等。
  12. cmake_install.cmake: 由CMake生成,包含用于将文件安装到指定目录的指令。
  13. CTestConfiguration.ini: 用于配置CTest(CMake的测试工具)的配置文件。
  14. CTestCustom.cmake: CTest的自定义配置文件,其中可以包含一些用户自定义的测试配置选项。
  15. CTestTestfile.cmake: CTest的测试文件配置,用于指定要运行的测试用例。
  16. my_pkg: 这个名字是你的功能包的名字,可能有多个,即ROS功能包的构建目录,其中包含了编译生成的中间文件、目标文件以及其他与构建过程相关的信息。

这些文件和目录是构建和测试过程中的临时文件和配置文件,它们会在ROS工作空间的生命周期内动态生成和修改。

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

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

相关文章

预览PDF并显示当前页数

这里写目录标题 步骤实例实例效果图 步骤 1.安装依赖 npm install --save vue-pdf2.在需要的页面&#xff0c;引入插件 import pdf from vue-pdf3.使用 单页pdf可以直接使用 <pdf :src"获取到的pdf地址"></pdf>多页pdf通过循环实现 html标签部分 &l…

Banana Pi BPI-M5 Boot Log 导出说明

准备&#xff1a; Preparation: 1、 一块bpi的开发板&#xff0c;一根ttl的串口线&#xff0c;以及一张烧录好镜像的sd/tf卡&#xff08;烧录到eMMC也行&#xff09;。 1. A BPI development board, a TTL serial port cable, and an SD/TF card with a burned image (it ca…

高并发架构设计(三大利器:缓存、限流和降级)

引言 高并发背景 互联网行业迅速发展&#xff0c;用户量剧增&#xff0c;系统面临巨大的并发请求压力。 软件系统有三个追求&#xff1a;高性能、高并发、高可用&#xff0c;俗称三高。三者既有区别也有联系&#xff0c;门门道道很多&#xff0c;全面讨论需要三天三夜&#…

Rust编程中的共享状态并发执行

1.共享状态并发 虽然消息传递是一个很好的处理并发的方式&#xff0c;但并不是唯一一个。另一种方式是让多个线程拥有相同的共享数据。在学习Go语言编程过程中大家应该听到过一句口号:"不要通过共享内存来通讯"。 在某种程度上&#xff0c;任何编程语言中的信道都类…

stm32超声波测距不准的解决方法(STM32 delay_us()产生1us)及stm32智能小车超声波测距代码(C语言版本)

首先要说明一下原理&#xff1a;使用stm32无法准确产生1us的时间&#xff0c;但是超声波测距一定要依赖时间&#xff0c;时间不准&#xff0c;距离一定不准&#xff0c;这是要肯定的&#xff0c;但是在不准确的情况下&#xff0c;要测量一个比较准确的时间&#xff0c;那么只能…

PHP中$_SERVER全局变量

在PHP中&#xff0c;$_SERVER 是一个全局数组变量&#xff0c;它包含了有关服务器和当前脚本的信息。$_SERVER 数组中的每个元素都是服务器环境的一个参数&#xff0c;如请求的方法、请求的 URI、客户端 IP 地址等。 PATH 系统环境变量的值&#xff0c;包含了多个目录的路径…

【Word自定义配置,超简单,图文并茂】自定义Word中的默认配置,比如标题大小与颜色(参考科研作图配色),正文字体等

▚ 01 自定义样式Styles中的默认标题模板 &#x1f4e2;自定义标题的显示效果&#xff0c;如下图所示&#xff1a; 1.1 自定义标题的模板Normal.dotm 1.1.1 选择所需修改的标题 新建一个空白Word文档&#xff0c;依次选择菜单栏的开始Home&#xff0c;样式Styles&#xff0c;…

Python生成随机数插件Faker的用法

目录 引言 一、Faker库的安装 二、Faker库的基本用法 1、导入Faker类 2、创建Faker对象 3、使用Faker对象生成随机数据 三、Faker库的高级用法 1、自定义数据生成规则 2、使用子模块进行特定领域的数据生成 3、与其他库结合使用 四、Faker库的应用场景 1、单元测试…

TCP与UDP

文章目录 TCP与UDP传输层的作用端口号UDPTCPUDP首部的格式TCP首部格式 TCP与UDP TCP/IP中有两个具有代表性的传输层协议&#xff0c;它们分别是TCP和UDP。TCP提供可靠的通信传输&#xff0c;而UDP则常被用于让广播和细节控制交给应用的通信传输。总之&#xff0c;根据通信的具…

MTK Camera2 的OPEN API流程认知

MTK的设计架构 再了解Camera的open api调用之前我们&#xff0c;需要了解Camera的架构&#xff0c;这样才能提高阅读代码的效率。 代码跟读&#xff1a; 在这个图中大致介绍了OpenCamera的具体调用&#xff0c;下面我们逐步分析Camera的open调用流程。 逐步分析 一、 我们抛…

如何使用PHPStudy本地快速搭建网站并实现远程访问

文章目录 [toc]使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2…

Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用

Flutter笔记 绘图示例 - 一个简单的&#xff08;Canvas &#xff09;时钟应用 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_2855…

【算法|动态规划 | 区间dp No.2】AcWing 1068.环形石子合并

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【AcWing算法提高学习专栏】【手撕算法系列专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

内衣洗衣机和手洗哪个干净?好用的内衣洗衣机推荐

在日常生活中&#xff0c;我们的衣服不可避免地会沾染上各种细菌、毛发和污渍&#xff0c;将它们与贴身衣物混合清洗&#xff0c;很容易发生交叉感染&#xff0c;而被感染后&#xff0c;贴身衣物也有可能导致我们人体引起皮肤病。这也是为什么大部分人都喜欢用手洗的原因&#…

Android WebView专题

WebView 专题 第一个WebView程序&#xff1a;加载远程网址 Layout添加WebView组件&#xff1b; <WebViewandroid:id"id/webView_first"android:layout_width"match_parent"android:layout_height"match_parent"/>初始化组件&#xff0c;加…

Socket网络编程(服务端和客户端代码示例)

本文主要讲解Socket网络编程。 首先介绍socket&#xff0c;包括TCP和UDP通信过程&#xff1b;然后介绍常用的函数&#xff1b;最后编写client-server例子&#xff0c;并进行测试。 文章目录 Socket介绍TCP通信过程服务器端通信过程&#xff1a;客户端通信过程&#xff1a; UDP通…

SA实战 ·《SpringCloud Alibaba实战》第13章-服务网关:项目整合SpringCloud Gateway网关

大家好,我是冰河~~ 一不小心[SpringCloud Alibaba实战》专栏都更新到第13章了,再不上车就跟不上了,小伙伴们快跟上啊! 在《SpringCloud Alibaba实战》专栏前面的文章中,我们实现了用户微服务、商品微服务和订单微服务之间的远程调用,并且实现了服务调用的负载均衡。也基于…

FusionDiff:第一个基于扩散模型实现的多聚焦图像融合的论文

文章目录 1. 论文介绍2. 研究动机3. 模型结构3.1 网络架构3.2 前向扩散过程3.3 逆向扩散过程3.4 训练和推理过程 4. 小样本学习4. 实验结果 1. 论文介绍 题目&#xff1a;FusionDiff: Multi-focus image fusion using denoising diffusion probabilistic models 作者&#xf…

【Mysql系列】Mysql基础篇

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Smart Link 和 Monitor Link应用

定义 Smart Link常用于双上行链路组网&#xff0c;提高接入的可靠性。 Monitor Link通过监视上行接口&#xff0c;使下行接口同步上行接口状态&#xff0c;起到传递故障信息的作用。 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个…