前言
原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正交流。
文章如有更新请访问 DFRobot 社区及 cnblogs 博客园,前者内容较全,后者排版及阅读体验更佳。
思兼的学用Klipper系列文章合集
一晃才发现小半年没有发表新文章了,仿佛还在上个月。
这是一篇借助豆包,基于我的大纲与测试结果自动生成并经过我修改的文章,不知道效果如何。其实我本地很多存货,苦于没有时间精力整理成文,借助 AI 可能会是一个很好的方法。同时部分程序代码使用 AI 进行辅助,至于感受会在文末总结。
在 3D 打印的领域里,Klipper 固件凭借出色的性能,深受广大爱好者青睐。早期基于电视盒子打造的 Klipper 上位机,常见配置是 1G 内存+ 8G eMMC 存储。随着模型复杂度增加,上传的模型切片文件越来越大、数量越来越多,再加上延时摄影临时抓取的大量图片以及渲染生成的视频,这点存储空间就显得捉襟见肘了。
之前我写过文章,包括跟着思兼学习Klipper(10)使能Klipper从U盘读取Gcode并打印 以及 跟着思兼学习Klipper(23) 玩一玩必趣 BTT Pi 上位机,分别介绍热插拔自动挂载 U 盘或 SD 卡实现脱机打印,以及利用Alist+Rclone+网盘给上位机扩容。今天我们要更进一步,探索新的更完善的扩容方案。
软件环境:
- DietPi for x86_64 Legacy (based on Debian Bookworm)
- mergerfs v2.40.2
硬件环境:
- KlipperBoxPro 上位机
- 4GB microSD 和 64GB U盘,以下简称移动存储
本文涉及的内容:
- mergerfs 实现上位机热插拔移动存储实现脱机打印和自动扩容
- udev 规则故障排查
- AI 辅助文章写作的感受
- AI 辅助编程的感受
一、现状与目的
更完善的热插拔脱机打印
- 也就是马琳(Marlin)时代,在电脑上将切好的模型文件拷贝到 SD 卡或 U 盘后,插到打印机上进行打印。
- 随着 Klipper 的出现,网络打印流程更加方便。且特殊情况可以通过上位机创建热点来实现局域网打印。
- 由于 Klipper 不支持自动挂载磁盘,所以要额外的设置/程序实现自动挂载移动存储到 $HOME/printer_data/gcodes 目录下,从而被 Klipper 访问
- 考虑到 U 盘稳定性欠佳,接口松动可能导致打印失败,目前一种策略是在识别到移动存储插入后,会把其中的 gcode 文件复制一份到宿主机 gcodes 文件夹


长期挂载作为系统扩容磁盘
- 除了热插拔脱机打印功能之外,我认为更重要的是针对小存储上位机如电视盒子/ WiFi 棒子的扩容功能
- 把诸如 Gcodes 和延时摄影视频,或者其他文件存储到移动存储设备上,从而避免主磁盘空间满了
- 通过给移动存储创建特定标签,从而只把指定设备挂载为扩容盘。此处为
KBOX_EXT_SD/KBOX_EXT_U1
二、目前方案的缺点
这次的方案既支持脱机打印,又支持自动扩容。相比直接用 udev + mount 或者 fstab 挂载,优势明显:
规避系统启动风险:fstab 挂载一旦配置有误,比如设备路径写错、文件系统类型指定错误,极有可能导致系统启动失败。而 mergerfs 挂载能有效避免这类问题,确保系统顺利启动。
灵活存储运用:既能实现移动存储设备即插即打印,方便快捷地开启打印任务;又能常规插在上位机上作为扩容存储设备,不管是存放更大的 swapfile 来优化系统运行,还是存储延时摄影素材、大量的 gcode 文件,都不在话下。
解决目录显示问题:普通 mount 操作遇到同名目录时,会隐藏原目录,导致里面的文件无法访问。mergerfs 则不会出现这种状况,所有文件和目录都能正常显示,方便用户管理文件。
便捷切片软件上传:以往切片软件上传文件,常挂载到 gcodes 子目录,之后还得手动移动文件到合适位置。现在新方案支持切片软件直接上传到用于扩容的移动存储目录,大大简化了流程,提高了工作效率。
降低板载存储损耗:板载 eMMC 存储更换不便,且频繁读写易磨损。新方案把数据存储任务转移到可热插拔的移动存储设备,如 sd 卡。sd 卡用完可轻松更换,有效减少 eMMC 的磨损,延长其使用寿命。
接下来,我们来看看具体实现步骤。
三、结构设计

