news 2026/9/5 5:41:54

Jetson Orin Nano 2边缘AI部署实战:从TensorRT优化到实体机器人控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Jetson Orin Nano 2边缘AI部署实战:从TensorRT优化到实体机器人控制

1. 项目定位与核心需求拆解

1.1 为什么是Orin Nano 2:入门级边缘AI的市场空白

过去两年里,我经手过不少边缘AI项目,从工业质检到零售分析,再到机器人本体上的实时推理,踩过的坑比写过的代码还多。早期大家一窝蜂用树莓派加USB加速棒做原型验证,很快就会发现带宽和功耗双双拉胯;后来转向Jetson Nano,算力又卡在INT8时代的老架构上,跑个稍微像样点的YOLOv8s都费劲。真正让我觉得“入门级边缘AI终于有得玩了”的转折点,就是NVIDIA Jetson Orin Nano 2平台的全面铺开。

这颗芯片本质上是Orin NX的“青春版”,但请别被这个定位骗了。它保留了Ampere架构的Tensor Core,虽然CUDA核心数被砍到512个,但深度学习推理靠的是Tensor Core而不是纯CUDA吞吐,所以它在跑经过TensorRT优化的模型时,实际表现和上一代Xavier NX不是一个量级的。更关键的是,Orin Nano 2把内存带宽做到了68GB/s,对边缘端实时推理来说,带宽往往比峰值算力更重要。

我们团队当时选型不是拍脑袋。项目需求是:在20W功耗墙内,跑通一个多路视频流的姿态估计加物体识别管道,同时预留串口、GPIO、CAN总线给机器人底盘。当时市面上能打的选项只有Orin Nano 2和树莓派5加Hailo-8,但Hailo的软件工具链对OpenCV、ROS2、GStreamer的集成深度远不如JetPack。既然要落地实体系AI,而不是只做图像分类演示,CUDA生态这个护城河是绕不开的。

1.2 实体AI的落地瓶颈:从“能推理”到“能动起来”

实体AI和纯云端AI最大的区别在于,模型输出的置信度分数只是第一步,真正的挑战在于闭环控制。你的模型说“前方1.2米有一个障碍物”,接下来机械臂或底盘必须在几十毫秒内做出动作决策,再通过实时总线发出去。这个过程里,任何一个环节掉链子——比如推理时延抖动超过30ms,或者TensorRT序列化失败导致回到动态图模式——都会让整个系统计划失去意义。

Orin Nano 2在实体AI场景里给的方案是“多级异构缓冲”。CPU侧的ARM A78AE核心负责ROS2通信、运动学解算和控制指令合成,GPU侧的Tensor Core专门喂给推理,而DLA(Deep Learning Accelerator)则可以承担那些固定拓扑的、不需要动态shape的模型。这样分工下来,推理和控制的耦合度大大降低,我实测下来,一个双路CSI摄像头加一个激光雷达的输入管道,CPU占用率大概能稳定在45%以下,这在以前的Jetson Nano上是不可想象的。

但平台能力再强,适配不当也会被白白浪费。我这篇文章的核心目的,就是基于我们团队在Orin Nano 2上从裸板到整机跑通实体AI完整链路的全过程,把硬件选型、系统烧录、模型优化、时延预算、电源设计和常见坑位一次讲透。无论你是刚开始接触边缘AI的入门开发者,还是正在考虑从旧平台迁移的团队,这篇都值得先存再看。

2. 硬件平台深度认识与选型建议

2.1 模块型号与新接口布局避坑指南

Jetson Orin Nano 2在硬件层面有两个非常容易踩坑的细节,新手完全没有概念。第一个是开发套件的载板(Developer Kit Carrier Board)上那个M.2 Key M插槽,它同时支持NVMe SSD和M.2 WiFi模块,但默认的PCIe通道复用映射会让很多人在插了WiFi后又想加硬盘时发现通道冲突。你需要预先在设备树(Device Tree)里改掉PCIe的x4/x1分配策略,否则系统会随机出现设备丢失。

