project/pitfalls-index.md

踩坑索引:34 个坑的主题分组与教训

知识库 · 项目卷宗 📅 初版 2026-10-08

这个项目累计踩了 34+ 个坑。这里按主题归类,每条只留一句话核心教训;「现象-排查-根因-修法」的完整过程在两处:坑 1~17 在博客长文《一次嵌入式联调踩的 17 个坑》,其余在项目原始交接文档(见文末)。

#一、怎么用这份索引

  • 排障时:按症状找主题分组,扫一眼教训句,命中再跳原文细读;
  • 写需求书 / 交接时:把相关坑位直接抄进「已知坑位」章节——HAL 需求书的 14 条坑位就是从这份索引里挑的;
  • 带编号跳转:坑 1~17 编号与博客长文一致;坑 18 之后是博客成文后新增的。

#二、数据正确性(3,最难发现的一类)

  1. 位置读数大了 256 倍(长文详解):解析帧字节偏移晚一位,把校验字节 0x6B 当数据低位。因线性变换保单调性,闭环自洽,系统「一切正常」存活很久,最终靠「行程 8259 圈 / 49 秒 = 万转 RPM」的物理数量级矛盾暴露。教训:自洽不等于正确;要换算物理单位的数据必须做数量级校验;不确定就打印原始字节。
  2. 硬件上限误判两次(长文详解):短样本测速(1.5 秒,还在加速段)得出「被驱动器钳住」的假结论。教训:测稳态不用积分推算;测量方法有系统偏差时重复实验也一样错;假象会伪装成「硬件限制」让你停止怀疑。
  3. 单位口径不一致(长文详解):把显示口径(已除 10)的值写进标定文件 → move 50 走到 5% 还报到位。教训:单位写进字段名(stroke_0p1);显示口径绝不当存储口径;换算点集中一处。

#三、硬件与寄存器(4)

  1. 电流表测 PWM 乱跳(坑 4,长文详解):INA219 12bit 单次转换是瞬时采样,采样点随机落在 PWM 导通 / 关断。改 128 次平均(只动 ADC 位不动 PGA,保校准不失效)。教训:先怀疑测量方法再怀疑被测对象;仪表时间分辨率必须匹配信号频率。
  2. PCA9685 僵死 SLEEP|EXTCLK(坑 5,长文详解):寄存器读回全对但灯全不亮,写回被弹回。两级自愈:纠正 + 读回校验,不行就通用调用软复位(0x00 写 0x06)。教训:数据对不等于有输出,芯片还有状态机层;要有自动兜底复位路径。
  3. LED 极性误判(坑 6,长文详解):用 8% 背光当验证条件——「不可观测的验证」,成功失败看起来一样。教训:验证条件必须能区分成功与失败;结论要写清成立条件。
  4. 语义相反的量共用返回值(坑 14,长文详解):低有效开关 level 与 pressed 相反。教训:语义相近取值相反的量,接口上就是两个东西。

#四、并发与资源独占(4)

  1. tcflush 放在抢锁前(坑 7,长文详解):刷掉别人正在等的应答 → 偶发「启动未确认」误急停。教训:清缓冲等顺手动作必须与锁持有顺序一致:先上锁再清理;偶发问题优先怀疑并发。
  2. 常驻服务占死 flock(坑 8,长文详解):garden-local 急停后不释放串口锁 → 之后所有电机命令排队假死。教训:常驻进程借独占资源必须用完即还;问一句「持有者生命周期多长」。
  3. PWM 兄弟通道被冲(坑 9,长文详解):每次重写 period 惊动共享控制器。教训:区分配置寄存器(变化才写)与设定值寄存器(每次写)。
  4. CLI_LOCK 假死(10-02 修复):长电机命令持锁到到位(最长 5 分钟),急停不杀进程就全排队。已用 run_garden_tracked + _kill_motor_job 修复。教训:排障第一步先 kill 残留 motor 进程。

#五、运动控制(7)

  1. 急停过冲是物理约束(坑 10,长文详解):50ms 停止延迟 x 40mm/s = 2mm 过冲。梯形收尾降速(平方曲线 + 8% 最低速)压到 1/6。教训:物理约束只能缓解不能修好;收尾段比加速段更容易被忽略。
  2. 高速定位震荡(坑 11,长文详解):每轮 3 秒探测本身走过剩余距离 → 来回打摆。修法:只探一次 + 真实位移回填速率 + 单段按剩余封顶。教训:探测本身也是动作;单次测量得到的速率不可信。
  3. 固定加速度吃掉行程(坑 12,长文详解):100 RPM/s 写死 → 300RPM 要 3 秒起步。改按目标速度反算(恒定加速时间 0.6s)。教训:恒定加速度和恒定加速时间是两种手感,短行程高速用后者。
  4. 堵转保护自锁(09-25):滑台顶死点 → 驱动器自我关闭,连急停都回 E2。0x3A 状态位确诊,0E 52 解除,已自动化(motor_start_recovering)。教训:撞限位后收尾急停回 E2 是常态,顺手发解保护帧。
  5. 方向装反三连修(09-25):v1 翻方向位破坏承重约定、v2 交换命名把「上」安到物理下端、v3 才是正解(MOTOR_DIR_FLIP + MOTOR_POS_INVERT,命名服从现场)。教训:软件自洽不等于语义正确;物理命名必须服从现场事实。
  6. 同构判据漏改(09-25):drv_motor_jog 修过的「任一限位触发即报错」在 drv_motor_goto 漏修 → 标定后立刻 move 误判撞限位。教训:同一判据散落多处时,改一处必须找全同构点。
  7. 水泵幽灵自开(10-06):garden-local 防僵死轮换重启时上拉未稳,按钮初值误读出「松开沿」→ 泵自开。修法:启动 500ms 内的松开沿只更新状态不触发。教训:常驻服务自动重启这类「好设计」会带来新的初值毛刺窗口。

