Imported from KCN-judu/auto_typer (
AGENTS.md). Install upstream withnpx skills add KCN-judu/auto_typer. Copyright stays with the author.
--- project-doc ---
Auto Typer 项目快速索引
本仓库包含 ESP32-S3 主固件、Electron 桌面控制台、共享 TCP 协议、Arduino 打包工具、独立硬件测试草图和硬件资料。修改前先从本索引定位源码入口,并以代码而不是历史文档为准。
工作规则
- 文件命名约定只约束文件名和路径名,不约束变量、函数、类型或类。桌面端 TypeScript 文件使用小驼峰,例如
motionProtocolClient.ts;固件 C++ 文件使用大驼峰,例如MotionProtocolServer.h。 - 不要把 CAN 发送成功、命令 ACK 或
block_ack当成机械动作完成。已接收原子块只有对应的block_result才是终态。 - 当前协议只接受绝对目标脉冲。桌面端维护累计逻辑位置;设备断电、急停、堵转或机构被人工移动后,计划位置可能与机械位置不一致。
- 每次上电前必须人工把完整机构放回定义的机械原点。固件的 pulse clear 只建立电气零点,不执行机械回零。
目录索引
src/auto_typer/:主固件,控制 OLED 和五台 Emm_V5.0 CAN 电机,提供 SoftAP 配网和 TCP7777原子运动协议。apps/desktop/:Electron + Vite + React 控制台,负责配网、连接、键位映射、文本规划、绝对脉冲编码、打印和恢复操作。shared/protocol/:桌面与固件共同遵守的 TCP NDJSON v1 TypeScript 类型源。shared/protocol/motionConfig.ts:桌面运动配置唯一真实来源;M4 目标、方向、profile、字符步进和派生容量不得在其他生产文件重复定义。tools/:固件源码编译、预编译 Arduino 库、离线 Arduino 工作区生成与验证脚本。src/test/test/:独立硬件连通性测试草图,不是生产固件入口。src/test/docs/:Typst 烧录与使用教程及真实界面截图。materials/:电机、PCB、外壳、说明书和供应商资料。
关键入口
src/auto_typer/auto_typer.ino:Arduino 生命周期入口,只调用无参autoTyperSetup()和autoTyperLoop()。src/auto_typer/AutoTyperFirmware.cpp:组装 Wi-Fi、CAN、反馈缓存、运行时和 TCP server;setup()/loop()的实际委托目标。src/auto_typer/network/ProvisioningWifiConnector.h与src/auto_typer/ProvisioningWifiConnector.cpp:SoftAP + STA 配网状态机和 HTTP/api/status、/api/provision、/api/finish。src/auto_typer/auto_typer_config.h:设备 ID、CAN 引脚、机器拓扑、运动参数和绝对脉冲目标默认值。src/auto_typer/auto_typer_types.h:任务、设备、运动、反馈和远程动作类型。src/auto_typer/auto_typer_runtime.h:启动清零、任务状态、readiness、故障、原子块转换和运行时事件。src/auto_typer/motion/MotionExecutor.h:动作状态机、ACK/脉冲/速度监督、取消和急停。src/auto_typer/transport/MotionProtocolParser.h:execute_block的结构与数值校验。src/auto_typer/transport/MotionProtocolServer.h:TCP7777NDJSON v1 会话、命令、快照与终态事件。src/auto_typer/protocol/EmmV5CommandCodec.h:Emm_V5.0 CAN 帧编码;位置命令使用绝对脉冲目标。src/auto_typer/can/:TWAI、TX 队列、RX 任务、事件解析、反馈缓存和协议 trace。shared/protocol/protocolTypes.ts:唯一共享 TypeScript 协议类型源。apps/desktop/electron/deviceLink.ts:Electron TCP 链路。apps/desktop/electron/runtime/provisioning_http.ts:桌面端 SoftAP HTTP 客户端。apps/desktop/electron/runtime/directPrintService.ts:无队列直接打印的原子接受、重复 ID、状态迁移和持久化所有者。apps/desktop/electron/runtime/localTextReceiver.ts:loopback HTTP API;start=true立即执行或拒绝。apps/desktop/src/domain/planner/motionBlockPlanner.ts:文本到动作块规划。apps/desktop/src/domain/planner/absoluteMotionEncoder.ts:逻辑位置到 M1-M5 绝对脉冲目标编码。apps/desktop/src/domain/runtime/executor/motionProtocolClient.ts:握手、快照、控制命令和 block 客户端。apps/desktop/src/ui/hooks/usePrintTaskController.ts:打印、普通取消回零、急停和内部调试操作编排。apps/desktop/src/ui/hooks/useDirectPrintWorker.ts:直接打印领取、readiness 和执行回报副作用边界。apps/desktop/src/ui/App.tsx:桌面 UI 主组件。
常用命令
npm run desktop:dev:启动 Electron 开发环境。npm run desktop:typecheck:检查 renderer 与 Electron TypeScript。npm run desktop:test:运行绝对运动编码和设备链路测试。npm run desktop:build:类型检查并构建桌面端。npm run firmware:test:运行固件宿主侧回归测试。npm run firmware:compile:编译主固件源码。npm run firmware:package:生成预编译AutoTyperCore。npm run firmware:package:upload:生成预编译库、编译配网示例并上传;自动识别不可靠时显式传入-- --port=<串口>。npm run firmware:workspace:生成 macOS 离线 Arduino 工作区。npm run firmware:workspace:verify:验证板型暴露和 starter sketch 编译。
启动与配网事实
- 无参
autoTyperSetup()启动串口、调用gWifi.begin(),再执行gApp.setup();固件没有编译期或 sketch 注入的 Wi-Fi 凭据接口。 - Wi-Fi 进入
WIFI_AP_STA,建立 SSIDwifi-setup、密码admin123、信道6的 SoftAP,并在端口80启动配网 HTTP server。 - 固件初始化 OLED、TWAI 和 CAN 队列;向 M1-M5 发送闭环模式/使能配置,清除五台电机脉冲位置,并验证 clear ACK 与近零输入脉冲。
/api/provision接收 SSID/密码并触发 STA 连接;连接超时为20000 ms。/api/finish只在 STA 已连接时成功;响应后约500 ms关闭 SoftAP,并通过consumeTcpReady()放行 TCP server 启动。- TCP server 同时只允许一个 client;连接后
3000 ms内未完成 handshake 会断开。 - handshake 后客户端连续
15000 ms不发送任何数据会被断开;桌面每秒发送 heartbeat,并容忍一次连续失败。
Wi-Fi 必须通过 SoftAP /api/provision 直接配网。不要重新引入 Secrets.h、FirmwareConfig、Wi-Fi 宏或上传环境变量;修改配网行为时必须同步 README 与 Typst 教程。
协议事实
客户端在 handshake 后可发送:
get_snapshotheartbeatexecute_blockcancelfinish_taskemergency_stopreset_fault
设备响应/事件包括:
handshake_ack、snapshot、heartbeat_ackblock_ack、block_resultcancel_result、finish_task_resultemergency_stop_result、reset_fault_resultfault、protocol_error
限制:
- 单行最大
8192bytes。 requestId最大64UTF-8 bytes,blockId最大48UTF-8 bytes。policy.maxRuntimeMs最大30000 ms。- 单动作
timeoutMs最大10000 ms。 wait.durationMs最大30000 ms,且不得超过所属 block 的policy.maxRuntimeMs。- 固件只有一个活动 block 槽;下一 block 必须等待当前
block_result。 - block 允许单个
motor_move、wait或line_feed_home;多动作 block 允许 M1/M2/M3 的 XY 同步组合,或同 profile 的 M5 绝对按压目标后紧跟 M5→0 的原子按压循环。 get_snapshot是任务、CAN、motor readiness 和 fault 的唯一显式观测路径;固件不主动推送 telemetry/motor state。
位置与任务事实
桌面逻辑位置为 {x, y, l, z},物理映射为:
- M1 =
x - M2 =
-y - M3 =
y - M4 =
l - M5 =
z
当前默认目标/参数:
- 坐标换算
80 steps/mm。 - XY 打印
1600 RPM、accelRaw=128、timeoutMs=10000。 - M5 按压
3000 RPM、accelRaw=255;正常按键使用一个原子块执行按下-2700、释放0。受控按压块的下压阶段出现新堵转,或确认已运动但在目标前连续约120 ms停止时,将其作为键盘接触,立即发送清堵转与重新使能命令并进入释放。LShift 解锁大写前,桌面将其配置坐标单独向 Y=0 方向偏移5 mm;随后使用同一高速目标和500 ms强制冲击窗口:窗口内不做触达完成判定,任何新的 M5 堵转或条件回报都执行清堵转、使能并重发高速下压,窗口结束后才释放。接触状态可能延迟到释放阶段才上报;此时按新的状态序列逐次执行清堵转、使能并重发绝对0,同一状态不得重复塞入 CAN 队列。只有 fresh 位置、速度和无故障状态确认 M5 到达0才成功,持续无法释放最终按 timeout 故障处理。 - M4 走纸到位是固定绝对序列
15680 -> 10880,120 RPM、accelRaw=240,前向保持1500 ms、释放稳定400 ms。 - 普通字符释放会让 M4 在当前目标基础上累计
-160pulses。 - 规划下一个普通字符前,如果该字符的 M4 释放目标将为
< 0,桌面必须先插入完整15680 -> 10880换行块,再继续该字符的 XY、按压和-160释放;普通目标允许到0,不得为负。
lineFeedPrimeRequired_ 初始为 true,只有完整成功的 M4 15680 -> 10880 语义动作才会清除。桌面连接后会基于 snapshot 自动执行同一套自检,App.tsx 也提供“自检并走纸到位”按钮;在后续 snapshot 确认五台电机 fresh/ready 且标志清除前,“开始打印”保持禁用。
Electron 直接打印事实
POST /api/print-text的start默认 false;false 只填充编辑器,true 必须同时提供clientRequestId并立即执行或拒绝。- 系统没有等待队列。打印中、手动动作、机器错误、断线或未就绪均返回
409,不得延迟到以后执行。 - 成功接受过的
clientRequestId永久拒绝复用并返回duplicate_client_request_id;接受前被拒绝的 ID 不登记。 - 已接受任务对外只有
printing、error、completed,分别与固件 Running/Error/Complete 语义对齐。 - Electron main 的
DirectPrintService是任务、ID 和执行槽唯一权威;renderer 通过 Hook 领取,所有回报必须匹配 execution token 和 revision。 - renderer/窗口/桌面程序中断时,未可靠完成的任务进入
error,不得自动重发机械动作。 - 规范 API 文档:
docs/print-api-reference.md。
远程 block 状态主线:
execute_block
-> 完整校验
-> block_ack + Queued
-> tick() 启动 MotionExecutor + Running
-> ACK/输入脉冲/速度/timeout 监督
-> block_result(done | failed | cancelled)
finish_task 只在没有 queued/planning/running/cancelling/active block 时接受;成功后 OLED 显示 Complete 3000 ms,然后回到 Idle。
取消与故障事实
- 桌面普通取消是协作式的:等待当前 block 完成,丢弃未发送 block,再提交 XY→0、M4→15680→10880、M5→0 的绝对回零序列,不发送
finish_task。 - 协议
cancel与断线只取消Queuedblock;Running block 不被普通取消中断。 - Running block 所属连接断开后继续受固件监督,但未发送的
block_result/fault不会跨会话投递;新连接通过轮询get_snapshot收敛到终态。 emergency_stop清空 CAN 队列、停止/失能/解锁五台电机、锁存 fault、使任务失败并显示Error。reset_fault必须携带confirmMechanicalOrigin: true。第一阶段清理执行器和 CAN fault,保留五轴绝对脉冲位置并验证 fresh/ready;桌面随后让 M5 回到0,再让 XY 以绝对目标回到机械原点。只有 XY block 返回done后,桌面才发送带establishXyOrigin: true的第二次reset_fault,此时只清除并验证 M1/M2/M3 电气零点;M4 位置始终保留,最后执行15680 -> 10880。CAN 或 motor readiness 未恢复时继续保持 fault。复位等待期间 TCP 会继续处理 heartbeat,并允许急停抢占;TWAI bus recovery 内部最多约800 ms不能被回调打断。- 急停或异常停止后不能假设绝对坐标仍可信,必须先人工检查并恢复机械原点。
文档维护
- 操作教程:
src/test/docs/operator-guide.zh-CN.typ。 - 协议说明:
shared/protocol/README.md。 - 独立测试草图说明:
src/test/test/README.md。 - 协议、配网、板型、目标脉冲、UI 流程或安全语义变化时,同步更新对应文档和截图。