TinyPilot:第 2 个月
一句话总结
TinyPilot 给我出了一个大难题,但事情仍在继续向前推进。
亮点
- 我暂停了 TinyPilot 的销售,以解决一个设计问题。
- 我正在为 TinyPilot 制造定制 USB 电源连接器。
- 我所有项目的总收入达到 3.6 千美元,是有史以来表现最好的月份之一。
目标评分
每个月开始时,我都会列出自己希望完成的事情。下面是我对照这些目标的完成情况:
销售 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 最早期开始,我就一直在和一个大问题苦苦斗争:电源。
Raspberry Pi 有一项特殊能力,可以伪装成其他 USB 设备。这正是它能够向目标计算机输入按键的原因。它告诉计算机自己是一个 USB 键盘,然后像 USB 键盘一样发送按键。
问题在于,唯一能够伪装成键盘的接口,同时也是接收电源的主接口。计算机的 USB 接口确实会输出少量电力,但不足以满足 Pi 官方要求的 3.0 安培。TinyPilot 的初始版本只使用 0.5 安培电力,虽然能够运行,但我一直担心供电不足会导致意外问题,所以迫切希望找到更好的解决方案。
最后,我找到了这条 USB OTG Y 型线缆,看起来正是我需要的东西:

一条看起来正是我需要的 USB OTG Y 型线缆
我买了一条,结果真的能用!它把 Raspberry Pi 的连接分成两路,让我可以同时接入电源和目标计算机。我把全部库存都换成了集成这条线缆的 TinyPilot v2。卖出六套并开始推广新版本后,有人联系我,问这条线缆是否能防止电源回流。
电源回流?我甚至不知道这也可能成为问题。
结果证明,这条 Y 型线缆并不是用来连接不同电源的。理论上,外部电源和计算机的 USB 接口都会输出 5 伏电力。实际上,无法保证两者都能产生恰好 5 V 的电压。USB 电源规范允许的范围是 4.4 - 5.25 V,因此如果计算机的输出电压降到 4.5 V,电流就会从外部电源反向流入计算机的 USB 接口,可能使接口过载并永久损坏。
读者一提出这个风险,我就暂停了销售,并聘请一家电气工程公司进行调查。他们确认风险确实存在,于是我联系客户,建议他们在我找到解决方案前断开外部电源。幸运的是,TinyPilot 不接外部电源也能运行,只是没那么方便。
我能在两周内从零制造出某种东西?
过去一个月里,我最意外的发现之一,就是制造业如今已经变得如此快速且廉价。
就在一周前,也就是 8 月 27 日,我请 TinyPilot 的电气工程合作伙伴设计一个连接器,以解决电源问题。设计第二天就完成了,他们随即订购了 100 块电路板进行印制。我们预计电路板会在本周末到货。测试和组装应该只需再花几天时间。
与此同时,我还在和一家 3D 打印设计公司合作,为电路板设计外壳。这家 3D 打印公司用了两天完成设计,目前正在打印最初的三个原型。一旦正式开始生产,他们每天能 3D 打印 50 个外壳。


正在以惊人速度成形的 TinyPilot 电源连接器
如果一切顺利,外壳和电路板最快下周就能准备好交付给客户。这意味着我们只用了两周,就从零开始做出了一个完整的实体产品。
包括设计、零件和人工在内,这一批的总成本预计约为每个 13 美元。即使是这样一个简单的项目,我也没想到周转时间和成本能低到这种程度。当然,前提是一切顺利。
HID descriptor(人机接口设备描述符)真是个恶魔
正如我上面所述,TinyPilot 需要向目标计算机呈现为一个 USB 键盘。它通过 USB 连接发送所谓的 HID descriptor。键盘、鼠标和 U 盘等 USB 设备都有 HID descriptor,用来声明设备能够执行哪些操作。
HID descriptor 是一段二进制数据,看起来像这样:
// 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 descriptor 简直易如反掌。很多人都用 Python 实现过虚拟键盘,相关过程也有详尽的文档记录。
实现虚拟鼠标就难得多了,还需要我进一步了解 HID descriptor 的工作方式。鼠标有更多种变化,例如按键数量、滚轮数量,以及定位方式(绝对定位还是相对定位)。调试非常痛苦,因为 descriptor 要么能用,要么不能用。如果生成了无效的 descriptor,就完全无法获得任何反馈来了解它哪里出了问题。最糟糕的是,每次尝试一个 descriptor,都必须重启 Raspberry Pi。
我花了五天时间进行繁琐的工作,才让基本的鼠标功能运行起来。对我来说,关键在于专注于工具。起初,我处理的是这种巨大的、没有结构的数据块:
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"这让人很难理解 descriptor,因为不从头开始就无法修改任何内容。我写了一个简易的 JavaScript 应用,让我可以输入不同格式的示例 HID descriptor,然后将其转换为等效的 shell 命令,用来生成文件:

我制作的一个简陋 JavaScript 应用,用来为我格式化 HID descriptor
接下来,我在自己的主目录中写了一些小工具脚本。它们都是非常简单的脚本,通常根本不值得单独存成文件:
#!/bin/bash
set -x
sudo journalctl -u init-usb-gadget这些不起眼的工具在两个方面帮了我。首先,当我连续几天都像在撞墙一样毫无进展时,它们让我有一种有所成就的感觉。虽然 HID descriptor 还不能工作,但至少我还在产出一些能够按预期运行的代码。其次,它们降低了我的认知负担,让我有更多脑力专注于眼前的问题。我不用再回忆查看 systemd 日志的语法,只需输入 ~/show-systemd-log 即可。
后来我发现,我遇到的大多数问题甚至都不是 HID descriptor,而是我用来创建它们的 shell 命令。一旦把其他烦琐的任务从脑中清除出去,我就意识到应该检查磁盘上的文件是否符合预期。结果并不符合。意识到这一点后,我很快就做出了一个能工作的鼠标 descriptor。
使用 TinyPilot 在远程笔记本电脑上模拟鼠标和键盘操作
旧项目
下面是一些我仍在维护、但不是当前开发重点的项目简要进展:
Is It Keto
| 指标 | 2020 年 7 月 | 2020 年 8 月 | 变化 |
|---|---|---|---|
| 独立访客 | 48,231 | 49,981 | +1,750 (+4%) |
| 总页面浏览量 | 118,980 | 125,599 | +6,619 (+6%) |
| Domain Rating(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 上,因为那里的 ROI 更高。
Is It Keto 唯一值得一提的事情,是我把展示广告从 AdSense 换成了 AdThrive。令人沮丧的是,这次转换耗费的精力远远超出了我的预期。接入过程包含许多琐碎步骤:他们让我填写一份表格,等一周,再让我填写另一份表格,如此循环往复。
最后,我们到了把网站切换到 AdThrive 广告的阶段,结果发现他们的 JavaScript 代码片段无法在 single-page app(SPA,单页应用)上运行,因此在基于 Vue 的 Is It Keto 代码上表现异常。我理解他们的客户可能大多使用 WordPress 网站,但……拜托!2020 年了,SPA 不该还算是什么意外情况吧。
这又打开了一罐全新的麻烦,因为 AdThrive 不断把有问题、拼凑式的 JavaScript 发给我,声称这些代码能让 AdThrive 和我的网站顺利配合。我运行后告诉他们不能用,他们就再发来一段以另一种方式出问题的 JavaScript 代码。
最后,我说服他们把代码托管在他们那边,让我退出调试环节。我不太喜欢他们在感觉测试不充分的情况下就把代码推向生产环境,但目前我没有精力去操心这件事。
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 是一个简单的临时解决方案。
- 发布了一篇新的博客文章:“How I Collected a Debt from an Unscrupulous Merchant(《我是如何从一个无良商家那里追回欠款的》)”
- 以及两篇新的读书报告。
经验教训
- 更早地与电气工程专家合作。
- 现在回头看,我当时已经偏离 Raspberry Pi 的主流使用方式太远,应该请专业电气工程师来审查我的计划。
- 遇到棘手的问题时,创建能够消除调试工作的工具。
- 创建工具会让你感到自己在持续取得进展,也能释放大脑,让你专注于问题的关键。
下个月的目标
- 销售 60 套 TinyPilot 套件和电源连接器。
- 测试三个新的营销渠道。
- 采访七名 IT 专业人士,了解他们是否会在工作中使用 TinyPilot。
随机一篇博客