#六、环境与工具链(6)

  1. systemd 沙箱禁 sudo(坑 13,长文详解):NoNewPrivileges=true 让面板链路里 sudo 全失效,直连正常经服务失败。教训:「直连 OK + 经服务 FAIL」先看沙箱;服务单元文件进版本管理。另:ReadWritePaths 必须含 garden-data,否则标定写盘 EROFS。
  2. Shell 连环暗礁(坑 15,长文详解):pkill -f 匹配到自己的命令行;PowerShell 吃 $( ) 和引号;CRLF 必须 sed -i 's/\r$//';PowerShell 读文件不指定编码产生「假语法错误」。教训:远程复杂命令一律写 .sh 文件 scp 过去跑——本项目 140+ 个 board_*.sh 都为此而生。
  3. printf 百分号(09-25):格式串里 % 要写 %%。
  4. 中文文案里用 ASCII 双引号(09-25):Python/bash 字符串被截断。纪律:中文文案一律用「」。
  5. echo 密码 | sudo -S <<'EOF'(09-25):heredoc 覆盖 stdin,sudo 把 heredoc 当密码读。正确姿势:先写普通文件再 sudo cp。
  6. re.findall 带捕获组只返回组内容(09-25):越界检查器静默漏报。教训:工具静默失败比没有工具更危险。

#七、前端(2)

  1. Grid 塞超列数子元素(坑 16,长文详解):三列 grid 塞 5 个元素换行挤压。改 flex 单行 + 分段按钮组,并覆盖全局 width:100%。教训:加子元素前先看容器布局模型。
  2. 保护窗口误伤(坑 17,长文详解):防拖拽轮询覆盖的 3 秒锁让按钮点击也「卡住 3 秒」。修法:isDrag 判断 + 用服务端返回值立刻渲染。教训:为 A 场景加的保护要检查是否误伤 B 场景;接口已返回新状态就别等轮询。

#八、语音模块专题(5,10-05 上线)

  1. 同步调 API 卡死识别:电机 API 阻塞到动作完成(分钟级),同步调用卡死主循环 → arecord overrun 丢音频 → 识别全碎。必须 call_api_async 后台线程(架构三铁律之一)。
  2. partial 任意位置匹配误触发风暴:「开灯」每 1.5 秒自动执行连中 12 次。修法:只认末尾词 + 命中即 Reset + 分级冷却(急停 0.8s / 电机 1.5s / 灯泵 3s)+ 风暴保护(10 秒最多 3 次)。教训:流式识别的中间结果不可当指令。
  3. 麦克风增益 100% 最差:放大的是 ADC / USB 供电噪声而非人声。定档 71%(代码启动自动设置),勿再上调。要质变换 USB 声卡 + 外接麦克风。
  4. 依赖安装坑:vosk 必须官方 PyPI(清华镜像页面空报 versions:none 假象);模型下载走 hf-mirror(比官方快 18 倍);amixer 控件真名是 Mic,代码不查返回码会静默失败。
  5. b/p/f 声母短词天然糊(「关泵」):小模型 + 麦克风硬件极限,用同义词(开水泵 / 停泵)弥补;选新词必须查子串冲突(「开水灯」含「开灯」)。

#九、SD 卡专题(3,当前最高风险)

  1. 间歇性只读 EROFS(errno=30,异常断电后出现):标定 / 写盘随机失败,严重时起不来。验证:echo t > ~/garden-data/_t。
  2. 已做的应对(10-07/08):全盘 dd 备份 garden-full-20261007.img + OTA 增量 tgz;串口 uboot 诊断(serial_*.ps1 / log);分区修复 restore_1p5k.sh、deep_diff.sh / diff_sectors.sh 比对。
  3. 待办:换卡。重装参考:sd_backup/ 里 ubuntu2404-rootfs.tar.gz + rebuild_ab.sh;语音模型丢了按交接 v2 第 5.2 节重下。

#十、相关链接

#十一、更新日志

📝共 1 条记录
日期类型更新内容
2026-10-08新增首次建档:34 坑按八大主题分组(数据 / 硬件 / 并发 / 运动 / 工具链 / 前端 / 语音 / SD 卡),每条一句话教训,坑 1~17 链接博客长文