TinyPilot:第二个月
原文由 Michael Lynch 于 发布,订阅该博客
一句话总结
TinyPilot 给我来了个措手不及,不过整体仍在向前推进。
亮点
- 为解决一个设计问题,我暂停了 TinyPilot 的销售。
- 我正在为 TinyPilot 定制生产一款 USB 供电连接器。
- 所有项目的总收入达到了 3600 美元,是迄今表现最好的月份之一。
目标完成情况
每个月初,我都会定下当月想要完成的目标。以下是完成情况:
售出 30 套 TinyPilot 套件
- 结果:售出 16 套 TinyPilot 套件
- 评分:C
本来进展顺利,有望超额完成目标,但中途出了岔子,不得不暂停销售。
测试三个新的营销渠道
- 结果:未测试任何营销渠道
- 评分:F
出于同样的原因,我把营销工作推迟到重新有产品可售之后。
为 TinyPilot 实现鼠标支持
- 结果:为 TinyPilot 添加了鼠标支持
- 评分:A
这个功能比我预想的要难,不过还是在月末前完成了。集成鼠标后,用户体验的提升超出我的预期。
TinyPilot
| 指标 | 2020 年 7 月 | 2020 年 8 月 | 变化 |
|---|---|---|---|
| 独立访客 | 4,930 | 2,284 | -2,646 (-54%) |
| 总浏览量 | 10,427 | 6,136 | -4,291 (-41%) |
| 销售收入 | $8,741.37 | $3,030.74 | -$5,710.63 (-65%) |
| 捐赠 | N/A | $94.06 | +$94.06 (+inf%) |
| 总收入 | $8,741.37 | $3,124.80 | -$5,616.57 (-64%) |
访问数据虽然不如上个月在 Hacker News 上爆发式增长时那么亮眼,但稳定的潜在客户流量依然让我满意。
没能达成销售目标,一方面是因为库存补充跟不上,另一方面更主要的是月中不得不暂停了销售。
捐赠算是个意外的惊喜。本月我收到了近 100 美元来自希望支持该项目的人的捐赠,其中一笔看似来自机器人。
唉,Y 型线!
从 TinyPilot 最早期开始,我就一直在为一个大问题头疼:供电。
树莓派有一个特殊能力,可以模拟其他 USB 设备。正是靠这个,它才能向目标电脑输入按键。它会告诉电脑自己是一块 USB 键盘,然后像真正的 USB 键盘那样发送按键。
问题在于,唯一能模拟键盘的那个接口,同时也是主要的供电口。电脑的 USB 口确实会输出一点电量,但不足以满足树莓派官方要求的 3.0 安培。最初版本的 TinyPilot 只靠 0.5 安培运行,虽然能用,但我一直担心供电不足会引发各种意外问题,所以急于寻找更好的解决方案。
最后,我找到了这根 USB OTG Y 型线,看起来正是我需要的:

这根 USB OTG Y 型线看起来正合我意
我买了一根,一试居然成功了!它把树莓派的连接一分为二,让我可以同时连接电源和目标电脑。于是我把整个供应都切换到了集成这根线的 TinyPilot v2。在卖出六套并开始宣传新版本后,有人联系我,问这根线是否能防止电流倒灌。
电流倒灌?我压根没意识到这会是个问题。
原来,这种 Y 型线本来就不是用来连接两个独立电源的。理论上,外部电源和电脑的 USB 口都输出 5 伏电压。但实际上,并不能保证两者都恰好是 5 伏。USB 供电规范允许的范围是 4.4 至 5.25 伏,所以如果电脑端的电压掉到 4.5 伏,电流就会从外部电源反向流入电脑的 USB 口,可能会导致接口过载甚至永久损坏。
读者一指出这个隐患,我立刻暂停销售,并聘请了一家电气工程公司来调查。他们确认风险确实存在,于是我马上联系了已购买的客户,建议他们在找到解决方案前先断开外部供电。好在 TinyPilot 即使不接外部电源也能工作,只是不太方便。
两周内从零造出一个硬件?
过去一个月里最让我惊讶的发现之一,就是如今制造的速度和成本之低。
就在一周前的 8 月 27 日,我请 TinyPilot 的电气工程合作方设计一款连接器来解决供电问题。设计第二天就完成了,他们随即下单印制了 100 块电路板。预计这周末就能到货,测试和组装也只需要再花几天。
与此同时,我还在和一家 3D 打印设计工作室合作,为电路板设计外壳。对方两天内就完成了设计,目前正在打印前三个原型。一旦开工,他们每天能打印 50 个外壳。


