1. 项目概述:当机械臂遇见流沙

几年前,我在一个艺术展上第一次看到动态沙画装置,一个金属球在沙面上缓缓移动,留下复杂而短暂的轨迹,那种数字与物理、秩序与混沌的结合瞬间吸引了我。当时我就想,能不能自己做一个?市面上有成品,但价格不菲,且封闭的系统让你无法自定义图案,失去了“创作”的灵魂。于是,这个用Arduino DIY一个沙画桌的想法就种下了。它本质上是一个二轴的数控(CNC)平台,只不过把雕刻刀换成了一个磁力球,把木板换成了细沙。

这个项目的核心价值在于,它完美地融合了硬件搭建、软件编程和艺术设计。你不仅是在组装一台机器,更是在创造一个能够表达动态美的工具。它适合所有对创客、互动艺术或自动化感兴趣的朋友,无论你是想给孩子做一个有趣的科学玩具,还是为自己工作室添置一个引人驻足的装置,亦或是深入学习步进电机控制与G-code解析的实战项目,它都能满足。整个过程,从切割木板、组装直线滑轨,到调试电机、编写转换脚本,每一步都充满了动手的乐趣和解决问题的成就感。最终,当看到自己设计的图案第一次在沙面上完美呈现时,那种满足感是无与伦比的。

2. 核心硬件选型与设计思路拆解

2.1 为什么是Arduino Uno + CNC Shield V3?

选择Arduino Uno作为主控,几乎是所有入门级数控项目的首选。原因很简单:生态成熟、资料海量、成本低廉。对于沙画桌这种不需要复杂图形处理或高速运算的应用,Uno的ATmega328P处理器性能完全足够。它的核心任务是接收运动指令(G-code),并计算出两个步进电机每一步的脉冲时序。

但直接驱动步进电机,Uno的IO口电流和驱动能力都不够,这就需要一块驱动板。这里选择了专业的CNC Shield V3扩展板。这块板子堪称“神器”,它直接插在Uno上,提供了最多4个步进电机驱动器的插槽(我们只用其中两个),并集成了限位开关、冷却风扇、主轴控制(这里用不上)的接口。更重要的是,它规范了接线,将混乱的杜邦线连接变成了整洁的模块化组装,极大提高了可靠性和美观度。你不需要再为如何连接电机、如何分配引脚而头疼,只需要按照标识插好即可。

2.2 运动系统的关键:步进电机、驱动器与传动

运动精度和流畅度直接决定了沙画图案的质量。这里选用了17HS4023两相步进电机,这是一个42步进电机,扭矩适中(大约0.4N·m),对于推动磁力滑块在沙面运动来说绰绰有余。步进电机的优势在于它可以进行精确的“步进”控制,配合微步进驱动器,可以实现远高于其基本步距角(通常1.8度)的分辨率,让运动更加平滑。

驱动器的选择是项目的亮点之一:TMC2209。这是一款带有静音驱动技术的步进电机驱动器。普通的A4988或DRV8825驱动器在运行时,电机通常会发出高频的“嘶嘶”声,在安静的室内相当恼人。TMC2209通过SpreadCycle和StealthChop2等专利技术,可以极大地降低电机运行噪音,实现近乎静音的运动,这对于一个放在客厅或工作室的艺术装置至关重要。同时,它支持最高256微步,让运动曲线极其平滑。

传动方面,采用了经典的“CoreXY”结构变体(从描述中的“H configuration”皮带推断)。这种结构并非简单的X、Y轴独立运动,而是通过两条皮带的协同作用来控制末端执行器(磁力球)的位置。它的优点是将电机都固定在了机架底部,减少了运动部件的质量,理论上可以获得更高的运动速度和加速度。我们使用GT2-6MM同步带和配套齿轮,这种带子齿形准确,传动几乎无滑差,是桌面级CNC的标配。

2.3 结构框架与磁力耦合设计

框架使用了MGN12H线性滑轨。这种滑轨属于微型滚珠直线导轨,相较于普通的光轴+直线轴承的方案,它具有更高的刚性、更顺滑的运动和更小的间隙,能有效避免图案绘制时的抖动和回差。600mm和550mm的长度决定了沙画区域的有效尺寸。

