news 2026/5/30 17:56:00

基于SCARA机械臂的DIY写字钟:从运动学算法到嵌入式实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SCARA机械臂的DIY写字钟:从运动学算法到嵌入式实现

1. 项目概述与核心思路

这个项目,我称之为“会写字的钟”,它本质上是一个融合了嵌入式控制、运动学算法和一点机械创意的桌面艺术品。它没有传统的指针或数字显示屏,而是通过一支马克笔,在白色书写板上“一笔一划”地写出当前的时间,每分钟自动更新一次,并用一个简单的擦除动作清空旧的时间。整个系统的核心,是借鉴了工业上常见的SCARA(Selective Compliance Assembly Robot Arm,选择顺应性装配机器人手臂)机械臂的运动原理,用三个廉价的9g舵机(伺服电机)实现了平面内的两轴定位和垂直方向的抬笔/落笔动作。

为什么选择SCARA结构?在DIY项目中,我们常常面临如何在有限预算和复杂度下实现精确平面运动的问题。SCARA结构以其在平面内的高刚性和相对简单的运动学正反解(即从坐标到舵机角度的换算)而著称。它由两个旋转关节(对应我们的两个主舵机)和一个末端垂直移动关节(对应我们的抬笔舵机)组成,非常适合这种在固定平面上进行书写作业的场景。与更常见的笛卡尔坐标(X-Y轴)直线运动平台相比,SCARA结构在相同的运动范围内,所需的物理空间更小,结构更紧凑,视觉上也更具机械美感。

整个项目的逻辑链条非常清晰:一块Arduino Nano作为大脑,从DS1307 RTC(实时时钟)模块读取精确的时间信息;然后,大脑根据预设的字体和坐标,计算出笔尖需要到达的每一个点的位置(X, Y坐标);接着,通过运动学反解算法,将这些坐标转换为两个主舵机需要转动的角度;最后,通过PWM信号驱动舵机转动,带动机械臂,控制笔尖完成书写和擦除动作。这个项目最难能可贵的是,它把一个看似复杂的机器人学问题,用不到100元的硬件成本和一段开源的代码就实现了,非常适合作为学习嵌入式系统、运动控制和机电一体化的入门实践。

2. 硬件选型与物料清单解析

工欲善其事,必先利其器。这个项目的硬件选择充分体现了“在满足功能的前提下追求极致性价比”的DIY精神。下面我们来逐一拆解每个核心部件的选型理由和注意事项。

2.1 控制核心:Arduino Nano

选择Arduino Nano而非更常见的Uno,主要基于两点考虑:尺寸成本。Nano在功能上与Uno几乎完全一致(同样基于ATmega328P芯片),但体积小巧得多,非常适合嵌入到这种结构紧凑的装置内部。其数字I/O口数量(22个)和PWM输出能力(6个)完全满足驱动3个舵机和连接RTC模块(I2C接口)的需求。

注意:市面上有大量国产兼容的Nano板,价格低廉,但需注意其USB转串口芯片可能是CH340,需要在电脑上额外安装CH340驱动才能被Arduino IDE识别。购买时最好选择明确标注“CH340驱动已安装”或自带CP2102等免驱芯片的版本,避免第一步就卡在驱动上。

2.2 时间基准:DS1307 RTC模块

RTC模块是项目的“心脏”,它保证了时钟在Arduino断电后依然能准确走时。DS1307是一款非常经典且廉价的RTC芯片。它通过一个32.768kHz的晶振提供计时基准,并自带一个涓流充电器,可以为后备电池(通常是一个3V的CR2032纽扣电池)充电,确保时间数据在完全断电的情况下也能保存数月。

这里有一个关键细节:DS1307的计时精度很大程度上取决于其外部晶振的精度。廉价的模块为了成本可能使用精度较差的晶振,日误差可能在数秒甚至更多。如果你对精度有更高要求,可以考虑升级到DS3231模块。DS3231内部集成了温度补偿晶体振荡器(TCXO),其年误差可以控制在分钟级别,远高于DS1307,但价格也稍贵。对于这个书写时钟而言,DS1307的精度已经足够,毕竟我们每分钟才更新一次显示。