正在以惊人速度成型的 TinyPilot 电源连接器
如果一切顺利,外壳和电路板最快下周就能交付给客户。这意味着我们仅用两周就从零做出了一款完整的实体产品。
算上设计、零件和人工,这一批的总成本大约是每件 13 美元。即使是这么简单的项目,我也没想到周期和成本能低到这种程度——当然,前提是一切顺利。
HID 描述符真要命
如上文所述,TinyPilot 需要向目标电脑表明自己是一块 USB 键盘。它通过 USB 连接发送一种叫做人机接口设备(HID)描述符的东西来实现。键盘、鼠标、U 盘等 USB 设备都有 HID 描述符,用来声明设备能做什么。
HID 描述符是一段看起来像这样的二进制数据:
// HID descriptor for a keyboard
// Source: https://www.kernel.org/doc/html/latest/usb/gadget_hid.html
static struct hidg_func_descriptor my_hid_data = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x06, /* USAGE (Keyboard) */
0xa1, 0x01, /* COLLECTION (Application) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x08, /* REPORT_COUNT (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
0x95, 0x05, /* REPORT_COUNT (5) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};为键盘创建 HID 描述符轻而易举。网上有很多人用 Python 实现过虚拟键盘,文档也很齐全。
实现虚拟鼠标则要难得多,我不得不深入了解 HID 描述符的原理。鼠标的变体很多,比如按键数量、滚轮数量、定位方式(绝对定位还是相对定位)等。调试非常痛苦,因为描述符要么能用,要么不能用。如果生成了一个无效的描述符,根本得不到任何关于哪里出错的反馈。更糟的是,每尝试一次描述符,都得重启一次树莓派。
我花了五天枯燥的摸索,才让基本的鼠标功能跑起来。对我来说,关键在于先把工具做好。一开始,我把描述符当成一大坨无结构的二进制来处理,像这样:
echo -ne \x05\x01\x09\x02\xA1\x01\x05\x09\x19\x01\x29\x08\x15\x00\x25\x01\x95\x08\x75\x01\x81\x02\x05\x01\x09\x30\x09\x31\x16\x00\x00\x26\xFF\x7F\x75\x10\x95\x02\x81\x02\xC0 > "${MOUSE_FUNCTIONS_DIR}/report_desc"这样很难对描述符进行思考,改任何一点都得重头来过。于是我写了一个简易的 JavaScript 小工具,可以把不同格式的 HID 描述符示例转换成对应的 shell 命令来生成文件:

我写的一个用于格式化 HID 描述符的简易 JavaScript 工具
接着,我在主目录下写了一些小小的实用脚本。这些脚本简单到平时根本不值得单独成文件:
#!/bin/bash
set -x
sudo journalctl -u init-usb-gadget这些看似笨拙的小工具在两方面帮了我。第一,当我连续几天撞墙般毫无进展时,它们至少让我有了点成就感——就算 HID 描述符还没跑通,我至少写出了能按预期工作的代码。第二,它们降低了我的认知负担,让我能把更多精力集中在核心问题上。不用再去回忆查看 systemd 日志的语法,直接输入 ~/show-systemd-log 就行。
后来发现,我的大部分问题根本不在 HID 描述符本身,而在于用来生成它们的 shell 命令。把其他繁琐事务从脑中清理掉后,我才想到应该去核对磁盘上的文件是否符合预期——结果并不符合。意识到这一点后,很快就做出了可用的鼠标描述符。
使用 TinyPilot 在远程笔记本上模拟鼠标和键盘操作
旧项目
以下是一些我仍在维护、但已非开发重心的项目的简要更新:
Is It Keto
| 指标 | 2020 年 7 月 | 2020 年 8 月 | 变化 |
|---|---|---|---|
| 独立访客 | 48,231 | 49,981 | +1,750 (+4%) |
| 总浏览量 | 118,980 | 125,599 | +6,619 (+6%) |
| 域名评分(Ahrefs) | 8.0 | 9.0 | +1.0 (+12%) |
| AdSense 收入 | $208.86 | $202.46 | -$6.40 (-3%) |
| AdThrive 收入 | N/A | $35.00 | N/A |
| Amazon 联盟收入 | $134.45 | $129.88 | -$4.57 (-3%) |
| 其他联盟收入 | $26.60 | $118.88 | +$92.28 (+347%) |
| 总收入 | $369.91 | $486.22 | +$116.31 (+31%) |
本月 Is It Keto 略有增长,尽管我一直想把精力都集中在 TinyPilot 上,因为那边的投入回报要高得多。
本月 Is It Keto 唯一值得一提的事,就是我把展示广告从 AdSense 换到了 AdThrive。令人沮丧的是,迁移过程比预想的要繁琐得多。他们的入驻流程有很多细碎步骤:让我填一份表,等一周,再让我填另一份,循环往复。
终于到了要把网站切换到 AdThrive 广告的时候,却发现他们的 JavaScript 代码在单页应用上无法正常工作,导致基于 Vue 的 Is It Keto 代码出现了异常。我理解他们很多客户可能用的是 WordPress,但……拜托!在 2020 年,单页应用不该是什么难题吧。
这下又捅了个新马蜂窝,因为 AdThrive 不断发给我一些有问题、东拼西凑的 JavaScript,号称能让 AdThrive 在我网站上正常运行。我一运行,发现不行,反馈给他们,他们又发来一段以另一种方式出错的新代码。
最后,我说服他们把代码托管在他们那边,把我从调试循环中摘了出来。我不太喜欢他们在测试似乎还不充分的情况下就推向生产环境,但眼下我实在没有精力去操心这个。
Zestful
| 指标 | 2020 年 7 月 | 2020 年 8 月 | 变化 |
|---|---|---|---|
| 独立访客 | 440 | 324 | -116 (-26%) |
| 总浏览量 | 1,247 | 841 | -406 (-33%) |
| RapidAPI 收入 | $18.05 | $9.36 | -$8.69 (-48%) |
| 总收入 | $18.05 | $9.36 | -$8.69 (-48%) |
Zestful 方面依然平静,不过我正在评估一个新的 API 市场。我一直急切想找一个能替代现有平台 RapidAPI 的选择。一家叫 Servernope 的新公司邀请我入驻他们的 API 平台。我告诉他们我没时间去配置,但他们可以代我创建一个 Zestful 的条目。于是他们真的创建了。
我还没有完全被说服。我对 RapidAPI 最大的不满之一,就是他们的分析数据展示得毫无用处。Servernope 似乎也有类似的问题,只不过我在 Servernope 上还没有付费用户,所以很难做对比。
总结
完成了什么?
- 调查了 TinyPilot 的供电问题,并开始生产用于修复的部件。
- 为 TinyPilot 添加了鼠标支持。
- 聘请了一名自由职业者来接管库存管理和部分调研工作。
- 在 eBay 上上架,以实现 TinyPilot 的国际销售。
- 我正在研究如何通过 Shopify 来实现,但 eBay 是一个便捷的过渡方案。
- 发布了一篇新博文:《我是如何向无良商家追回欠款的》
- 以及两篇新的读书报告。
经验教训
- 更早地与电气工程专家合作。
- 回过头看,我对树莓派的用法已经偏离主流足够远,本就应该请专业电气工程师来审核方案。
- 遇到难题卡住时,先做一些能减少调试工作的工具。
- 做工具能让你感到自己在前进,并让大脑腾出空间专注于问题的本质。
下月目标
- 售出 60 套 TinyPilot 套件及电源连接器。
- 测试三个新的营销渠道。
- 访谈七位 IT 从业者,了解他们是否会在工作中使用 TinyPilot。
随机一篇博客
评论
登录后参与讨论