Marelleo:我给孩子们做的故事盒子
孩子把玩偶放到盒子上,故事就开始播放,拿下来就停。做它的人此前对电子一窍不通,为了三个孩子从面包板一路做到定制电路板,全靠拆坏东西学会了这一切。
中文
复制


一切始于假期里的一次不爽
去年夏天,和几个朋友、外加一小群孩子一起度假,我偶然看到了 Toniebox。说实话,我觉得这东西很棒。孩子把一个小玩偶放到盒子上,故事就开始播放。拿下来,就停。没有屏幕,没有菜单,也不用喊家长过来。两岁的孩子一秒钟就能上手,这大概已经是易用性的天花板了。
交互手势无可挑剔。商业模式就差得远了。所有这些盒子都是一个套路。硬件卖个还算合理的价格,钱在后面赚,赚在内容上。不管是 Lunii 和它那封闭的曲库,还是 Yoto 和它的卡片包,又或者 Toniebox 和它的玩偶,每一个新故事都得掏钱买,从一个我没得选的曲库里选,装在一个我控制不了的设备上。你买的不是播放器,你买的是一个披着木头玩具外衣的订阅服务。这一点让我很不爽。
与此同时,我多年来一直跟自己说,我想搞搞电子。不是玩票那种,是真正弄懂它。问题是我对此一窍不通。我有一把电烙铁,每三年拿出来一次,焊一下耳机线,从来没做过任何东西。就是那种知道电阻是什么、却从来没亲手挑过一个的人。
这两个念头在开车回家的路上撞到了一起。这就是我的项目了。一个 RFID 读卡器,一个标签,一个盒子,放上什么东西就播放对应的音轨。不是为了做产品。只为了我的孩子,顺便学点东西。
面包板,或者说犯错的权利
我已经知道自己不想要什么。Raspberry Pi 是一台完整的电脑,只为了播一个 MP3,太大、太费电,开机还要二十秒。孩子放下玩偶可不会等二十秒,他们早就跑开去玩了。另一头,那些真正底层的芯片,要用 C 语言配上四百页的数据手册来编程,对一个想当晚就听到故事的初学者来说,门槛高得离谱。
翻资料的时候,我碰到了两样让这个项目成为可能的东西。首先是 ESP32 开发板,一颗内置 WiFi 的微控制器,性能够强,能解码 MP3,又足够简单,可以像 Arduino 那样编程,价格只要几欧元。然后是 面包板,那块布满小孔的板子,元件直接插进去,不用焊任何东西。
这听起来像是个细节,可它却是整个项目成败的关键。在面包板上,弄错不会付出任何代价。拔下来,重新开始,什么都不会损坏。学习的时候,这正是你需要的那种特性。
于是我读文档,和 Claude 反复讨论,在笔记本上画接线图。快得让人有点不敢信,我做出了第一个电路。把标签放上去,它就会播放一段音轨。样子很丑,一块铜线缠成的意大利面,扬声器光秃秃地躺在桌上。但它能用。几个小时,我就有了一个会讲故事的东西。从小到大,我自己亲手做出来的东西,好像还没有哪一件让我这么高兴过。

电位器、烟雾和滑雪蜡的气味
接下来的事就没那么光彩了。为了调音量,我加了一个电位器,就是那个小旋钮,说到底不过是个可变电阻。只不过接错线之后,它什么也调不了了。它变成了一根连接正极和负极的普通导线。这事有个名字,叫短路,而且升温快得吓人。
它冒烟了。还散发出一股非常特别的气味,我琢磨了好一阵才想起是什么,然后猛然认出,是滑雪蜡。烧焦的蜡。现在我一闻就能立刻认出来,而这从来都不是什么好消息。
电池是另一项工程,也是真正让我动脑子的一块。锂电池不是接上两根线就完事的。你需要一个充电控制器,一颗专用芯片,由它决定何时充、怎么充,在合适的时机停止,并在任何蠢事发生之前切断。你还得把它牢牢固定住,因为锂电池在壳体里晃来晃去、被挤压,正是那些没人想看的视频里的经典场景。