第二个是显示接口。开发套件的HDMI和DisplayPort是通过板载的DisplayPort to HDMI转换芯片输出的,这意味着如果你的显示器分辨率超过4K60,带宽会被转换芯片的规格卡住。我实测下来,4K120的显示器接上去只能跑到4K30,不是SoC算力不够,而是转换芯片限流了。如果你的项目需要高刷新率显示,比如可视化调试界面或者AR叠加显示,备一个USB-C转DP的有源线会更稳。

模块本身的散热设计算是让人放心的。默认的散热方案包含一个涡轮风扇加纯铜均热板,实测在25度室温、20W功耗模式下,满载推理半小时,芯片结温可以稳定在68度左右。但如果你跑的是15W模式,风扇的策略会自动调整,噪音会低很多,适合办公环境下的原型开发。千万别为了静音直接关掉风扇——Orin系列的DVFS(动态电压频率调节)很激进,一旦温度超过85度,CPU频率会直接从2.2GHz暴跌到600MHz,整机表现断崖式下跌。

2.2 与上一代Orin Nano的性能变迁对比

很多从Jetson Nano直接跳到Orin Nano 2的开发者,最大的感受就是“终于不用再盯着每秒多少帧的日志吊胆了”。这里我整理了一份实测对比数据,同样是YOLOv8m、TensorRT FP16精度、640x640输入、批量大小为1,跑在官方JetPack 6.0镜像上:

指标Jetson Nano(老款)Orin Nano 2(新款)提升幅度
峰值算力(FP16)0.47 TFLOPS8 TFLOPS约17倍
内存带宽25.6 GB/s68 GB/s约2.7倍
YOLOv8m推理时延约410 ms约22 ms约18.6倍
多路视频解码不支持支持8路1080p30 H.264/H.265
功耗(典型)5W~10W7W~25W上限提高

别看功耗上限在涨,实际能效比反而是大幅优化的。同样的YOLOv8s模型,老Nano跑1帧的耗电量是Orin Nano 2的大约6倍。也就是说,如果你做的是电池供电的移动机器人,用Orin Nano 2在同样电池容量下,能跑的推理量和续航时间都远超上一代。这也是为什么我们最终决定把这颗芯片放进机器人主控里,而不是继续用验证板。

3. 系统烧录与基础环境搭建

3.1 全新模块的初始烧录:从零到JetPack 6.0

如果你拿到的是开发套件,恭喜你,烧录流程比模块加自制载板的情况省心多了。官方Developer Kit只需要用USB-C线连到一台Ubuntu主机(或者Windows上跑虚拟机也行,但强烈建议用原生Ubuntu),下载NVIDIA SDK Manager,选择目标设备,它就会自动下载JetPack镜像并写入。整个过程大概20分钟,前提是你的网络稳定,因为镜像本体加依赖包下载量通常在10GB以上。

这里有个容易踩坑的点:SDK Manager烧录完成后,首次启动会停留在JetPack配置界面,需要你登录NVIDIA开发者账号。很多人以为这一步可以跳过,但实际上它决定后续能否直接使用NGC(NVIDIA GPU Cloud)上的预训练模型仓库以及一些额外的库。建议提前注册好账号,省得卡在这一步不知所措。

如果你用的是模块加第三方载板,那流程就复杂得多。你需要用USB Recovery Mode进入模块的恢复模式(需要按住模块上的Recovery按键并同时复位电源),然后在PC端用jetson-agx-orin-devkit.conf之类的配置脚本调用NVIDIA_L4T工具链烧写。核心命令大致是:

sudo ./tools/kernel_flash/l4t_initrd_flash.sh --external-device nvme0n1p1 \ -c tools/kernel_flash/ornano.conf \ jetson-orin-nano-devkit nvme0n1

这条命令会把根文件系统烧到NVMe SSD上,而非模块自带的eMMC。对跑实体AI的项目来说,这一步几乎是必须的——eMMC只有16GB(老版)或64GB(新版),装上JetPack再配置完环境就爆了。有条件的话,建议直接上512GB或者1TB的NVMe SSD,后续装ROS2、OpenCV、TensorRT缓存、数据集副本时才不会捉襟见肘。

3.2 驱动安装翻车现场与UVM模块冲突排查

