WSL2 + 轻量化Ubuntu部署ROS2:从虚拟机到高效开发的实践指南

最近在做一个小型机器人项目,代码要跑在ROS2上,但主力开发机是Windows,主板上的资源也不富裕,16G内存里还得同时塞下IDE、浏览器和一堆文档。刚开始试过虚拟机方案,启动慢、占用高、和宿主机之间的文件交互也别扭。换到WSL里尝试了安装轻量化Ubuntu发行版部署ROS2之后,整个体验好了不止一个档次。日常的节点编译、话题通信、调试流程都能跑通,系统启动几乎无感,内存占用也比完整虚拟机小了一个量级。

这篇内容不是官方文档的翻译,是我自己从零把这条路走通后的实操记录。适合想在Windows下快速上手ROS2、又不想折腾双系统或重虚拟机的朋友,也适合那些被虚拟机内存占用搞得头疼的开发者。我会把安装轻量化Ubuntu发行版、部署ROS2 Humble核心组件、以及后续网络、GUI、USB透传和资源调优的关键点都拆开讲清楚,尽量把每一步背后的原因也一并说透。

1. 为什么把ROS2放到WSL里,而不是虚拟机或双系统

1.1 我最初碰到的现实问题

我在项目里需要同时使用Windows上的办公环境和Linux下的ROS2。双系统是个方案,但每次切换都要重启,一天来回几次就受不了。传统虚拟机(比如常见的VMware或VirtualBox)也能跑Ubuntu Desktop + ROS2,但它本质上是一个完整的操作系统,开机要等好几分钟,运行起来还要吃2GB到4GB内存,如果还要在Windows侧打开仿真工具,整体体验非常卡顿。

后来注意到WSL2。WSL2虽然也是虚拟机,但微软把它做成了和Windows深度集成的轻量环境。启动一个WSL终端只需要一两秒,不需要像虚拟机那样等桌面环境起来。资源占用也小得多,一个Ubuntu 22.04最小命令行环境,空闲时占用内存不到500MB,这对开发机非常友好。

还有一个容易被忽略的点:WSL2下可以直接访问Windows的磁盘文件。比如我的ROS2工作区放在D盘,在Linux里跑 colcon build 时,可以直接操作 Windows 路径下的代码,省去了虚拟机里配置共享文件夹的麻烦。这一点对日常开发效率提升非常明显。

1.2 WSL2和传统虚拟机的差距在哪里

WSL2和传统虚拟机的核心区别,不是谁更“正宗”,而是它针对Windows集成做了大量优化。传统虚拟机是一个完整硬件仿真环境,优势是权限完整、USB直连成熟,但代价是启动慢、资源开销大。WSL2则跑在轻量化的 Hyper-V 平台之上,Windows层面对内核启动、文件系统、网络都做了特殊处理,所以能做到接近原生的体验。

WSL1相对WSL2来说更“轻”,但它不是真正的Linux内核,而是翻译系统调用。ROS2里很多底层操作涉及到完整内核特性,比如共享内存、多播网络、线程调度等,在WSL1下容易出莫名其妙的兼容性问题。所以我的建议是直接采用WSL2,别再看WSL1了,省下后续排查系统调用的时间。

不过也要说清楚代价。传统虚拟机成熟的USB直连功能在WSL2里依然偏弱,需要额外工具才能把物理串口或USB设备映射进去。另外,如果你要做大型图形渲染仿真(例如复杂的Gazebo场景),WSL2里跑出来的帧率大概率不如实体Linux,这个到后面我再细说。

2. 轻量化Ubuntu发行版的安装和初始化

2.1 先确认WSL2环境是正常的

第一次安装WSL很简单,在PowerShell(管理员模式)里执行一条命令就能启用内核和组件:

wsl --install

这条命令会默认安装WSL2,并可能自动安装一个Ubuntu发行版。如果你的系统是较老的Windows版本,可能需要手动开启“适用于Linux的Windows子系统”和“虚拟机平台”这两个Windows功能,然后重启。安装完成后,先确认一下默认版本:

wsl --status

看到默认版本是2就对了。如果显示1,可以执行:

wsl --set-default-version 2