然后是一个很蠢的细节。我电池的接头和充电板上的对不上。两个白色小插头长得几乎一样,间距却不同,根本插不进去。于是周二晚上十一点、眼看就要完工的时候,我做了那种时候谁都会做的事,把接头剪掉,把电池直接焊上去。
后果立刻显现,而我事先完全没想到。接头没了,也就没有任何东西可以拔下来,电路里也压根没有开关。整个盒子永远开着。一天二十四小时。一块锂电池草草焊在一个永不关闭的物件上,摆在一间儿童卧室里。这么写出来,已经不需要再多说什么了。
就是从那一刻起,我不再把这件事当小事。害怕谈不上,真正变的是我知道自己手里拿的是什么。它已经超出了桌角小玩意的量级,要住进孩子们的日常生活。这个项目后面的一切,都是从这一点出发的。
从面包板到洞洞板
第一个后果是离开面包板,而这并不只是安全问题。
面包板靠摩擦力固定。每根线都被一个小小的弹簧夹住,拿来试东西再好不过,想长久可靠却是灾难。电路一挪,某个接触就断了,而由此产生的故障比彻底坏掉糟糕得多。它是间歇性的。你在代码里找一个 bug 找了一个半小时,把同一个函数读了二十遍,结果是一根线不再接触了。

接下来是洞洞板,同样是网格孔,但换成印刷电路板,每个元件都焊上去。你失去了犯错的余地,得到的是一块能撑住的电路。我真正学会焊接就是在这个阶段,更重要的是,我明白了维修焊接和制造焊接完全是两回事。维修是重做一个原本存在的焊点。制造是一口气做一百个,个个干净,个个一致,而且心里清楚,第一百零一个才是会出问题的那个。
孩子把旋钮拧到电线扯断
外壳这块我运气很好,François Lagunas 把 3D 打印机借给我,还帮我度过了最初的几次尝试。没有他,我大概还在拿尺子裁纸板。模型我用 Fusion 360 在免费的个人版许可下画,然后打印。

第一版又大又脆弱。质量控制来得比预想中快,形式是三个孩子,分别 21 个月、5 岁和 7 岁。
他们像野兽一样拧旋钮,把它拧坏了。音量旋钮最后转起来没有限位,一圈又一圈,一边转一边把线缠在自己身上,直到把每一根都扯断。我打开盒子,里面是一小窝扭成一团的铜线。我就是在那儿学到了整个项目最重要的一条规则。五岁的孩子不会去转旋钮,他们会把它拧下来。而且遇到阻力时他们不会停手,松了才停。

于是我推倒重来。我用卡尺把每一个尺寸重新量了一遍,一个部件一个部件地量,让每个孔都落在该在的位置,让每个零件都靠塑料本身固定,而不是靠它的线缆。我加厚了壁,加了凹槽,降低了高度。一版又一版,这东西不再像个原型,开始像个正经物件了。
既然原则是任何地方都不能松,我索性把自攻螺丝也弃用了。直接拧进打印出来的塑料,第一次、第二次还行,到第三次材料就沿着层间裂开。孔再也吃不住力,这个零件只能重打。真正的解法叫黄铜嵌件。把它放在孔上,用烙铁头压下去,黄铜升温,把周围的塑料熔化,自己沉进去。冷却之后,零件里就嵌进了一段金属螺纹,拧上拧下一百次都没问题。

接下来是我没法靠任何技术论证替自己通过的唯一一关,我妻子喜欢这个盒子。不是客气地喜欢,她把它放上了客厅的架子,和那些门铃响时你不会收起来的东西摆在一起。这也顺带定下了立方体这个形状,原本我并不确定。一件给孩子的东西,如果不必藏起来,那它最终就会被用起来。
开头那张照片里,这些都还看得见。顶面刻着一个圆,告诉你小玩偶该放在哪儿,因为天线就在正下方;旁边是音量旋钮,播放键,以及前壁上凸起的名字。小玩偶是上了漆的木人,脚底粘着一枚 NFC 贴纸。换成任何东西都行,玩具车、代币、一块扁平的鹅卵石。由孩子决定什么讲什么故事,这正是我想要的。
我不想留下任何悬着的东西
到那一步,我已经有一个相当好用的版本了。但一个用导线连起来的电路,焊得再好,终究还是一个用导线连起来的电路。总有一根线在拽着焊点,总有一个模块靠引脚吊着,总有一个连接器在你晃动时会松。而我刚刚花了几周时间,非常经验主义地测量过我的孩子晃东西的力度有多大。
于是我换了类别,开始设计一块印刷电路板。把散落的一切收拢到一块板上,电源、充电器、功放、SD 卡读卡器、连接器。每个元件各就各位,没有东西晃动,没有东西凸出来。
我用 Claude 把手工电路变成了干净的原理图,分工的有趣之处也正在这里。它读数据手册读得很好,能看出某个引脚需要上拉,能算出一个阻值,会从库里取封装而不是凭记忆画。但它不会布线。布线,也就是在元件之间实际画出每一条铜箔走线、且绝不与另一条交叉,是我在 KiCad 里手工完成的。491 条走线,整晚整晚地以十分之一毫米为单位挪动线条,只为在两个相距零点八毫米的焊盘之间挤进一条连接。