在系统层面,最容易翻车的环节是NVIDIA驱动的安装。虽然JetPack自带驱动,但总有些场景需要你手动重装驱动,比如你在跑PyTorch的某些底层扩展时,可能会因为驱动版本太新或太旧导致CUDA上下文初始化失败。最常见的报错是nvidia-smi has failed because it couldn't communicate with the nvidia driver

这个报错在Orin平台上,十有八九是内核模块加载顺序混乱导致的“UVM已加载但设备映射失败”。注意,这不是X86平台那种“驱动版本不匹配”,而是JetPack的内核模块和你的根文件系统不在同一个/lib/modules/$(uname -r)/路径下。解决方式是先把驱动模块路径明确指定:

sudo depmod -a sudo modprobe nvidia sudo modprobe nvidia-uvm

如果modprobe nvidia-uvm报错说“module has been loaded in a different kernel version”,那你需要重新编译并安装JetPack底层的nvidia-kernel-common包,或者直接检查/etc/modprobe.d/里是否残留在X86平台编写过的blacklist-nvidia.conf,把blacklist nvidia-uvm那行注释掉。

另外要提醒的是,Orin平台不同于Desktop GPU,它的驱动是和L4T内核(Linux for Tegra)强绑定的,不要试图从NVIDIA官网下载桌面版的.run文件来安装。我在某个群里看到有人用NVIDIA-Linux-aarch64-550.100.run去强行装,结果把模块的Device Tree搞坏了,只能重新刷机。牢记:在Orin上装驱动,只认JetPack仓库里的dpkg包,不认.run安装包。

4. 边缘AI推理管道优化与实体场景落地

4.1 TensorRT模型优化:从ONNX到Engine的全流程实录

边缘AI部署的核心,是把训练好的PyTorch或TensorFlow模型转换成TensorRT的Engine文件。很多人以为这一步就是装个TensorRT然后调API,实际走下来,最常见的坑全集中在“动态shape”和“插件的选择”上。

以我们项目的姿态估计模型(基于HRNet变体)为例,训练框架是PyTorch,导出ONNX时如果同时导出了动态batch维度和动态分辨率维度,TensorRT的构建时间会指数级上升。实测下来,同样的模型,如果允许输入分辨率在[1x384x384, 1x640x640]内动态变化,构建时间需要45分钟;而固定分辨率为512x512后,构建时间压缩到6分钟,且推理时延还能再降10%左右。

所以我们的经验是:除非你的业务确确实实需要动态分辨率,否则在导出ONNX时就写死输入尺寸。边缘端推理的客户需求通常很集中,不像云端要兼容各种分辨率。写死输入尺寸,既省构建时间,又减少显存碎片,双赢。

另外,TensorRT构建Engine时要注意选择精度模式。Orin Nano 2的Tensor Core对FP16的加速效果非常明显,但并不是所有层都对FP16友好。比如常见的SiLU激活函数,在FP16模式下如果遇到负区间输入,精度损失会直接导致后续层输出偏差。这种情况建议在该层前后插入Identity节点并设置为FP32计算域,或者直接用TensorRT的SetLayerPrecision接口单独指定这一层精度。

import tensorrt as trt logger = trt.Logger(trt.Logger.WARNING) builder = trt.Builder(logger) network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser = trt.OnnxParser(network, logger) with open("pose_model.onnx", "rb") as f: parser.parse(f.read()) config = builder.create_builder_config() config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30) # 1GB workspace config.builder_optimization_level = 3 # 最高优化级别 # 固定输入尺寸 input_tensor = network.get_input(0) input_tensor.shape = [1, 3, 512, 512] # 混合精度策略:允许FP16,但保留关键层为FP32 config.set_flag(trt.BuilderFlag.FP16) for i in range(network.num_layers): layer = network.get_layer(i) if "SiLU" in layer.name or "Sigmoid" in layer.name: layer.precision = trt.float32 layer.set_output_type(0, trt.float32) engine = builder.build_engine(network, config)