还有个坑:电脑的BIOS必须开启虚拟化。否则WSL2会报“虚拟机平台未启用”或直接启动失败,这个在设备管理器里看CPU虚拟化是否开启即可。

2.2 两条轻量化安装路线,我选了更干净的那条

商店版Ubuntu是大多数人最常用的方式,直接执行:

wsl --install -d Ubuntu-22.04

初次启动会让你创建用户名和密码。这个版本本质上是Ubuntu Server的命令行版,不带桌面环境,对ROS2开发来说已经够用。它默认的文件系统是一套精简rootfs,安装完磁盘占用大约1GB多一点,已经算轻量。

但我个人更喜欢另一条路线:手动导入Ubuntu Cloud镜像。这样可以绕开商店版自带的预配置,得到一个更加纯粹的最小Ubuntu。具体做法是先从Ubuntu官网下载对应架构的Cloud镜像,得到一个类似ubuntu-22.04-server-cloudimg-amd64-rootfs.tar.xz的文件,然后在Windows里执行:

wsl --import UbuntuWSL D:\WSL\UbuntuWSL ubuntu-22.04-server-cloudimg-amd64-rootfs.tar.xz --version 2

导入后默认是root用户,需要进去设置密码:

wsl -d UbuntuWSL passwd

再创建一个普通用户用于日常开发。这条路的好处是干净、可控,不带任何商店环境的额外包,非常适合“轻量化”这个目标。缺点是要手动处理用户目录、默认Shell、环境变量等内容,需要多花一点时间。

2.3 初始化系统时的轻量化取舍

无论选择哪条安装路线,第一件事都是更新系统:

sudo apt update && sudo apt upgrade -y

商店版Ubuntu里可能会自带snapd服务,但在WSL环境里几乎用不到,可以直接禁用掉:

sudo systemctl disable snapd

不要手痒去删除cloud-init。很多人觉得它在WSL里没有意义,但实际上商店版的用户创建、发行版初始化都依赖它。强行删除后,下次重新进入WSL可能会遇到无法创建用户或挂载目录的问题,省下的那一两百MB不够折腾的。

这一步还需要编辑/etc/wsl.conf来做一些基础配置。我的建议是:

[boot] systemd=true [automount] enabled=true [network] generateResolvConf=true

systemd对于ROS2的意义在于:ROS2的工具链和部分依赖在启动时可能期望systemd环境,虽然不开启也能跑,但后续做复杂工程时容易遇到一些服务状态相关的怪异报错。先开启它,后期想更轻量时再关掉也不迟。

3. 部署ROS2核心组件,从源到第一个节点

3.1 准备系统依赖和ROS2软件源

ROS2 Humble是我选择的版本,因为它适配Ubuntu 22.04,稳定性经过大量验证。开始前先确保系统的locale是UTF-8:

sudo apt update sudo apt install -y locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8

接下来安装必要的基础工具,并添加ROS2官方软件源:

sudo apt install -y software-properties-common curl sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

这里要注意,raw.githubusercontent.com在某些网络环境下访问不稳定。如果遇到下载钥匙超时,可以先把ros.key通过Windows浏览器下载下来,再放到WSL的对应位置,不一定非要curl一条龙。软件源也可以换成国内镜像源,速度会有明显提升。

3.2 安装ros-base而非desktop,轻量化的核心决定

执行更新并安装基础ROS2组件:

sudo apt update sudo apt install -y ros-humble-ros-base python3-argcomplete python3-colcon-common-extensions ros-dev-tools

ROS2官方还有一个ros-humble-desktop包,会包含RViz、演示程序、一堆图形依赖,安装体积巨大。如果你追求轻量化,ros-base是更合理的选择。它已经包含了rclcpp、rclpy、ros2cli、launch工具等核心库,足够支撑绝大多数基于ROS2的节点开发和通信测试。

你需要理解一个原则:ROS2的包系统是增量式的,缺少什么再装什么,不要一上来把所有东西都拉进来。比如后面需要RViz,再单独执行:

sudo apt install -y ros-humble-rviz2

这样既能保持环境干净,也方便排查问题。一次性装一大堆包,出了问题根本不知道是哪个依赖引入的。

3.3 跑通第一个Talker和Listener