2.3 执行机构:9g微型舵机

舵机是这个项目的“肌肉”。我们选择了最常见的9g微型舵机(如SG90或MG90S)。这类舵机内部包含一个小型直流电机、减速齿轮组和一个位置反馈电位器,形成一个闭环控制系统。当我们发送一个特定宽度的PWM脉冲(通常周期20ms,脉宽在0.5ms到2.5ms之间)时,舵机会转动到对应的角度(通常是0-180度)。

为什么是三个?两个用于控制机械臂在平面内的运动(X和Y方向),这构成了SCARA的两个旋转关节。第三个舵机则用于垂直方向的“抬笔”和“落笔”动作。这个“抬笔”舵机的安装和联动机构是机械设计的关键,需要保证笔能被稳定地提起一定高度,避免在移动过程中划伤书写面,同时落笔时又能施加稳定的压力以确保字迹清晰。

实操心得:购买舵机时,尽量选择同一品牌、同一批次的。不同品牌甚至同品牌不同批次的舵机,其中位点(对应1.5ms脉宽的角度)和线性度可能有细微差异。这种差异在校准环节会被放大,导致两个主舵机难以同步,书写轨迹出现扭曲。多买一两个作为备用也是明智之举。

2.4 机械结构材料:塑料板与铝型材

原始项目使用了塑料板作为基板和铝型材作为机械臂。这是一个非常实用的选择:

  • 塑料板(如亚克力或PVC板):易于切割、钻孔,重量轻,绝缘性好,是制作基板和结构件的理想材料。厚度建议在3-5mm,以保证整体刚性。
  • 铝型材(如2020或2040欧标铝型材):质量轻、强度高、表面有标准槽孔,方便使用配套的T型螺母和螺栓进行灵活装配和调节。用它来制作机械臂,既能保证强度,又便于调整舵机的安装位置。

如果手头没有铝型材,也可以用多层激光切割的亚克力板叠加,或者甚至用结实的水条、轻木条来替代,核心是保证连接牢固,臂长与代码中定义的L1L2L3参数严格一致。

完整的物料清单与工具参考表

类别名称规格/型号数量备注
电子部分Arduino NanoATmega328P1兼容版即可
RTC模块DS1307 (带电池座)1建议选择带电池的套装
微型舵机9g (SG90/MG90S)3用于X, Y轴和抬笔
杜邦线公对公、公对母若干连接电路
微型面包板可选1方便调试,最终可焊接
USB数据线Micro USB1为Arduino供电和编程
电源5V/2A直流电源1稳定供电,避免USB供电不足导致舵机抖动
机械部分塑料基板亚克力板,~3mm厚1约20cm x 15cm
铝型材2020或类似,长度按需2-3根制作机械臂
连接件T型螺母、螺栓、舵机盘用于固定舵机和铝型材
书写面板白色白板或光面塑料板1A5大小左右,需光滑
笔具白板笔或记号笔1笔头粗细适中,墨水充足
笔夹自制或3D打印1用于将笔固定在抬笔舵机上
辅助工具电烙铁及焊锡1套最终固定电路
螺丝刀套装1套
热熔胶枪/AB胶1辅助固定
尺子、记号笔1测量和标记
切割工具勾刀(亚克力)、手锯(铝材)1根据材料选择

3. 机械结构设计与组装要点

机械结构的精度直接决定了书写质量。SCARA机械臂的几何关系是固定的,我们必须严格按照代码中定义的参数来构建物理模型。

3.1 关键尺寸参数的理解

在提供的代码开头,定义了以下几个核心尺寸(单位:毫米):

  • #define L1 35:从左侧舵机旋转中心到第一个关节(肘关节)的长度。
  • #define L2 55.1:从第一个关节(肘关节)到笔尖安装点的长度。
  • #define L3 13.2:从笔尖安装点到右侧舵机旋转中心的虚拟连杆长度(这是一个用于运动学计算的参数,在物理上体现为两个主舵机旋转中心的相对位置关系)。
  • #define O1X 22#define O1Y -25:左侧舵机旋转中心在坐标系中的坐标。
  • #define O2X 47#define O2Y -25:右侧舵机旋转中心在坐标系中的坐标。