构建完Engine后,记得做一次序列化保存,下次加载时直接用反序列化读取即可,不用重新构建。这里要留意一个坑:Engine文件和当前TensorRT版本、GPU架构强绑定,换模块或者升级JetPack后必须重新构建。不要试图把Orin Nano 2的Engine文件拷给NX或者AGX Orin用,必定报错。

4.2 多路视频流与GStreamer管道设计

实体AI系统经常会涉及多路摄像头输入。Orin Nano 2硬件上支持8路1080p30的解码,听着很爽,但如果你用OpenCV的VideoCapture直接拉8路流,CPU会直接爆掉。正确姿势是使用GStreamer作为底层管道,把硬件解码器(NVDEC)的作用发挥出来。

这里分享一段我们实测稳定的双路CSI摄像头加一路RTSP流采集方案:

gst-launch-1.0 \ nvarguscamerasrc sensor-id=0 ! \ video/x-raw(memory:NVMM), width=1280, height=720, format=NV12, framerate=30/1 ! \ nvvidconv ! \ video/x-raw(memory:NVMM), format=I420 ! \ nvv4l2h264enc bitrate=8000000 ! \ h264parse ! \ rtph264pay name=pay0 pt=96 config-interval=1

这段命令把CSI摄像头0的图像经过硬件编码后封装成RTSP流,可以推到局域网里的其他设备上做实时监控。核心是nvarguscamerasrcnvv4l2h264enc这两个插件,它们直接调用硬件ISP和编码器,CPU占用率几乎可以忽略不计。如果用普通的v4l2src加软件x264enc,8路流的CPU占用会直接冲到90%以上,推理任务基本就别想跑了。

在实体AI场景里,我通常会把图像采集和推理解耦,通过共享内存或者ZeroMQ把原始帧传给推理线程。这样即便推理偶尔出现时延抖动,采集端也能继续以30fps的频率运行,不会丢帧。如果你用ROS2,可以配合image_transportCompressedImage话题减少带宽占用,但会增加一点点CPU开销,需要平衡。

4.3 实体AI闭环控制案例:机械臂视觉抓取

讲一个完整的实体AI落地案例。我们做了一个桌面级机械臂分拣项目——识别不同颜色的乐高块并放到指定位置。听起来简单,但涉及到视觉识别、坐标标定、运动控制三者的紧密配合。

视觉部分,我们用Orin Nano 2上的CSI口接了一个全局俯视摄像头,跑YOLOv8s检测乐高块的位置和颜色,模型经过TensorRT优化后单帧推理约12ms。相比之前的方案——在PC上推理再通过局域网下发给机械臂,Orin Nano 2实在太多:本地推理意味着时延从“网络不确定性的几十毫秒”变成“确定性的12ms”,这让机械臂的抓取成功率从82%直接提升到了94%。

运动控制部分,我们用了Modbus RTU协议通过USB转RS485和机械臂通信,控制频率为20Hz,每个控制指令包含目标坐标和夹爪开合状态。这里的一个经验是:控制指令的发送线程必须用独立的高优先级任务,否则一旦推理线程突然拉满CPU,控制指令延误会直接导致机械臂抖动。

整条链路的时延预算如下:

环节时延备注
摄像头采集到内存约8ms取决于曝光时间和ISP处理
图像预处理(缩放、归一化)约3ms用Python的cv2或CUDA加速
YOLOv8s推理约12msTensorRT FP16
后处理(NMS、坐标映射)约5msNumPy 向量化
运动指令下发约2ms通过Modbus总线的周期
总时延约30ms含系统调度开销

30ms的总时延对于机械臂抓取场景是绰绰有余的。而老平台的时延通常在150ms以上,碰到网络波动还会更高,分拣任务经常出现“眼看抓到了,但收盘时机械臂已经离开”的尴尬局面。这就是为什么Orin Nano 2的确定性时延表现,是实体AI落地的关键加分项。

5. 常见问题与排查技巧实录

5.1 系统启动与电源稳定性

实体AI项目里最容易被忽视的是电源设计。Orin Nano 2在25W模式下的瞬态功耗可以跑到40W以上,如果电源模块的响应速度不够快,电压跌落会直接触发SoC的欠压保护,表现为系统随机重启、USB设备掉线、或者推理线程莫名崩溃。