最巧妙的设计在于“磁力耦合”绘图头。绘图头本身(带着磁力球)并不直接安装在皮带上,而是通过一个装有N52强磁铁的滑块,在另一根独立的滑轨(主滑块导轨)上运动。而在沙盘底部,另一个磁铁与它上下隔板相吸。这样,当顶部的磁铁滑块被皮带驱动时,底部的磁铁就会同步移动,带动磁力球在沙面划出痕迹。这种非接触式传动,完全避免了机械结构侵入沙箱,保证了沙面的纯净,也简化了结构。

注意: N52是钕铁硼磁铁的一种牌号,表示其磁能积。数字越大磁性越强。15mm直径的N52磁铁吸力已经非常强,操作时要小心防止夹伤手指或突然吸合损坏部件。建议在组装时,先用纸板或塑料片隔开上下磁铁,对齐位置后再缓慢抽离。

3. 机械结构组装与核心要点

3.1 木制结构件的加工与准备

原作者使用了3mm的木板进行激光切割。这是快速获得高精度结构件的好方法。文件格式提供了 .dxf .skp (SketchUp)。如果你没有激光切割机,可以选择:

  1. 在线激光切割服务 :将设计文件上传至相关平台,选择材料(椴木板、亚克力等)并付费,几天后就能收到成品。
  2. 3D打印 :使用PLA或PETG材料打印各个连接件。但需要注意3mm木板的强度和刚性通常优于3D打印的薄壁件,可能需要增加厚度或添加加强筋。
  3. 手工制作 :如果有较强的动手能力,可以用手锯、线锯配合台钻,参照图纸尺寸在木板上画出轮廓进行切割和打孔。这需要极大的耐心和精度。

核心结构件主要包括:电机座、皮带张紧器、滑轨安装座、轴承座(用于支撑5mm光杆作为从动轮轴)以及那个关键的、用于安装顶部磁铁滑块的“笔架”。在切割或打印后,建议对所有木制件的孔位进行试装配,确保螺丝和光杆能够顺利穿过。

3.2 直线运动系统的精密组装

组装顺序和精度是成败的关键。建议遵循以下流程:

  1. 安装底座板 :将作为整个运动系统底座的大板(激光切割件)平整固定。确保它绝对水平,任何扭曲都会在后续被放大。
  2. 固定长边滑轨 :先将两根MGN12H滑轨的滑块暂时拆下。把滑轨本体用螺丝固定在底座板的长边预设位置上。 这里有个关键技巧 :不要一次性拧紧所有螺丝。先轻轻带上所有螺丝,然后用一根已知平直的长铝型材或高精度直尺,同时靠住两根滑轨的侧面,调整它们直至完全平行且共面,再逐步交叉拧紧螺丝。平行度误差是导致运动卡顿、异响甚至失步的主要原因。
  3. 安装电机与短边滑轨 :将步进电机安装到电机座上,并固定到底座板一端。短边的滑轨(550mm)需要与长边滑轨垂直。使用直角尺或利用“3-4-5”勾股定理法(在相交处量取300mm、400mm,对角线应为500mm)来校准垂直度。
  4. 搭建CoreXY皮带系统 :这是组装中最需要理解的一步。按照“H”形或“CoreXY”的走线图,将GT2皮带绕过电机轮、惰轮和滑块上的皮带夹。 务必保持所有皮带轮所在的平面平行 ,否则皮带会跑偏磨损。安装完后,用手推动滑块,感受阻力是否均匀、有无卡点。然后使用皮带张紧器调整张力——皮带不能太松(会打滑、产生回差),也不能太松(增加电机负载、产生噪音)。以手指按压皮带中部,能有轻微弹性(约2-3mm位移)为佳。

3.3 磁力绘图头的安装与校准

  1. 安装顶部磁铁滑块 :将N52磁铁嵌入激光切割的滑块中,并用胶水或螺丝从背面固定。然后将这个滑块安装到那根独立的“主滑块导轨”上。
  2. 连接皮带 :将这个顶部滑块与CoreXY系统的运动部分(通常是两个滑块的连接块)进行刚性连接。这样,CoreXY系统就驱动着顶部磁铁滑块运动。
  3. 安装底部磁铁与绘图球 :在沙盘底板的对应位置,安装另一组N52磁铁。然后在沙盘表面放置一个直径稍大的金属球(如不锈钢球或包裹了金属壳的球),这个球会被底部的磁铁吸住。
  4. 间隙校准 :这是魔法发生的地方。调整沙盘底板的高度(通过垫片或可调支脚),使底部磁铁与顶部磁铁之间的距离恰到好处。距离太近,吸力过大,运动阻力激增,电机可能失步;距离太远,吸力不足,底部的球可能无法被可靠带动,甚至脱落。 实操心得 :理想的间隙是让底部磁铁刚好能牢牢吸住金属球并使其悬空,但当你用手推动顶部滑块时,又能相对顺畅地移动。可以通过在沙盘底部撒一层薄沙,让球在上面运动,观察划痕是否连续来判断耦合是否可靠。

