首页 / 资讯中心 / 文章详情

超迷你写字机器人DIY:从悬挂结构到STM32固件全解析

超迷你写字机器人DIY:从悬挂结构到STM32固件全解析 ★ FEATURED ARTICLE
简介超迷你写字机器人完整工程包X-Bot-master面向嵌入式爱好者、机器人竞赛选手及STM32开发者提供从软件算法到硬件设计的全套可复现方案。压缩包共170个文件约10.66MB以C语言源码55个.c、75个.h为核心涵盖步进电机控制、G代码解析、STM32外设驱动等模块另含Keil工程配置uvprojx/uvoptx、电路原理图与PCB设计文件schdoc/pcbdoc及3D结构模型stp便于二次开发与硬件复刻。资源包还附带编译脚本、Hex固件及项目说明文档可直接烧录验证。设计整合了路径规划、运动学算法与电源管理、电机驱动等电路模块展现小型机电一体化系统的完整开发链路。已有57人学习下载适合希望深入理解写字机器人软硬件协同设计的开发者参考。1. 为什么一个超迷你写字机器人值得自己画板、写C固件、搭结构【C】这个标签在创客社区里多半是“原创”或“C语言”的缩写但真正值钱的不是这个字母而是压缩包里同时出现软件、电路、结构这三样东西。超迷你写字机器人说白了就是一台两轴的桌面数控笔绘仪两个步进电机拉着一支笔走XY平面舵机管抬笔落笔于是你的名字、课程表、PCB丝印都能被一笔一画写出来。适合谁做电子、嵌入式新手拿它练C语言、串口协议和步进驱动最合适老玩家可以把它当后续改装平台换激光头或微点胶针就是一台桌面三轴小设备。关键是它从机械装配到固件解析都由自己控制而不是买一套免调试成品。2. 悬挂式结构选型与装配超迷你桌面写字机器人先搭哪根轴2.1 同步带悬挂式、龙门式、并联式为什么我选悬挂式超迷你写字机器人常见的结构有三种但能压缩到A5纸面积、用28mm小步进电机带动的我认为首选悬挂式也就是固定电机在底座后方用两根同步带差速拖动X滑块。这有点像CoreXY布局两根皮带从左右两个固定电机出发绕到X轴滑块上再回到另一个电机通过两个电机的同向/反向转动合成X和Y方向的运动。优点很直接运动平台上只有X滑块、笔架和舵机重量可以控制在50g以内惯性小28步进电机就能获得不错的加速度。龙门式则是整根横梁被两个Y轴电机拖着走负载多了一个横梁小电机起步时会明显“点头”结构也需要更多加强筋。并联式类似小型Delta虽然看着炫但三个臂长、方向、球头都有误差超迷你尺寸下反而容易让笔画变形。我一般建议新手的选型标准是有效书写面积小于A5、电机轴径5mm、同步轮20齿这种情况下悬挂式的性价比最高。如果以后要做A3大篇幅、跑高频激光打标再考虑龙门式。结构选型的核心不是哪种高级而是连电机一起放在弹簧秤上称一下运动部分总重越轻提速空间越大。2.2 一份能直接上机的结构件清单尺寸、轴承、皮带轮参数“超迷你”不代表可以省略精度。我按200mm×210mm的底座给你一套常用规格3D打印件数量大概控制在5件以内底板、两个电机座、X滑块、笔架、舵机支架。部件规格/参数说明直线光轴Ø8mm×300mm2根两根轴间距按120~160mm设计直线轴承LM8UU4个X滑块上2个约束用2个内径8mm活动间隙尽量选POM塑料版本GT2同步带6mm宽两条各400mm齿距2mm带内加凯夫拉线更好GT2同步轮20齿内孔5mm2个电机轴直径5mm缩紧螺丝固定步进电机NEMA1128mm×28mm1.2A/相扭矩约0.15N·m足够悬挂式抬笔舵机SG90或MG90SMG90S金属齿轮更耐冲击底板5mm亚克力或铝板200×210mm铝板更稳亚克力切便宜这里有两个参数比什么都重要同步轮用20齿而不是16齿因为20齿对应电机转一圈走40mm20×2mm配合16细分就是3200步/圈脉冲当量0.0125mm/步写出来的字笔画边缘不会有明显阶梯。另一个是光轴间距不要比打印板宽度大太多超迷你平台宽度120mm就够否则X滑块悬臂太长笔尖会画弧线。2.3 舵机抬笔 vs 电磁铁抬笔写字机器人最小的“第三轴”写字机器人除了XY两轴最关键的其实是有没有可靠的第三轴——抬笔。最常见做法是用舵机抬笔不是步进电机。SG90参数是50Hz PWM占空比范围大概在 2.5%~7% 之间对应摇臂转动角度约 180°。笔架通过一根连杆被舵机摇臂带动落笔时笔尖轻轻压在纸面抬笔时笔尖离开纸面2mm以上就够。电磁铁方案我也试过固定行程8mm的推拉式电磁铁通电瞬间吸合速度很快但力量曲线和弹簧复位很难调笔压忽重忽轻而且电磁铁线圈电阻低的版本电流可能到1A控制板上要多留一路MOS管。对初学者舵机方案明显更稳。舵机PWM的“中位值”要对着笔尖刚好触纸的位置我给自己的调参方法是先用180°扫角测出舵机臂两端角度再取中间偏下10°作为落笔点这样笔尖有自然弹性不会把纸压出沟痕。需要注意的是舵机摇臂和笔架的连接孔位会直接影响“笔压一致性”。连杆长度建议15~25mm太短会放大舵机虚位太长则抬笔时间变慢。抬笔从0到2mm的耗时控制在100ms左右字迹结尾的拖笔现象就会明显减少。2.4 装配顺序与光轴平行度校正用卡尺和垫片代替调平神器结构件打印或切割回来后装配顺序不能乱。我自己的顺序是先固定光轴再装滑块最后装同步带和电机座。这样如果后面发现滑块卡涩不用把整套皮带拆掉返工。先固定光轴时用卡尺两两量光轴两端距离。比如前端距离120.2mm后端距离121.5mm说明两根光轴不平行度超过1.3mm滑块装上后一定会在某一位置憋住。这个误差用打印件自带的螺丝孔很难完全避免处理方式是在光轴支架和底板之间垫0.1mm黄铜垫片或铝箔纸一点一点校准。误差控制在0.3mm以内滑块滑动才顺滑。同步带张紧是一个“玄学但可量化”的点装好后用手指压皮带中段下压量不超过5mm太紧会让电机轴和轴承发热太松则起步时皮带有空回表现是写短横线头尾有延迟。最后装舵机时先把舵机臂摆到水平再连笔架连杆不要把舵机臂拧死留1~2°余量让舵机自己找位置。3. 电路与电源用STM32F103C8T6带两个步进驱动的最小系统3.1 控制板选型为什么用STM32而不是Arduino很多写字机器人的开源固件跑在Arduino上因为人家用C封装好了。但你这个项目标签是“C”而且结构、电路都自己设计我建议主控直接选STM32F103C8T6。理由是72MHz主频四个定时器两个硬件串口还有完整HAL/标准库能纯C写Flash 64KB这样一个几千行的解析器加插补器也就占十几KB。Arduino Nano的优势是上手快但USB转串口芯片占掉一块板面积GPIO也没那么灵活。如果你坚持用Arduino后面引脚表要改成D2/D3/D4/D5这类编号。固件逻辑可以照搬但底层寄存器操作换成digitalWrite会让最高脉冲频率掉不少。我见过有人用Arduino写写字机最高步进频率只能到 4kHz而STM32直接控制GPIO翻转跑到30kHz都没问题。这是超迷你写字机提速的关键。3.2 A4988/DRV8825 的接线表与 16 细分设置步进驱动板我用A4988便宜市场上成熟的模块很多。它需要一路电机电源8~35V和一路逻辑电源3.3/5V。超迷你平台电机小12V供电足够电流限制调到每相0.8A左右。主控引脚功能连接对象PA0X轴STEP脉冲A4988模块STEPPA1X轴方向A4988模块DIRPA2Y轴STEP脉冲A4988模块STEPPA3Y轴方向A4988模块DIRPA5舵机PWM信号SG90信号线PA9UART_TXUSB转TTL的RXPA10UART_RXUSB转TTL的TXA4988板上的MS1/MS2/MS3三个跳线全不接或全接高电平可设1/16微步。如果模块默认接高那就是16细分。这里有个容易踩的小坑不同厂牌的A4988模块跳线默认状态不一样上电前先万用表量一下MS1对GND电压确定是“1”还是“0”再决定下不下跳线帽。16细分下200步/转的电机变成3200步/转声音也小很多。STEP脉冲最小宽度在A4988手册里是1µs实际固件里定时器中断翻转GPIO时先置高、做两次空操作约几十ns、再置低抗干扰差一点的模块也能可靠触发。但DIR电平必须在STEP上升沿前至少5µs稳定所以如果改变方向我习惯先在主循环里设置DIR延时5µs再开始发脉冲。3.3 三路电源12V、5V、3.3V怎么安排才不互相干扰整个系统其实有三路电源12V给电机驱动5V给舵机3.3V给MCU。很多第一次做的人用一个USB口的5V同时喂舵机和逻辑芯片结果舵机一抬笔MCU血线掉到3.0V复位整幅图乱走。我常用的做法是找一个DC5.5接口12V适配器12V先进一个DC-DC降压到5V5V再经AMS1117-3.3给MCU。12V同时给A4988的VMOT。注意A4988模块上的VDD逻辑电源可以接3.3V或5V我接5V因为数字逻辑在5V电平下对噪声容限更高但如果主控是别家的3.3V板子需要先把逻辑电平串电阻再进板。接线顺序是先把所有GND拧在同一个端子再分别接12V、5V、3.3V最后通电。电机电源和MCU电源的地线必须连在一起这叫共地不共地时驱动板不知道MCU输出的STEP电平基准在哪非常容易出现随机丢步。共地以后把电机A/B四条线拧成两对双绞线远离串口线基本就不会有干扰问题。3.4 共地信号线与电机线分开走最容易被忽略的稳定性问题我见过最典型的翻车场景控制板用笔记本USB供电电机用另一个12V适配器供电两个电源的GND没有接在一起。空机测试时电机转得挺好一写字就有一轴突然停住或者整张图对角线方向出现错位。用示波器探STEP引脚发现波形上叠了毛刺负向毛刺都超过2V了。原因是电机回馈噪声通过地环路和信号线耦合到了STEP和DIR线上。解决其实不复杂把驱动板GND、降压模块GND、主控GND接到同一个端子排上信号线尽量短STEP和DIR不要和电机线平行走线。如果机箱是金属底板还可以把GND通过一个100nF瓷片电容接到机箱形成高频泄放路径。这一条不算软件bug但排除它比改代码省时间得多。4. 固件C代码实战串口G代码解析到步进脉冲的四个模块4.1 脉冲当量换算同步轮 20 齿、16 细分下每秒多少步写字机器人固件最先需要确定的是“1mm等于多少个步进脉冲”。超迷你结构用GT2同步带齿距2mm同步轮20齿转一圈走40mm。步进电机步距角1.8°16细分后一圈要 200×16 3200 个脉冲。于是STEPS_PER_MM 3200 / 40 80 步/mm200mm行程对应16000步用int32存坐标绰绰有余。把这个换算用宏定义写在固件顶部后面G代码里的X、Y坐标单位mm都转成步数。#define BELT_PITCH_MM 2.0f /* GT2齿距 */ #define PULLEY_TEETH 20 /* 同步轮齿数 */ #define MOTOR_STEPS 200 /* 步距角1.8°电机 */ #define MICRO_STEP 16 /* 1/16细分 */ #define MM_PER_REV (PULLEY_TEETH * BELT_PITCH_MM) /* 40.0 */ #define STEPS_PER_REV (MOTOR_STEPS * MICRO_STEP) /* 3200 */ #define STEPS_PER_MM (STEPS_PER_REV / MM_PER_REV) /* 80.0 */ static int32_t mm_to_steps(float mm) { return (int32_t)(mm * STEPS_PER_MM 0.5f); }0.5f是为了四舍五入否则浮点转int会直接截断长线段累计误差会偏小。如果你换了同步轮齿数只需要改PULLEY_TEETH整个速度规划和脉冲当量都会跟着变。注意G代码给出的坐标通常是从原点开始固件里要把绝对坐标减去当前坐标得到相对移动量再交给插补器。4.2 Bresenham直线插补用最少的整数运算算 XY 联动写字机的直线运动不能X先走完、Y再走那样笔迹会变成直角折线。正确的做法是让X和Y按各自的步数比例在同一个定时器周期内交替走步。最经典的算法是Bresenham它只用整数加法和比较适合嵌入式中断。typedef struct { int32_t tx, ty; /* 目标坐标步数 */ int32_t x, y; /* 当前坐标步数 */ int32_t dx, dy; int32_t err; int8_t sx, sy; uint8_t active; } motion_t; void motion_start(motion_t *m, int32_t tx, int32_t ty) { m-tx tx; m-ty ty; m-dx (tx m-x) ? tx - m-x : m-x - tx; m-dy (ty m-y) ? ty - m-y : m-y - ty; m-sx (tx m-x) ? 1 : -1; m-sy (ty m-y) ? 1 : -1; m-err m-dx - m-dy; m-active 1; } /* 返回值bit0 X轴要走一步bit1 Y轴要走一步 */ uint8_t motion_step(motion_t *m) { if (!m-active) return 0; /* 防止dx/dy为0时除零直接判断目标到达 */ if (m-x m-tx m-y m-ty) { m-active 0; return 0; } uint8_t ret 0; int32_t e2 2 * m-err; if (e2 -m-dy) { m-err - m-dy; m-x m-sx; ret | 0x01; } if (e2 m-dx) { m-err m-dx; m-y m-sy; ret | 0x02; } if (m-x m-tx m-y m-ty) { m-active 0; } return ret; }逻辑说明err的初值是dx-dy每次迭代比较2*err和-dy/dx的关系相当于判断当前点在理想直线段的哪一侧。如果X方向偏差更大这一步走X如果Y方向偏差更大走Y如果正好在45°对角线上两步同时走这就是斜线比普通逐轴走好看的原因。参数说明这个函数每一次调用产生0~2个步进脉冲放到定时器中断里调用就得到了一条从当前点指向目标点的斜线段。想要调整速度不是改这个函数而是改定时器中断触发频率。4.3 G代码行解析器从串口读一行到落笔开写固件接收G代码的流程是串口中断收按行缓存收到换行符后调用parse_line。写字机器人的G代码很精简主要就是G0 X.. Y..抬笔移动和G1 X.. Y..落笔移动。#include string.h #include stdlib.h static float parse_coord(char cmd) { char *p strchr(line_buf, cmd); if (p NULL) return -1.0f; return strtof(p 1, NULL); } void parse_line(char *buf) { char *p; int g_num 0; /* 找到G命令编号 */ p strstr(buf, G); if (p) g_num atoi(p 1); if (g_num 0) { pen_state 0; /* 抬笔 */ } else if (g_num 1) { pen_state 1; /* 落笔 */ } /* 如果没有X、Y坐标只改抬笔状态不移动 */ if (strchr(buf, X) || strchr(buf, Y)) { float x_mm parse_coord(X); float y_mm parse_coord(Y); if (x_mm 0) x_mm last_x_mm; if (y_mm 0) y_mm last_y_mm; motion_start(motion, mm_to_steps(x_mm), mm_to_steps(y_mm)); last_x_mm x_mm; last_y_mm y_mm; servo_set(pen_state); /* 先抬笔/落笔再启动运动 */ TIM2-CR1 | TIM_CR1_CEN; } }逻辑说明strchr(buf,X)找不到时返回NULL直接用-1.0f作哨兵值后续判断把它替换成上一次坐标解析G代码时不依赖空格位置所以上位机发G1X10Y20能解析发G1 X10 Y20也能解析。参数说明pen_state控制舵机的PWM脉宽。我一般把抬笔设为1100µs落笔设为1450µs。如果你的舵机是180°标准舵机这个范围对应笔架连杆从升到降能用万用表量PWM脉宽确认。注意G0/G1不只控制运动还要控制笔状态否则笔一直压着纸写出来的字会在笔画之间连成一片。4.4 定时器中断发脉冲让它不再“拽着你写字”脉冲产生最稳的方式是用定时器溢出中断作为节拍每个节拍调用一次motion_step再根据返回的bit0/bit1翻转X/Y的STEP引脚。void TIM2_IRQHandler(void) { TIM2-SR ~TIM_SR_UIF; /* 清中断标志 */ uint8_t r motion_step(motion); if (r 0x01) { GPIOB-BSRR GPIO_PIN_0; /* X STEP 高 */ __NOP(); GPIOB-BRR GPIO_PIN_0; /* X STEP 低 */ } if (r 0x02) { GPIOB-BSRR GPIO_PIN_1; /* Y STEP 高 */ __NOP(); GPIOB-BRR GPIO_PIN_1; /* Y STEP 低 */ } /* 走到目标后停表省电同时避免无谓中断 */ if (motion.active 0) { TIM2-CR1 ~TIM_CR1_CEN; } }逻辑说明__NOP()的作用是给CPU三个空周期让STEP高电平持续时间大约50~100ns。对于A4988这类老驱动1µs才是保险宽度所以我实际项目中会在motion_step返回位后主动调用一个3µs的延时函数再拉低。更专业的做法是用TIM定时器的比较输出翻转模式但上面的代码最容易新手理解。速度规划方面我把TIM2的预分频值改成动态可调启动时预分频大速度慢走完加速段后减小预分频。常见的简化实现是static uint16_t accel_tbl[16] { 8000, 6200, 4800, 3800, 3000, 2400, 1900, 1500, 1200, 1000, 900, 800, 750, 720, 700, 680 };这里的数值是定时器计数周期数值越小脉冲频率越高。每次中断里处理完一步把TIM2-ARR accel_tbl[step_index]当剩余步数不足16步时再反过来走这张表。这个办法牺牲了一点平滑度但实际写字时比裸启动稳定得多长斜线不会中途丢步。5. 写字机器人避坑排查丢步、镜像、笔压不稳的5条实证经验5.1 丢步且方向随机多数是共地没做好现象空跑测试电机时一切正常真正写字画图时某根轴会突然反向或停在半路之后继续画的整幅图都偏移了几毫米。这种丢步不是每次都有多半在有舵机抬笔动作的一瞬间发生。原因驱动板逻辑地和主控地没有连在一起STEP脉冲信号没有共同参考电位。舵机一启动母线电压瞬间波动地线上产生干扰电压驱动板把噪声当成有效脉冲。解决先把所有模块GND接到同一个端子排再给STEP和DIR信号加一个1kΩ下拉电阻到地并把电机线双绞。若仍有偶发丢步把A4988的电流限制从0.8A调到1.2A扭矩余量大了丢步概率会低很多。5.2 写出来左右镜像不是改代码是先把同步带换成“S”型现象喂给固件“PGJ”写出来却是“JGP”或者文字整体左右颠倒。有人第一反应是改代码但代码逻辑其实没问题。原因悬挂式结构中两个电机的位置和同步带绕法决定了X轴正方向。如果两根同步带有一根装反了差速方向就反了。解决先在固件里把X轴DIR引脚取反试试如果取反后变成上下镜像就检查同步带绕法应该呈“S”型轨迹而不是同向平行。这个坑非常容易踩所以我习惯在结构装配完跑一个“L”型测试路径而不是直接写字步进几秒钟就能看出轴向是否反向。5.3 笔迹深浅不一抬笔舵机装完要留 0.3mm 余量现象写横线时颜色很深写竖线时颜色很浅或者一个字的起笔和收笔粗细明显不同。这不是圆珠笔没油是笔尖压力在行程中变化。原因笔架装在X滑块上时滑块微小倾斜或者舵机连杆接近行程末端导致落笔时笔尖和纸面的角度不是90°压力被分解成侧向力笔画自然发虚。解决把落笔点设在舵机输出轴行程的中间位置附近让摇臂两端有余量装好结构后手动转动舵机臂用塞尺塞进笔尖和纸面之间确认落笔后间隙不超过0.3mm。这0.3mm是为了保证笔尖有弹性不是压死。如果用的是水性笔最后一段笔画颜色变化明显还可以把最高速度降低30%。5.4 字迹断线步进电机扭矩不够时先看速度和供电现象写斜线、斜撇时笔画中间出现一段空白或毛刺单独测试电机空转时没有异响但装上笔架后手能明显感觉到振动。原因悬挂式的X滑块本身不重但笔尖与纸面的摩擦会产生切向阻力加上没有梯形加减速步进电机的启动频率超过扭矩曲线就会在中间某一步失步。此时STEP脉冲还在发实际轴没走笔尖自然“愣”了一下。解决先降速把TIM2的初始ARR值加大一倍再看A4988的电流电位器调到输出相电流接近电机额定值最后确认同步带没有打滑。如果还断线把抬笔机构改成轻量化连杆减少落笔时Z轴的弹性变形。5.5 结构件共振往回翻车先降 1/4 速度再找机械松点现象写字速度一快底座明显抖动写出来的字像是“毛毛虫”手握底板能感觉到高频振动伴随噪声增大。原因3D打印PLA件的刚性不够电机座和底板连接处没有加强筋当脉冲频率和结构固有频率接近时产生共振。步进电机在中速区间本来就会产生明显振动恶劣机械结构会把振动放大。解决先把最高速度降到原来的1/4确认字迹恢复光滑再逐个排查螺丝是否松动给电机座加三角形加强筋或贴一片3mm铝板。如果还振把步进驱动从A4988换到DRV8825并提高细分到1/32共振会明显减弱代价是最高速度受主控定时器频宽影响。6. 调试顺序建议先画 20mm 方框再让它写你名字装好第一台机器后我最想做的事就是赶紧让它写出“Hello World”。但我用血泪经验告诉你先别急着写字先跑一个20mm×20mm的正方形。为什么要先画方框因为方框能一次性暴露三个问题X轴实际距离是否等于理论距离、Y轴是否垂直、抬笔落笔是否稳定。把G代码里的G1 X20、G1 Y20、G1 X0、G1 Y0循环几遍然后用卡尺量纸上的边长。如果X方向量出来是18.5mmY方向是19.8mm说明X轴的脉冲当量不对按比例修正STEPS_PER_MM即可如果两条对角线长度差超过2mm说明两根光轴不平行机械上再垫垫片。第二个要测的是“田”字先画一横抬笔再画一竖。重点看横竖交叉点有没有明显的断线或重影。断线说明抬笔后落笔位置偏移往往是结构装配时XY滑块有虚位重影说明落笔瞬间笔尖在纸上滑了一小段距离需要把舵机落笔速度放慢或在笔架上加一个缓冲弹簧。第三个是同心圆。用G02/G03圆弧代码或直接用固件里的画圆测试功能。如果圆不圆、椭圆的长短轴方向固定优先怀疑结构垂直度如果圆上有重复的锯齿说明步进电机在低速段产生了共振试着把细分从16改成32或者提高速度跳过共振区。全部通过后再让机器写你的名字。写第一遍时不要用钢笔或针管笔用一支0.5mm中性笔中性笔对笔压宽容度高即使舵机调得不够完美字迹也不会断线。我自己的习惯是每改一次结构或固件参数都强制自己先跑一遍方框和“田”字再跑整个文本。这个过程不到五分钟却能省掉后面排查丢步、镜像的半小时。希望这个顺序对你也有用祝你的超迷你写字机器人第一笔就落在该落的地方。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站