这里的坐标系原点(0,0)被定义在书写平面的左下角。O1YO2Y为负值,意味着两个舵机的旋转中心位于书写平面下方。这是为了让机械臂有足够的运动空间覆盖整个书写区域。L3这个参数非常重要,它不是一个真实的连杆,而是连接笔尖点和右侧舵机中心的一个“虚拟连杆”,用于简化运动学反解计算。在物理装配时,你需要确保两个舵机旋转中心的水平距离为O2X - O1X = 25mm,垂直距离一致(Y坐标相同)。

3.2 组装步骤与精度控制

  1. 制作基板与安装舵机:在塑料基板上,精确测量并标记出两个主舵机(左、右)的安装位置。这两个位置必须严格对应(O1X, O1Y)(O2X, O2Y),但注意Y坐标是负值,意味着你需要将舵机安装在书写板下方的某个平面上。钻孔并用螺丝牢固固定舵机。舵机轴心的高度需要仔细设计,使得当机械臂水平伸展时,笔尖能刚好接触到书写板表面。

  2. 制作机械臂:根据L1L2的长度切割铝型材。L1连杆的一端通过舵机盘与左侧舵机输出轴固定,另一端与L2连杆通过一个旋转关节(可以用一个螺栓和螺母充当轴,确保转动顺滑但无明显晃动)连接。L2连杆的另一端,就是笔的安装点。

  3. 设计抬笔机构:这是最容易出问题的部分。第三个舵机(抬笔舵机)需要安装在基板上,并通过一个巧妙的连杆或凸轮机构,将旋转运动转换为笔的垂直升降。一种简单有效的设计是:将抬笔舵机竖直安装,在其舵机盘上垂直固定一根短臂,短臂的末端通过一个活动接头(如鱼眼轴承或简单的松配合孔)连接笔夹。当舵机转动时,短臂推动或拉动笔夹,实现抬落笔。关键是要保证笔的升降行程足够(约5-10mm),且运动轨迹尽可能垂直,避免横向晃动。

  4. 整体调试与固定:在初步组装后,不要急于拧死所有螺丝。先手动移动机械臂,检查各个关节的运动范围是否顺畅,有无干涉。特别是笔尖在移动到书写区域四个角落时,是否会与支架或其他部分碰撞。确认无误后,再逐步紧固所有连接。

避坑指南:机械组装最大的敌人是“虚位”或“回差”。在舵机盘与轴的连接、连杆之间的铰接处,如果存在间隙,会导致笔尖的实际位置与计算位置出现误差,书写出的线条会抖动或出现双线。解决方法包括:使用带橡胶垫的舵机盘以增加摩擦力;在铰接处使用带法兰的轴承或添加垫片消除轴向间隙;在所有螺丝连接处使用螺纹胶(如乐泰242)或防松螺母。

4. 电路连接与系统集成

电路部分相对简单,核心是确保电源稳定。舵机在启动和堵转时瞬间电流很大,可能超过1A,如果供电不足会导致Arduino复位或舵机抖动无力。

4.1 接线图与原理

遵循以下连接方式:

  • Arduino Nano 5V -> 所有模块VCC:为RTC模块和三个舵机供电。
  • Arduino Nano GND -> 所有模块GND:共地至关重要。
  • Arduino Nano A4 (SDA) -> DS1307 SDA
  • Arduino Nano A5 (SCL) -> DS1307 SCL:这是I2C通信线,用于读取时间。
  • Arduino Nano D2 -> 抬笔舵机信号线(黄色/橙色线)
  • Arduino Nano D3 -> 左侧舵机信号线
  • Arduino Nano D4 -> 右侧舵机信号线