4. 电路连接与固件烧录详解

4.1 电子元件接线全指南

接线遵循CNC Shield V3的标准定义,这大大简化了工作:

  1. 安装驱动器 :将两个TMC2209步进电机驱动器分别插入CNC Shield的X轴和Y轴插槽(通常标记为X和Y)。 注意方向 ,板子上的缺口标记要对准插槽上的标记。插入前,确保驱动板上的微步进设置跳线帽已根据你的需要插好。对于平滑度要求高的沙画桌,建议设置为16或32微步。
  2. 连接电机 :将两个17HS4023步进电机的4根线(通常为A+, A-, B+, B-)接入对应驱动器旁的接线端子。接线顺序错误会导致电机抖动不转或力矩变小。如果电机转向错误,可以通过交换同一相(如A+和A-)的两根线来解决。
  3. 连接限位开关 :限位开关用于机器的“归零”(Homing)。它告诉机器物理边界在哪里。将两个限位开关(常开型)分别接到CNC Shield上标有X-Limit和Y-Limit的端口。通常,开关一端接信号针,另一端接GND。当滑块触碰到开关,信号针与GND接通,Arduino便知道到达了极限位置。
  4. 供电 :将12V 3A的直流电源接入CNC Shield的电源输入端子, 务必注意正负极 。同时,用一根USB线连接Arduino Uno和电脑,用于供电和编程。在调试阶段,可以只接USB供电,但驱动电机时务必接上12V电源,否则电流不足。

重要安全提示 :在接插任何线缆,尤其是电源线时,请确保电源是关闭的。先接好所有信号线,最后再连接主电源。TMC2209等驱动器对静电敏感,拿取时尽量避免触碰芯片引脚。

4.2 Arduino固件解析与配置

项目提供的 sandTable.ino 代码是这个沙画桌的大脑。它主要做了以下几件事:

  1. 初始化与引脚定义 :引入了 AccelStepper 这个强大的步进电机控制库,它支持加速度控制,让运动启停更平滑,避免“起步冲、停车抖”。代码中定义了与CNC Shield对应的电机控制引脚。
  2. 运动参数设置
    • maxSpeed :电机最大速度(步/秒)。太高会导致失步,太低影响绘图效率。需要根据你的机械结构和皮带张力实测调整。
    • acceleration :加速度(步/秒²)。合理的加速度能使运动更柔和。
    • width height :定义沙画区域的实际尺寸(单位:步数)。 这是你必须修改的关键参数! 它需要根据你实际组装的有效行程,结合电机的步距角、微步数、皮带轮齿数计算得出。例如,如果电机每转200步,设置32微步,主动轮20齿,GT2皮带齿距2mm,那么电机每步对应的直线移动距离为 2mm / (200 * 32) * 20 ≈ 0.00625mm 。如果你的有效行程是300mm,那么对应的 width height 就是 300 / 0.00625 = 48000步 。代码中的初始值需要替换为你计算出的值。
  3. 归零(Homing)流程 :上电后,机器会先执行归零操作。电机会以较慢速度向限位开关方向移动,一旦触发限位开关,便停止并记录该点为坐标原点(0,0)。这确保了每次开机绘图都从同一个基准点开始。
  4. G-code解析与执行 :代码的核心是一个简单的G-code解释器。它通过串口监听来自电脑的指令,主要识别 G0 (快速移动)和 G1 (线性插补移动)命令,后面跟着X、Y坐标值。解析后,调用 AccelStepper 库的函数驱动电机移动到目标位置。

烧录步骤

  1. 在Arduino IDE中安装 AccelStepper 库(工具 -> 管理库 -> 搜索安装)。
  2. 用USB线连接Uno,选择正确的板卡型号和端口。
  3. 打开 sandTable.ino 文件,根据你的机器参数修改 width height maxSpeed 等。
  4. 点击上传。上传成功后,打开串口监视器,可以看到机器启动并开始归零。

5. 从图案设计到G-code生成的工作流

5.1 利用Sandify.org进行可视化设计