那份文件在发出去之前,必须逐行拿放大镜过一遍,原因很具体。板子不是一块一块订的。最低起订量是五块,一次性生产并贴片。里面错一处,不是修修补补的事,是五块板子进垃圾桶,外加整张账单。
于是我让它把整份原理图从头到尾逐行重读了一遍。它找出了三处我根本不可能发现的问题,每一处都会让这单报废。
下单前拦下的三个错误
那颗会毁掉一切的电阻。 为了给处理器提供 3.3 V,我用了一颗降压转换器,并在它周围放了两颗电阻组成分压。这是设定输出电压的常规做法。问题在于我选的这颗芯片有两个系列,可调输出版本和固定输出版本。我拿的是固定输出的。加上我的分压电路,稳压环路读到的电压会远低于实际值,判定输出太弱,然后继续往上推。算下来,本该是 3.3 V 的电源轨上会出现 13.7 V。WiFi 模块、SD 卡、NFC 读卡器,上电一秒之内全部烧毁。
装反的二极管。 在 KiCad 里,二极管的 1 号焊盘是阴极,而我的文件把它放反了。那个位置的二极管一反向,5 V 就出不来,3.3 V 也就不存在,板子根本起不来。五块板子一次性全哑,而且不实际做出来根本发现不了。
还有那个什么都没检查的检查器。 KiCad 会自动校验走线是否满足最小间距。我那份配置里的最小间距是零。它照常运行,报告零错误,然后对任何东西一律放行,悄无声息。这是最糟糕的一类 bug,那个让你安心的工具。
有一次角色反了过来,让我颇为得意。我抢在它之前发现物料清单里有两个元件缺货。我们把这件事做成了一个小程序,查询厂商的目录,返回每个料号的库存和价格,免得再出现两眼一抹黑的情况。料号不是理所当然的。要在下单当天复核,而不是前一天。
160 欧元的电路板,什么也没发生
我从 JLCPCB 下单,由他们负责制造电路板并完成贴片。160 欧元,我拿到了五块已经组装好的板子,够我留一块,其余的分给表兄弟和朋友。拆开那个包裹,是整个项目里最痛快的时刻之一。绿色的板子,干净利落,元件对齐得严丝合缝,上面印着我的名字。而这一切,都来自我窝在沙发上画出来的一个文件。

第一次上手这个东西,USB 插不进去。工厂在插口下面加了一小条材料,是装配时用来固定电路板的断裂式凸片,到手后需要自己掰掉。在一块三十欧元的板子上徒手掰断它,我得先做一番心理建设。足足犹豫了十分钟。
然后插上电测试。什么反应都没有。NFC 读卡器的 LED 在闪,但识别不到任何玩偶,没有声音,网络上也看不到设备。什么都没有。
我花了十五分钟骂自己是个老糊涂,刚把 160 欧元烧在了没用的板子上,活该。那阵子确实难受。之后我开始排查,按部就班,把线束一根一根拔下来。
问题出在两根线上。我把 NFC 读卡器排线上中间那两根导体接反了,就是走串行链路的那两根。这条链路本来就是交叉的。一端发送的,另一端必须接收。直连的话,两端同时说话,没人听。模块正常上电,LED 欢快地闪着,就是永远不应答。这种故障看着像大问题,其实只是粗心。
最精彩的还在后面。线接好了,还是不行。两个原因叠在一起。第一,程序只在启动时询问读卡器一次,不重启的话,修好了也看不出来。第二,插着 USB 时电源开关根本断不了电,因为它控制的是电池那一路的晶体管,而 USB 走另一条路给板子供电。所以我一直在“重启”一块根本没重启的板子,去测试一个早就修好的问题。
终于把线拔掉再插回去,期待已久的那行字落到了控制台上:
PN532 pret
bibliotheque : 4 figurine(s)
volume : 3 [3-21]
有那么三十秒,我以为还是坏的,因为我什么都听不见。音量旋钮一直拧在最底下,最小。用一天调试换来一个音量问题收尾,倒也算一种诗意的公平。
除此之外,这块板子第一次上电就工作正常,完全不需要返工。 没有一根飞线,没有一条要刮开的走线,也没有一个要换掉的电阻。对于一块由三个月前还不知道封装是什么的人设计的首版板子,我确实没指望能做到这样。
剩下的就是把所有东西装进外壳,这次是永久固定。