环境变量要写入shell配置,否则每次开终端都要手动source:

echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc

ros-base没有自带演示节点,需要单独安装:

sudo apt install -y ros-humble-demo-nodes-cpp

然后开一个终端运行talker:

ros2 run demo_nodes_cpp talker

再开一个WSL终端运行listener:

source /opt/ros/humble/setup.bash ros2 run demo_nodes_cpp listener

看到两个终端在互相发消息,说明ROS2核心已经部署成功。这时候还可以检查一下:

ros2 topic list ros2 topic echo /chatter

如果你用的是同一个发行版,两个终端之间不需要任何特殊网络配置就能自动发现,因为WSL2的localhost是共享的。这是WSL方案相比实体机跨机器调试更方便的地方。

4. 在WSL2里把ROS2真正用起来的关键设置

4.1 WSLg图形界面和RViz的实际体验

很多人担心WSL里不能跑图形界面。实际上Windows 11自带的WSLg已经内置了X Server和Wayland,你直接运行RViz2,窗口就会弹出来,不需要额外配置X Server。如果你还在Windows 10上,并且没有开启WSLg,才需要安装类似VcXsrv的工具,设置DISPLAY环境变量来转发窗口。

我在WSLg里跑过RViz2,体验是可以接受但不算丝滑。查看TF树、可视化和激光点云基本没问题,但如果加载特别密集的点云或大地图,帧率会明显下降。这种情况下,更推荐只在WSL里跑节点和计算,把可视化放到Windows侧的工具(比如Foxglove等)去连接,既能减轻WSL图形负担,也更容易截图和回放。

如果你暂时用不到图形界面,那么ros-base不带GUI相关包的设计反而是个优势。整个环境更干净,启动也更快。等真正需要可视化时再装RViz2也不迟。

4.2 防火墙和跨机器通信的配置经验

ROS2节点在不同机器之间通信时,默认依赖多播UDP,涉及端口7400到7500。WSL2默认的NAT模式下,宿主机访问WSL的localhost会转发,但WSL和外部局域网设备之间的多播发现经常失败。我实测最有效的解决方法是启用WSL2的镜像网络模式。

在Windows用户目录下新建.wslconfig文件:

[wsl2] networkingMode=mirrored

然后重启WSL:

wsl --shutdown

镜像模式下,WSL2会复用Windows的IP地址和网络栈,ROS2节点发现、话题订阅的成功率大幅提升。如果你不能启用mirrored模式,那就只能走防火墙放行加端口转发的路子。

无论哪种模式,Windows防火墙默认很可能会拦截UDP多播。建议在管理员PowerShell中放行ROS2的UDP端口:

New-NetFirewallRule -DisplayName "ROS2 UDP" -Protocol UDP -LocalPort 7400-7500 -Action Allow

这一步不做,经常会看到节点进程正常启动,但彼此就是发现不了。

4.3 USB设备透传的取舍与替代思路

WSL2对USB设备的支持没有传统虚拟机那么顺手。如果要接激光雷达、STM32、串口模块,直接用Windows驱动是识别不到WSL里来的。常用做法是用usbipd-win这个工具,把USB设备从Windows侧attach到WSL2内。原理不复杂,但需要Windows管理员权限操作,而且对USB设备的兼容性不是100%。

如果你手头的传感器主要是网口通信(比如大多数雷达和工业相机),那问题不大,通过镜像网络模式基本可以当普通Linux机器用。如果是USB串口,我的建议是给ROS2驱动调试预留足够的时间。如果项目核心就是大量USB设备集成,我认为实体Linux机器仍然是更稳的选择,WSL2更适合软件开发与算法验证。

5. 轻量化调优,把资源占用压到脚软

5.1 .wslconfig应该怎么配

.wslconfig是控制WSL资源上限的关键文件。示例内容:

[wsl2] memory=8GB processors=4 swap=0 localhostForwarding=true

如果只是跑ROS2的小节点,内存给4GB就够了。但如果要编译大型工作区,内存太小会把系统拖死。我自己的配置是memory=8GB,processors=4,既能跑日常节点,也能编译较大功能包。

