meArm机械臂控制全攻略:从Arduino接线、舵机归中到逆运动学与偏差校准

发布时间:2026/9/17 9:29:37
meArm机械臂控制全攻略:从Arduino接线、舵机归中到逆运动学与偏差校准 代码传上去机械臂咔哒一声整个歪向一边紧接着舵机开始疯狂抖动。如果你也玩过meArm大概率见过这个场面。第一次用Arduino Uno控制meArm机械臂时我花了整整一天排查最后发现只是舵机没有归中就急急忙忙装上了摇臂。这个看似简单的入门项目坑并不比大型机械臂少。这篇文章我会从硬件选型、接线供电、完整控制代码、实测操作到偏差排查把整个meArm的控制链路完整走一遍所有代码都可以直接复制到Arduino IDE里上传运行。适合刚入手机械臂、想把理论运动学落到实物的读者也适合已经被机械臂偏差折磨到想砸键盘的朋友。1. 开箱之前先搞清楚meArm到底是个什么东西1.1 meArm的身世与定位meArm是一个开源桌面机械臂方案最初的设计目标是让普通人用最低的成本理解工业机械臂的工作原理。整套东西的核心就是4个SG90舵机、几块亚克力板和一些螺丝拼起来之后大概有20厘米长抓个小木块、巡个线、做做视觉定位演示都够用。它和UR5e、Panda这类工业/协作机械臂的区别不只是价格和精度。meArm的每个关节用的是普通模拟舵机没有角度反馈没有力矩感应全靠舵机内部的电位器闭环。这意味着你发给它90度它可能实际停在87度或者93度而且这个误差会随着负载、电压、磨损程度变化。理解这一点是后续所有避坑内容的前提。1.2 硬件清单与选型玩meArm之前先把硬件备齐。官方套件通常包含部件规格数量亚克力结构件3mm激光切割板1套舵机SG90 9g舵机4个螺丝包M2/M3内六角螺丝若干舵机摇臂十字/圆盘形若干Arduino Uno兼容板即可1块面包板400孔以上1块杜邦线公对公、公对母各若干若干电源4节AA电池盒或5V/3A适配器1个舵机选型这里多说一句。市面上SG90的水货特别多最明显的特征是外壳透明、齿轮是塑料的、工作电压标3.5V到6V但实际扭矩虚标。我建议预算够的话直接上MG90S金属齿轮舵机多花几块钱但寿命长很多。你要是打算以后升级抓取更重的东西那就别用SG90了直接上MG996R加PCA9685舵机驱动板。1.3 软件环境清单Arduino IDE直接去官网下载新版别再装1.0.x老版本了。如果你用的是兼容Uno板大概率会遇到CH340串口芯片驱动问题——板子插上电脑没反应多半就是驱动没装。Windows下装好CH340驱动后在设备管理器里能看到COM口编号。Arduino IDE装好后不需要任何第三方库meArm控制只需要内置的Servo.h这点比其他机械臂项目省心多了。不过我还是建议你顺手装上ServoInput库后面做角度校准的时候能省不少事后面避坑章节会用到。1.4 值得加钱买的几个扩展件基础套件能跑通但有几个东西我觉得是加了不亏的PCA9685 16路舵机驱动板如果你想把meArm从4自由度往5自由度扩展或者想摆脱Arduino引脚限制这个板子是必入的。它用I2C通信一路信号线加一路电源线就能控制16路舵机。HC-06蓝牙模块把串口指令改成无线控制手机连上蓝牙就能操纵机械臂演示效果拉满。PS2手柄接收模块meArm官方固件天然支持PS2手柄接线接好直接手柄控制比电脑发串口指令有手感得多。这些扩展件都不贵但能让你从一个机械臂动起来的入门者进阶到机械臂随心所欲动的阶段。2. 组装与接线很多后续Bug都在这一步种下2.1 四自由度是meArm的设计精髓先弄明白meArm的4个舵机各管什么底座舵机控制整个上半身水平旋转对应机械臂术语里的腰关节左臂舵机控制大臂上臂俯仰对应肩关节右臂舵机控制小臂前臂俯仰对应肘关节爪部舵机控制夹爪开合为什么是4个舵机而不是3个或者5个因为要在结构简单和能完成大部分演示动作之间取平衡。3个自由度只能让末端到达二维平面内的某些点4个自由度配合起来就能覆盖三维空间里一个扇区的大多数位置。工业上5自由度、6自由度机械臂能覆盖且优化的姿态更多但对入门做演示来说meArm的4自由度已经够用。2.2 组装顺序与舵机归中这是整个组装过程里最容易被跳过、却是最重要的一步。必须在把摇臂装到舵机之前让所有舵机回到中位90度。正确做法是先把舵机接到Arduino上烧录一段简单的归中程序#include Servo.h Servo myServo; void setup() { myServo.attach(9); myServo.write(90); } void loop() {}然后等舵机转到90度位置再安装摇臂。摇臂要尽量对准舵机输出轴的齿形套进去之后让摇臂处于你认为的手臂水平方向。所有舵机都归中并装好摇臂后再去组装机械臂连杆结构。如果你跳过这一步直接组装结果就是开头那个场面——代码让机械臂摆出水平姿态实际看起来却歪着脖子。更麻烦的是之后你用逆运动学计算角度时所有坐标都会整体偏移排查起来非常痛苦。2.3 接线方案meArm的4个舵机控制信号线分别接到Arduino的数字引脚。我习惯的分配是舵机位置信号线引脚电源地线底座D9舵机电源正极公共GND左臂D10舵机电源正极公共GND右臂D11舵机电源正极公共GND爪部D12舵机电源正极公共GND舵机的三根线颜色一般是棕色GND、红色VCC、橙色信号。把所有舵机的红线并到一起接电源正极棕线并到一起接GND信号线单独接Arduino引脚。接线这里最容易犯的错是顺序错乱导致多个舵机串在一起工作异常。我建议每接一个舵机就在纸上记一下颜色和引脚千万别凭记忆。2.4 供电的电流账SG90舵机正常工作电流大约100mA到250mA听起来不大但堵转瞬间电流能到650mA甚至更高。4个舵机同时动作峰值电流随随便便超过2.5A。Arduino Uno板载稳压芯片AMS1117-5.0最大输出只有1A用USB口给4个舵机供电结果只有一个供电不足舵机抖动Arduino随机重启。正确供电方案是分开供舵机电源4节AA镍氢电池盒4.8V或5V/3A以上的电源适配器Arduino电源USB供电或者9V/12V电源接DC口关键一步把面包板上的GND和Arduino的GND引脚用杜邦线连起来共地共地这件事用大白话说就是两个电源各自为政但必须让它们有一个共同的电位参考点信号线才能正确传输0和1。不共地Arduino说输出3.3V高电平舵机接收端看到的却可能是完全不同的电平指令自然乱套。另外一个提醒很多人贪方便直接拿5V电源接到了Arduino的5V引脚想着反正都是5V。这其实是拿板载稳压器做旁路了轻则发热严重重则烧毁稳压芯片。舵机电源走自己的回路Arduino走USB或DC口中间只共用GND这是最稳妥的结构。3. 完整代码让机械臂按你的指令动起来3.1 代码架构设计直接写4个servo.write()当然能让机械臂动但那样代码没法扩展。我给的代码分成三层底层舵机对象初始化和角度范围保护控制层坐标逆解把末端要去哪个点换算成两个关节各转多少度指令层串口协议解析方便上位机发指令这样设计的好处是你以后想从串口控制换成蓝牙、PS2手柄或者Python上位机只需要改指令层运动学逻辑不用动。3.2 完整可运行代码下面这套代码我实测过直接复制进Arduino IDE上传就能跑。机械臂的连杆尺寸参数L1、L2需要根据你的实际套件微调我给的数值是标准meArm套件的。#include Servo.h // 引脚定义 #define PIN_BASE 9 #define PIN_LEFT 10 #define PIN_RIGHT 11 #define PIN_CLAW 12 Servo servoBase, servoLeft, servoRight, servoClaw; // 连杆尺寸单位mm按你的套件实际测量 const float L1 92.0; // 肩关节轴心到肘关节轴心的距离 const float L2 78.0; // 肘关节轴心到夹爪中心的距离 // 角度限位防止舵机撞机械限位 const int BASE_MIN 0, BASE_MAX 180; const int LEFT_MIN 20, LEFT_MAX 160; const int RIGHT_MIN 20, RIGHT_MAX 160; const int CLAW_MIN 15, CLAW_MAX 85; // 当前角度 int angleBase 90; int angleLeft 90; int angleRight 90; int angleClaw 50; // 方向系数如果你的舵机安装方向和我的相反改成-1 const int DIR_LEFT 1; const int DIR_RIGHT -1; void setup() { Serial.begin(9600); servoBase.attach(PIN_BASE); servoLeft.attach(PIN_LEFT); servoRight.attach(PIN_RIGHT); servoClaw.attach(PIN_CLAW); writeAll(angleBase, angleLeft, angleRight, angleClaw); } void loop() { if (Serial.available() 0) { String cmd Serial.readStringUntil(\n); cmd.trim(); if (cmd.length() 0) return; char prefix cmd.charAt(0); if (prefix R || prefix r) { // 复位到初始姿态 smoothMove(90, 90, 90, 50, 20); } else if (prefix A || prefix a) { // 角度模式A底座 左臂 右臂 爪 int a1, a2, a3, a4; sscanf(cmd.c_str() 1, %d %d %d %d, a1, a2, a3, a4); smoothMove(a1, a2, a3, a4, 15); } else if (prefix P || prefix p) { // 坐标模式Px z 爪开合x和z是末端在肩关节坐标系下的坐标 float x, z; int claw; sscanf(cmd.c_str() 1, %f %f %d, x, z, claw); moveTo(x, z, claw, 90); } } } // 将末端坐标逆解为关节角度 void moveTo(float targetX, float targetZ, int clawAngle, int baseAngle) { float r sqrt(targetX * targetX targetZ * targetZ); r constrain(r, 30, L1 L2 - 5); // 末端必须在可达范围内 // 余弦定理求肘关节角度弧度 float cosElbow (L1 * L1 L2 * L2 - r * r) / (2 * L1 * L2); cosElbow constrain(cosElbow, -1.0, 1.0); float elbowAngle acos(cosElbow); // 求肩关节角度弧度 float atan1 atan2(targetZ, targetX); float atan2Value atan2(L2 * sin(elbowAngle), L1 L2 * cos(elbowAngle)); float shoulderAngle atan1 - atan2Value; int shoulderDeg degrees(shoulderAngle); int elbowDeg 180 - degrees(elbowAngle); // 机械臂的右臂舵机装法通常要这样转换 // 把计算结果映射到舵机角度范围 int leftDeg 150 - shoulderDeg; int rightDeg 60 elbowDeg; leftDeg constrain(leftDeg, LEFT_MIN, LEFT_MAX); rightDeg constrain(rightDeg, RIGHT_MIN, RIGHT_MAX); clawAngle constrain(clawAngle, CLAW_MIN, CLAW_MAX); smoothMove(baseAngle, leftDeg, rightDeg, clawAngle, 15); } // 线性插值移动让动作平滑而不是瞬跳 void smoothMove(int targetBase, int targetLeft, int targetRight, int targetClaw, int stepDelay) { targetBase constrain(targetBase, BASE_MIN, BASE_MAX); targetLeft constrain(targetLeft, LEFT_MIN, LEFT_MAX); targetRight constrain(targetRight, RIGHT_MIN, RIGHT_MAX); targetClaw constrain(targetClaw, CLAW_MIN, CLAW_MAX); int steps 0; steps max(steps, abs(targetBase - angleBase)); steps max(steps, abs(targetLeft - angleLeft)); steps max(steps, abs(targetRight - angleRight)); steps max(steps, abs(targetClaw - angleClaw)); if (steps 0) return; for (int i 1; i steps; i) { int nb map(i, 0, steps, angleBase, targetBase); int nl map(i, 0, steps, angleLeft, targetLeft); int nr map(i, 0, steps, angleRight, targetRight); int nc map(i, 0, steps, angleClaw, targetClaw); writeAll(nb, nl, nr, nc); delay(stepDelay); } angleBase targetBase; angleLeft targetLeft; angleRight targetRight; angleClaw targetClaw; } void writeAll(int base, int left, int right, int claw) { servoBase.write(base); servoLeft.write(DIR_LEFT * left); servoRight.write(DIR_RIGHT * right); servoClaw.write(claw); }上传之前记得改两个东西一是DIR_LEFT和DIR_RIGHT符号看你的舵机实际转动方向二是L1和L2尺寸必须用尺子量你手里套件的实际数据不同批次的亚克力板尺寸有细微差异。3.3 正逆运动学的入门理解很多初学者看到moveTo()函数里的acos和atan2就发怵其实逻辑很直白。机械臂的运动学有两类问题正运动学知道关节角度求末端位置。比如底座90度、左臂90度、右臂90度末端在哪个坐标这个直接根据连杆长度和角度用三角函数就能算。逆运动学反过来想要末端到达某个坐标每个关节应该转多少度这就难一些需要解方程组。上面的代码做的是平面逆解。我把机械臂简化成两根连杆大臂L1和小臂L2末端目标点在前方某个位置。已知两边长度和第三边距离r用余弦定理直接求出肘关节角度再用反正切求出肩关节角度。这个过程和初中几何里已知三角形三边求夹角没有本质区别。为什么要单独讲这个因为很多meArm教程只教调角度不教调坐标。但实践中最自然的操作方式是告诉机械臂夹子去抓那个位置而不是去想每个舵机该转多少度。理解了逆解你就从手动拧旋钮升级到了输入坐标。3.4 串口协议怎么发指令代码上传后打开Arduino IDE自带的串口监视器波特率选9600换行符设为换行NL CR都可以。然后就能发指令了指令含义示例R复位到初始姿态RA底座 左臂 右臂 爪四路角度直接控制A90 60 120 45Px z 爪末端坐标控制P80 100 50第一次跑的时候先用A命令小范围测试比如A90 90 90 50观察每个舵机是否转到预期角度。别一上来就用P命令万一逆解算出一个反人类的姿态机械臂可能会猛甩一下。4. 实测从单舵机测试到一次完整抓取4.1 先做单舵机Sweep测试把整个机械臂组装好之前我强烈建议先做一次单舵机Sweep测试。方法是把某个舵机的摇臂拆下来单独接到Arduino烧录下面这段代码#include Servo.h Servo testServo; void setup() { testServo.attach(9); Serial.begin(9600); } void loop() { testServo.write(0); delay(1000); testServo.write(90); delay(1000); testServo.write(180); delay(1000); }观察舵机是否能在三个角度之间顺畅转动有没有卡顿、异响、抖动。如果舵机在1秒延迟后没有立刻到位或者有嗡嗡声先怀疑供电问题用万用表量一下舵机电源两端电压空载时应该稳定在5V左右。单独测这个动作的意义是提前分辨出舵机本身有问题还是后面组装导致的机械问题。四个舵机全部测过一遍再组装能排除至少一半的后期故障原因。4.2 一次完整的抓取动作分解机械臂最经典的演示是抓取小物件我习惯把它拆成5个关键姿态点初始姿态底座90左臂70右臂120爪开50机械臂手肘弯着待命对准目标上方底座转动到目标方向左臂和右臂配合让爪子悬在物体上方下降抓取两臂协调让爪子下降到物体高度同时爪子张开合爪抬起爪子闭合夹住物体两臂抬起搬运放置底座转到目标位置两臂下降爪子张开放下用代码实现就是多次调用smoothMove()每次传入一个姿态点// 伪代码实际用串口发也一样 smoothMove(90, 70, 120, 50, 15); // 初始 smoothMove(135, 80, 110, 50, 15); // 对准目标 smoothMove(135, 55, 140, 80, 10); // 下降且张开爪 smoothMove(135, 55, 140, 30, 10); // 合爪抓取 smoothMove(135, 70, 120, 30, 15); // 抬起 smoothMove(45, 70, 120, 30, 15); // 旋转到放置点 smoothMove(45, 55, 140, 30, 10); // 下降 smoothMove(45, 55, 140, 80, 10); // 放爪 smoothMove(45, 70, 120, 80, 15); // 回到待机每个姿态点我都是先用A命令手动试探出来的。大致流程是发一个猜测的角度看爪子位置然后一点点调整直到爪子正好停在目标位置。这个过程很枯燥但能让你对机械臂的脾气建立直觉。4.3 平滑插值让动作像样smoothMove()函数里我用了一个简单的线性插值思路把起点到终点的角度差分成若干小步每次只走一步而不是直接跳到目标角度。为什么要这么设计因为servo.write()是让舵机以最快速度转向目标角度如果直接从一个姿态切到另一个姿态机械臂会产生猛烈的鞭梢效应——末端爪子甩出去的速度不是你能控制的既容易撞到旁边的东西也容易损坏舵机齿轮。插值步数我取的是四路舵机里角度差最大的那个值。比如底座要转90度、其他舵机只转10度那就分成90步每步之间延迟15毫秒整个动作大约1.35秒完成就很优雅。步进延迟可以根据你想要的速度调整但别低于5毫秒舵机响应不过来反而会丢步。4.4 参数调优的实操心得调meArm的过程中有几个参数我反复折腾总结出来供你参考夹爪开合角度不同批次套件的爪子结构有差异CLAW_MIN和CLAW_MAX别按我的默认值死搬。先手动给角度测试夹爪完全张开和完全合拢时的实际角度再回填到代码里。连杆长度L1/L2用游标卡尺量别用尺子估。L1差2毫米末端坐标就差好几毫米抓取小螺丝之类的东西时根本对不准。舵机上限位meArm的亚克力结构件本身没有物理限位角度给过头舵机会推着塑料件硬憋轻则咔咔响重则扫齿。LEFT_MIN/MAX和RIGHT_MIN/MAX宁可设置保守一点。5. 避坑指南机械臂偏差到底从哪来5.1 偏差的五个来源“机械臂偏差”这四个字是搜索热词也是所有meArm玩家绕不开的坎。我总结下来偏差主要来自五个层面舵机中位偏差模拟舵机的电位器本身就有制造公差标称90度实际可能停在87度或93度。这个误差在装摇臂时会被放大成明显的姿态歪斜。齿轮虚位舵机内部尼龙齿轮之间、输出轴齿和摇臂齿之间都有配合间隙负载变化时这个间隙会导致末端几毫米的游移。连杆装配间隙亚克力板和螺丝之间的配合精度不高拧太紧卡死拧太松晃动。理想的松紧度是零件不晃动但能感受到轻微阻力。重心偏移机械臂伸出越远重心越靠前舵机承受的力矩越大电位器反馈越不准末端下垂越多。供电电压漂移电池电压从充满的5.6V掉到4.2V舵机脉宽和角度的映射关系会发生偏移导致同一个角度指令实际位置变了。5.2 一次完整排查链路拿一个很典型的故障现象举例机械臂空载运行正常但抓取一个小木块后爪子明显下垂而且发出持续嗡嗡声。排查过程我是这样走的第一步区分是电气问题还是机械问题。先拆掉爪部的物体空载运行同样的动作。如果空载正常说明不是信号和供电故障而是负载超出了舵机的保持力矩。SG90的堵转力矩大约是1.8kg/cm夹一个小木块不应该超载那就要再往下查。第二步检查机械安装。把机械臂翻过来看各个关节的螺丝如果发现某个转动轴处的螺丝松动高速运动时关节就会打滑表现为爪子下垂但舵机还在响。拧紧螺丝再试。第三步查供电电压。用万用表量舵机电源正负极抓取瞬间电压如果掉到4.5V以下说明电源内阻太大或者电池快没电了。换电池或换更大功率适配器。第四步查舵机本身。如果所有外部原因都排除了把一个已知良好的舵机换到故障位置测试。舵机扫齿、电机退磁、电位器磨损都会导致力矩下降这在二手舵机上尤其常见。经过这四步90%的机械臂歪了爪子下垂嘎嘎响都能定位到根因。别一上来就觉得是代码问题绝大多数情况下硬件检查更优先。5.3 软件校准法如果机械臂运行稳定只是角度指令和实际位置有固定偏差那就是典型的系统误差可以用软件校准消除。方法很简单对每个舵机发一个已知角度比如90度然后用量角器实测实际角度记录偏差值。每个舵机测三个点30、90、150做一个线性校准表// 校准数据示例发送角度 - 实际角度偏差 struct CalibItem { int sendAngle; int actualAngle; }; CalibItem baseCalib[] { {30, 32}, {90, 89}, {150, 153} }; int calibratedWrite(int channel, int sendAngle) { // 根据校准表线性插值得到实际应该发送的角度 // 这段逻辑建议放在writeAll()之前调用 return sendAngle; // 默认不做校准替换为插值逻辑即可 }校准的时候有个小技巧给爪部夹一根细长的针针尖对准下面的坐标纸这样末端位置能读得比较准。固定末端后用A命令控制机械臂到达不同位置读取实际坐标和理论坐标的差反过来修正连杆参数或者角度偏置。校准完成后我建议在代码里加一个CALIBRATED开关保留原始角度模式和校准模式调试时可以随时切换对比。5.4 什么时候该换总线舵机软件校准能解决固定偏差但解决不了实时变化的非线性偏差。如果你做了完整校准机械臂在负载状态下还是不够准那就是模拟舵机的物理上限到了。这个时候考虑升级总线舵机比如幻尔、松灵这些厂商的串行总线舵机。总线舵机的优势在于带角度反馈控制器能读到舵机当前实际角度形成闭环级联接线4个舵机一根总线串联接线大幅简化故障诊断堵转、超温、电压异常都能通过协议返回总线舵机的学习曲线稍微陡峭一点但如果你是冲着真正的机械臂控制、甚至是后面的ROS开发去的总线舵机的角度反馈几乎是必需品。meArm原版设计虽然是为模拟舵机准备的但市面上也有改装件可以把它升级为总线舵机版本。6. 从meArm出发5自由度甚至更远的路6.1 给meArm加自由度4自由度的meArm有一个明显限制末端姿态变化少爪子永远朝下或者朝一个固定方向。想把爪子转到任意角度至少需要5个自由度。常见的改造方式是在底座上加一个“腰部旋转”舵机或者在爪子后面加一个手腕旋转舵机。前者需要重新设计底座结构后者简单一些直接换一个带旋转舵机的夹爪模块。加了第5个自由度之后运动学从平面问题变成空间问题逆解难度上一个台阶。这时再用手解方程的方式效率就很低了建议直接上运动学库比如Python的现代机器人库、IKPy或者ROS2里的MoveIt。6.2 Python上位机把控制权从串口交到电脑我用Python给meArm写过一个简单的上位机其实核心就是串口通信加一个坐标输入界面import serial import time # 换成你板子对应的串口号 ser serial.Serial(COM3, 9600, timeout1) time.sleep(2) def send(cmd: str): ser.write((cmd \n).encode()) time.sleep(0.1) # 复位 send(R) time.sleep(1) # 角度模式 send(A90 70 120 50) time.sleep(2) # 坐标模式 send(P80 100 45)这段代码虽然简单但它是后续所有复杂控制的基础。你可以扩展成用滑块实时发送角度、读取机械臂回传的当前状态、甚至接上摄像头做颜色识别然后自动抓取。Python控制机械臂的生态已经非常成熟了除了pySerial这种底层库还有机械臂方向的专用Python库封装了运动学、轨迹规划、仿真驱动meArm只是小试牛刀。6.3 ROS/Gazebo仿真与轨迹规划如果你以后想走真正的机械臂开发路线绕不开ROS和Gazebo。在Gazebo里搭建一个UR5e或者Panda机械臂模型用MoveIt做轨迹规划在仿真环境里验证算法然后迁移到实物上这是目前机械臂开发的主流流程。这个路线需要学的工具链包括ROS2建议直接学Jazzy版本和Gazebo HarmonicMoveIt做运动规划支持RRT、OMPL等路径规划算法RViz做可视化调试TF2做坐标变换管理机械臂的轨迹规划算法从meArm的smoothMove()线性插值开始到S形速度规划、圆弧插补、笛卡尔空间规划这是一个逐步递进的学习路径。meArm能让你直观感受到末端位置随时间平滑变化这件事的重要性这个直觉对理解MoveIt里的规划器非常有帮助。6.4 具身智能与强化学习方向2025年之后机械臂领域最火的概念是具身智能也就是让机械臂通过感知和交互自主学习操作。meArm虽然精度低、自由度少做不了复杂的深度强化学习训练但它有一个无可替代的优势成本低可以放心让程序折腾。你可以尝试的思路是用简单的深度Q网络让meArm学习“看到目标物体后爪子闭合”这个策略。状态空间是摄像头画面或者简单的位置传感器读数动作空间是爪子的开合和左右移动。虽然效果很初级但整个感知-决策-执行的闭环能完整跑通。再往后走就是真人了。工业上的具身智能机械臂练习平台通常会用松灵、幻尔这些厂商的带力觉反馈机械臂配合深度相机做手眼标定上手成本从几千到几万不等。meArm作为第一个练手项目最大的价值是让你以最小的代价理解机械臂控制的完整链路。玩meArm这一年多我最大的体会是机械臂控制难的地方不在代码而在电脑里的数学模型和现实里的物理世界之间的鸿沟。模型算出来完美平滑的轨迹放到实物上可能因为一个螺丝松动就整个偏掉。所以我现在每次上电第一件事不是发指令而是让机械臂先执行复位程序观察四个舵机是否都能平稳回到初始位置。然后在底座和各个关节的固定螺丝上点一点螺纹胶再在舵机摇臂上贴一圈角度刻度纸。这些小习惯听起来土却是最省心的维护手段。如果你也准备入坑meArm希望这篇文章能帮你少走我当初走过的弯路。