“爸爸,这个我们已经听过了”
正是这句话催生了整个软件部分,也把我们带回了起点。一个装着固定曲库的盒子,哪怕曲库是我自己做的,恰恰会变成我想避免的那个问题。内容必须属于我们,而且必须能在没有工具、没有数据线、没有我的情况下更换。
一切都走网页,因为没有屏幕
盒子自己提供页面。在手机或电脑的浏览器里输入它的地址,就能看到玩偶、SD 卡上现有的故事,以及当前正在播放的内容。不用安装,不用更新,不用账号。
第一次开机时,它会自建一个 WiFi 网络。手机连上去,设置页面会自动弹出来,跟酒店里一模一样。盒子对所有域名解析请求都回答自己的地址,手机便不请自来地打开了页面。你从列表里选好家里的网络,输入密码,它连上家里,再把自己的网络关掉。
第一个版本是用蓝牙做的。能用,但需要一个专门的 app,对一个你打算送人的东西来说这说不过去;而且蓝牙协议栈占了 300 KB 内存,相当于芯片全部内存的百分之九,只为了在盒子的一生中用上一次。我毫不犹豫地把它扔了。
你自己的 MP3
你从页面上传文件,文件存进 SD 卡,再把它和某个玩偶关联起来。一个玩偶可以带任意多条音轨,顺序随你排,会一直播到最后一条,不循环。这一下什么都打开了。自己录一段声音,在出门时给孩子讲故事;把他们点名要听的歌放进去循环;从网上找到什么就塞什么。MP3 和 M4A,手机或 Mac 直接导出的两种格式,不用转码。
一个公仔,一个网址,就是一台收音机
一条音轨不一定非得是文件。你可以给玩偶一个网址,盒子连上去,边接收边播放,什么都不存。它建立连接,一小块一小块地接收音频,解码后送给功放,同时始终保留几秒钟的缓冲,用来吸收网络的抖动。连接断了会重试几次才放弃。家里的 WiFi 总有死角,而一个两岁的孩子不该去理解音乐为什么停了。
我孩子的收音机做成了小木人的样子,我看着很满意。
通过 WiFi 自行更新
这部分我最得意,因为它解决的是成品设备特有的问题。盒子已经拧死、组装完毕,摆在客厅里。想修点什么,总不能每两周拆一次。所以它自己获取新版本。
它查询的是一个固定地址,写死在程序里,并且刻意做到无法从网络更改。这是出于安全考虑。一个会接受“去哪里找软件”这种指令的盒子,也会接受被塞进任何东西,同一个 WiFi 下的人就足够了。
如果有更新的版本,页面上会出现一个按钮。它把新版本下载到第二块存储区,也就是当前没在运行的那块,校验收到文件的指纹,确认一切完好才切换过去。所以传输中途断电也不会让它变哑。最坏的情况是以旧版本重启,像什么都没发生过一样。
安全网,以及它本会毫无用处的那一次
剩下的是封闭设备最怕的那种噩梦,某个版本能正常启动,但网络坏了。版本本身有效,盒子切了过去,从此再无修复的途径。于是有了试用期,新装的版本必须证明自己能连上网。连续三次启动都见不到网络,盒子就自行退回上一个版本,甚至在打开无线模块之前就退了。
它确实派上了用场。 我发布过的一个版本会反复打开配网页面,尽管它对家里的网络了如指掌。它读取保存的凭据太早,那时无线模块还没启动,于是断定自己没有凭据。我什么都不用做。三次启动之后它自己退回了上一个版本,我可以从容地修。
同一类错误,还有更好笑的一次。每个盒子都会开一个网络,名字带上硬件地址的后四位,好让同一屋檐下的两个盒子区分开。可我在无线模块启动之前就去读那个地址,那时它返回六个零。全世界每个盒子都会叫 Marelleo-0000。
有一次,网络本可以什么都不做。我的发布脚本只编译了两个硬件变体中的一个,也就是原型。而正式那块板子会收到另一个变体的镜像。音频和 SD 卡的引脚定义是反的,内存在错误的总线上查找,头部还宣称有 16 MB 内存,而那颗芯片只有 8 MB。最糟的是,试用期根本发现不了这个问题,因为 WiFi 本身会工作得完美无缺。它会在自以为健康的状态下又聋又瞎。我们是在按下按钮前一刻才发现的。
最后一个轶事,给觉得这种细节有意思的人。有一天,更新开始失败,而且没有任何错误信息。传输会启动、有进展,然后盒子突然重启,悄无声息。无声的失败其实信息量很大。没有错误,意味着程序没时间写错误,所以它不是停下了,是被打断了。下载任务有 8 KB 栈,我在里面放了一个 4 KB 缓冲区。安全连接的加密握手就没剩下什么了。沉默本身就是线索。
三个孩子,三种我没计划过的用法
这是项目里最好的时刻,而且不在任何规格说明里。他们每个人都把盒子变成了自己的东西,而三种用法没有一种是我当初设想的。
7 岁
她的音乐播放列表放在一个玩偶上,故事放在另一个上,还有讲昆虫的播客。她自己挑,自己要求加内容,自己管理自己的曲库。
5 岁
故事。很多故事,串在同一个玩偶里一直排到最后一轨,反复播放,直到我都能背下来。
21 个月
她的摇篮曲,还有她的幼儿播客,都是直播。谢谢 France Inter 和 Radio Pomme d'Api。
一个玩偶,一个手势,每个人在同一个盒子里都有自己的格子。这正是我一开始想要的东西,而它是通过软件实现的,不是通过某个商品目录。差别一句话就能说清。没人把内容卖给我,也没人能从我这拿走。
我买了一台 3D 打印机,在地下室搭了个工作间
有一个我没预料到的后果,而且跟盒子无关。
我开始严重滥用 François 的好意,因为我每一个外壳都是他的打印机做出来的。更重要的是,这一切我实在太享受了。那些晚上、那些周末、那些完全说不过去的小时,全耗在两毫米的圆角或者一个凹槽的深度上。我决定这不会是我最后一个电子项目,因为我是真心喜欢。于是我买了一台 Bambu Lab A1。
我跟自己说这是一笔有用的开销,不用反复再买的备件、修而不是扔的玩具、定制的收纳。这些都是真的。但它不是理由。
而且我把它装在了客厅里。一台半米宽的机器,会吹风、会震动、能一口气跑十四个小时、散发着热塑料的味道,就摆在 Marceau 学走路的房间正中间。当时我觉得这完全合理。我被毫不含糊地请了出去,而且完全活该。没人会把一台生产设备装在客厅里。

