树莓派3B安装ROS Kinetic全攻略:从系统配置到多机通信
1. 为什么现在还有人折腾树莓派3B装ROS Kinetic先把结论摆在前面树莓派3B跑ROS Kinetic这件事放在今天看确实有点复古但它依然是很多人入门机器人操作系统最省钱、最直观的一条路。原因不复杂——Kinetic是ROS1里对ARMv7支持最成熟的几个发行版之一配套的教程、驱动包、社区问答沉淀得足够厚而树莓派3B这块板子二手价格已经低到可以随便买两三块做分布式实验。你花很少的钱就能搭出一个主控传感器节点的真实机器人雏形这是纯在电脑上跑仿真给不了的手感。我自己第一次接触这套组合是为了给一个两轮差速小车做底层控制。当时手头只有一块树莓派3B、一个电机驱动板和一个激光雷达目标很明确让树莓派当上位机跑导航同时通过串口跟下位机通信。选Kinetic而不是更新的版本是因为那个雷达的ROS驱动包只维护到Kinetic换版本就得自己改源码时间成本不划算。这个取舍逻辑其实很典型——在嵌入式机器人项目里版本选择往往不是选最新的而是选生态最匹配的。这篇文章面向三类人一是刚拿到树莓派、想入门ROS但不知道从哪下手的新手二是手里有旧板子想废物利用的爱好者三是需要给课程或小项目搭一套低成本验证平台的开发者。我会把整个安装过程拆开讲透包括镜像怎么选、源怎么配、编译卡死怎么办、串口权限怎么处理这些实际会卡住人的地方。很多教程只告诉你敲哪几行命令但真正让你熬夜的是那些命令背后的坑这篇重点就在这。需要提前说明的是树莓派3B的硬件规格决定了它跑ROS会比较吃力四核Cortex-A53、1GB内存、没有硬件浮点加速的短板在编译大型包时会暴露得很明显。所以整个安装策略的核心思路是——能用二进制包就别源码编译能裁剪的依赖就裁剪。理解这一点后面所有操作你都会觉得顺理成章。2. 系统镜像与ROS版本的前置决策2.1 为什么必须锁定Ubuntu Mate 16.04而不是Raspbian这是新手最容易走弯路的地方。ROS Kinetic官方支持的Ubuntu版本是Xenial16.04而树莓派官方系统Raspbian是基于Debian的包管理体系和依赖命名跟Ubuntu有差异直接在上面装ROS会遇到大量依赖找不到的问题。所以正确做法是刷Ubuntu Mate 16.04 for Raspberry Pi 3这个专门为树莓派适配的镜像。你可能会问能不能用Ubuntu Server 16.04可以但Mate版本自带桌面环境对于需要看rviz、跑图形化调试工具的初学者更友好。代价是系统本身占用更多内存1GB的板子跑起来会紧巴巴。我的建议是如果你打算纯做无头节点headless用Server版省内存如果要接显示器调试用Mate版。两者装ROS的步骤完全一致。镜像下载后写入SD卡这里有个细节很多人忽略SD卡的读写速度直接决定系统流畅度。我实测过Class 4的老卡和Class 10的卡开机时间能差一倍以上编译时的IO等待更是天壤之别。建议至少用16GB Class 10的卡如果手头有eMMC转接方案更好但3B没有原生eMMC接口只能靠SD卡。2.2 首次启动后必须做的三件事刷完系统第一次开机别急着装ROS先把基础环境理顺否则后面全是坑。第一件是扩展文件系统。Ubuntu Mate镜像写入SD卡后根分区默认只占用了镜像大小剩下的空间没被利用。用sudo raspi-config进Advanced Options里的Expand Filesystem把整张卡的空间释放出来。不做这一步装到一半提示磁盘空间不足是常事。第二件是换软件源。默认的国外源在国内访问速度极慢apt update能卡到你怀疑人生。编辑/etc/apt/sources.list换成国内可用的镜像地址。这里我不具体点名某个源因为镜像可用性会随时间变化你自己搜Ubuntu 16.04 armhf 镜像源找当前可用的即可。换完记得sudo apt update验证一下速度。第三件是设置静态IP或固定主机名。ROS的多机通信依赖主机名解析如果树莓派的IP每次开机都变后面配置多机通信会非常痛苦。可以在路由器里绑定MAC地址或者直接在系统里配静态IP。主机名建议改成有意义的名字比如pi-robot方便在/etc/hosts里做映射。提示这三件事做完再往下走能省掉后面至少一半的排错时间。我见过太多人跳过这步结果编译到一半空间爆了或者apt源慢到以为板子坏了。2.3 ROS Kinetic的安装方式对比装ROS Kinetic有两条路apt二进制安装和源码编译。对树莓派3B来说强烈建议走apt安装。原因很直接源码编译在1GB内存的板子上编译一个roscpp相关的大包就可能因为内存不足被OOM killer干掉而且编译时间动辄几小时。apt安装的好处是官方和社区已经帮你编译好了armhf架构的deb包直接下载安装即可。缺点是有些第三方包没有armhf的二进制版本只能自己编译但核心的ROS基础包都能apt搞定。安装方式耗时内存压力适用场景apt二进制30分钟到1小时低绝大多数情况推荐源码编译数小时到十几小时极高易OOM需要改源码或装无二进制包时理解了这张表你就明白为什么我一直强调能apt就apt。下面进入具体操作。3. 从零开始配置ROS Kinetic软件源3.1 添加ROS官方源的正确姿势ROS Kinetic的apt源配置有一套标准流程但直接照搬官网命令在树莓派上会出问题因为官网默认的源地址对armhf架构的支持需要额外确认。完整步骤如下。先安装必要的工具sudo apt install -y dirmngr gnupg2 lsb-release然后添加ROS的密钥。这一步是验证软件包来源合法性的不能跳过sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1FB78E7839FECB5FAF2C4A3D5B3A如果这个keyserver连不上很常见换用备用地址sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key 421C365BD9FF1FB78E7839FECB5FAF2C4A3D5B3A接着把ROS源写进sources.listecho deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/ros-latest.list这里$(lsb_release -sc)会自动解析成xenial前提是你的系统确实是16.04。如果你刷错了系统版本这一步就会写入错误的源后面apt update会报一堆404。所以先确认系统版本再操作用lsb_release -a看一眼。3.2 apt update报错的几种典型情况和处理执行sudo apt update时最常见的报错有三类。第一类是密钥验证失败提示NO_PUBKEY。这说明上一步的密钥没导入成功。解决办法是记下报错里的密钥ID用sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key 那个ID单独导入。第二类是404 Not Found通常是源地址写错了或者系统版本不匹配。检查/etc/apt/sources.list.d/ros-latest.list里的内容确认xenial拼写正确。第三类是连接超时这是网络问题。ROS官方源在国内访问不稳定可以考虑用国内镜像源替换。替换时注意镜像站是否同步了armhf架构的包有些镜像只同步了amd64用上去照样404。注意每次改完源都要重新apt update不要跳过。update失败的情况下强行install装出来的东西可能不完整。3.3 安装ROS基础包的取舍源配好后安装命令是sudo apt install -y ros-kinetic-ros-base这里我特意选的是ros-base而不是desktop-full。原因很实际desktop-full包含rviz、gazebo、各种仿真工具体积巨大在树莓派3B上装完可能占掉好几个GB而且很多组件你根本用不上。ros-base只包含核心通信库、消息系统和基础工具足够跑节点通信和大部分传感器驱动。如果你确实需要rviz做可视化可以单独装ros-kinetic-rviz按需添加比一次性全装明智得多。这就是前面说的能裁剪就裁剪策略的具体落地。装完后初始化rosdepsudo rosdep init rosdep updaterosdep init如果报错说文件已存在说明之前装过可以跳过。rosdep update需要联网拉取依赖数据库国内网络下可能要多试几次或者配置代理这里指网络代理配置用于加速下载不涉及任何特殊用途。4. 环境变量配置与工作空间初始化4.1 让ROS命令随处可用装完ROS后roscore、rosrun这些命令默认不在PATH里需要source环境变量。临时生效用source /opt/ros/kinetic/setup.bash但每次开终端都敲一遍太麻烦写进~/.bashrcecho source /opt/ros/kinetic/setup.bash ~/.bashrc source ~/.bashrc这里有个容易踩的坑如果你后面创建了自己的catkin工作空间工作空间的setup.bash也要source而且顺序很重要——必须先source ROS系统环境再source工作空间环境否则工作空间里的包可能覆盖不掉系统包。正确的.bashrc顺序是source /opt/ros/kinetic/setup.bash source ~/catkin_ws/devel/setup.bash4.2 创建catkin工作空间catkin是ROS1的构建系统你的所有自定义包都放在工作空间里编译。标准创建流程mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_makecatkin_make第一次运行会在src目录下生成CMakeLists.txt的软链接并在devel和build目录里建立构建环境。如果这一步报错八成是Python环境或cmake版本的问题先确认python --version是2.7Kinetic依赖Python2cmake版本不低于2.8.3。编译完成后devel目录下会有setup.bashsource它之后你的工作空间就激活了。可以用echo $ROS_PACKAGE_PATH检查如果输出里包含你的工作空间路径说明配置成功。4.3 树莓派3B编译时的内存优化技巧这是本篇最实用的经验之一。树莓派3B只有1GB内存catkin_make默认会并行编译多个文件内存瞬间打满然后系统卡死或者编译进程被杀。解决办法有两个。第一个是限制并行编译数量catkin_make -j2-j2表示同时只编译2个任务牺牲速度换稳定。如果还是卡降到-j1。第二个是增加swap空间。默认swap可能只有100MB编译大包时不够用。可以临时扩大sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile这样就有了2GB的swap缓冲。但要注意swap在SD卡上读写会拖慢速度也会增加SD卡磨损所以这是权宜之计不是长久方案。编译完成后可以sudo swapoff /swapfile关掉。我自己的习惯是小包直接-j4快速过遇到大包比如带大量模板的C包就切-j1加swap稳字当头。这个判断需要一点经验但踩过一两次OOM之后你自然就有感觉了。5. 串口、网络与多机通信的实战配置5.1 树莓派串口被系统占用的问题树莓派3B的硬件串口/dev/ttyAMA0默认被蓝牙模块占用了而很多机器人底层通信恰恰要用这个串口。如果你直接把下位机接到GPIO的TX/RX引脚上会发现收不到数据原因就在这里。解决办法是把蓝牙换到软件串口把硬件串口释放出来。编辑/boot/config.txt加上dtoverlaypi3-miniuart-bt enable_uart1然后在/boot/cmdline.txt里删掉consoleserial0,115200这段如果存在避免内核占用串口输出日志。重启后/dev/ttyAMA0就是可用的硬件串口了/dev/serial0会指向它。这个坑我踩过整整一个下午当时以为是接线问题反复检查杜邦线最后才发现是蓝牙抢占。记住树莓派3B的串口问题先查蓝牙占用再查接线。5.2 串口权限与udev规则普通用户默认没有串口读写权限每次都要sudo很烦。把用户加入dialout组sudo usermod -a -G dialout $USER重新登录后生效。但更稳妥的做法是写一条udev规则给特定设备固定权限和别名。比如你的下位机是CH340芯片可以创建/etc/udev/rules.d/99-robot.rulesKERNELttyUSB*, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, MODE:0666, SYMLINKrobot_base这样无论插拔多少次设备都会以/dev/robot_base这个固定名字出现代码里就不用写死ttyUSB0这种会变的路径。这个技巧在多设备场景下特别有用能避免昨天还好好的今天设备名变了这种玄学问题。5.3 多机通信的ROS_MASTER_URI配置当你用一台电脑做上位机、树莓派做下位机时需要配置多机通信。核心是两个环境变量ROS_MASTER_URI和ROS_IP。假设电脑IP是192.168.1.100树莓派IP是192.168.1.101roscore跑在电脑上。那么树莓派的~/.bashrc里加export ROS_MASTER_URIhttp://192.168.1.100:11311 export ROS_IP192.168.1.101电脑上则设置ROS_IP192.168.1.100。两边都要确保/etc/hosts里能互相解析主机名否则ROS的话题通信会因为主机名解析失败而断掉。实测中最容易出问题的是防火墙和IP变动。如果通信时断时续先ping一下对方再检查ROS_IP有没有设成127.0.0.1设成本地回环就只能在单机通信了。这个错误非常隐蔽因为roscore能启动但跨机话题就是收不到。6. 安装后的验证与常见故障排查6.1 用最小案例验证ROS是否真的跑通装完别急着上复杂项目先用官方的小海龟案例验证。开三个终端# 终端1 roscore # 终端2 rosrun turtlesim turtlesim_node # 终端3 rosrun turtlesim turtle_teleop_key如果能看到小海龟窗口并且用方向键能控制它移动说明ROS核心通信、图形显示、键盘输入这条链路全通了。这一步在树莓派3B上可能会有点卡因为图形渲染吃资源但只要能动就说明没问题。如果turtlesim_node启动报错说找不到显示检查是不是在无头模式下运行需要配置DISPLAY环境变量或者用VNC连上桌面。6.2 编译报错、依赖缺失、节点启动失败的排查链路故障排查我总结成一条链路按顺序走基本能定位问题。第一步看报错的第一行而不是最后一行。很多人习惯看最后的Error但真正的根因往往在开头比如某个头文件找不到后面一连串错误都是它的连锁反应。第二步确认依赖是否装全。用rosdep check 包名检查缺什么补什么。如果是自己写的包package.xml里的依赖声明要和实际include的头文件对应。第三步检查环境变量。echo $ROS_PACKAGE_PATH看工作空间有没有被包含rospack find 包名看能不能定位到包。定位不到就是环境没source对。第四步看节点日志。~/.ros/log/目录下有每次运行的详细日志比终端输出全得多。节点启动失败但终端没报错时去这里翻。故障现象最可能原因快速验证roscore起不来端口11311被占用lsof -i:11311话题收不到数据ROS_IP设错echo $ROS_IP串口无数据蓝牙占用或权限不足ls -l /dev/ttyAMA0编译OOM内存不足dmesg6.3 树莓派3B性能瓶颈的应对经验最后说点实在的。树莓派3B跑ROS性能瓶颈主要在三处CPU编译、内存容量、SD卡IO。应对策略分别是编译时限制并行度、运行时关掉不必要的节点、把日志和bag文件写到外接U盘而不是SD卡。我个人的经验是这块板子适合做轻量级节点——传感器数据采集、串口转发、简单控制逻辑都没问题。但如果你想在上面跑SLAM或者图像处理会非常吃力帧率低到没法用。这时候正确的做法是把重计算放到上位机树莓派只做数据采集和转发通过ROS的分布式通信把算力用在刀刃上。这个架构思路比单纯优化树莓派本身更有效。还有个小技巧把~/.ros/log的日志级别调低减少磁盘写入。默认的INFO级别在长时间运行时会产生大量日志拖慢SD卡。在launch文件里设置outputscreen并配合roscd清理旧日志能明显改善长期运行的稳定性。整套流程走下来从刷系统到跑通小海龟顺利的话一个下午能搞定遇到串口和网络问题可能要多花半天。但只要把上面这些坑提前避开树莓派3B加ROS Kinetic这套组合依然是目前性价比最高的机器人入门方案之一。

