开发一款实时追踪Claude API使用情况的机器人手臂
你是否每隔五分钟就不得不运行一次“/usage”?是否总在担心自己即将达到五小时的使用上限?你并不孤单。我们称之为“克洛德代码焦虑”。我看到了令人惊叹的“Clawdmeter”项目——一个专为追踪令牌使用量而设计的M5Stack仪表盘,非常漂亮。但当我低头看看自己的办公桌时,发现我的四自由度机械臂机器人myPalletizer 260也配有屏幕、蓝牙功能,甚至还有一个“脑袋”。既然可以将机器人变成一个会动、会呼吸、能实时追踪使用情况的得力助手,何必还要再建一个新仪表盘呢?目标很简单:不再频繁输入“/usage”,而是让机器人来告诉我们我们的使用情况如何。
myPalletizer 260 Basic Basic 固件是开源的(这很棒!),但多年来一直未更新,且依赖于标准的 Arduino IDE 和库。而原始的 Clawdmeter 项目则使用了更为现代的技术栈:PlatformIO、ESP-IDF 以及用于图形显示的 LVGL。
这意味着我不能直接插入 Clawdmeter 的代码。虽然我用它作为逻辑和 API 数据包的蓝图,但不得不从头开始手动重写 UI UI 渲染和 BLE BLE 配置,使用适用于 M5Stack Basic 的旧版 Arduino Arduino 库。这是一次真正从零开始的移植工作。
将“高级”界面适配至M5Stack
我必须仅使用 M5Stack.h.h 库,将高分辨率的 AMOLEDLED 效果移植到 M5Stack 的 320x240 SPI SPI 屏幕上——基本上是用基本的图形原语手动绘制。
精准把握配色方案:我并未随意猜测“橙色”,而是从Anthropic的品牌标识中提取了精确的十六进制代码,并将其转换为M5Stack支持的RGB565格式(例如,#d97757转换为0xDBAB)。此外,我还需灵活调整字体大小(比如将大百分比使用3号字),以确保在办公桌对面也能清晰阅读。
布局数学(320x240):我为边距和面板宽度设置了常量(PANEL_W、PANEL_H),以保持布局整洁,避免硬编码绝对像素坐标。由于 M5Stack.h 是低级接口,我将 drawRoundRect 和 fillRoundRectRect 包装成辅助函数,如 drawPanel 和 drawPill,使 UI 代码更清晰。
可视化“焦虑”:使用条逻辑
为了使数据一目了然,我编写了一个辅助函数(pct_color),根据使用次数的整数值返回不同的RGB565颜色:正常使用时为 sage green(智利绿),推压时为 terracotta(赤陶色),而进入“焦虑区”时则变为刺眼的红色。
无闪烁的UI更新:在简单的LCD项目中,刷新数据时屏幕闪烁是最令人烦恼的问题之一。我使用了一个简单的状态检查(changed = (usage_data.ok != last_ok))来确保M5.Lcd.fillRect命令仅在实际收到新的BLE数据时才会执行,从而保持界面稳定流畅。
双动画系统(像素与钢铁)
这里正是项目真正展现其魅力的地方,将屏幕图形与实体伺服运动完美结合。
屏幕(像素艺术动画):特别感谢 @amaanbuilds 和 claudepix 图库,为这些出色的像素艺术 Clawdd 动画提供了支持!为了在景观屏幕上适配方形动画,我使用了一些缩放计算。M5Stack 实际屏幕上的一个“像素”只是一个微小的 LED LED LED 灯珠。如果将 20x20 的 Clawdd 动画按原比例绘制,它会显得像一颗极小的点!为了放大显示,我将每个“逻辑”像素转换为一个由 12x12 个物理像素组成的方块(2000 块 × 1222 像素 = 24000 像素),然后将其居中放置在宽 32000 像素的屏幕上,只需简单的 4000 像素横向偏移即可。
内存优化(为什么不使用GIF?):你可能会想:“为什么不直接把GIF存到SD卡上?”虽然这是可行的,但对于ESP32来说效率很低。解码GIF需要大量库文件,并消耗CPU周期。此外,从SD卡读取数据并写入屏幕时,两者必须共享SPI总线,导致延迟。因此,我将每一帧以轻量级的2D字字节数组形式存储在程序只读区(progmem),然后通过fillRect立即绘制出来。
动画的核心幻觉:在最基本的层面上,动画就是以特定的时间戳绘制一组特定的像素排列。在我的代码中,这可以简化为三个部分:一个像素映射数组(帧)、一个持续时间数组(保持时间)以及一个当前帧计数器。
让机器人动作起来:我创建了一个二维数组(anim_poses),其中包含一系列关节角度。当克洛德开始工作时,机器人会循环这些姿势,模拟出“点头”或“工作”的动作。我采用直接的关节角度控制,而不是复杂的逆运动学(IK)——这样更简单,并能确保机械臂不会碰到自身的基座。
屏幕与机械臂同步:每当动画计时器触发,代码就会执行两项操作:绘制下一帧(drawSplash())并立即将关节角度发送给机械臂(myCobot.writeAngles())。从软件角度来看,两者是同步的,但实际上,物理伺服电机无法跟屏幕刷新的速度保持一致。由于我们在机械臂完成上一次动作前就已发出新的坐标指令,导致实际运动出现明显的抖动——但系统仍然能正常运行!
守护进程:连接 macOS 与蓝牙
原始项目使用了 Linux Linux 特有的工具(bluetoothctl 和 D-Bus)。由于我使用的是 Mac,因此我用 Python Python 并结合 bleak bleak 库重写了该守护进程。
异步架构:BLEBLE 可能会有些麻烦。使用 Python 的 asyncio,可以让守护进程在后台保持连接,同时主循环在 155 秒的轮询间隔中休眠。
GATT 服务发现:该脚本通过扫描特定的服务 UUID(如 4c41555a...)来识别服务,而不仅仅依赖名称,然后动态查找 RX RX 特性。
钥匙串安全(macOSOS 版本):为了避免以纯文本形式存储 API API 密钥,我使用 subprocess subprocess subprocess 调用 security find-generic-password-password-password 命令,直接从 macOS macOS macOS 钥匙串中获取你的 Claude 令牌。(代码片段:显示 read_token() Python Python 函数)
展望未来:未来计划
每15秒轮询一次API对使用条目来说可以接受,但对于物理反应而言感觉会卡顿。下一版本将使用Claude Code的hooks.json文件,在您按下回车键的毫秒级瞬间通过BLE发送“正在思考”的信号。我还希望在机器人上添加一个物理“停止”按钮,该按钮能通过BLE向主机发送数据,实际终止Claude进程。
本文编译自hackster.io





