1. 项目概述
去年夏天,我在工作室捣鼓一台老旧的绘图仪时突然想到:能不能用更简单的硬件实现类似的功能?于是就有了这个基于Arduino的写字机项目。这个看似简单的装置,实际上融合了机械结构设计、电机控制和路径规划等多个技术领域,特别适合想要从纯电子项目转向机电一体化开发的Maker们。
写字机的核心原理是通过两个步进电机控制笔在X/Y轴上的移动,配合舵机实现抬笔/落笔动作。相比市面上的成品绘图仪,DIY方案最大的优势在于完全可控的硬件和软件架构。你可以自由调整机械结构、更换不同类型的笔,甚至扩展激光雕刻模块。我在实际测试中,用这台机器成功完成了从签名到简单插画的各种书写任务,精度足以满足日常创意需求。
2. 硬件设计与选型
2.1 核心组件清单
这个项目的硬件部分可以拆解为运动机构、控制电路和辅助部件三大模块。经过多次迭代测试,我最终确定的配置方案如下:
- 主控板:Arduino Uno R3(兼容板即可)
- 运动机构:
- 42步进电机 ×2(保持扭矩≥0.25N·m)
- A4988驱动模块 ×2
- GT2同步带及配套滑轮
- 直线光轴(8mm直径)及直线轴承
- 笔控机构:
- SG90微型舵机
- 3D打印的笔架(可适配多种笔型)
- 结构框架:
- 2020铝型材搭建的300×300mm工作区域
- 亚克力底板(5mm厚度)
提示:步进电机选型时要特别注意保持扭矩参数。我最初试用的28步进电机在快速移动时会出现丢步现象,更换为42电机后问题解决。
2.2 机械结构设计要点
写字机的机械精度直接决定最终书写质量。在结构设计上有几个关键点需要特别注意:
-
同步带预紧调节:必须保证同步带有适当的张紧力。太松会导致回程间隙,太紧则会增加电机负载。我的经验是在皮带中部施加1kg压力时,下垂量控制在3-5mm为宜。
-
直线轴承安装:光轴与轴承的配合公差很关键。我试过几种国产轴承,最终选择了内径8.02mm的型号配合8mm光轴,既保证顺滑度又不会有明显晃动。
-
笔架减震设计:在笔架与舵机连接处加入硅胶垫片,能有效吸收写字时的微小震动。这个改进让我的笔画稳定性提升了约30%。
3. 电路连接与配置
3.1 接线示意图
整个系统的电路连接相对简单,但有几个易错点需要特别注意:
code复制Arduino Uno → A4988驱动模块 → 步进电机
│ │
│ └── VMOT(12V), GND, 1A/1B, 2A/2B
│
└── 舵机信号线(D9)
关键配置参数:
- 驱动模块VREF电压:0.8V(对应电机电流1A)
- 步进模式:1/16微步(通过驱动模块上的MS1-MS3跳线设置)
- 舵机角度范围:落笔55°,抬笔120°(需根据实际笔架调整)
3.2 电源方案选择
我测试过三种供电方案:
- USB供电(5V) - 电机乏力,仅适合测试
- 12V/2A开关电源 - 能满足基本需求
- 12V/5A工业电源 - 运行最稳定
实测表明,当两个电机同时加速时,瞬时电流可能超过2A。因此推荐使用至少3A的电源,并在每个驱动模块的VMOT端加装1000μF的电解电容来平抑电压波动。
4. 固件开发与优化
4.1 基础运动控制
使用AccelStepper库可以大大简化步进电机控制。以下是核心的运动控制代码框架:
cpp复制#include <AccelStepper.h>
#include <Servo.h>
AccelStepper stepperX(AccelStepper::DRIVER, 2, 3);
AccelStepper stepperY(AccelStepper::DRIVER, 4, 5);
Servo penServo;
void setup() {
stepperX.setMaxSpeed(1000);
stepperX.setAcceleration(500);
// 同理设置Y轴参数
penServo.attach(9);
liftPen(); // 初始状态抬笔
}
void loop() {
// 运动指令示例
moveTo(100, 100); // 移动到(100,100)位置
delay(1000);
}
void moveTo(long x, long y) {
stepperX.moveTo(x);
stepperY.moveTo(y);
while (stepperX.distanceToGo() != 0 || stepperY.distanceToGo() != 0) {
stepperX.run();
stepperY.run();
}
}
4.2 笔迹优化技巧
直接使用直线插补会产生生硬的转角,通过以下改进可以获得更自然的书写效果:
-
速度曲线优化:在转角处降低速度,我使用的算法是在距离目标点5mm时开始减速,公式为:
cpp复制float decelDist = min(5.0, distanceToTarget * 0.3); currentSpeed = maxSpeed * (decelDist / 5.0); -
笔划连接处理:连续书写时,在笔划末端添加0.5mm的过冲补偿,可以有效避免"断笔"现象。
-
舵机动作时机:在移动指令完成前50ms触发舵机动作,利用运动惯性实现更流畅的笔触转换。
5. 上位机软件设计
5.1 图像矢量化处理
我开发了一个简单的Processing脚本,可以将位图转换为写字机可执行的路径:
java复制PImage img = loadImage("input.png");
ArrayList<PVector> path = new ArrayList<PVector>();
void setup() {
img.filter(THRESHOLD, 0.6);
for (int y = 0; y < img.height; y+=2) {
for (int x = 0; x < img.width; x++) {
if (brightness(img.get(x,y)) < 128) {
path.add(new PVector(x*scale, y*scale));
}
}
}
savePathToTXT(path);
}
这个脚本实现了基本的二值化和扫描线转换,对于复杂图像建议使用专业的Inkscape进行手动描边后再导入。
5.2 通信协议设计
通过串口发送的指令格式为:
code复制G1 X100 Y200 F500
M03 S55
M05
其中:
- G1:直线移动指令
- X/Y:目标坐标(步数)
- F:移动速度(步/秒)
- M03:落笔指令(S参数为舵机角度)
- M05:抬笔指令
我在Arduino端实现了一个简单的指令解析器,可以缓存多行指令实现连续书写。
6. 校准与调试
6.1 机械校准步骤
-
归零校准:
- 安装限位开关(我用的是机械微动开关)
- 编写归零程序使机器自动寻找原点
- 记录下开关触发时的步进值作为软限位
-
步距校准:
- 命令机器移动100mm
- 实测实际移动距离
- 计算并调整stepsPerMM参数:
cpp复制float actualDist = 98.5; // 实测值 float newStepsPerMM = currentStepsPerMM * (100 / actualDist);
-
笔压调整:
- 在落笔状态下观察笔尖与纸面的接触情况
- 调整舵机角度使笔尖产生适当压力(我使用5g压力传感器辅助测量)
6.2 常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 笔画不直 | 同步带松动 | 重新张紧皮带 |
| 丢步现象 | 电流不足 | 调整驱动模块VREF电压 |
| 笔触不稳 | 框架刚性不足 | 增加铝型材支撑 |
| 串口通信中断 | 波特率不匹配 | 统一设置为115200 |
| 书写尺寸错误 | 步距参数错误 | 重新校准stepsPerMM |
7. 进阶改进方向
完成基础功能后,我尝试了几种提升方案:
-
Z轴扩展:增加第三个电机控制笔压,实现更精细的笔触控制。这需要改用RAMPS 1.4这类支持多轴的控制板。
-
实时控制:通过蓝牙模块连接手机APP,实现无线控制和图案传输。测试时发现HC-05模块的传输速率足够满足需求。
-
多笔系统:设计可旋转的笔架,配合颜色识别传感器,实现多色书写。这个改进使我的机器可以绘制简单的彩色插画。
-
激光扩展:将笔替换为500mW激光头(需特别注意安全防护),配合GRBL固件升级为激光雕刻机。这个改装需要额外添加激光控制模块和急停开关。