相关新闻

为AI对话加一层外部记忆:claude-mem的架构与实操复盘

为AI对话加一层外部记忆:claude-mem的架构与实操复盘

说实话,我一开始做 claude-mem 这个工具的动机特别朴素:每次用AI对话工具聊需求,开头说得很清楚的项目背景,聊到一半就被上下文窗口“挤”出去了,它真的会一本正经地问我之前已经确认过的问题。那种感觉就像你刚把文…

2026/10/12 12:43:55 阅读更多 →
嵌入式串口通信协议IMX头部8字节拆解:同步、长度、CRC与粘包处理

嵌入式串口通信协议IMX头部8字节拆解:同步、长度、CRC与粘包处理

做嵌入式串口通信的时间越长,我越意识到一个铁律:拿到任何一版协议文档,最先要啃透的永远是帧头。IMX头部就是这类帧头区域的核心,它决定了收发的双方能不能在同一张“地图”上对齐——数据从哪里开始、一帧到底有多长、这条消息是…

2026/10/12 12:43:55 阅读更多 →
葡萄叶病害检测数据集:VOC+YOLO双格式1609张开箱即用

葡萄叶病害检测数据集:VOC+YOLO双格式1609张开箱即用

简介:本资源是面向农业AI与计算机视觉初学者的葡萄叶片病害检测专用数据集,适用于目标检测模型训练与验证,特别适配YOLO系列及Pascal VOC兼容框架。数据集共1609张单叶高清图像,覆盖Black Measles、Black Rot、blight fungus和hea…

