
简介面向备战电子设计竞赛、完成单片机课程设计或开展悬挂运动控制实验的读者这份Word文档以SPCE061A单片机为核心围绕主控制、电机驱动、检测反馈与悬挂模块四部分给出从方案论证、系统框图到硬件电路和程序实现的完整参考。资料包共1个doc文件约517KB体量轻便便于直接查阅原理图与代码片段。内容先比较位移传感器、步进电机、直流电机加光电编码盘等定位方案指出相对坐标掉帧、步进电机失步与功耗偏高等问题进而说明编码盘测量角位移、局部闭环修正误差的实现思路寻迹部分对比图像识别与反射式红外传感器阵列采用多个红外对管分辨黑白轨迹反馈链路则用无线数传替代有线连接以减少线缆牵引误差。文中还涉及L298驱动直流电机正反转与停转、PWM调速、点阵液晶和触摸屏设定参数并显示状态以及漆包线间隔刮漆探测实际路程等细节。整体内容偏重工程取舍保留多种方案的对比理由便于在课程报告或答辩中说明选型依据。已有993人学习可作为梳理模块选型、搭建调试框架的案头资料。1. 从一张坐标纸说起悬挂运动控制系统要交付的到底是什么在 80cm×100cm 的坐标纸上让一支笔从原点走到任意指定点误差不超过 5mm再画一个直径 50cm 的圆圆心偏差压在 1cm 以内最后贴着一条随手画的黑线走完全程偏差 1mm。这就是一套悬挂运动控制系统要交付的全部内容。它是典型的双线悬吊结构两根线各由一个直流电机收放笔挂在两根线的交点下方靠左右线长差的配合把笔送到平面上的任何位置。麻烦的地方不在机械而在于你很难知道笔此刻到底在哪——线在带轮上打滑、编码盘丢脉冲、电机和无线模块互相干扰误差会一路累积下去。这套方案用 SPCE061A 做核心配光电编码盘测角、局部闭环校正段纠偏、无线数传回传寻迹信号把位置误差按在毫米级。适合要交自动化、测控类毕设或课程设计、手上有原理图和代码却不知道怎么讲清楚的人直接照着结构做一遍。2. 方案论证与选型四条技术路线的取舍与理由选型这一章不是走过场。悬挂结构最怕的是先做出来再想办法因为一旦电机、传感器、通信方式定错后面所有算法都建立在错误的前提上。下面四条路线每一条当时都有两个看起来更能打的备选最后都没选理由值得写清楚——答辩时被问得最多的也正是这些。2.1 位置测量为什么放弃位移传感器和步进电机最早的想法很讨巧把光电鼠标拆了当悬挂物从鼠标接口直接取坐标偏移量精度高、现成、不用自己算。但这条路走不通的地方在于它是相对坐标。鼠标每帧给出的是相对上一帧的位移一旦掉帧或者笔被碰了一下系统没有任何办法知道自己错了因为它压根不知道自己在哪。另外那几年市面上鼠标基本是 USB 接口协议栈对一颗 16 位单片机来说太重短期内写不出来。这个方案被否掉不是因为精度是因为它没有绝对参考。第二个备选是步进电机。步进电机转角可控一步 0.9°配上带轮能算出线位移理论上毫米级没问题。问题出在功率上题目要求悬挂物重量不小于 100g还得有足够的加速度这就需要较大的转矩而步进电机转矩越大静止时的锁死电流越大电源功耗直接顶到天花板。更麻烦的是高频失步——运转频率一高转子跟不上定子磁场丢一步就是 0.9°而且系统自己不知道丢了。要闭环就必须加编码器那就绕回第三条路。最终选的是直流电机加光电编码盘。编码盘与电机轴同轴透射式红外对管数码盘缝隙把脉冲变成角位移这是工业控制里的常规做法。直流电机便宜、好买、驱动电路简单配一片 L298 就能正反转步进电机则要配上时序脉冲产生电路硬件复杂度反而上去了。方案精度成本硬件复杂度致命问题位移传感器鼠标原理高低低相对坐标掉帧无法自校正步进电机毫米级理论中高需时序驱动大转矩下功耗高高频失步直流电机光电编码盘毫米级实测低低L298 即可需自行处理方向判别与丢脉冲这张表里最后一行那个致命问题是真会咬人的后面第 5 章会专门讲怎么把它压住。2.2 轨迹探测放弃摄像头用 8 对红外对管拼出方向感寻迹的第一反应是用 CCD 或 CMOS 成像拍一张坐标纸的照片让单片机做图像识别找黑线走向。这个方案在两三周的周期里做不完图像二值化、细化、方向提取每一步都要调参而且一颗 16 位单片机的算力和 RAM 都不够跑完整帧。它被否掉是时间原因不是原理原因。选的是反射式红外对管阵列。原理很朴素黑色吸收光、白色反射光反射强度不同光敏三极管的导通状态就不同。把 8 对管子围成一个环套在画笔周围调整间距让黑线无论往哪个方向延伸都至少有一对管子压在线上。这个至少有一对是整个寻迹算法的地基间距定错了后面全乱。具体取值可以这样核算环半径取 30mm8 对均布相邻两对之间的弧长约 23.6mm黑线宽度按 20mm 画那么任意方向上黑线至少能盖住一对管子的中心。如果线画得细10mm 以下就要么缩小环半径要么加密到 12 对否则会出现整条线从两对管中间穿过去的死区。这个数字关系是实打实算出来的不是拍脑袋。2.3 控制策略局部闭环怎么把累计误差按死在半路纯开环的做法是算出现在到目标点两根线各要收放多少换算成脉冲数发给电机数够了就停。问题在于所有误差都是单向累积的——带轮打滑一点点、码盘漏掉一个脉冲、线在轮上叠了一层单次看不出来走完 50cm 之后就偏出去好几毫米而且系统毫无察觉。局部闭环的思路是在悬线上造绝对参考点。悬线用 0.29mm 漆包线在中部按固定长度剥出一小段裸线检测端用两个图钉做成一对触点一个接高电平一个接单片机输入。笔运动时线从两个图钉之间滑过平时漆层绝缘、输入保持高电平一旦滑到裸线段两个图钉被裸铜短接输入被拉低程序立刻知道线长此刻应该等于标定值直接把当前累计计数强制写成这个值。误差就此归零重新开始累积。这跟伺服系统里的回零开关、光栅尺上的参考标记是同一个思想用离散的绝对参考点切碎长距离累积误差。代价也要说清楚——校正点之间照样会漂所以裸线段的位置和长度要按行程设计一般让整段行程里能经过 1 到 2 次校正点最合适裸线段太短高速通过时可能采样不到太长一次经过会连续触发好几回得靠软件加封锁窗。2.4 通信方式无线数传替掉线缆省下的不只是几根线探测模块装在悬挂物上跟着笔一起在纸面上跑主控在架子外面。两者之间要传 8 路红外状态和若干控制信号。最直接的做法是拉一根排线成本几乎为零。但排线本身有重量和刚度。笔在纸面上走排线会随位置变化产生方向不定的拖拽力这个力直接作用在两根悬线上让左右线长差偏离计算值——误差不大但它是随位置变化的系统性偏差标定都标不掉。越往纸的边缘走拖拽越明显。这就是有线方案最坑的地方你以为是算法不准其实是线在拽。所以改成无线数传。用的是现成的微功率数传模块视距条件下标称可靠传输 500m这里实际通信距离不到 2m余量充足。链路建立之后探测端负责把 8 路红外的位图打包成一帧发出去主控端解析后决定转向。代价是引入了延迟和丢包一帧往返十几毫秒丢一帧就可能让笔走成 Z 字。处理办法写在 5.2 里——探测端本地先做一次粗判断只把结论发上去而不是把原始数据甩给主控。3. 硬件设计四个模块的电路与参数核算硬件部分最容易出的问题是参数对不上电机选大了电源扛不住选小了加速度不够码盘分辨率算错了程序里补偿半天也补不回来。这一章把每个模块的关键数字过一遍给的是可以从原理图直接核对的值。3.1 直流伺服回路减速比、牵引力与脉冲当量执行机构是带减速箱的直流电机额定 12V减速比 30:1输出力矩大于 2400 g·cm带轮平均直径 12mm。牵引力可以按力矩除以半径估算半径 6mm 即 0.6cm2400 ÷ 0.6 4000g。悬挂物要求大于 100g也就是说拉力余量有四十倍加速度能拉得很高机构响应才跟得上算法。真正要算清楚的是脉冲当量也就是一个编码脉冲对应多少毫米悬线。码盘装在电机轴上测的是电机转角经减速箱折算到输出轴再由带轮转成线位移带轮周长 π × 12mm ≈ 37.7mm即输出轴转一圈收放 37.7mm 线减速比 30:1输出轴一圈对应电机轴 30 圈码盘按 20 线、单路计数电机轴一圈 20 个脉冲输出轴一圈就是 600 个脉冲脉冲当量 37.7 ÷ 600 ≈ 0.063mm。这个数字是理论分辨率。实测精度远达不到因为还有打滑、线的叠绕、码盘边缘的机械误差最后能稳定在毫米级就已经很好。但它决定了控制周期的上限一次点到点运动走 500mm约 8000 个脉冲中断处理必须扛得住这个频率。/* 编码盘脉冲 → 悬线长度换算SPCE061A 外部中断中累加计数 */ #define PPR 20 /* 码盘刻线数单路计数 */ #define GEAR_RATIO 30 /* 减速箱减速比 */ #define PULLEY_D 12.0f /* 带轮平均直径单位 mm */ #define PI_F 3.1415926f /* 一个脉冲对应的悬线长度编译期算好运行时不重复除 */ const float MM_PER_PULSE (PI_F * PULLEY_D) / (PPR * GEAR_RATIO); static volatile long g_pulse_l 0; /* 左线累计脉冲正为正转收线 */ static volatile long g_pulse_r 0; /* 中断服务里根据方向标志做加减不要在这里做浮点运算 */ void IRQ_Encoder(void) { if (g_dir_l 0) g_pulse_l; else g_pulse_l--; } float pulse_to_mm(long pulse) { return pulse * MM_PER_PULSE; }代码里刻意把浮点乘法放在中断外面。中断只做整数加减是因为 SPCE061A 没有浮点单元一次软浮点乘除要几百个周期放在中断里必然丢脉冲。工程上这种地方翻一次车就够记一辈子现象是电机转得越快位置越不准查半天以为是机械问题其实是中断超时。3.2 L298 驱动两根 IO 管正反转的真值表电机驱动没有自己搭 H 桥直接用专用芯片 L298 的两路功率输出。一片 L298 带两个电机刚好外围只需要续流二极管。控制端只有两根线一路接 PWM 输出记作 C一路接普通 IO 做方向记作 D。真值很简洁D 输出低电平时电机正转D 输出高电平时电机反转C 端没有 PWM 时电机停转。实际使用中还有个细节——L298 有约 1.5V 的饱和压降12V 供电到电机端只剩 10V 出头占空比要按这个折算否则算出来的加速度永远达不到。/* L298 单路电机控制duty 0~255 对应占空比dir 决定方向 */ void motor_out(int ch, int duty, int dir) { if (duty 0) { pwm_set(ch, 0); /* C 端无输出电机自由停转 */ io_clr(DIR_PIN(ch)); return; } if (duty 255) duty 255; /* 占空比钳位防止溢出反转 */ if (dir 0) io_clr(DIR_PIN(ch)); /* D 低 → 正转收线 */ else io_set(DIR_PIN(ch)); /* D 高 → 反转放线 */ pwm_set(ch, duty); }duty的上限钳位不能省。占空比超过 255 会回绕成小值现象是给满速反而变慢这种 bug 靠看代码很难发现只能靠加钳位堵死。3.3 光电前端反射式判黑白、透射式数脉冲两种光电传感器用的是同一套信号调理电路区别只在光路结构。反射式用于判黑线。红外发射管和光敏三极管并排朝下探测到黑线时反射回来的光很弱光敏三极管不导通A 点被上拉电阻拉成高电平探测到白色底板时反射强三极管导通A 点被拉低。这个电平再送进 74HC14 施密特反相器整形单片机收到的就是干净的数字量黑线对应低电平白底对应高电平。施密特触发器在这里不是可选项。光电管的输出在黑白交界处是缓慢过渡的模拟量直接进 IO 口会在阈值附近疯狂抖动一秒能翻转几十次。加了施密特整形之后只有一个干净的边沿计数和判位才准。透射式用于数码盘。发射管和接收管分列码盘两侧码盘转过一条缝隙就通一次光接收端出一个脉冲。信号处理路径和反射式完全一致。区别是这里对边沿的响应速度要求高得多所以接收管后面的负载电阻要取小一些上升沿才够陡。3.4 局部闭环装置图钉开关与定长裸线段这套装置是整个系统里最土也最见效的部分成本几毛钱。悬线选 0.29mm 漆包线一是细、轻对笔的拖拽小二是漆层本身就是绝缘层正好用来做过零检测。在线的中段按固定长度把漆刮掉露出一段裸铜。检测端用两个图钉一个接高电平一个接单片机输入并加下拉。线在正常段滑动时漆层隔开两个图钉输入保持低滑到裸线段两个图钉被裸铜短接输入被拉高产生一个校正信号。这个信号的用法是强制赋值而不是累加修正一旦捕获到上升沿程序立刻把当前线长的脉冲计数写成标定值L_CAL误差清零。这也是为什么它叫局部闭环——它不修正控制量它直接修正状态量。提示图钉触点的压力要调。压太紧线走不动还会磨破漆层压太松裸线段过去了都没接触上。我一般先把线穿过去用手拉一段感觉到明显阻力但不卡死为止。4. 算法与软件流程三套运动解算的推导与落地机械和电路只能保证能动能不能走到位全看算法。三种运动模式对应三套解算点到点用勾股定理圆周用余弦定理寻迹用一组位图加状态轮换。它们的共同点是都不做实时轨迹规划而是把连续运动拆成足够小的步一步一步逼近。4.1 点到点勾股定理算出左右线差再折算脉冲设左定滑轮中心 A(0, H)右定滑轮中心 B(W, H)H 是横梁高度坐标系以坐标纸左上角为原点、y 轴向下为正。悬挂物在 P(x, y) 时两根线的长度用勾股定理直接写出来L_A √(x² (H−y)²)L_B √((W−x)² (H−y)²)要从当前位置走到目标点 T(tx, ty)只需要算两组线长相减就得到每个电机该收放多少线再除以脉冲当量换成脉冲数。这里不需要解什么逆运动学方程因为结构本身就是解耦的——两根线各管一个自由度。#define H_BAR 1000.0f /* 横梁高度 mm按实测标定 */ #define W_BAR 800.0f /* 两滑轮中心距 mm */ /* 单根悬线长度滑轮横坐标 px悬挂点 (x, y) */ float line_len(float x, float y, float px) { float dx x - px; float dy H_BAR - y; return sqrtf(dx * dx dy * dy); } /* 点到点算出两轴的脉冲增量交给运动子程序执行 */ void plan_goto(float tx, float ty) { float la0 line_len(g_x, g_y, 0.0f); float lb0 line_len(g_x, g_y, W_BAR); float la1 line_len(tx, ty, 0.0f); float lb1 line_len(tx, ty, W_BAR); /* 目标线长减当前线长正数表示要收线 */ g_need_l (long)((la1 - la0) / MM_PER_PULSE); g_need_r (long)((lb1 - lb0) / MM_PER_PULSE); g_mode MODE_GOTO; }两个轴要同时启动、按各自速率走。如果让一个轴走完再走另一个笔会先画一条横线再画一条竖线走出直角拐弯而不是直线。正确做法是两个电机同时给 PWM谁先到谁先停笔走的是一条近似直线——严格说是一段折线但步长足够小时看不出来。这里有个容易忽略的细节线长变化量和脉冲数之间是线性关系但两根线的张力不是。当笔走到靠近某个滑轮的位置时那根线短、张力大另一根线长、张力小两边同样的占空比产生的实际速度不同会走歪。处理办法是在运动过程中按剩余脉冲数动态调整占空比让两边同时到达。这就是先到先停之外要补的一层。4.2 圆周运动余弦定理配角度步进画圆不能像点到点那样一次算完得把圆周拆成很多小段。设左滑轮 A、右滑轮 B、圆心 O、半径 R笔当前在圆周上的 C 点∠AOC 记作 α∠BOC 记作 β两条线长用余弦定理AC √(AO² R² − 2·AO·R·cos α)BC √(BO² R² − 2·BO·R·cos β)而 α 和 β 不是独立的A、O、B 三点固定∠AOB 是常量三角形 AOB 和点 C 的相对位置决定了 α β 2π − ∠AOB。所以只要让 α 从 0 按固定步长递增到 2πβ 就唯一确定了两根线长也随之确定。控制过程就是不断地α 加一步、算线长、换成脉冲、走一小段。#define STEP_DEG 0.2f /* 角度步进0.2° */ const float STEP_RAD STEP_DEG * PI_F / 180.0f; /* 圆周运动α 递增逐点解算两条线长 */ void run_circle(float ox, float oy, float r) { float ao line_len(ox, oy, 0.0f); /* 圆心到左滑轮距离 */ float bo line_len(ox, oy, W_BAR); /* 圆心到右滑轮距离 */ float ang_aob angle_aob(ox, oy); /* ∠AOB结构定死后是常量 */ for (float a 0.0f; a 2 * PI_F; a STEP_RAD) { float ac sqrtf(ao*ao r*r - 2*ao*r*cosf(a)); float b 2 * PI_F - ang_aob - a; /* α β 2π − ∠AOB */ float bc sqrtf(bo*bo r*r - 2*bo*r*cosf(b)); step_to_line(ac, bc); /* 走一小步内部做差值与脉冲换算 */ if (key_pressed()) break; /* 留一个中断出口 */ } }步长 0.2° 是有讲究的。半径 250mm 时0.2° 对应的弧长约 0.87mm跟脉冲当量在同一量级再细也没意义因为机械精度到不了再粗就会在圆周上看出棱角。如果画的圆更大步长要相应减小保持每步弧长不超过 1mm这个原则。角度步进还有一个隐藏好处它是开环推进的不依赖位置反馈。哪怕中途丢了几步圆还是闭合的只是某个局部的半径略微偏一点不会像点到点那样越走越偏。这也是为什么圆周运动的实测圆心偏差能压到 4~9mm。4.3 任意轨迹寻迹主探测器轮换加三对屏蔽寻迹是三种模式里最难写的因为黑线是随手画的没有任何先验信息系统必须一边走一边判断方向。8 对红外对管围成一圈编号 0~7。某一时刻可能有一对、两对甚至三对管子压到黑线程序读到的是一张 8 位位图。如果简单地取压线管子的平均方向会出大问题黑线是弯的笔头附近可能同时压住当前段和下一段两个方向一平均笔就往夹角方向走了直接脱线。解决办法是引入主探测器的概念。每次只认一个主方向并且屏蔽掉主探测器之后的三个管子8 对里只用 5 对。主探测器不是固定的它跟着黑线走每次探测完把本次压线的所有管子相对于当前主探测器的角度偏移取平均得到下一个状态的主探测器。这样笔转弯时主探测器跟着转永远是朝前看。/* 8 路红外位图 → 下一个主探测器编号 */ unsigned char pick_main(unsigned char hit, unsigned char last) { int sum 0, cnt 0; for (int i 0; i 8; i) { if (!(hit (1 i))) continue; /* 相对角度归一到 -4 ~ 3避免跨 0 号位时正负跳变 */ int off ((i - last 8 4) % 8) - 4; sum off; cnt; } if (cnt 0) return last; /* 全白保持原方向 */ /* 四舍五入后再模 8得到新的主探测器编号 */ int avg (sum 0) ? (sum cnt / 2) / cnt : (sum - cnt / 2) / cnt; return (unsigned char)((last avg 8) % 8); } /* 屏蔽主探测器之后的 3 对只保留 5 对参与下一次判断 */ unsigned char mask_tail(unsigned char hit, unsigned char main_idx) { for (int k 1; k 3; k) hit ~(1 ((main_idx k) % 8)); return hit; }off那行取模是关键。如果直接写i - last当 last0、i7 时会得到 7实际应该是 −1方向判断整个反掉。加上84再取模再减 4就把任意两个编号的差值归一化到 −4~3这是处理环形数组的通用写法踩过一次就忘不掉。转向控制律很简单主探测器的偏移量就是误差偏移为正说明线在右边左电机多收一点、右电机多放一点偏移为负则相反。误差大的时候给大占空比误差小的时候给小占空比接近零时维持当前速度直行。这就是最朴素的 P 控制够用了加积分反而会因为无线延迟而震荡。4.4 主程序状态机与人工调零主程序是个典型的按键轮询状态机。上电初始化、显示欢迎画面然后进主循环读键值六个按键分别对应六件事手动调零、设定坐标、执行运动、画圆、寻迹、人工轨迹。手动调零是每次开机必做的。系统上电时不知道笔在哪必须让两个电机同时收线直到顶到限位把线长计数值清零建立坐标原点。调零子程序里给四个方向键左正转、左反转、右正转、右反转人工把笔挪到原点附近再按键确认程序把当前位置写成 (0, 0) 对应的线长。运动子程序是共用的读入目标坐标 → 读当前线长 → 算两轴脉冲差 → 开 PWM 输出 → 循环显示实时坐标 → 判断是否到位 → 关输出。三个运动模式点到点、圆周、寻迹都调用它只是喂进去的目标点来源不同。提示调零之后不要立刻跑长距离。先在原点附近走一个 50mm 的小方块确认两边线长计数是同步增减的再放开跑。左右计数一正一负说明某一路的方向判别接反了跑远了会直接把线绷断。5. 避坑与排查调试台上最容易翻车的五件事这一章写的都是实际调出来的毛病不是理论上的可能性。每一条都有明确的现象现象背后有原因原因对应一个具体改法。按这个顺序查能省掉大量以为算法错了其实是硬件的时间。5.1 编码盘丢脉冲越走越偏且偏差随速度增大现象让它走 100mm低速时准一给大占空比就少走两三毫米跑完整个行程能差出 1cm。原因脉冲太窄中断响应不过来。码盘 20 线电机高速旋转时一个脉冲的宽度可能只有几十微秒而中断服务里如果做了浮点运算、或者被 PWM 刷新和液晶刷屏占着就会漏掉边沿。解决中断里只做整数加减所有浮点换算挪到主循环把编码器中断优先级提到最高液晶刷屏改成分块刷新不要整屏重写。如果还丢就换分辨率低一些的码盘——分辨率高但丢脉冲还不如分辨率低但不丢。5.2 无线延迟与丢包寻迹走成 Z 字现象寻迹时笔左右摆动线越弯摆得越厉害直线段反而正常。原因反馈回路被无线链路拉长了。探测端采到数据、打包、发出去、主控解析、算出转向、电机响应一个来回十几到几十毫秒。在这段时间里笔已经往前走了等指令到的时候已经偏了一修就过冲。解决把判断下沉到探测端。探测端本地先做一次主探测器选择只把该往左/往右/直行 偏移量这一个小字节发上去主控收到直接执行不做二次运算。帧里加序号和校验超时没收到新帧就沿用上一帧的转向宁可直行也不要乱转。5.3 红外阵列阈值漂移换张纸就误判现象同一套参数在 A 张纸上好好的换 B 张纸就整片误判或者环境灯一开就乱。原因反射式光电管输出的是模拟量纸面反光率、环境光、供电电压下降都会让阈值偏移。用固定阈值比较等于把系统绑死在某一张纸上。解决上电做一次自标定。让笔在白纸上停一秒记下 8 路各自的基准值再让笔压到黑线上停一秒记下黑线值取两者中点作为动态阈值。这比调电位器靠谱得多而且换纸不用重调。5.4 图钉开关抖动一次经过触发多次校正现象走过校正段时计数被连续改写好几次位置数据在那一瞬间跳变。原因机械触点的弹跳。裸线段滑过图钉的几十毫秒里接触时断时续边沿触发会捕获到一串脉冲。解决软件消抖加封锁窗。捕获到第一个上升沿后先延时 5ms 再确认电平确认有效才执行校正校正完立刻封锁该中断 200ms等线完全滑过去再放开。/* 校正段中断消抖 封锁窗 */ void IRQ_Calib(void) { if (g_lock_ms 0) return; /* 封锁窗内直接丢弃 */ if (read_calib_pin() 0) return; /* 只要上升沿 */ delay_ms(5); /* 5ms 后复检滤掉弹跳 */ if (read_calib_pin() 0) return; g_pulse_l CAL_PULSE_L; /* 强制赋值误差清零 */ g_pulse_r CAL_PULSE_R; g_lock_ms 200; /* 200ms 内不再响应 */ }CAL_PULSE_L和CAL_PULSE_R是校正点对应的理论脉冲数必须在安装时实测标定不能算——线在带轮上绕了几层算出来的值跟实际能差好几个脉冲。5.5 机械打滑与线长累积同一个圆画两次圆心不一样现象连续画两个相同的圆第二个圆心明显偏了或者走完一次长距离回原点时差出好几毫米。原因线在带轮上叠绕。第一层和第二层的有效半径不同同样的脉冲数对应的线长不一样跑得越远叠得越多误差越大。解决带轮开 V 型槽让线始终落在槽底不叠层加一个张紧轮保持张力恒定每次长距离运动前先回零把累积误差清掉单次行程尽量不超过校正段间距的两倍让闭环校正有机会介入。6. 验收与答辩用五张测试表把毫米级说清楚做到能跑只是及格线能证明它达标的才算交付。我的做法是把功能指标拆成五张表每张表对应一类测试每类测三次取最差成绩。答辩时先报指标再报数据最后主动说短板——这个顺序比先讲原理再讲实现有效得多因为评委最想知道的就三件事做没做出来、准不准、哪里不准。第一张是功能对照表把题目要求的每一项和实际实现的性能并排列出来让做到没做到一眼可见。功能项要求实测任意设定坐标点触摸屏菜单下设定点阵液晶触摸屏6 键菜单自定义轨迹运动80cm×100cm 纸面时间150s误差5mm达标阶梯/直线/抛物线均完成圆周运动圆心任意、直径含 50cm误差≤1cm达标直径可任意设定原点到点运动时间100s达标实时坐标显示液晶显示画笔坐标达标连续黑线寻迹时间120s偏差1mm达标断续黑线寻迹时间120s偏差1mm达标第二张是点到点测试表取三个有代表性的目标点各测三次记录时间和落点。这里必须记最差的一次不能记平均值——评委问的是能不能保证不是平均怎么样。目标位置第一次时间/落点第二次第三次(80, 60)65s / (79.8, 60.2)67s / (79.4, 60.5)65s / (79.8, 60.5)(70, 70)57s / (69.6, 69.2)55s / (69.6, 69.6)59s / (69.7, 69.5)(60, 80)67s / (59.7, 79.8)67s / (59.4, 79.5)70s / (59.8, 79.8)三组数据的最大偏差出现在 (60,80) 那一组X 方向偏了 0.6cm。这个点离左滑轮最远、线最长、打滑最明显正好能用来说明局部闭环为什么必要。第三、四张是寻迹表连续和断续分开测因为断线处的表现完全是两回事连续线考验方向跟随断线考验失去目标后能不能保持原方向继续走。序号连续线最大偏差耗时断续线最大偏差耗时12mm37s3mm47s21mm39s5mm49s33mm42s2mm49s第五张是圆周表圆心偏差和轨迹偏差分开记。这两个指标说的不是一回事圆心偏差是整体平移多半是原点标定误差轨迹偏差是圆的形状不圆多半是步长或张力问题。答辩时能分开解释说明真的调过。圆心位置圆心偏差最大轨迹偏差耗时(25, 25)9mm13mm57s(25, 50)4mm12mm59s(50, 25)7mm10mm62s表格摆出来之后主动说短板靠近边缘时张力变化大圆心偏差会到 9mm断续线在断口处靠惯性直行最多偏 5mm。这些数字不丢人藏起来才丢人——被追问出来的那一刻前面所有数据都不可信了。从那以后我每次交方案都会先问自己一句这套东西如果让别人照着做他能不能复现我的数据如果不能那说明我记的是结果不是方法。测试条件、仪器、重复次数、最差值这四样缺一不可缺了就不是验收是自证。这套悬挂运动控制系统的原理图、源码和完整文档我已经整理在一起按上面的结构对着看能少走不少弯路。希望帮到你。本文还有配套的精品资源点击获取