一根横梁在转,一个滑块在横梁上进退。两个动作合起来,就能把一条数学公式,慢慢画成一个真实存在的图形。手机上选一条曲线,它就开始画。
下面每一条都是现场算出来的,不是图片。点任意一个图案,看它一笔一笔画出来——这就是机器实际走的路线。
手机上换一条曲线,发过去的只是十几个字节的几个数字。同一台机器、同一段程序,画出完全不同的图案。
笔尖每秒只走 8 毫米。一条五叶玫瑰线要画两分半,一只蝴蝶曲线要二十分钟。它不是打印机,是让你看着它长出来。
换个笔头就换一种画法:紫外光在余辉板上留痕、球头针在细沙里犁沟、真笔在纸上画。同时手机里也存着一份。
一根横梁绕中心转,一个滑块在横梁上前后走。就这两个动作,能把笔尖送到圆盘内任何一个位置。
笔尖做成磁吸快换,换个头就换一种画法。同一条曲线,在三种介质上是三种完全不同的东西。
画完一个图案要换下一个,笔必须先抬起来再移动,否则会在纸上拖出一条难看的连线。
滑块上装一个微型推挽电磁铁,行程 2 毫米。通电压下、断电弹起——断电时笔是抬起的,所以哪怕中途没电,笔也不会一直压在纸上洇出一个墨点。
笔尖要发光、电磁铁要通电,可横梁一直在转——转动的东西怎么供电?
传统做法是滑环(碳刷蹭着铜环导电),但那是全机唯一会磨损的零件,几年就要换。
改用一对同轴线圈隔空送电:一个固定在底座、一个跟着转盘转,中间不接触,靠电磁感应传 5V / 2W。就是手机无线充电那套东西,成熟、便宜、永远不会磨坏。
这是个摆件,会一天到晚一直画。纸会画满,沙会画乱,都需要人来收拾——那它就变成一个需要伺候的东西了。
长余辉板的痕迹会在一两分钟内自己淡掉,永远有新的在长出来、旧的在消失,不需要任何人管。想要一张能拿在手里的作品时,再换上纸笔头画一张。
想象一根钟表指针,但它是贯穿中心的一整根,上面串着一颗能前后滑的珠子。指针转到哪、珠子滑多远,就决定了珠子在桌面上的位置。
玫瑰线的公式 r = cos(kθ) 里那个 r,会变成负数。负数的意思是「往反方向走」。
一条五叶玫瑰线画完要过中心 5 次,一条蝴蝶曲线要 74 次。所以「贯穿」不是为了好看,是必须。
难点在这:横梁一直在转,怎么给转动的东西供电?答案是不供电——让内轴和外管转得不一样快,这个「差」就是滑块走的距离。
从传动选型到控制程序,几个关键决定和它们背后的算账。
丝杆看起来更「精密」,但一算转速就出局了:滑块最快要跑 36.7 mm/s,换成常见的丝杆意味着电机得转到 1100 转,那个转速下步进电机的力气基本掉光了。
很自然会想「把每个图案的坐标点都存进去」。但一只蝴蝶画下来有 9 万多个点,存成数据是 37 KB;存成公式只要 16 个字节。
| 存坐标点 | 存公式 | |
|---|---|---|
| 一只蝴蝶 | 37 KB | 16 字节 |
| 20 个图案 | 740 KB 要外挂存储芯片 | < 1 KB 芯片自带的就够 |
| 手机换图案 | 传几十 KB | 传 16 字节 |
| 手机走开后 | 要传完才能画 | 照画不误 |
机器每秒问自己 200 次同样的三个问题:横梁现在转到哪了?按公式滑块该在哪?那电机该转到哪?
// 每 5 毫秒执行一次 void on_tick(void) { theta += THETA_STEP; // ① 横梁匀速转,自己记着转了多少 float rho = curve_eval(&cur, theta); // ② 代公式,算出滑块该在哪 float target = theta + rho / 62.8f * 360.f; // ③ 换算成电机2该转到的角度 stepper_goto(MOTOR_INNER, target); stepper_step(MOTOR_OUTER); }
第 ③ 行里那个 theta 千万不能漏。滑块的位置是靠「内轴比外管多转了多少」决定的,横梁自己转的那部分必须先加回去,否则横梁一转滑块就乱跑。这是整个程序唯一容易写错的地方。
typedef struct { uint8_t type; // 哪一类:玫瑰线/蝴蝶/心形… float a, k, phase; // 三个参数 float turns; // 转几圈才画完 } curve_t; // 一共 16 字节
手机上选「玫瑰线 k=5」,蓝牙发过去的就是 {0, 110, 5, 0, 0.5} 这么几个数。想要七叶?把那个 5 改成 7 就行——同一台机器,同一段程序。
横梁的角度不需要去「读」——它是步进电机一步一步走出来的,走了多少步芯片自己一清二楚。全机只要两个一块钱的霍尔开关:一个装在转盘上,每转一圈校对一次;一个装在横梁一端,开机时让滑块回零。低速轻载下电机几乎不会走丢,这两个开关纯粹是买个保险。