强烈建议的供电方案:不要仅依赖Arduino Nano的USB口或板上5V稳压器为所有设备供电。最佳实践是使用一个外部的5V/2A以上的直流电源(如手机充电器),其正极(+5V)同时连接到舵机电源的正极Arduino Nano的VIN引脚(如果电源是5V,也可接5V引脚,但要注意不要同时从USB和此引脚供电),负极(GND)连接到所有设备的GND。Arduino Nano则通过USB线仅用于上传程序。这样可以提供充足且稳定的电流,避免因电压跌落引起的问题。

4.2 集成与绝缘处理

在电路焊接或使用面包板调试无误后,可以考虑将元件集成到一块小型PCB或洞洞板上,并用扎带或螺丝固定在基板背面,使整体更整洁。务必注意绝缘,特别是金属螺丝不要短路PCB上的线路。可以用热熔胶或绝缘胶带覆盖裸露的焊点。

5. 核心代码解析与运动学原理

项目的灵魂在于代码。它不仅要读取时间、驱动舵机,更重要的是实现从“目标坐标”到“舵机角度”的转换,即运动学反解。

5.1 运动学反解算法详解

代码中的set_XY(double Tx, double Ty)函数是实现运动学反解的核心。它输入笔尖的目标坐标(Tx, Ty),计算出左右两个舵机需要转动的角度,并转换为PWM脉宽发送出去。

其原理基于平面几何中的余弦定理。我们把机械臂简化成两个三角形:

  1. 左侧三角形:由左侧舵机旋转中心O1、肘关节、笔尖点T构成。已知三边长度:L1(O1到肘关节)、L2(肘关节到T)、c(O1到T的距离,通过坐标计算得出)。利用余弦定理可以求出角a2,进而得到左侧舵机需要转动的总角度(a2 + a1 - π),其中a1是向量O1->T与水平轴的夹角。
  2. 右侧三角形:需要先求出肘关节的位置H。已知L3(笔尖点到右侧舵机中心的虚拟杆长)和角度关系,可以计算出H点坐标。然后,在由右侧舵机中心O2H点和肘关节构成的三角形中,再次应用余弦定理,求出右侧舵机需要转动的角度。

代码中的return_angle函数就是余弦定理的实现:return acos((a*a + c*c - b*b) / (2*a*c));SERVOFAKTORLEFTSERVOFAKTORRIGHT是比例系数,用于将计算出的弧度值转换为舵机所需的微秒数。SERVOLEFTNULLSERVORIGHTNULL则是两个舵机的机械零点偏移量,用于校准。

5.2 主程序逻辑与时间管理

loop()函数中,程序的核心逻辑是每分钟检查一次时间是否变化 (if (last_min != minute()))。如果变化了,则执行以下步骤:

  1. 附着舵机:重新连接舵机信号线(如果之前为了省电而分离了)。
  2. 落笔lift(0)将笔放下。
  3. 书写时间:调用number()函数,依次书写小时、冒号、分钟。number()函数内部通过一系列drawTo()调用,勾勒出数字的笔画。drawTo()函数则将目标点(pX, pY)与上一个点连线,并细分为多个小步,通过多次调用set_XY()实现平滑的直线移动。
  4. 抬笔并移动到擦除器lift(2)将笔抬到最高位置,然后移动到擦除器(代码中固定点(74.2, 47.5))上方,再lift(1)降至擦除高度。
  5. 分离舵机:书写完成后,调用detach()方法断开舵机信号。这是一个非常实用的省电和防抖技巧。舵机在收到信号时会持续用力保持位置,导致发热和耗电。断开信号后,舵机轴会处于松弛状态,可以手动移动(虽然我们的结构不允许),更重要的是停止了电流消耗。

5.3 字体与笔画生成

数字的书写是通过number()函数硬编码实现的。每个数字(0-9以及冒号“:”)都是一系列直线段和圆弧段的组合。例如,数字“0”被定义为一个近似的椭圆,通过bogenGZS()(画顺时针弧)函数完成。bogenUZS()bogenGZS()函数利用参数方程,通过微小角度增量计算圆弧上的点,从而驱动笔尖画出平滑曲线。