3.1 移动存储初始化
主要目的是选择合适的文件系统,对扫描到的移动存储设备格式化,设置分区标签为 KBOX_EXT_SD/KBOX_EXT_U1 等,方便后续正确挂载,并忽视其他存储设备。
3.1.1 文件系统选择
因为使用 microSD 或 U 盘这种闪存设备,且只存储简单文件无高级特性需求,考虑到 Windows/Linux 系统兼容性,存储寿命等因素,这里推荐如果需要 Windows 下也可以访问,推荐 exFAT 文件系统,否则可以尝试 f2fs 文件系统。其他如 ext4、btrfs 等也可以选择。
3.1.2 上位机安装必备软件包
# 安装 exFAT 或 f2fs 文件系统支持包
sudo apt install exfatprogs f2fs-tools util-linux attr
3.1.3 移动存储设备初始化脚本
使用步骤:
- 将待格式化的磁盘插入上位机
- 在上位机 ssh 终端中输入
sudo bash prepare_storage.sh
对设备进行初始化,根据提示选择正确的设备,如果不确定,可以在插拔移动存储前后,在终端输入 lsblk,对比后确认。
主要功能:
- 自动扫描并列出所有可用磁盘,排除根目录所在磁盘,避免误格式化
- 显示扫描到的移动存储,供用户选择【注意:磁盘会被清空,请务必选择正确的磁盘】
- 允许用户选择 exFAT 还是 f2fs 文件系统。
- 根据设备是 SD 卡还是 U 盘设置不同的分区标签
- 在新分区上创建 gcodes 和其他目录
#!/bin/bash
# '''
# Author: sjqlwy sjqlwy@yeah.net
# Date: 2025年4月13日
# Description:初始化存储设备用于系统扩容以及脱机打印
# '''
# 获取根目录所在设备
root_device=$(df / | tail -1 | awk '{print $1}' | sed 's/[0-9]*$//')
# 扫描可用的 SD 卡和 U 盘
devices=()
sizes=()
for device in /sys/block/*; do
device_name=$(basename $device)
if [[ $device_name == "mmcblk"* || $device_name == "sd"* ]]; then
device_path="/dev/$device_name"
if [ "$device_path" != "$root_device" ]; then
devices+=("$device_path")
size=$(blockdev --getsize64 "$device_path")
# 将大小转换为GB并保留1位小数
size_gb=$(printf "%.1f" $(echo "scale=1; $size / 1024 / 1024 / 1024" | bc))
sizes+=("$size_gb GB")
fi
fi
done
# 显示可用设备供用户选择
if [ ${#devices[@]} -eq 0 ]; then
echo "未找到可用的 SD 卡或 U 盘。"
exit 1
fi
echo "可用的设备有:"
for i in "${!devices[@]}"; do
echo "$((i + 1)). ${devices[$i]} (${sizes[$i]})"
done
# 获取用户选择
read -p "请输入你要选择的设备编号 (1 - ${#devices[@]}): " choice
if ! [[ $choice =~ ^[0-9]+$ ]] || [ $choice -lt 1 ] || [ $choice -gt ${#devices[@]} ]; then
echo "无效的选择。"
exit 1
fi
selected_device=${devices[$((choice - 1))]}
# 卸载设备上的所有分区
for partition in $(lsblk -n -o NAME $selected_device | grep -E '^[^[:space:]]+[0-9]+$'); do
umount "/dev/$partition" 2>/dev/null
done
# 删除原有分区表
parted -s "$selected_device" mklabel gpt
if [ $? -ne 0 ]; then
echo "删除原有分区表失败,请检查设备状态。"
exit 1
fi
# 创建新分区
parted -s "$selected_device" mkpart primary 0% 100%
if [ $? -ne 0 ]; then
echo "创建新分区失败,请检查设备状态。"
exit 1
fi
# 等待内核识别新分区
sleep 2
# 通知内核重新读取分区表
partprobe "$selected_device"
# 获取新分区的设备路径
if [[ $selected_device == *"mmcblk"* ]]; then
new_partition="${selected_device}p1"
else
new_partition="${selected_device}1"
fi
# 检查新分区是否存在
if [ ! -b "$new_partition" ]; then
echo "新分区 $new_partition 未被识别,请检查设备状态。"
exit 1
fi
# 生成合适的 LABEL
if [[ $selected_device == *"mmcblk"* ]]; then
label="KBOX_EXT_SD"
else
existing_labels=$(lsblk -o LABEL | grep '^KBOX_EXT_U')
max_num=0
for existing_label in $existing_labels; do
num=$(echo $existing_label | grep -oE '[0-9]+$' | sed 's/^0*//')
if [ -n "$num" ] && [ $num -gt $max_num ]; then
max_num=$num
fi
done
new_num=$((max_num + 1))
label="KBOX_EXT_U${new_num}"
fi
# 让用户选择文件系统格式
echo "请选择文件系统格式:"
echo "1. exfat(双系统访问,推荐)"
echo "2. f2fs"
read -p "请输入对应的数字 (1 - 2): " fs_choice
if [ "$fs_choice" != "1" ] && [ "$fs_choice" != "2" ]; then
echo "无效的选择,请输入 1 或 2。"
exit 1
fi
if [ "$fs_choice" == "1" ]; then
fs_type="exfat"
mkfs.exfat -n "$label" "$new_partition"
# 给 exfat 分区添加 msftdata 标签
partition_number=$(echo "$new_partition" | grep -oE '[0-9]+$')
parted -s "$selected_device" set "$partition_number" msftdata on
else
fs_type="f2fs"
mkfs.f2fs -l "$label" "$new_partition"
fi
if [ $? -ne 0 ]; then
echo "格式化新分区为 $fs_type 格式失败,请检查设备状态。"
exit 1
fi
# 修改 mount_point 为和 label 相同的格式
mount_point="/mnt/$label"
mkdir -p "$mount_point"
mount "$new_partition" "$mount_point"
if [ $? -ne 0 ]; then
echo "挂载新分区 $new_partition 失败,请检查设备状态。"
exit 1
fi
# 获取当前 sudo 执行用户
user=$(logname)
# 创建目录
mkdir -p "$mount_point/gcodes"
mkdir -p "$mount_point/timelapse"
# 根据文件系统格式决定是否修改目录所有者
if [ "$fs_type" == "f2fs" ]; then
chown -R "$user" "$mount_point/gcodes" "$mount_point/timelapse"
fi
# 卸载新分区
umount "$mount_point"
if [ $? -ne 0 ]; then
echo "卸载新分区 $new_partition 失败,请手动卸载。"
fi
echo "设备 $selected_device 已成功删除原有分区,创建了 $fs_type 分区,标签为 $label,并创建了 gcodes 和 timelapse 目录。"
注意:
- 必须排除根目录所在磁盘避免误选择
- 增加显示磁盘大小避免误选择
- 一般 mSD 槽只有一个,U 盘可以有多个,所以预留了相关处理
- exFAT 分区需要添加 msftdata 标签,否则在 Windows 下是隐藏分区不可见
- 创建 f2fs 分区后,需要将 gcodes 目录所有者转到当前非 root 账户来获得读写权限
- 由于 exFAT 不支持复杂权限管理,所以无法修改目录所有者,采用 mount 挂载的时候指定 UID GID 来实现。
- 对于 exFAT 这种非 POSIX 标准文件系统,df -i 显示 inode 数为 0
- 注意 exFAT 的标签长度有限制,所以这里设置为
KBOX_EXT_Ux
而不是 KBOX_EXT_USBx
- 考虑到脱机打印,需要在 Windows 和 Linux 下都能访问移动存储,这里推荐 exFAT 文件系统
- 如果仅做扩容盘使用,可以选择 f2fs 文件系统
- 关于文件系统的兼容性问题,可以移步 https://trapexit.github.io/mergerfs/faq/compatibility_and_integration/
至此我们获得了一个标签为 KBOXEXT* 的移动存储,并可以在 Windows 下访问 (exFAT)。
3.2 上位机设置
3.2.1 安装必要软件包:
# 安装 mergerfs,此处使用了镜像源,且下载 Klipper Pro 系列上位机所使用的 x86_64(amd64) 架构软件包
wget https://cors.isteed.cc/https://github.com/trapexit/mergerfs/releases/download/2.40.2/mergerfs_2.40.2.debian-bookworm_amd64.deb
sudo dpkg -i mergerfs*.deb
# 创建目录 local_gcodes 用于存放从原 ~/printer_data/gcodes 目录迁移来的模型切片文件
cd && mkdir ~/printer_data/local_gcodes
mv ~/printer_data/gcodes/* ~/printer_data/local_gcodes/
注意:
- 由于系统自带的版本老旧(2.33.5),我们总是推荐从其项目主页下载手动安装最新版,以获得最新的特性与更好的兼容性。
- mount 后
~/printer_data/local_gcodes
目录中的文件不可见,所以我们提前移出
3.2.2 创建 udev 规则实现自动挂载
既往使用直接将移动存储设备挂载到 ~/printer_data/local_gcodes
子目录下,存在诸多不便,所以本次使用 /mnt/目录下,然后使用 mergerfs 整合到虚拟目录。udev 规则如同智能管家,能识别标签为 KBOX_EXT_SD/USBx 设备插入,并按规则自动挂载到指定的 /mnt/[LABEL] 目录。在 /etc/udev/rules.d/ 目录创建新规则文件,文件名可自定义,建议遵循规范便于管理,如创建名为 99-kboxext-mount.rules 的文件(数字表示优先级,越小越高,这里用 99)。
# 创建一个脚本,查找根目录所在磁盘用于排除,且输出符合 udev 规则。key:vaule
tee $HOME/kbox_scripts/get_rootfs.sh > /dev/null << 'EOF'
#!/bin/bash
device=$(/bin/findmnt -n -o SOURCE /)
echo "root_device=$device"
EOF
# 创建自动挂载规则,我们仍然参考 homeassistant 的脚本
# 注意这里使用 pi 用户
sudo tee /etc/udev/rules.d/99-kboxext-mount.rules > /dev/null << 'EOF'
# Get the root device
IMPORT{program}="/bin/bash /home/pi/get_rootfs.sh"
ENV{root_device}="%E{root_device}"
# Import the partition info into the environment variables
IMPORT{program}="/usr/sbin/blkid -o udev -p %N"
# Exit if partition is not a filesystem
ENV{ID_FS_USAGE}!="filesystem", GOTO="abort_rule"
# Exit if the label doesn't start with KBOX_EXT_
ENV{ID_FS_LABEL}!="KBOX_EXT_*", GOTO="abort_rule"
# Exit if it's the root device
ENV{DEVNAME}=="%E{root_device}", GOTO="abort_rule"
# Determine the mount point using the label
ENV{mount_point}="/mnt/%E{ID_FS_LABEL}"
# General mount options
ACTION=="add", ENV{mount_options}="relatime,sync,uid=pi,gid=pi"
# Filesystem-specific mount options
# ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="{mount_options},utf8,gid=100,umask=002"
ACTION=="add", ENV{ID_FS_TYPE}=="f2fs", ENV{mount_options}="$env{mount_options}"
ACTION=="add", ENV{ID_FS_TYPE}=="exfat", ENV{mount_options}="$env{mount_options},utf8"
# Create the mount point directory if it doesn't exist and mount the device
ACTION=="add", RUN{program}+="/usr/bin/mkdir -p %E{mount_point}", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=no --collect -o %E{mount_options} $devnode %E{mount_point}"
# Umount the device on 'remove' action (a.k.a unplug or eject the USB drive)
ACTION=="remove", RUN{program}+="/usr/bin/systemd-umount %E{mount_point}"
# Exit
LABEL="abort_rule"
EOF
# 增加可执行权限,并设置生效
sudo chmod +x /etc/udev/rules.d/80-kboxext-mount.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# sudo systemctl restart udev
注意:
- 这里统一使用 pi 账户挂载,使得上传 gcode 时有正确的读写权限
- 这里创建一个独立的脚本,用于获得符合 udev 规则的输出变量
- 如何写 udev 规则,之前有文章介绍过
- 不同系统 udev 规则文件位置和格式可能有差异,需根据实际操作系统版本和 udev 版本调整,遇到问题可查阅官方文档或在技术论坛求助。
sudo udevadm test $(udevadm info -q path -n /dev/mmcblk0p1)
是一个 很重要的故障排查命令
至此,我们可以实现插入移动存储设备后,系统自动挂载到 /mnt/KBOXEXT* 目录下。

- 预处理移动设备
- 在moonraker之前启动mergerfs挂载, systemd service
- 识别到KBOX_EXT_开头的设备则自动挂载到/mnt udev
3.2.3 创建 mergerfs 服务实现灵活扩容
创建 mergerfs 服务系统来实现系统启动时自动创建虚拟目录,且在 moonraker 服务之前启动,以便能正确读取 gcodes 目录。
参考 mergerfs 官网并做了一些修改。
cat << _EOF_ > /tmp/mergerfs-klipper.service
[Unit]
Description = MergerFS Service for Klipper Hot-Swap Expansion
After = local-fs.target
Before = moonraker.service
[Service]
Type=simple
KillMode=none
ExecStart=$(which mergerfs) \
-f \
-o cache.files=auto-full \
-o category.create=epff \
-o func.getattr=newest \
-o dropcacheonclose=true \
/mnt/KBOX_EXT_SD/gcodes=RW,100M:/mnt/KBOX_EXT_U1/gcodes=RW,100M:$HOME/local_gcodes=RW,200M \
$HOME/printer_data/gcodes
ExecStop=$(which fusermount) -uz $HOME/printer_data/gcodes
Restart=on-failure
[Install]
WantedBy = multi-user.target
_EOF_
sudo mv /tmp/mergerfs-klipper.service /lib/systemd/system/mergerfs-klipper.service
sudo systemctl enable --now mergerfs-klipper.service
注意:
local-fs.target
的核心用途是确保在系统启动期间,所有本地文件系统(像根文件系统、/home
、/var
等分区)都能正确挂载。在达到这个目标状态之后,系统才会继续启动其他依赖于本地文件系统的服务。
- 注意需要
-f
参数
- 注意这里的选项,为了保证文件完整性,启用了缓存
- mergerfs 使用多种策略和选项控制优先写入哪个目录,这里选择的策略为
epff
,即如果存在目标文件夹则优先写入,否则按由左至右首次发现的<u>可用</u>目录写入。
- mergerfs 默认只会向剩余可用空间大于 4G 的目录写入文件,由于我测试用的 mSD 卡是 4G 的(由于 1000/1024 实际不足4G,所以总不会写入),需要增加额外参数
- 即使不存在可移动存储,mergerfs 仍然可可以正确挂载
- local_gcodes 位于板载存储,总是可用,但是至少留有 200MB
四、拓展内容
4.1 写入策略问题
存储设备写入策略复杂,优先写入哪个设备由策略、RW/RO/NC 挂载、保留的最少空间等因素决定。我们希望有 sd 卡插入时优先写入 sd 卡,但默认最小保留空间为 4G,若磁盘所在文件系统可用空间少于 4G,系统就不会往该磁盘写入数据。我测试时用的 4G sd 卡,格式化后可用空间不足 4G,导致系统一直不往 sd 卡写入,这个问题排查了很久。另外,写入策略还有先发现先写入的特点,即先挂载的节点优先写入。解决办法一是更换容量更大的 sd 卡,确保格式化后可用空间大于 4G;二是深入了解系统存储管理机制,根据实际情况调整写入策略相关设置。例如,可通过修改 mergerfs 的配置文件,调整最小保留空间等参数,但这需要一定的技术基础,操作前建议备份相关配置文件,以防设置错误导致系统异常。
4.2 通过 runtime 接口调试
mergerfs 的日志信息相当于没有,需要参考官方文档:https://trapexit.github.io/mergerfs/runtime_interfaces/ 使用运行时接口
sudo apt-get install attr
sudo mergerfs -f -o cache.files=off,func.getattr=newest,dropcacheonclose=false,category.create=all /mnt/KBOX_EXT/gcodes:/home/pi/local_gcodes=RO /home/pi/printer_data/gcodes
getfattr -n user.mergerfs.category.create /home/pi/printer_data/gcodes/.mergerfs
# 创建文件
sudo mergerfs -f -o cache.files=off,func.getattr=newest,dropcacheonclose=false,category.create=all /mnt/KBOX_EXT/gcodes=RW:/home/pi/local_gcodes=RO /home/pi/printer_data/gcodes
touch /home/pi/printer_data/gcodes/new-file
getfattr -n user.mergerfs.allpaths /home/pi/printer_data/gcodes/new-file
# 报错 read-only fs
# 显示所有值
getfattr -d /home/pi/printer_data/gcodes/.mergerfs
4.3 关于cache.files
https://trapexit.github.io/mergerfs/faq/technical_behavior_and_limitations/#i-notice-massive-slowdowns-of-writes-when-enabling-cachefiles
4.4 支持参数化挂载多个目录
目前仅以 gcodes 目录演示,计划增加 timelaspe 目录,以及其他可能目录。
4.5 UDEV 规则故障排查
当 udev
规则未生效时,可以按照以下步骤进行排查:
4.5.1 规则文件语法检查
- 检查规则文件路径:确保规则文件存放在
/etc/udev/rules.d/
目录下,且文件名以 .rules
结尾,通常文件名以数字开头(如 80-kboxext-mount.rules
),数字表示规则执行的优先级。
- 检查语法错误:
udev
规则文件使用特定的语法,任何语法错误都可能导致规则不生效。可以使用 udevadm test
命令来测试规则文件的语法。例如,对于规则文件 80-kboxext-mount.rules
,可以使用以下命令:
sudo udevadm test $(udevadm info -q path -n /dev/mmcblk0p1)
将 /dev/mmcblk0p1
替换为你要测试的实际设备。如果规则文件存在语法错误,该命令会输出相应的错误信息。
4.5.2 设备属性检查
- 重新加载规则:有时候规则文件修改后,
udev
可能没有及时加载新规则。可以使用以下命令重新加载规则:
sudo udevadm control --reload-rules
- 触发规则:重新加载规则后,需要触发规则以使其生效。可以使用
udevadm trigger
命令触发设备的添加或移除事件。例如,对于设备 /dev/mmcblk0p1
,可以使用以下命令触发添加事件:
sudo udevadm trigger --verbose --action=add --sysname-match=/dev/mmcblk0p1
sudo udevadm info -q path -n /dev/mmcblk0p1
sudo udevadm info -q env -n /dev/mmcblk0p1
4.5.3 设备属性检查
- 查看设备属性:使用
udevadm info
命令查看设备的属性,确保规则中使用的属性(如 ID_FS_LABEL
、ID_FS_TYPE
等)与实际设备的属性一致。例如,查看 /dev/mmcblk0p1
的设备属性:
udevadm info --attribute-walk --name=/dev/mmcblk0p1
该命令会输出设备的详细属性信息,检查规则中使用的属性是否正确。
- 检查设备路径和类型:确保规则中对设备路径和类型的过滤条件符合实际设备。例如,如果规则中使用了
KERNEL
或 ENV{ID_PATH}
进行过滤,需要检查设备的内核名称和路径是否满足条件。
4.5.4 权限和依赖检查
- 检查外部脚本权限:如果规则中使用了外部脚本(如
RUN
指令调用的脚本),确保脚本具有可执行权限。可以使用 chmod
命令添加执行权限,例如:
chmod +x /path/to/your/script.sh
- 检查依赖项:确保规则中使用的命令和工具(如
blkid
、systemd-mount
等)已经正确安装,并且在 udev
运行环境中可用。
4.5.5 日志和调试信息查看
- 查看系统日志:
udev
的相关信息通常会记录在系统日志中,可以使用 journalctl
命令查看系统日志,查找与 udev
相关的错误信息。例如:
sudo journalctl -u systemd-udevd.service
- 添加调试信息:在规则文件中添加调试信息,使用
RUN
指令将调试信息输出到日志文件中。例如,在规则中添加以下内容:
ACTION=="add", RUN{program}+="/bin/echo 'Device added: %E{DEVNAME}' >> /var/log/udev_debug.log"
这样,当设备添加事件触发时,会将设备名称记录到 /var/log/udev_debug.log
文件中,方便查看调试信息。
通过以上步骤,应该能够逐步排查出 udev
规则未生效的原因。
最终效果
经过一系列设置和优化,我们的方案基本达成预期目标。现在,既能从电脑拷贝切好的 gcode 文件,插卡就能直接打印,大大提高了打印效率;又实现了持久化扩容,有足够空间存放模型切片文件、延时摄影素材等。热插拔功能让使用存储设备更加便捷,有效解决了早期 Klipper 上位机存储不足的问题,为 3D 打印工作提供了更稳定、高效的存储解决方案。希望大家通过这篇文章,都能顺利实现 Klipper 上位机的热插拔自动扩容,享受更流畅的 3D 打印体验。如果在实践过程中遇到问题,欢迎随时交流探讨。
关于 AI 辅助写作
多了一些废话,还是需要人工参与大量校正
关于 AI 辅助编程
需要作者懂一些基础编程知识,否则生成的代码不可用都不知道如何 DEBUG
还需要我继续学习如何更好地使用 AI 工具。