于是我从市电拉了一根网线到地下室,在那儿搭了个打印站。说实话,比我预想的好用。我往沙发上一坐就能发起打印,它在两层楼下的黑暗里自己跑,第二天早上我下去取件。楼上再没有噪音,也闻不到热塑料的味道,客厅还是客厅。第五版外壳就是从那儿出来的,就是开头照片里那个。
想自己做一个的话
需要的东西我都放在一个公开仓库里了:github.com/Zebra-Rodeo/marelleo。
要打印的三个外壳零件、可以直接丢进 JLCPCB 的板子制造文件(连同物料清单和元件位置)、固件源码,还有从零开始的文档,买什么、花多少钱、按什么顺序做、模块版本的引脚定义,以及那些让我搭进去好几个晚上的坑。全部 MIT 许可,随你怎么用。
你可以先从面包板版本做起,一次都不用焊,真上瘾了再订板子。我就是这么走过来的,也推荐这么走。在面包板上犯错不花一分钱。
用法有两种。照着文件原样复刻,得到和我家孩子手里一模一样的盒子。或者把它当起点,换个外壳、换个喇叭、换几个按键,代码改成你喜欢的。这种情况只有一件事要知道,仓库里用大字写着。固件是照着这套具体装配写的,引脚定义就在代码里,挪一根线就得改一行。我特意标出来,因为这种细节最容易让你找一晚上的故障。
你要是做了一个,我很想看看。
Marelleo 这个名字的来历
来自 marelle,法语里的跳房子,就是一只脚踩进格子里往前跳的那个游戏。但主要还是来自 Marceau、Ella 和 Léonie,这个盒子是他们的。
感谢 François Lagunas 提供打印机、给出建议,以及那份耐心。也感谢我的妻子。几个月来,这个项目占满了夜晚和周末,她始终陪伴着我;我还没来得及开口解释,她就已经同意买下那台打印机了。