这种方法的优点是直接、无需复杂的字体库,缺点是字体是固定的,修改字形比较麻烦。如果你想自定义字体或书写文字,就需要重新设计每个字符的笔画路径坐标。

6. 校准:从理论到现实的桥梁

校准是让这个项目从“能动”到“好用”的最关键一步。代码开头通过#define CALIBRATION宏定义开启了校准模式。在校准模式下,程序不会书写时间,而是反复让机械臂在两个预设点之间移动,这两个点被设计为使得两个舵臂互相垂直。

6.1 校准步骤详解

  1. 上传校准代码:确保代码中#define CALIBRATION一行没有被注释掉,而#define REALTIMECLOCK被注释掉。然后上传代码到Arduino。
  2. 机械调零:给系统上电。两个主舵机会转动,试图让笔尖移动到预设的校准点。此时,你需要松开固定舵机盘的螺丝,手动调整舵机输出轴的位置,使得两个机械臂尽可能地互相垂直(成90度角)。这一步是粗调,目的是让机械的“零位”接近软件的“零位”。
  3. 调整零点偏移量:调整SERVOLEFTNULLSERVORIGHTNULL这两个常量的值。这两个值直接加到计算出的舵机角度上,用于补偿机械安装的误差。通过串口监视器(代码中需启用Serial)观察,或者直接目测机械臂位置,微调这两个值,直到机械臂在移动过程中,在两个校准点都能保持完美的垂直状态。每次修改后需要重新上传代码。
  4. 调整比例因子:如果完成上一步后,机械臂移动90度实际对应的物理位移不准确(例如,代码让它画一个10mm的线,它只画了8mm),则需要调整SERVOFAKTORLEFTSERVOFAKTORRIGHT。增大因子会使舵机对相同坐标变化反应更“剧烈”(移动角度更大)。通常需要反复迭代调整NULL值和FAKTOR值,直到机械臂的运动范围精确覆盖整个书写板,且移动直线平直。
  5. 抬笔高度校准:调整LIFT0(落笔)、LIFT1(中间高度)、LIFT2(最高)这三个值。这些值是直接发送给抬笔舵机的PWM微秒数。通过修改它们,确保:LIFT0时笔尖刚好接触板面并有一定压力;LIFT1时笔尖完全离开板面但不过高;LIFT2是移动到擦除器上方时的高度。

6.2 校准实战技巧

  • 使用激光笔辅助:在笔夹上临时固定一个低功率激光笔,关闭房间灯光,可以在墙上投射出清晰的光点。这样能极其精确地观察笔尖(光点)的实际运动轨迹,比肉眼观察笔尖本身要容易得多。
  • 分步校准:先只连接一个舵机进行校准,调好它的NULL和FAKTOR值,然后再连接第二个,这样能隔离问题。
  • 记录成功参数:一旦校准成功,立即将最终的SERVOFAKTORLEFTSERVOFAKTORRIGHTSERVOLEFTNULLSERVORIGHTNULLLIFT0/1/2值记录下来。这些值是专属于你这套机械结构的“指纹”,换一套材料或重新组装后,都需要重新校准。

7. 常见问题排查与优化建议

即使按照指南操作,你也可能会遇到一些问题。下面是一些常见故障及其解决方法:

现象可能原因排查与解决思路
舵机完全不动或抽搐1. 电源功率不足。
2. 信号线接触不良或接错。
3. 舵机损坏。
1. 使用外接5V/2A以上电源单独为舵机供电。
2. 检查杜邦线连接,确保信号线(黄/橙)接在正确的数字引脚上。
3. 单独测试舵机:用servo.write(90)简单程序测试。
书写笔画扭曲、不圆滑1. 机械结构有较大虚位或松动。
2. 舵机NULL/FAKTOR值校准不准。
3. 两个舵机性能不一致。
1. 紧固所有机械连接,消除间隙。
2. 重新执行精细校准流程,使用激光笔辅助。
3. 尝试交换左右舵机看问题是否跟随舵机转移。
写字断墨或笔迹太浅1. 落笔高度(LIFT0)太高,压力不足。
2. 书写板表面太光滑或不适合该笔。
3. 笔尖磨损或墨水不足。
1. 减小LIFT0值,增加落笔压力。
2. 更换不同材质书写板或使用出墨更流畅的笔(如白板笔)。
3. 更换新笔。
擦除不干净1. 擦除器(通常是海绵或橡皮)位置不准或压力不够。
2. 擦除动作轨迹未完全覆盖字迹。
1. 调整擦除器的安装位置和高度,确保笔经过时能有效接触。
2. 在代码中调整擦除动作的路径坐标,使其来回擦拭。
时间不准或RTC不工作1. DS1307模块电池没电或未安装。
2. I2C接线错误(SDA, SCL接反)。
3. 库文件未正确安装。
1. 检查并更换CR2032电池。
2. 检查A4/A5引脚连接。使用I2C扫描示例程序检查设备地址(DS1307通常是0x68)。
3. 在Arduino IDE中确认已安装DS1307RTCTime库。
运行一段时间后错位1. 舵机因持续受力发热导致性能漂移。
2. 电源电压波动。
1. 确保在非移动时段代码执行了servo.detach()
2. 使用更稳定的线性电源,或在舵机电源端并联一个大电容(如1000uF)缓冲电流冲击。

项目优化方向

  1. 增加Wi-Fi/网络对时:用ESP8266模块替换Arduino Nano,连接网络后通过NTP协议获取精确时间,无需手动设置,也解决了DS1307累积误差问题。
  2. 设计更优雅的机壳:使用3D打印或激光切割,为整个机械结构和电路设计一个美观的外壳,提升成品质感。
  3. 实现更多功能:修改代码,使其不仅能写时间,还能写日期、温度湿度(需加传感器)、甚至简单的图形或短句。
  4. 改进擦除机制:目前的“画线擦除”可能效果不佳。可以改为控制一个额外的舵机带动一块小橡皮或毛刷进行物理擦除。

这个项目最迷人的地方在于,它清晰地展示了软件算法如何驱动硬件实体,去完成一个具象的任务。当你第一次看到自己组装的机械臂颤颤巍巍却准确地写出一个数字时,那种跨越虚拟与现实的成就感,是单纯编程或单纯做手工都无法比拟的。它需要耐心,尤其是校准阶段,可能需要反复调整几十次参数。但一旦调通,它就会成为一个稳定可靠、充满极客趣味的桌面伙伴。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 17:51:27

从零起步,如何打造专属向量引擎 API 中转工作流?

序言 用了快两年的各类API工具和开发框架,最近才真正理解什么叫"选对工具能让工作效率翻倍"。作为一个长期在数据处理和应用开发领域摸爬滚打的技术从业者,我对API调用的稳定性、成本和易用性一直都很挑剔。最近在几个实际项目中接触并深度使用…

作者头像 李华
网站建设 2026/5/30 17:50:03

如何高效构建跨平台流程图工具:draw.io桌面版完整打包指南

如何高效构建跨平台流程图工具:draw.io桌面版完整打包指南 【免费下载链接】drawio-desktop Official electron build of draw.io 项目地址: https://gitcode.com/GitHub_Trending/dr/drawio-desktop 你是否想在Linux系统中离线使用功能强大的流程图工具&…

作者头像 李华
网站建设 2026/5/30 17:49:49

为什么说semi-utils是摄影师的智能批量处理工具?

为什么说semi-utils是摄影师的智能批量处理工具? 【免费下载链接】semi-utils 一个批量添加相机机型和拍摄参数的工具,后续「可能」添加其他功能。 项目地址: https://gitcode.com/gh_mirrors/se/semi-utils 还在为几百张照片一张张手动添加水印而…

作者头像 李华
网站建设 2026/5/30 17:49:45

暗黑破坏神2存档编辑器:5分钟掌握角色自定义与装备管理

暗黑破坏神2存档编辑器:5分钟掌握角色自定义与装备管理 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 想要彻底掌控暗黑破坏神2的单机游戏体验吗?d2s-editor为您提供了一套完整的Web端存档编辑解决方案。…

作者头像 李华