2026/10/12 12:43:55 阅读更多 →

最新新闻

website-rebuild-skill 源码化阶段:如何把逐字移植的机器产物重构成人能读的工程

website-rebuild-skill 源码化阶段:如何把逐字移植的机器产物重构成人能读的工程

【免费下载链接】website-rebuild-skill 复刻网站的 Agent Skill:抓只读镜像、从压缩代码逐行还原、自动比对验收。An agent skill that mirrors a website, rebuilds it from the minified code, and verifies the result with automated diffs. 项目地址&#xff…

2026/10/12 13:41:54 阅读更多 →
基于SpringBoot的大健康养老公寓管理系统:从毕设选题到答辩全攻略

基于SpringBoot的大健康养老公寓管理系统:从毕设选题到答辩全攻略

1. 为什么选“大健康养老公寓管理”这个题目每年到这个时间点,总有同学来找我聊毕业设计的事,问得最多的就是:有没有合适的题目推荐?要求还五花八门——好过审、工作量够、技术栈主流、最好还能润色到简历里。我通常会反问一句&am…

2026/10/12 13:41:54 阅读更多 →
CAD二次开发中点在多边形内的高精度实时判断方案

CAD二次开发中点在多边形内的高精度实时判断方案

1. 这不是数学题,是CAD里每天都在发生的“位置判断”实战在CAD二次开发的实际项目中,“点是否在多边形内”绝不是教科书里一个画个示意图就能打发的几何问题——它是某高校土木系BIM协同平台里构件自动归类的触发条件,是某工业设计公司电缆布…

2026/10/12 13:41:54 阅读更多 →
动态规划空间压缩实战:前缀和与后缀最大值求解两段不重叠子数组最大和

动态规划空间压缩实战:前缀和与后缀最大值求解两段不重叠子数组最大和

1. 从一道“数学考试”题看动态规划的空间压缩技巧“数学考试”这个标题乍一看像是讲备考策略,实际上它是一道经典的算法题,出现在某在线编程平台的每日一题栏目中。题目的核心是:给定一个长度为 n 的整数序列,要求选出两个不重叠…

2026/10/12 13:41:54 阅读更多 →
NGS-GNN:面向临床响应预测的图神经网络实战

NGS-GNN:面向临床响应预测的图神经网络实战

简介:本资源是一个面向生物信息学初学者与机器学习实践者的轻量级教学项目,聚焦于下一代测序(NGS)数据分析与Python建模的交叉实践。项目以Jupyter Notebook为核心载体,提供可复现的端到端分析流程,涵盖环境…

2026/10/12 13:41:54 阅读更多 →
C语言播放《下山》:从Beep到WAV的音频编程全解析

C语言播放《下山》:从Beep到WAV的音频编程全解析

前段时间在编程群里看到有人甩了个标题:「疯狂的往左」用 C 语言播放《下山》。一看名字就知道,这是典型的整活向练手题——不用图形界面,不用现成的音乐库,纯粹拿 C 语言的朴素能力让电脑把这首国风歌“唱”出来。我第一次见这种…

2026/10/12 13:40:52 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练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/11 14:36:54 阅读更多 →