简介:这是一份基于STM32平台的Marlin三轴机械臂控制程序源码,适用于嵌入式课程设计、期末大作业及毕业设计等场景,特别适合需要快速完成项目落地的本科和高职学生,也可作为机械臂运动控制方向的学习模板。代码由作者手工编写,注释详细,包含关键参数与设计思路,核心逻辑清楚,作者自述曾获九十八分并得到导师认可,整体可读性强,便于二次开发。压缩包共含168个文件、约3.38MB,主要包含三十六份头文件、三十三份C语言源文件,覆盖定时器、模数转换、I2C通信等外设驱动;同时提供工程配置文件、烧录文件及说明文档,可直接编译烧录到STM32平台运行,部署简单,整体结构清晰。项目已经过严格调试,功能完善、界面友好、操作便捷,适合课程验收与答辩展示;目前已有152人学习浏览。读者既可将其作为期末项目整体提交,也可在此基础上扩展运动学算法、无线遥控、轨迹规划等高级功能,是一份很有参考价值的完整源码包。
1. 用STM32跑Marlin做三轴机械臂,一个能直接下地的控制方案
期末大作业最常卡在两个地方:步进电机动起来容易,让机械臂末端沿目标轨迹平滑走起来就不知道怎么写了。Marlin里恰好有一套现成的答案——G代码解析、梯形加减速、定时器中断发脉冲,这三部分被封装得很完整,自己从零写的轮子很难比它更稳。把Marlin接到STM32之后,真正需要动手的部分只剩运动学映射:把关节电机转动的角度翻译成末端位置,而这也是答辩时最能展示技术深度的点。下面按改造一台三轴机械臂的常规路径讲,适合手里有F103C8T6开发板和一套肩、肘、腕机械结构的人照着落地。
2. 拆开Marlin,先认清关节臂和直轴机的运动学区别
2.1 Marlin把最麻烦的运动规划封装成了三段流水线
Marlin最初由Sprinter固件发展而来,面向的是直线轴3D打印机,但它真正的资产不是打印逻辑,而是那套从G代码到脉冲的三层流水线。第一层是G代码解析器,把G0、G1这类指令翻译成目标位置;第二层是planner,负责速度规划,把连续运动切分成一个又一个block;第三层是stepper的定时器中断,读取block,把位置增量换算成步进脉冲。主循环大部分时间在排队、读串口、维护状态,高频脉冲全部交给中断处理,所以即便F103主频不高,跑三轴仍然轻松。
机械臂和3D打印机在G代码层是兼容的,都需要解析G0/G1,都需要加减速规划。不同点落在坐标语义上:直轴机器输入的是直线位移,步进电机直接推动丝杠;关节臂输入的是末端位置,步进电机驱动旋转关节,末端坐标与电机角度之间隔着非线性映射。所以“Marlin改机械臂”本质上是把笛卡尔运动学替换成关节运动学,而不是把整个固件推倒重写。
2.2 走第一步之前先理解参数:把步/mm换成步/度
先看Marlin里DEFAULT_AXIS_STEPS_PER_UNIT这个参数。它表示一个坐标单位对应多少个步进脉冲,默认单位是毫米。对机械臂要做的最基础改动,就是把这个单位从毫米换成“度”。举例:关节电机配1:10减速箱,驱动器16细分,电机一转需要3200个脉冲,输出轴转一圈是360度,则步/度=3200/360≈8.89。如果用直驱,就把数值直接设为8.89。改完这个参数,G0 X45就能让对应轴转45度,这是第一层映射,简单且直接。
第二层映射才是关键。Marlin默认把G0 X Y Z解析成三个互相独立的直线轴,而机械臂需要的是把末端笛卡尔坐标反解成关节角。Marlin 2.x自带SCARA运动学,SCARA本身就是双转动关节串联结构,肩-肘型平面机械臂几乎可以直接套用。下表能看清一次连续运动中数据在各模块间的流转,也标注了改造时每个模块怎么处理。
| 模块 | 在直轴3D打印机里的角色 | 机械臂改造时的处理 |
|---|---|---|
| GCode解析器 | 把G0/G1转成目标坐标 | 保留,坐标语义由运动学决定 |
| planner | 做加减速并生成block | 保留,加速度上限调到机械臂能承受的范围 |
| stepper | 按block发脉冲 | 保留,引脚映射指到关节电机驱动器 |
| endstops | 打印平台限位和归零 | 保留,接到各关节限位开关 |
| temperature | 热床和喷嘴PID | 裁剪,不参与机械臂运动 |
| tool/extrude | 挤出机送丝 | 裁剪,末端换成舵机爪或激光头 |
从表里能看出,要动的主要是打印专属部分,运动控制段基本不用碰。这正是拿Marlin做机械臂最省力的地方。
2.3 F103C8T6为什么够用,什么时候才需要F407
担心F103主频低跑不动Marlin是多余的,可以用脉冲频率估算验证。假设基座关节要2度/ms的极快速度,换算2000度/s,配1:10减速箱和16细分,电机需要2000/360×10≈55.6转/s,一转3200脉冲,合计约178kHz。72MHz定时器产生这个频率没有压力,实际瓶颈在机械结构和电源。期末大作业通常把16细分速度控制在500度/s以内,F103C8T6余量充足。
只有同时做三轴闭环、加编码器回读、跑串口屏动画,或者驱动Delta这类并联机构时,才值得换F407。判断标准很简单:先算末端速度和细分下的脉冲频率,再决定主控选型。
3. 搭建工程,把Marlin源码跑在STM32开发板上
3.1 开发环境选择:PlatformIO比Keil更适合接手Marlin
Marlin 2.x官方维护的构建系统是PlatformIO,源码目录自带platformio.ini,安装VS Code的PlatformIO插件后,打开工程就能编译。Keil也能读Marlin源码,但Marlin封装了HAL库的多个中间层,手动在Keil里建工程要处理大量外设初始化代码,对期末作业周期不划算。少数人习惯Keil,但想保持“源码拿过来就能出固件”的稳定交付状态,PlatformIO更合适。
常见做法是:先装VS Code和PlatformIO插件,下载好Marlin 2.x源码,把platformio.ini里的default_envs改成自己主板对应的环境,编译验证一次环境没问题,再去动配置。第一次编译要下载工具链,等几分钟是正常的。
提示:不要一开始就改复杂参数。先把默认配置原样编译通过一次,确认工具链没问题再做裁剪,报错时才能分清是环境问题还是配置问题。
3.2 主板宏和引脚映射要同步核对
Marlin降低配置成本的思路是减少手工进出引脚映射:先查你手上的板子对应哪个pins文件。F103系列常见板卡在Marlin源码里的pins目录下都有定义,只要在Configuration.h把MOTHERBOARD设成对应宏,X_STEP_PIN、X_DIR_PIN这些引脚编号就从pins文件自动读取。下图是我按习惯的接线映射,不同板卡请以各自pins文件为准。
| 功能 | Marlin引脚宏 | 常见接线 |
|---|---|---|
| 基座关节脉冲 | X_STEP_PIN | 驱动器PULSE |
| 基座关节方向 | X_DIR_PIN | 驱动器DIR |
| 肘关节脉冲 | Y_STEP_PIN | 驱动器PULSE |
| 肘关节方向 | Y_DIR_PIN | 驱动器DIR |
| 腕部/升降 | Z_STEP_PIN、Z_DIR_PIN | 驱动器PULSE/DIR |
| 使能 | X_ENABLE_PIN等 | 接地或连驱动器ENA,按需 |
| 限位 | X_MIN_PIN等三路 | 常闭触点接GND和限位IO |
接下来是Configuration.h的关键参数修改,这里给一个参考片段:
#define MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V2_0 // 选择板卡后,引脚宏从对应pins文件自动读取,避免手动映射出错 #define DEFAULT_AXIS_STEPS_PER_UNIT { 8.89f, 8.89f, 8.33f, 97.0f } // 前三项单位是“步/度”:基座和肘用8.89,腕部按1:12减速算约8.33 #define DEFAULT_MAX_FEEDRATE { 500, 500, 200, 50 } // 单位是度/分钟,限制G0指令速度上限 #define DEFAULT_MAX_ACCELERATION { 500, 500, 100, 400 } // 单位是度/秒平方,初学用偏小值,避免上电启动瞬间丢步MOTHERBOARD宏决定编译进哪个pins文件,选错板卡后的典型表现是串口没输出或编译报未知引脚。DEFAULT_AXIS_STEPS_PER_UNIT在机械臂里的语义已经不是步/mm而是步/度,改完这一步,G0坐标单位就落到了角度域。MAX_FEEDRATE是速度硬上限,G代码里的F值超过它会被钳位;MAX_ACCELERATION控制加减速冲击,调太小运动发肉,调太大启动和停止瞬间容易丢步。
3.3 裁剪打印专属模块,让固件轻下来
机械臂用不上热床和挤出机,但直接删文件很容易让工程编译失败。最稳的方式是在Configuration.h里把EXTRUDERS设为0,在Configuration_adv.h里关掉温度相关的PID_ADDITIONAL_TERM,编译器就不会再生成加热相关任务代码,不需要手动删源文件。这样运动控制代码被完整保留,打印相关功能被物理隔离。
编译和烧录用几条命令就能完成:
pio run # 编译,首次会下载工具链,时间较长 pio run -t upload # 通过调试器或串口烧录到STM32 pio device monitor -b 115200 # 打开串口,进入Marlin交互命令行烧录时注意BOOT0跳线在串口ISP方式下需要置于1,烧完拨回0再复位。upload后串口只有乱码,先查波特率是否与配置一致;完全没输出,优先检查BOOT0状态和晶振启动。SPI方式烧录则可以跳过BOOT0设置。
4. 逆运动学替换,让G0 X100 Y50真正驱动到末端位置
4.1 先把正解逆解的数学立住
平面肩-肘两轴机械臂,设肩关节角theta1,肘关节角theta2,大臂L1,小臂L2,末端位置满足:
x = L1*cos(theta1) + L2*cos(theta1+theta2) y = L1*sin(theta1) + L2*sin(theta1+theta2)这是正运动学,从关节角推末端坐标。但作业里用户更常用末端坐标下达指令,所以需要逆解:
c2 = (x^2 + y^2 - L1^2 - L2^2) / (2*L1*L2) theta2 = acos(c2) theta1 = atan2(y, x) - atan2(L2*sin(theta2), L1 + L2*cos(theta2))c2必须落在[-1,1]区间,超出说明目标点不在机械臂工作空间内。实际处理时做钳制比返回失败更友好,把超限点拉到最近可行位置,再往串口回一条提示。
下面是一个可以对照移植的C++骨架,只是示意逻辑,实际工程还要结合连杆参数和轴方向校正:
// 逆解骨架:输入末端XY坐标,输出关节角(弧度) bool arm_inverse_kinematics(float x, float y, float &theta1, float &theta2) { const float L1 = 100.0f, L2 = 80.0f; // 大臂小臂长度,单位mm float c2 = (x*x + y*y - L1*L1 - L2*L2) / (2.0f * L1 * L2); if (c2 < -1.0f || c2 > 1.0f) { theta1 = theta2 = 0.0f; return false; // 空间外,返回失败 } theta2 = acos(c2); theta1 = atan2(y, x) - atan2(L2*sin(theta2), L1 + L2*cos(theta2)); return true; }调用方拿到角度后,乘以轴的步/度换算成脉冲增量。这里acos和atan2都用弧度,Marlin内部坐标默认用度,集成时一定做一次弧度与度的转换。很多轨迹偏差不是逻辑问题,是单位不统一造成的。
4.2 不要自己重写运动学引擎,直接挂SCARA
自己去改Marlin的planner是很费劲的事。Marlin 2.x自带SCARA运动学,inverse_kinematics()函数会在planner规划每段运动时被自动调用,把笛卡尔坐标转成关节角。对两连杆结构来说,最省力的方案是直接启用SCARA,然后把SCARA_LINKAGE_1和SCARA_LINKAGE_2设置成你的大臂和小臂长度:
// Configuration.h 中启用SCARA并设置臂长 #define MORGAN_SCARA #define SCARA_LINKAGE_1 100 // 大臂长度,单位mm #define SCARA_LINKAGE_2 80 // 小臂长度,单位mm #define SCARA_OFFSET 0 // 零点偏移修正,装配有偏差时再调启用后,Marlin里的X轴和Y轴不再对应直线电机,而是SCARA的两个旋转关节,G0 X100 Y50传入的就是末端坐标,系统内部完成逆解再驱动步进电机。这一步做完,运动学引擎就不需要自己维护,作业里把臂长参数填对即可。
4.3 第三轴和末端执行器:Z轴直通,M280控制舵机
SCARA模式下Z轴仍保留直线语义,可以把Z的步/度配成某个关节的脉冲比例,用同一个空间映射腕部旋转或升降。末端夹爪用舵机时,Marlin内置M280指令可以直接输出PWM。在Configuration_adv.h里启用SERVO0_PIN等宏后,M280 P0 S90会让0号舵机转到90度,接夹爪就是开合动作。
裁剪后的指令体系就很完整了:G0/G1负责末端坐标和速度,M280控制夹爪,M114回读当前笛卡尔坐标确认运动结果。SCARA模式下M114回读的是换算后的末端坐标,不是关节角,拿它做点位验证正合适。
4.4 跑一组最小运动测试
给机械臂写一段测试脚本验证逆解是否挂对:
G28 ; 各轴归零 G0 X80 Y0 F600 ; 末端到(80,0),速度600度/分钟 G0 X0 Y80 F600 ; 再摆到(0,80),观察关节跟随情况 M114 ; 回读当前位置,确认坐标变化G28依赖限位开关。如果机械臂没装限位,先用G92把当前点设为零点代替。X80 Y0能到,X0 Y80轨迹抖动,多半是SCARA_LINKAGE参数或方向取反;完全不动,先用M119确认使能和限位状态。
5. 调试顺序、关节PID自整定与逆解往返验证
5.1 按这个顺序调能省下大量时间
调试顺序固定五步:先用M119看限位开关状态,再临时把DEFAULT_MAX_ACCELERATION调低一半手动单轴微动,确认方向没有接反,然后G28归零,接着低速跑点到点运动,最后逐步加回速度和加速度。第二步最容易被忽略:默认加速度对直轴打印机合适,对关节臂往往偏高,第一步就丢步会让你分不清是运动学问题还是电源问题。
5.2 借Marlin的PID框架做关节闭环
Marlin的M303是温度环自整定,不能直接套到关节上。如果加装了编码器和力传感器想对关节做闭环,可以借用Marlin的PID代码结构,在定时中断里每10ms采样一次,把PID输出叠加到速度给定上。温度环里M301的格式是M301 P1.0 I0.1 D10,关节用时从小P开始,参考初值P0.5 I0.05 D3,再观察振荡逐步修正。每个关节的负载和惯量都不同,需要单独标定,不存在一组参数通吃所有关节。
5.3 最有说服力的验证实验:逆解往返测试
最后值得做一个看起来简单但极能说明问题的实验:给机械臂走一个正方形闭环路径,连续下发G0指令,每隔一段用M114回读末端实际位置,把期望位置和回读位置画在同一张图上。正方形四角能闭合,说明正解与逆解的一致性在允许误差内;出现系统性偏角,重点检查SCARA_OFFSET和安装零点;只在某些方向偏差大,优先检查对应关节的步/度参数是否算错。这个实验能同时暴露运动学参数、方向配置和机械装配三个层面的问题,是检验整份源码是否真正可用的最短路径。
本文还有配套的精品资源,点击获取