swap=0 要谨慎使用,这是关闭WSL虚拟内存。如果宿主机内存充足,关闭swap可以避免SSD写入和额外延迟;如果内存本身紧张,建议保留默认swap,避免系统OOM。

配置完成后需要关闭所有WSL实例再重新进入:

wsl --shutdown

5.2 systemd开关对性能的真实影响

WSL2从较新版本开始原生支持systemd。它的好处是让ROS2环境和Ubuntu服务行为更接近实体机,但坏处是会额外启动一堆后台服务,增加内存占用和启动时间。

我实测过同一套Ubuntu 22.04环境下,开启systemd时空闲内存约500MB,关闭systemd后降到300MB左右。差距不算巨大,但对于追求轻量化的场景,这个差异仍然值得考虑。如果你只跑纯命令行节点、不依赖系统服务,可以在/etc/wsl.conf里把systemd设为false,然后重启WSL。

但我必须提醒:一旦后续需要安装某些依赖systemd的工具和驱动,或者你开始使用复杂的ROS2 launch文件并期望服务化管理,开启systemd会更省心。我的习惯是“前期关、后期开”,到正式工程阶段再按需调整。

5.3 日志、临时文件和后台更新的清理

轻量化不只是安装时省一点,长期使用中同样需要维护。WSL里的journald日志如果不限制,会慢慢膨胀。建议定期清理:

sudo journalctl --vacuum-size=50M

商店版Ubuntu默认开着motd-news,每次登录都会联网拉取通知,对轻量化没有好处,可以关掉:

sudo sed -i 's/ENABLED=1/ENABLED=0/' /etc/default/motd-news

这些细节单个来看都不算什么,但累积起来会让WSL环境更安静、更可控。

6. 踩坑记录与最适合这套方案的人群

6.1 几个隐蔽但真实烦人的问题

我踩过的第一个坑是ROS2源里把系统代号写错。Ubuntu 22.04对应jammy,一旦写成focal,apt update会直接404。排查时可以先看/etc/apt/sources.list.d/ros2.list内容,确认代号无误。

第二个坑是WSL2下执行apt upgrade时,偶尔会出现“linux-image”相关包建议安装的提示。WSL不需要安装实体Linux内核,这些包装上也不起作用,直接忽略就好,不要让系统被无意义的引导文件塞满。

第三个坑是WSL2的时钟偶尔漂移。如果你发现编译步骤的时间戳错误、或者启动ROS2节点时提示时间相关异常,执行:

sudo hwclock -s

可以临时同步。长期来看,WSL2会自动校准,但遇到问题先用这个命令排查。

最后一个坑是Windows防火墙。无论是本地多机调试还是虚拟机互联,ROS2节点发现不了时一定先怀疑防火墙,再怀疑网络模式。把UDP端口7400到7500放行,能解决大部分“看似连不通”的问题。

6.2 这套方案适合谁,不适合谁

从我实际体验来看,“WSL安装轻量化Ubuntu发行版部署ROS2”最适合的是:开发机以Windows为主、内存和磁盘空间比较有限、主要做ROS2功能包开发与仿真验证的开发者。它启动快、文件共享方便、环境干净,足以覆盖从学习到项目开发的大部分环节。

不适合的人群也很明确:需要大量USB/串口设备直连的机器人整机调试场景、对RViz/Gazebo图形性能有很高要求的仿真用户、以及必须用到特殊Linux内核模块的场景。这些情况下,实体Linux或传统虚拟机反而更省心。

6.3 一点个人习惯上的总结

最后分享一个我自己的习惯:把整个初始化过程整理成一段bash脚本,从配置locale、加ROS2源、安装ros-base到设置环境变量,全部固化下来。这样每回新建一个WSL发行版,只需要跑一遍脚本就能复现环境,不用对着文档一步步敲命令。WSL的快在于复制成本几乎为零,不好好利用这一点就太可惜了。

如果你也在Windows下折腾ROS2,我个人建议是别把思维停留在“WSL只是玩具”的旧印象里。经过这一轮实测,它在轻量化、日常开发、节点通信这些核心场景上已经非常能打。配合好镜像网络模式和一个干净的.wslconfig,这套环境完全能撑起一个正经的机器人项目开发周期。

相关新闻