要让机器动起来,我们需要告诉它运动的路径,这就是G-code。但直接编写G-code过于枯燥。这里引入了Sandify.org这个强大的在线工具。它专为沙画机、粉笔绘图机等设计,内置了海量的几何图案、利萨如图形、螺旋、波浪等生成器。

操作流程非常简单:

  1. 访问Sandify.org网站。
  2. 在“Machine”设置中,输入你机器的实际绘图区域尺寸(单位毫米,例如300mm x 300mm)。这确保了生成的图案不会超出边界。
  3. 在“Pattern”中选择你喜欢的图案类型,并调整参数(如大小、复杂度、循环次数)。
  4. 实时预览图案效果。
  5. 设计满意后,点击“Export”导出G-code文件(.nc或.gcode格式)。

Sandify的优势在于它能生成连续、不间断的路径,这对于沙画来说非常重要,可以避免笔触(磁力球)频繁抬起放下造成的图案不连贯。

5.2 Python转换脚本:桥梁的作用

Sandify导出的G-code是标准的数控代码,但我们的Arduino代码是一个经过简化的解释器,它可能无法处理原始G-code中的所有注释行、复杂循环(G2/G3圆弧)或特定的格式。因此,需要一个“转换器”来净化并适配代码。

项目提供的 converter.py 脚本就是这个桥梁。它的核心任务通常包括:

  1. 读取原始G-code文件
  2. 过滤无用信息 :删除所有注释(以 ; () 开头的行)、删除非G0/G1的命令(如设置单位、选择平面等)。
  3. 坐标缩放与偏移 :根据你的机器实际步数/mm的比例,将G-code中的毫米坐标转换为Arduino程序能理解的步数坐标。有时还需要进行原点偏移。
  4. 优化路径 :可能添加必要的抬笔( M03 S0 模拟)、落笔( M03 S1000 模拟)命令,虽然沙画机是始终接触的,但这里可能用其他代码控制绘图状态。或者将连续的微小线段合并,减少串口通信压力。
  5. 输出简化指令 :生成一个只包含精简移动命令(如 G1 X12345 Y5678 )的文本,甚至直接转换成Arduino代码中所需的数组格式。

运行脚本 :你需要在电脑上安装Python。将 sandify.org 导出的.gcode文件和 converter.py 放在同一目录下。打开命令行(终端),进入该目录,运行类似 python converter.py input.gcode output.txt 的命令。得到的 output.txt 就是可以被Arduino程序读取的最终路径文件。

5.3 数据传输与图案绘制

如何把生成的路径数据送给Arduino呢?这里有几种常见方案:

  1. 串口直接发送(调试用) :打开Arduino IDE的串口监视器,将 output.txt 的内容复制粘贴进去。Arduino程序会逐行读取并执行。这种方式简单,但每次重启都需要重新发送,适合调试单个图案。
  2. 集成到Arduino程序中(推荐) :将 output.txt 中的坐标数据,以数组的形式直接硬编码到 sandTable.ino 程序中。例如,定义一个 const long PROGMEM path[][2] = {...}; 的数组。这样做的好处是脱机运行,无需连接电脑。缺点是图案大小受限于Arduino的闪存(Flash)容量。Uno的32KB闪存可以存储相当复杂的图案了。
  3. 使用SD卡模块(进阶) :这是评论中有人提到的优化方向。给Arduino加上一个SD卡读写模块,将多个G-code文件保存在SD卡中。通过添加几个按钮和一个显示屏,就可以实现图案选择、开始/暂停等交互功能,让装置完全独立且易用。这需要额外编写菜单和文件读取代码。

6. 调试、优化与问题排查实录