我们的做法是:外接12V电源时,在输入端口并联一个470μF的电解电容加一个100μF的陶瓷电容,用来吸收瞬态电流尖峰。这个改动看起来低端,但实测下来系统稳定性能提升一个档次——以前是几小时崩一次,现在是连续运行一周零重启。

另外一个大家经常忽略的问题是地环路干扰。如果同时给Orin开发板供电和给电机驱动板供电,务必确保两边的GND在单点连接,否则会产生地环路电流,轻则影响USB串口通信稳定性,重则烧毁设备。我们为实体AI机器人设计了统一的电源树,从电池到DC-DC再到SoC电源全部单点接地,这个设计习惯值得大家参考。

5.2 推理时延抖动与RTSP卡顿的软硬件联动排查

有阵子我们的系统总会在运行半小时后出现推理时延从22ms涨到300ms的怪问题。CPU占用率并不高,GPU也没有满载,但就是莫名掉速。排查了大半天发现,问题出在散热上——风扇策略的设置太保守,导致SoC模块的温度缓慢爬升到92度后触发了温控降频,但降频后的性能又恢复了温度平衡,然后频率又被抬升,如此反复造成时延抖动。

解决方式有三种:调整风扇策略(在/etc/nvpower/nvfancontrol.conf中修改TRIGGER_TEMPERATURE),或者干脆用固定中速风扇保持恒定风量,再或者把功耗模式调低一个档位(比如从25W降到20W),牺牲一点峰值性能换取完全稳定的时延保证。我的建议是,对时延敏感的应用直接选第三种方案,把功耗固定在20W,系统运行在最平缓的DVFS曲线上,时延的标准差能压缩到2ms以内。

如果你遇到RTSP视频流卡顿,先别急着怀疑网络带宽。我们的经验是先检查NVDEC的解码器利用率,tegrastats命令可以直接看:

sudo tegrastats

关注DEC字段,如果解码器的利用率长期超过80%,说明你的视频路数已经逼近硬件上限,这时候需要降低分辨率、码率或帧率。否则即使网络带宽够,解码也跟不上。另外,可以开启GStreamer的sync=true来强制同步帧间隔,视频卡顿的观感会好很多。

还有一些常见的场景问题,我整理成一个速查表:

常见问题可能原因推荐排查步骤
推理时延偶发跳变温控降频或内存带宽竞争查看tegrastats里的温度与CPU/GPU频率是否波动
USB摄像头无法识别供电不足或载板USB过滤设计问题用带外部供电的USB HUB,避免多设备共用口
串口数据乱码波特率错误或电平转换芯片质量问题确认波特率一致,用示波器测信号波形
TensorRT引擎加载失败Engine版本与当前JetPack不匹配trtexec --loadEngine测试,必要时重建Engine
ROS2话题延迟高QOS策略配置不当将QoS设为BEST_EFFORT配合KEEP_LAST(1),适合图像流
机械臂运动轨迹偏移相机标定参数不准确或畸变校正未开启用棋盘格重新标定内外参,加上畸变系数

5.3 板级供电策略与风扇噪音控制的平衡

最后再专门聊一下功耗和散热这对“冤家”。我见过太多开发者,从X86平台迁过来时习惯性把所有性能拉满,结果发现Orin Nano 2在25W模式下的发热量真的不小。如果你把设备放在封闭的金属壳里,温度会迅速飙升到100度以上,系统直接进入热保护。反过来,如果你过于顾虑发热而一直跑7W模式,那算力优势就全浪费了。

我的建议是分成两级策略。第一级:在软件层用nvpmodel -m 1把模块切换到20W模式,并在/etc/nvpower/nvfancontrol.conf里设定风扇在55度时开始加速,75度时全速转。第二级:在硬件层优化散热途径,除了散热风扇,还可以在模块底部贴一块导热硅脂到金属外壳,利用外壳作为散热面。一个简单的铜片加几个导热垫,实测结温能再降10度左右,噪音也不过是低了一个档位而已。