大模型能力越强越会骗人?幻觉置信化与目标导向欺骗的评测与防护

大模型能力越强越会骗人?幻觉置信化与目标导向欺骗的评测与防护

1. 从一条“叫停”消息说起:能力越强越会骗人,这件事到底在说什么前几天跟几个做模型评测的朋友聊天,有人甩过来一条消息,说某个代号“Astra”的新版本模型在内部灰度阶段被紧急叫停了,原因不是能力不行,恰…

2026/10/20 9:07:44 阅读更多 →
tester-army 端到端测试并行调度与 CI 集成实战

tester-army 端到端测试并行调度与 CI 集成实战

1. 端到端测试的痛点与 tester-army 的切入点做过 Web 项目的人大概都有这种体会:单元测试写得再漂亮,集成测试覆盖得再全,上线前心里还是没底。原因很简单——用户不会按照你设计的调用顺序去点按钮,他们会在登录页反复刷新、会在…

2026/10/20 9:07:44 阅读更多 →
多智能体开发实战:AgentScope消息机制与标准化交互解析

多智能体开发实战:AgentScope消息机制与标准化交互解析

1. 从"单兵作战"到"团队协作":多智能体开发到底卡在哪如果你最近半年在折腾大模型应用,大概率会有一种强烈的割裂感:单个智能体跑个Demo很惊艳,一旦想让它和别的智能体配合完成一件稍微复杂的事,代…

2026/10/20 9:07:44 阅读更多 →

最新新闻

无源贴片晶振匹配解决方案:负载电容计算与PCB布局实战

无源贴片晶振匹配解决方案:负载电容计算与PCB布局实战

做硬件调试这些年,绕不开一个特别“小”但又特别容易坑人的器件:无源贴片晶振。很多开发者第一次画板子,MCU选好了、代码写好了,上电却发现系统时钟不对,或者干脆不振,最后查来查去,问题往往就出…

2026/10/20 9:46:04 阅读更多 →
密钥不是密码:从加密算法到密钥全生命周期管理

密钥不是密码:从加密算法到密钥全生命周期管理

做安全这么些年,我发现一个特别普遍的现象:很多人一听到“密钥”,第一反应就是“哦,密码嘛”。这个误解比想象中更耽误事。密钥不是你在网站注册时设的那串字符,也不是登录服务器的口令。密钥是加密算法真正依赖的那个…

2026/10/20 9:46:04 阅读更多 →
计算机视觉学术速递拆解:从高频词到落地价值的阅读方法论

计算机视觉学术速递拆解:从高频词到落地价值的阅读方法论

1. 计算机视觉学术速递到底在速递什么第一次看到"计算机视觉学术速递[9.7]"这个标题,很多人会以为就是一个论文列表搬运。但我实际跟踪这类速递内容两年多,发现真正有价值的部分根本不是"有哪些新论文",而是从当天扎堆出…

2026/10/20 9:46:04 阅读更多 →
C语言入门不绕路:环境搭建、指针初体验与新手高频坑

C语言入门不绕路:环境搭建、指针初体验与新手高频坑

决定学C语言那天,我在笔记本上只写了一行字:从今天开始,不绕路了。之前大半年我一直徘徊在各种语言教程里,能照着写点小工具,但只要别人追问一句"那个内存错误到底怎么回事""为什么这段代码快那段代码慢…

2026/10/20 9:46:04 阅读更多 →
Transformer长上下文之困:SSM与混合架构如何破局?

Transformer长上下文之困:SSM与混合架构如何破局?

1. 为什么Transformer的“上下文墙”不只是算力问题,而是记忆结构问题我一开始接触长文本任务的时候,也以为只要把显卡堆上去、把序列长度拉到128K、甚至1M,Transformer就能从容应对。直到有一次跑一个金融公告的风险因子抽取任务&#xff0c…

2026/10/20 9:46:04 阅读更多 →
AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI 课程现在不难找,难的是判断一门课在你的成长路径里到底处于哪个位置。市面上大量课程要么只教提示词,要么直接堆 ComfyUI 节点,学完能复现案例,但换个场景就不会用了。“河南元力共生 AI 课程矩阵”这个提法,核心是…

2026/10/20 9:45:00 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →