ROS Master多设备连接

Bash Shell

Shell是位于用户与操作系统内核之间的桥梁,当用户在终端敲入命令后,这些输入首先会进入内核中的tty子系统,TTY子系统负责捕获并处理终端的输入输出流,确保数据正确无误的在终端和系统内核之中。Shell在此过程不仅仅是一个监听者,还会积极地从tty子系统读取用户的命令输入,并对其进行解析来识别用户意图(比如当你输入ls时,是Shell解析这个命令并调用/bin/ls文件的来直接解析)。Bash Shell(基础 shell)是 Linux/Unix 系统中用户与操作系统内核交互的基本命令行界面,它是系统启动后为用户提供的默认命令解释器环境

Bash和Shell其实是包含关系。Shell是命令行解释器的统称 ,有Bash、Zsh、Fish、Dash等多种命令行解释器,Bash是Shell的最流行方式,Ubuntu系统默认使用的也是Bash,当然你可以通过在终端中输入特定命令行可以切换(一般这几种命令行解释器的命令是兼容的,但是存在一些语法和交互功能的差异),一般使用Bash就足够了。

Bash Shell与终端不同点:Bash Shell是命令行解释器程序,终端则是输入输出设备/界面。可以理解为终端是"显示器+键盘",而Bash是运行在这个显示器上的"智能程序"。一般的执行流程是-------你在终端输入命令 → 终端将输入传给Shell → Shell解释执行 → 结果返回终端显示