如果项目允许,优先选用半导体制冷片配合主动散热来为Orin Nano 2降温。我们有个产品因为要放在密闭防水箱体内,风扇进风口会积水汽,后来改成了用铝制外壳作为被动散热体,在室内环境跑35W上限也不虚。当然这种方案就别追求什么极致便携了,工程上永远有取舍。

5.4 参考代码库与持续集成建议

对正在从零搭建Orin Nano 2项目的团队,一个建议是把环境搭建过程做成脚本化、容器化。JetPack 6.0原生支持Docker运行CUDA加速容器,你可以基于nvidia/cuda:12.2.2-runtime-ubuntu20.04镜像构建自己的推理环境。但注意容器里的GPU访问需要挂载设备节点,最关键的是把/dev/nvidia0/dev/nvidia-uvm/dev/nvidiactl这几个设备都暴露进容器,否则即使能启动容器,CUDA运行时也会找不到设备。

docker run -it --runtime nvidia \ --device /dev/nvidia0:/dev/nvidia0 \ --device /dev/nvidia-uvm:/dev/nvidia-uvm \ --device /dev/nvidiactl:/dev/nvidiactl \ -v /tmp/argus_socket:/tmp/argus_socket \ -v /usr/lib/aarch64-linux-gnu/tegra:/usr/lib/aarch64-linux-gnu/tegra \ -v /usr/lib/aarch64-linux-gnu/tegra-egl:/usr/lib/aarch64-linux-gnu/tegra-egl \ -v ~/tensorrt_engines:/models \ my_edge_ai_image:latest

为什么建议容器化?因为团队协作时,每个人在自己电脑上搭出来的环境千奇百怪,通过Docker镜像可以把依赖锁死在同一版本,避免“在我这能跑,到你那不行”的尴尬情况。我们用GitLab CI做持续集成,每次提交代码后在Orin上跑一遍回归推理测试,确保模型精度不掉、时延不超预算,这套流程实测能省下大量联调时间。

6. 一些个人心得

我记得第一次把Orin Nano 2接到机械臂上跑通视觉抓取闭环时,办公室的同事都围过来看——一个不到手掌大的板子,实时识别并分拣乐高块,整个过程干脆利落,没有延迟卡顿,和之前用笔记本连着路由器折腾半天的对比实在太强烈了。那一刻我才真正感受到了“入门级边缘AI平台”的意义:不是给你一个能跑benchmark的玩具,而是让你能用低成本、低功耗、小体积的方案去逼近真实产品。

在我看来,硬件形态的收敛正在改变实体AI的开发方式。基于Orin Nano 2,你能在原型验证阶段就把能耗、散热、体积、时延这些真实产品的约束全部考虑进去,而不是等到产品化阶段才痛苦地做减法。如果你也在评估新一代边缘AI平台,我建议直接入手Orin Nano 2开发套件,先把官方JetPack和TensorRT的demo跑通,再逐步加你自己的模型和传感器。这个平台的学习曲线没有想象中陡峭,值得花一个周末去摸透。后面有想进一步讨论部署细节的朋友,评论区见,我来陪聊。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 5:41:04

App Store 4.3拒审全解析:从审核逻辑到产品差异化实战指南

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

作者头像 李华
网站建设 2026/9/5 5:40:05

RK3588边缘AI视觉零拷贝跨进程通信:DMA-BUF实战指南

1. 为什么边缘AI视觉一定绕不开跨进程通信先说结论&#xff1a;在RK3588上做边缘AI视觉&#xff0c;如果还没把“零拷贝跨进程通信”纳入架构设计&#xff0c;那你大概率已经或者即将被性能问题按在地上摩擦。我去年接手了一个基于RK3588的智能视频分析盒子&#xff0c;硬件资源…

作者头像 李华
网站建设 2026/9/5 5:39:42

多模态AI心理分析:情感识别与行为模式的技术实现

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

作者头像 李华
网站建设 2026/9/5 5:39:35

从编码器到译码器:数字电路信息压缩与工程实践全解析

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

作者头像 李华
网站建设 2026/9/5 5:39:28

AI绘画进阶:利用Stable Diffusion打造角色一致性工作流

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

作者头像 李华