6.1 机械与运动调试

  • 问题:电机不动或只振动。

    • 排查 :首先听声音。如果是有节奏的“咔哒”声但不转,通常是相序接错。交换电机同一相的两根线试试。如果是无声或轻微振动,检查驱动器供电(12V是否接入)、使能信号(EN引脚是否被正确拉高或拉低)。用万用表测量电机接线端是否有电压变化。
    • 解决 :核对电机线序,参考驱动器手册确认接线;检查CNC Shield与Arduino的插接是否牢固;确认代码中电机引脚定义正确。
  • 问题:运动过程中失步(图案错位)。

    • 排查 :这是最常见的问题。表现为画出来的圆不闭合、直线歪斜。原因可能是机械阻力过大、电机速度/加速度设置过高、电源功率不足或皮带打滑。
    • 解决
      1. 机械检查 :手动推动滑块,感受全程阻力是否均匀。重点检查滑轨是否平行、皮带张力是否适中、所有轴承和轮子转动是否顺畅。
      2. 参数调整 :在代码中逐步降低 maxSpeed acceleration ,直到不失步为止,再慢慢向上调优。
      3. 电源检查 :确保12V 3A电源质量可靠。在电机启动瞬间,电流需求很大,劣质电源会导致电压骤降,驱动器复位。可以用万用表监测电机运动时的电源电压。
      4. 驱动器电流 :TMC2209需要通过板上的电位器或UART设置电机电流。电流太小则扭矩不足易失步,太大会导致电机和驱动器过热。参考电机规格书,将电流设置为额定电流的70%-80%进行调试。
  • 问题:运行噪音过大。

    • 排查 :如果使用了TMC2209还噪音大,可能是驱动器未工作在静音模式(StealthChop)。
    • 解决 :检查TMC2209的跳线设置,确保其模式正确。也可以通过焊接连接其UART引脚,用TMC的配置软件(如 tmc-uart-helper )精细调整静音相关参数。

6.2 软件与坐标系统调试

  • 问题:图案尺寸不对或变形。

    • 排查 :根本原因是物理移动距离与代码计算的步数不匹配。
    • 解决 :重新校准“步数/mm”这个核心参数。在代码中编写一个简单程序,让X轴移动100mm(用卡尺精确测量),记录下代码中发送的步数。计算: steps_per_mm = 发送的总步数 / 100.0 。然后用这个值去更新代码中所有的相关计算,并重新生成G-code。
  • 问题:归零后原点位置不对。

    • 排查 :限位开关安装位置不合适,或者归零方向错误。
    • 解决 :在代码中,归零通常是让电机向负方向运动直到触发限位开关。触发后,机器会认为这个点是0。如果你的图案总是偏在一边,可以尝试在触发限位开关后,让电机再反向移动一个固定距离(如10mm),将这个点作为实际的绘图原点(0,0)。这可以通过修改归零后的代码逻辑实现。
  • 问题:从Sandify到最终绘图,图案旋转或镜像了。

    • 排查 :CoreXY结构的运动学决定了X电机和Y电机对末端执行器移动的贡献是耦合的。如果电机的安装方向或皮带的绕线方向与代码中的运动学模型不匹配,就会产生旋转或镜像。
    • 解决 :这是一个系统性的调试。可以先让代码只驱动一个电机(如注释掉Y电机相关动作),看滑块是否只沿X轴移动。如果不是,检查皮带连接和电机转向。通过单独测试和组合测试,配合修改代码中电机运动方向的正负号(例如,将 motorX.setPinsInverted(true, false, false) 中的 true 改为 false ),直到机器运动方向与坐标系完全一致。

6.3 沙面效果优化

  • 问题:沙面线条不清晰或断断续续。

    • 原因 :磁力球与沙的相互作用。球太重会陷得太深,移动阻力大;球太轻或磁力不够,可能划痕太浅。沙粒的粗细和湿度也有影响。
    • 优化
      1. 球的选择 :尝试不同材质和重量的球,如空心钢球、实心不锈钢球、玻璃弹珠(内部有金属芯的)。找到阻力与划痕深度的平衡点。
      2. 沙的选择 :推荐使用120目或更细的干燥海沙或石英沙。沙粒太粗图案粗糙,太细(如面粉)容易板结。保持沙的干燥和松散。
      3. 刮平技巧 :每次画完,需要一个刮板将沙面重新刮平。刮板的平整度直接影响下一幅画的基础。可以用一块边缘绝对平直的长木板或亚克力板。
  • 问题:图案边缘有抖动或毛刺。

    • 原因 :机械间隙(背隙)或结构刚性不足。当电机换向时,间隙会导致运动延迟。
    • 优化 :使用软件背隙补偿。在代码中,如果检测到运动方向改变,就额外多发送等于背隙值的步数。这个值需要通过实验测量:命令机器朝一个方向移动一段距离,标记位置;然后反方向移动同一段距离,测量实际返回位置与起点的偏差,这个偏差就是背隙值。

完成所有调试后,你的沙画桌就应该能稳定、安静、精确地绘制出各种美妙的图案了。这个项目最大的乐趣在于,它永远有优化空间:你可以增加Z轴实现提笔落笔,加入LED灯带随音乐变化,甚至接入摄像头让机器实时描绘人的轮廓。它不仅仅是一个作品,更是一个持续学习和创造的平台。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