交互式Shell与非交互式Shell 

 简单来说,交互式Shell用户可以 直接输入命令 并 实时看到输出 的 Shell,会显示 PS1 提示符(如 user@host:~$),等待用户输入。比较常见的场景:1,直接打开终端 2,通过 SSH 登录后手动操作(如 ssh user@192.168.1.1 后进入 Shell3,手动运行 bash -i(强制交互模式)

非交互式Shell,不等待用户输入,直接执行 单条命令 后退出,所以说一般是看不到的,不会显示 PS1 提示符,执行完命令后立即关闭。比较常见的场景:1,通过 ssh user@host "command" 远程执行命令。2,使用 Python paramiko.exec_command("command")。3,运行 Shell 脚本(如 bash script.sh),如果输入bash -i script.sh会强制交互式

登录式Shell和非登录式Shell

登录式 Shell 的关键特征是:

  1. 以用户身份初始化完整的登录会话(加载登录配置文件,如 ~/.bash_profile)。

  2. 通常出现在系统首次登录时(如 SSH 登录、本地终端登录、su - username)。

.sh脚本文件

我们平常为了方便而写的脚本文件,实际上就是一个纯文本文件,包含一系列 Shell 命令(如 Bash、Zsh 等支持的语法),将需要手动逐条输入的命令,预先整体写入文件,实现 自动化执行。比如,以下脚本文件(文件名demo.sh),Shell解析器就会一行一行的解析每一行(即每一条)内容。

#!/bin/bash
echo "Hello World"
ls -l
date

执行的.sh文件的方式有以下几种

  1. bash demo.sh:显式指定解释器(bash),启动一个新的子 Shell 进程来执行脚本。直接调用 /bin/bash 程序,将 demo.sh 作为参数传递给它,忽略 Shebang 行(即首行的#!/bin/bash)
  2. ./demo.sh:依赖脚本首行的 Shebang(如 #!/bin/bash)。与bash的区别还有重要的一点就是bash demo.sh不需要赋予文件执行权限,而./demo.sh必须赋予文件执行权限
  3. source demo.sh(也可以简写为. demo.sh):不启动子Shell,直接在当前 Shell 进程中逐行执行脚本,并且会忽视Shebang。脚本中定义的变量、函数、别名等会影响当前 Shell。而前两种执行方式脚本中定义的变量、函数不会影响当前 Shell 环境。一般用于加载环境配置,比如
# 加载环境配置(如 ~/.bashrc)
source ~/.bashrc# 脚本中修改当前 Shell 的工作目录
source change_dir.sh  # 脚本内容: cd /some/path

在交互式Shell和非交互式Shell说到过,bash  运行Shell脚本时会启动一个非交互式Shell,也就是启动一个新的子Shell来运行这个脚本,并且这个子Shell进程是非交互式的Shell,执行完毕后,控制权返回给父 Shell。而source不会启动子Shell,所以说它会在当前的交互式Shell运行。

.bashrc文件

.bashrc 文件是 Linux 系统中非常重要的配置文件,它与是否安装 ROS 无关,是 Bash shell的标准配置文件(它是一个纯文本文件,使用 Bash 语法 编写),"rc" 通常代表 "run commands" (运行命令)。文件名中的点(.)表示它是隐藏文件,在Linux系统用户主目录下,按ctrl+h键可以显示隐藏文件。

.bashrc的内容语法(完全遵循Bash语法):

  1. export PATH="$PATH:/my/custom/path" 变量定义。用来设置环境变量,影响所有子进程
  2. alias ll='ls -alF' 起别名,在终端输入ll就相当于输入ls -alF
  3. greet() { echo "Hello, $USER!"; } 函数定义
  4. if [ -d ~/projects ]; then
      echo "Projects directory exists"
    fi   条件循环判断

.bashrc如何运行?

当启动非登录的交互式 Bash shell 时,打开新的终端时,通过bash命令启动新的Shell时,.bashrc文件都会自动启动

必须需要注意的是在非交互式Shell中默认不会自动加载.bashrc,也就是说你在使用bash执行脚本时在新打开的Shell子进程中不会加载.bashrc也就不会启动对应的环境(但是子进程会继承父进程的环境变量)。在交互式Shell中默认会加载.bashrc(因为 ~/.bash_profile 或 ~/.profile 通常会显式调用 .bashrc)。登录式Shell会加载 ~/.bash_profile 或 ~/.profile,~/.bash_profile 或 ~/.profile 通常会显式调用 .bashrc所以.bashrc也会自动调用。非登录式Shell不会加载配置文件。

其实在非交互式Shell不会自动加载.bashrc,这是因为.bashrc的开头有以下代码。这表示:仅当Shell是交互式时,才继续执行后续内容。非交互式Shell会直接return退出,也就是说即使你在非交互式Shell单独调用source ~/.bashrc,也不会加载.bashrc的配置内容。这是为了避免用户自定义配置影响自动化任务而设置的,为了安全起见也不要试图去修改它!!!

case $- in*i*) ;;*) return;;
esac

除此之外还有.bash_profile和.profile文件。.bashrc在非登录的交互式Bash Shell(不需要重新认证的子会话,如图形终端新建窗口、bash 命令启动等,直接继承父 Shell 的环境变量)自动加载;.bash_profile在Bash登录Shell(需要用户认证的完整会话,如系统登录、SSH 连接等,全新环境(会重新读取配置))自动加载,也就是说.bash_profile登录时一次性设置。.profile是在所有Shell的登录会话都会加载,但是前提是.bash_profile不存在。也就是说只有在用户使用Bash并且存在./bash_profile时才会跳过.profile的加载,如果用户使用其他命令解释器则会自动加载.profile,所以说.profile是跨 Shell 的通用环境变量。

1,网络配置

确保所有设备(PC端,嵌入式端等等)连接在同一个局域网下,在每台设备的终端输入ifconfig查看IP地址,由于不同网络下IP地址经常改变,所有推荐将每台设备设置为静态IP地址。

使用ping命令测试各PC之间的连通性,如果都能ping通后就可以开始下一步了

2,环境变量配置

在所有PC上编辑~/.bashrc文件,添加以下环境变量:

export ROS_MASTER_URI=http://<master_ip>:11311  # 主机的IP地址。ROS 默认使用 11311 端口 作为 roscore 的通信端口,这是由 ROS 的设计者设定的标准配置。
export ROS_IP=<local_ip>  # 本机的IP地址
export ROS_HOSTNAME=<local_ip>  # 本机的IP地址

然后执行

source ~/.bashrc

3,主机名解析

主机名解析就是将上面的ROS_MASTER_URI=http://<master_ip>:11311中的master_ip用一个名字来代替,比如master-pc=192.168.1.1,这时只需要将192.168.1.1替换为master-pc即可,类似于变量赋值。当然,你也可以直接输入为192.168.1.1而不需要主机解析,但是这样的话如果主机的ip地址频繁变换,就需要在每个从机的./bashrc中重新修改主机的ip地址,从机数量少的话还可以,从机数量多的话就会很麻烦。

主机名解析的实现方式一般有以下几种:

1,使用/etc/hosts文件:

首先,在所有参与ROS通信的计算机上编辑/etc/hosts文件,添加所有ROS计算机的IP和主机名映射,格式如下:

192.168.1.100   master-pc
192.168.1.101   slave1-pc
192.168.1.102   slave2-pc

保存文件后测试解析:

ping master-pc
ping slave1-pc

 但是这种方式看起来是使用了主机解析,但它只是增强了可读性,而没有解决频繁手动修改IP的缺点,如果 Master 的 IP 地址变了,还是需要手动修改所有从机的/etc/hosts文件的配置

 2,使用DNS:

DNS一般是用于学校或者企业,适用于本地有DNS服务器或路由器支持DNS绑定的场景

在路由器或 DNS 服务器上,将主机名(如 master-pc)绑定到 Master 的 IP。所有从机自动通过 DNS 解析 master-pc,无需手动改 IP。这样IP地址变动时,只需改DNS记录所有从机自动生效

 3,使用mDNS:

适用于小型网络,如实验室或者家用

确保所有机器安装 avahi-daemon(Linux 默认通常已安装):

sudo apt install avahi-daemon  # Ubuntu/Debian

直接使用 .local 主机名(无需配置 /etc/hosts):

export ROS_MASTER_URI=http://master-pc.local:11311

4,使用静态DHCP绑定:

适用于家用/实验室路由器支持DHCP静态绑定的场景

在路由器后台,将 Master 的 MAC 地址绑定到一个固定 IP(如 192.168.1.100)。所有从机直接用这个 IP,因为 Master 的 IP 永远不会变

4,防火墙配置

UFW(Uncomplicated Firewall)是一款基于 iptables 的简单易用的防火墙配置工具,广泛应用于基于 Debian 和 Ubuntu 的 Linux 系统中,用于管理和配置网络防火墙规则。UFW 支持允许或拒绝特定的网络连接。即使系统中没有安装 UFW,也不意味着没有防火墙阻拦网络连接。UFW 只是一个简化的防火墙管理工具,而在 Linux 系统中,底层的防火墙功能通常由 iptables 或 nftables 实现(iptables 是 Linux 系统中强大的防火墙配置工具,但它的命令复杂,规则编写难度较大,对普通用户不太友好。UFW 则提供了一种简化的接口,使用户可以用更直观、简洁的命令来管理防火墙规则,比如,启用防火墙只需执行sudo ufw enable,而使用 iptables 则需要编写多条复杂的命令)。

先使用命令查看防火墙配置工具ufw是否安装

dpkg -l | grep ufw

如果 ufw 已经安装,会显示相关的软件包信息;如果没有任何输出,说明 ufw 未安装。此时需要输入命令进行安装:

sudo apt update
sudo apt install ufw

安装后查看防火墙活跃状态

 sudo ufw status

如果输出Status: inactive,表示防火墙处于未启用状态,网络端口处于相对开放状态,外界可以直接访问系统暴露的端口。

如果防火墙处于活跃状态,则需要确保所有PC的防火墙允许ROS通信(默认端口11311)

sudo ufw allow 11311/tcp

就能允许外部设备通过 22 端口(通常用于 SSH 服务)访问本地系统 

 5,测试连接

在主PC上启动ROS Master:

roscore

在其他PC上测试连接:

rostopic list

如果连接成功,会显示 Master 上已发布的 Topic 列表。如果 Master 刚启动 roscore,默认只有 /rosout 和 /rosout_agg

$ rostopic list
/rosout
/rosout_agg

6,同步时间

需要时可以选用此功能

在ROS多机通信中,时间同步(Time Synchronization)是一个关键但容易被忽视的配置。指的是让所有参与ROS通信的计算机保持高度一致的系统时间(最好误差在毫秒级)。

通常使用NTP来实现时间同步 :

 NTP是一种网络协议,用于同步计算机的系统时间,计算机通过NTP客户端从时间服务器(如ntp.ubuntu.com)获取精确时间,局域网内通常可达毫秒级同步

 基本原理

NTP(Network Time Protocol)实现时间同步的原理是一个分层、多源校正的精密时间同步体系,其核心设计目标是在不可靠的网络环境中实现高精度的时间同步(局域网内通常可达毫秒级,理想条件下可达亚毫秒级)。

NTP采用层级化的时间源结构,类似于金字塔:

  • Stratum 0
    最顶层,直接连接原子钟、GPS或铯钟等高精度物理时钟设备,不直接参与网络通信

    • 示例:实验室原子钟、卫星时间信号。

  • Stratum 1
    直接与Stratum 0设备同步的NTP服务器(时间误差通常<100μs)。

    • 示例:国家授时中心服务器、Google的time.google.com

  • Stratum 2
    从Stratum 1同步的服务器,误差逐层递增(每层增加约1ms)。

    • 示例:企业级NTP服务器、公共NTP池(如pool.ntp.org)。

  • Stratum 3及以下
    更低层级的同步节点,适用于普通客户端设备。

NTP通过以下四个时间戳计算时间偏差(Clock Offset)和网络延迟(Round-Trip Delay):

假设客户端(A)与服务器(B)交互:

  1. T₁:客户端发送请求时的本地时间(A的时钟)。

  2. T₂:服务器收到请求时的本地时间(B的时钟)。

  3. T₃:服务器回复响应时的本地时间(B的时钟)。

  4. T₄:客户端收到响应时的本地时间(A的时钟)。

 最终时间偏差是多次测量的统计结果(通常采用最小二乘法Marzullo算法过滤异常值)。

中国的NTP服务架构是分层级的,国家授时中心是stratum1,其他运营商比如阿里云,腾讯云等部署了多台次级服务器。所以你执行命令时会使自己的PC端自动连接到附近最优的服务器,由于所有的NTP服务器本身已经同步(都溯源到国家授时中心或GPS/原子钟) ,所以连接了NTP的各个服务器就可以实现同步。

比如下面的方式一就是将其连接到了最优的服务器,但是如果你需要更高的精度,还可以指定同一NTP服务器,这时就需要在文件/etc/systemd/timesyncd.conf,添加如下内容指定特定服务器(比如阿里云)

[Time]
NTP=ntp.aliyun.com

实现方式(Ubuntu系统)

方法一:使用系统默认的timesyncd(使用简单)

如果使用 systemd-timesyncd(即 timedatectl 管理的 NTP 客户端),通常不需要额外安装 ntp 或 ntpdate,因为 timesyncd 已经是一个轻量级的 NTP 客户端,默认集成在 systemd 中。

# 检查当前同步状态
timedatectl status# 如果未启用NTP,运行:
sudo timedatectl set-ntp on# 手动强制同步
sudo systemctl restart systemd-timesyncd

方法二:安装完成的ntp包(更精确控制)

sudo apt install ntp
sudo systemctl restart ntp  # 启动或重启 NTP 服务,立即应用配置并开始同步。# 查看同步状态
ntpq -p

ntpq -p输出示例如下

   remote           refid      st t when poll reach   delay   offset  jitter
============================================================================
*ntp.ubuntu.com  .POOL.          16 u   25   64    1    5.123   -0.432   0.871
+time.google.com .GOOG.           1 u   12   64    7    1.234    0.567   0.123
  • * 表示当前主同步源。

  • offset:本地时钟与服务器的偏差(单位:毫秒)。

  • jitter:网络延迟的波动程度。

验证时间同步:

ntpdate -q 192.168.1.100  # 查询与某台机器的时间差

 7,共享ROS包

此功能如果需要可以选用,不做详细解释

方法1:同步工作空间

  • 使用rsync或git同步工作空间

  • 确保所有PC上的包路径相同

方法2:NFS共享

  • 设置NFS服务器共享工作空间

  • 其他PC挂载该共享目录

方法3:独立编译

  • 在各PC上独立维护代码库

  • 确保版本一致

 8,启动管理

可以使用roslaunch在多台机器上启动节点:

<launch><machine name="pc1" address="192.168.1.101" user="user" password="pass" env-loader="/opt/ros/noetic/env.sh"/><machine name="pc2" address="192.168.1.102" user="user" password="pass" env-loader="/opt/ros/noetic/env.sh"/><node machine="pc1" name="node1" pkg="your_pkg" type="node1"/><node machine="pc2" name="node2" pkg="your_pkg" type="node2"/>
</launch>

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

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

相关文章

Trae + LangGPT 生成结构化 Prompt

Trae LangGPT 生成结构化 Prompt 0. 引言1. 安装 Trae2. 克隆 LangGPT3. Trae 和 LangGPT 联动4. 集成到 Dify 中 0. 引言 Github 上 LangGPT 这个项目&#xff0c;主要向我们介绍了写结构化Prompt的一些方法和示例&#xff0c;我们怎么直接使用这个项目&#xff0c;辅助我们…

《安富莱嵌入式周报》第352期:手持开源终端,基于参数阵列的定向扬声器,炫酷ASCII播放器,PCB电阻箱,支持1Ω到500KΩ,Pebble智能手表代码重构

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版 https://www.bilibili.com/video/BV1DEf3YiEqE/ 《安富莱嵌入式周报》第352期&#xff1a;手持开源终端&#x…

python 浅拷贝copy与深拷贝deepcopy 理解

一 浅拷贝与深拷贝 1. 浅拷贝 浅拷贝只复制了对象本身&#xff08;即c中的引用&#xff09;。 2. 深拷贝 深拷贝创建一个新的对象&#xff0c;同时也会创建所有子对象的副本&#xff0c;因此新对象与原对象之间完全独立。 二 代码理解 1. 案例一 a 10 b a b 20 print…

day22 学习笔记

文章目录 前言一、遍历1.行遍历2.列遍历3.直接遍历 二、排序三、去重四、分组 前言 通过今天的学习&#xff0c;我掌握了对Pandas的数据类型进行基本操作&#xff0c;包括遍历&#xff0c;去重&#xff0c;排序&#xff0c;分组 一、遍历 1.行遍历 intertuples方法用于遍历D…

SpringMVC的请求-文件上传

文件上传客户端三要素 1. 表单项type“file” 2. 表单的提交方式是post 3. 表单的enctype属性是多部分表单形式&#xff0c;及enctype“multipart/form-data” <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <he…

在Ubuntu系统如何让MySQL服务器支持远程连接

目录 问题描述 解决方案 步骤一&#xff1a;检查MySQL配置文件 ​编辑 步骤二&#xff1a;修改bind-address参数 ​编辑 步骤三&#xff1a;重启MySQL服务 步骤四&#xff1a;验证更改 步骤五&#xff1a;检查防火墙设置 步骤六&#xff1a;测试远程连接 注意事项 …

JSON工具-JSONUtil

对象转JSON JSONUtil.toJsonStr可以将任意对象&#xff08;Bean、Map、集合等&#xff09;直接转换为JSON字符串。 如果对象是有序的Map等对象&#xff0c;则转换后的JSON字符串也是有序的。 //region 处理POST请求&#xff0c;将TreeMap转换为JSON字符串返回/*** 处理POST请求…

死锁 手撕死锁检测工具

目录 引言 一.理论联立 1.死锁的概念和原因 2.死锁检测的基本思路 3.有向图在死锁检测中的应用 二.代码实现案例&#xff08;我们会介绍部分重要接口解释&#xff09; 1.我们定义一个线性表来存线程ID和锁ID 2.表中数据的查询接口 3.表中数据的删除接口 4.表中数据的添…

Java 中 SQL 注入问题剖析​

一、引言​ 在当今数字化时代&#xff0c;数据是企业和组织的核心资产之一。许多应用程序都依赖于数据库来存储和管理数据&#xff0c;而 Java 作为一种广泛使用的编程语言&#xff0c;常被用于开发与数据库交互的应用程序。然而&#xff0c;SQL 注入这一安全漏洞却如同隐藏在…

安全理念和安全产品发展史

从安全理念的发展历史来看,技术与产品的演进始终围绕 “威胁对抗” 与 “业务适配” 两大核心展开。以下从七个关键阶段解析安全技术与产品的发展脉络,并结合最新实践与未来趋势提供深度洞察: 一、密码学奠基阶段(1970s 前) 安全理念:以 “信息保密” 为核心,防御手段…

【Ansible自动化运维】二、Playbook 深入探究:构建复杂自动化流程

​ 在 Ansible 自动化运维体系中&#xff0c;Playbook 是极为关键的部分。它允许我们以一种结构化、可重复的方式定义和执行一系列复杂的任务&#xff0c;从而构建高效的自动化流程。本篇文章将深入探究 Ansible Playbook 的各个方面&#xff0c;助您掌握构建复杂自动化…

springboot项目中常用的工具类和api

在Spring Boot项目中&#xff0c;开发者通常会依赖一些工具类和API来简化开发、提高效率。以下是一些常用的工具类及其典型应用场景&#xff0c;涵盖 Spring 原生工具、第三方库&#xff08;如Hutool、Guava&#xff09; 和 Java 自带工具。 1. Spring Framework 自带工具类 (…

23种设计模式-行为型模式-模板方法

文章目录 简介场景解决代码关键优化点 总结 简介 模板方法是一种行为设计模式&#xff0c;它在超类中定义了一个算法的框架&#xff0c;允许子类在不修改结构的情况下重写算法的特定步骤。 场景 假如你正在开发一款分析文档的数据挖掘程序。用户需要向程序输入各种格式&…

解决Long类型前端精度丢失和正常传回后端问题

在 Java 后端开发中&#xff0c;可能会遇到前后端交互过程中 Long 类型精度丢失的问题。尤其是在 JavaScript 中&#xff0c;由于其 Number 类型是双精度浮点数&#xff0c;超过 16 位的 Long 类型值就会发生精度丢失。 问题背景 假设有如下实体类&#xff1a; public class…

PowerPhotos:拯救你的Mac照片库,告别苹果原生应用的局限

如果你用Mac管理照片&#xff0c;大概率被苹果原生「照片」应用折磨过——无法真正并行操作多个图库。每次切换图库都要关闭重启&#xff0c;想合并照片得手动导出导入&#xff0c;重复文件更是无处可逃…… 直到我发现了 PowerPhotos&#xff0c;这款专为Mac设计的照片库管理…

android 14.0 工厂模式 测试音频的一些问题(高通)

1之前用tinycap&#xff0c;现在得用agmcap 执行----agmcap /data/test.wav -D 100 -d 101 -i CODEC_DMA-LPAIF_RXTX-TX-3 -T 3 报错1 agmcap data/test.wav -D 100 -d 101 -i CODEC_DMA-LPAIF_RXTX-TX-3 -T 3 Failed to open xml file name /vendor/etc/backend_co…

以库存系统为核心的ERP底层架构设计

在企业资源计划&#xff08;ERP&#xff09;系统中&#xff0c;库存系统常被视为基础模块。但在现代企业的数字化进程中&#xff0c;库存系统不仅仅是一个模块&#xff0c;它已经逐步演化为驱动整个ERP生态的核心引擎。本文从架构设计的角度&#xff0c;探讨为何库存系统应被置…

辛格迪客户案例 | 北京舒曼德医药实施电子合约系统(eSign)

01 北京舒曼德医药科技开发有限公司&#xff1a;医药科技的数字化先锋 北京舒曼德医药科技开发有限公司&#xff08;以下简称“舒曼德医药”&#xff09;作为国内医药科技领域的领军企业&#xff0c;致力于创新药物的研发、临床试验和市场推广。公司以“科技兴药、质量为先、服…

【UE5】RTS游戏的框选功能+行军线效果实现

目录 效果 步骤 一、项目准备 二、框选NPC并移动到指定地点 三、框选效果 效果 步骤 一、项目准备 1. 新建一个俯视角游戏工程 2. 新建一个pawn、玩家控制器和游戏模式,这里分别命名为“MyPawn”、“MyController”和“MyGameMode” 3. 打开“MyGameMode”,设置玩家…

vim定位有问题的脚本/插件的一般方法

在使用vim的过程中可能会遇到一些报错或其他不符合预期的情况&#xff0c;本文介绍一些我自己常用的定位有问题脚本/插件的方法&#xff08;以下方法同样适用于neovim&#xff09; 执行了某些命令的情况 这种情况最简单&#xff0c;使用:h 命令&#xff0c;如果插件有文档的话…