ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Arduino的自制乒乓球发球机:从机械设计到PID控制

基于Arduino的自制乒乓球发球机:从机械设计到PID控制 1. 从“想练球”到“自己做台发球机”方案与材料选型乒乓球发球机这东西市售成品价格通常在两三千起步好的型号五六千甚至上万都很正常。但如果你拆开一台看内部结构会发现核心原理一点都不玄一个存球漏斗、一套送球机构、一组(或两组)高速摩擦轮、一个控制板、两个电机驱动通道就这么简单。我是在疫情后重新捡起乒乓球的时候动了自己做的念头——球馆里和人对练需要搭子发球机成了刚需但那个价格实在下不去手加上我本身玩Arduino玩了很久自然就想到了自己动手。如果你也打算自己做先把预期放对这不是一个“零焊接基础一晚上搞定”的项目而是需要机械、电子、代码三块能力同时在线才能做得顺手的中级DIY项目。但反过来讲只要你有基本的Arduino编程经验会用3D打印机或者能动手做木工活90%的坑我都能在这篇文章里帮你提前踩平。先说方案选型这是整个项目最关键的决策点。市售发球机的主流方案有两种单轮直推式和双轮摩擦式。单轮直推是一个摩擦轮加一个直线推送装置成本低但出球旋转能力弱双轮摩擦是上下或左右两个轮子反向旋转球从中间高速穿过通过两个轮子的转速差可以实现上旋、下旋、侧旋可控性极强。我选的是双轮方案原因很简单——既然要自己做就要做得比玩具级更强双轮是“可玩性”的分水岭。具体到材料清单我按核心模块拆开来说主控Arduino Uno理由不必多讲资料最多、库最全、出问题最好排查。如果你想上联网或手机App控制可以用ESP32但初版建议Uno起步后面我会讲为什么。摩擦轮驱动两个370电机带轮子直径约55mm-60mm配L298N或BTS7960驱动模块。370电机的好处是扭矩够、转速够、便宜10块钱一个坏了不心疼。送球电机N20减速电机转速控制在30-60RPM左右用来把球一颗一颗从漏斗拨进摩擦轮间隙。扭矩是刚需普通130电机带不动球堆的重量。摩擦轮轮体我用的3D打印PLA轮毂加硅胶外圈。硅胶外圈非常重要——没有硅胶的抓球力球会打滑导致出球速度不稳。你也可以直接买现成的发球机摩擦轮淘宝有卖搜索“发球机摩擦轮”就行省去打印调参时间。电源12V 5A开关电源或者两块18650锂电池组3S加降压模块。我测试阶段用开关电源便携化阶段换锂电。结构件3D打印外壳加铝型材支架。纯打印也行但强度一般击球瞬间的震动很容易让PLA件疲劳裂纹。传感器两颗限位开关用于存储机构的防卡死检测后面控制逻辑部分我会具体讲用途。这套配置总成本在200元到300元之间前提是你已经有3D打印机和基本工具。如果你没有打印机外壳件可以去淘宝找人代打加100元左右成本整体仍然远低于市售成品。材料到位后下一件事是搞清楚机械结构怎么搭——迎面撞上的第一个问题就是中心距怎么算这直接决定了球的出球质量和稳定性。2. 机械结构的搭建与参数计算中心距、摩擦轮压紧与送球漏斗2.1 核心结构布局送球漏斗与摩擦轮组的相对位置整个发球机的机械核心其实就是一个L型通路球从上方漏斗滚入顺着斜面滑到两个摩擦轮的切点位置摩擦轮高速旋转把球从前方隙缝中弹出。上下轮布局是最常见的结构因为球靠重力落入切点最自然不需要额外加导向机构。我第一版结构图走了不少弯路——一开始把送球电机放在摩擦轮正上方结果球在下落过程中被拨片和摩擦轮之间卡住几乎每分钟停一次。后来参考成品机型的结构后发现送球轮应该放在摩擦轮组的斜后方用拨片把球以一定初速度推进摩擦轮切点球在到达切点前已经具备了一定的向前速度这样出球更顺、卡球率更低。结构参数上两个摩擦轮的中心距是关键中的关键。中心距太大会导致球和轮体接触不充分出球无力甚至空转太小会压死球电机负载骤增转速上不去严重时直接把电机堵转烧掉。合理的做法是中心距 摩擦轮半径和 球半径 - 压紧量。乒乓球直径40mm两轮半径各30mm合起来轮外径间自然纵向间隙是20mm而球直径40mm所以理论上轮间无压缩时球穿过两轮的缝隙会被压扁20%8mm。真实设计时不能压这么狠压紧量控制在3mm到5mm之间最合适即中心距 30 30 20 - 4 76mm左右这里的邻居是数学关系推导实际以你的轮径和球径为准。这个3-5mm的压紧量是反复试出来的经验值。小于3mm时球偶尔打滑出球忽快忽慢大于5mm时电机明显吃力噪声变大而且球在出口处的形变恢复过快会产生明显的“弹弓效应”落点飘忽不定。2.2 摩擦轮与驱动同步设计轮子的同步性和结构刚度对控球稳定性影响非常大。第一版我偷懒把两个电机用支架直接固定在亚克力底板上跑起来后发现上下轮转速差在负载下会达到10%以上出球轨迹根本压不住。原因是两个独立电机的转速受到负载波动影响当一个轮子瞬间压到球的中心位置而另一个还没完全接触时负载差异会被放大。解决办法是给两个摩擦轮加机械联动用一根同步带把两个轮子连接起来主电机驱动上轮下轮通过同步带跟随旋转。这样无论球的受力如何变化两个轮子的线速度永远一致转速差完全消除。联动方案牺牲了部分转速独立调节能力后面讲控制逻辑时你会看到双轮独立调速才能实现旋转球控制但对第一版来说优先保证稳定出球比实现旋转功能更实际。如果你一定要做独立双轮调速来实现旋转球机械上需要注意两点一是两个轮子的中心距调节必须有独立的张紧结构不能靠外壳强行挤压固定二是电机选型尽量一致避免A电机的转速-扭矩特性和B电机差异过大。2.3 3D打印结构设计避坑清单结构件我前后打了好几版踩过的坑集中在这几条壁厚不够摩擦轮支架承受的是高频冲击载荷壁厚至少要3mm以上如果你用PLA材料建议加填充到40%以上否则共振一段时间就会出现层间开裂。轴承位公差电机轴和轮毂连接处需要加轴承直接让电机轴硬怼支架孔的话孔磨损会非常快。3D打印的小孔精度不太行FDM成型后热收缩明显建议轴孔预留0.2mm过盈量压入后用螺丝锁紧。漏斗斜面的角度乒乓球之间的静摩擦系数不小漏斗斜面角度至少要45度以上才能顺畅自滑低于这个角度球会卡成拱形结构。这个拱桥效应非常烦人——球堆互相卡住形成受力自锁结构你用多大力推都推不动。电机散热370电机连续运转10分钟以上外壳温度能到60度以上。如果你把电机完全封闭在打印件里热量散不出去电机磁性会退化转速直线下降。拆开打印件在电机背部留通风孔或者直接用带金属外壳的电机座辅助散热。机械搭建完成后下一步是接线和电路保护这步虽然看起来平淡但七八成的故障都出在这里。3. 电路与驱动MOS管还是驱动模块接线保护与供电设计3.1 驱动方案对比L298N模块 vs 分立MOS管方案Arduino的GPIO输出能力最多20mA根本没有办法直接驱动370电机这种大电流负载所以必须加驱动电路。市面上最常见的方案是L298N模块价格便宜、接线傻瓜化、社区资料多。但L298N有个比较明显的问题它的饱和压降在2V左右这意味着12V电源实际到电机两端只有10V而且模块本身发热严重持续大电流下芯片温度会飙到70-80度。用L298N驱动两个370电机全速运行半小时模块烫得拿不住这是正常现象不是故障但会对MOS管可靠性产生隐患。我最后用的是分立式双半H桥MOS管方案具体型号是IRLZ44NVgs阈值低1V-2V可以直接用Arduino的5V电平驱动不需要额外加电平转换。再加上两个栅极驱动电阻10Ω-100Ω之间都可以防振铃。这个方案的优点是压降极低满载时的导通电阻只有0.022Ω12V电源几乎无损到电机转速明显比L298N方案高发热顶多是微温。如果想省事不上MOS管也可以用TB6612FNG模块它比L298N的压降低得多适合12V以下中小功率电机驱动能力2A每通道对370电机刚好够用。它的MOS管方案参数质量和保护电路做得比L298N好价格也就10多元。3.2 接线逻辑与电源布线的三大注意事项电路布线的核心原则是“大电流路径和小信号路径分开”。如果你把电机线、电源线和Arduino的信号线(舵机PWM线、限位开关线)捆成一束走线电机启停时的瞬态电流会在线束里产生感应电动势干扰控制信号轻则串口数据乱码重则直接让单片机复位。实测中最典型的故障就是球机每次击球瞬间Arduino莫名重启——这就是你线缆布局导致的干扰不是程序问题。布线顺序建议是电源部分12V开关电源 → 保险丝(5A) → 电解电容(470uF/25V)并联一个0.1uF瓷片电容 → 分别给驱动板和降压模块供电。逻辑部分降压模块输出5V给Arduino供电注意Arduino的VIN不要直接接12V因为板载稳压芯片的散热能力有限12V转5V压差大发热严重。电机驱动信号Arduino的PWM引脚 → 栅极驱动电阻 → MOS管栅极。PWM信号线尽量远离电源线走线。电源布线的关键细节有三个第一储能电容必加。电机启动瞬间冲击电流是稳态电流的好几倍两个电机同时启动时峰值电流能达到5A以上。12V开关电源如果不带过流保护的可能会直接打嗝保护带过流保护的会直接断开输出。在电源输出端并联大电解电容能顶住这个瞬时冲击。第二共地必须做。驱动板的GND、Arduino的GND、电源的GND必须共地否则PWM信号没有参考基准MOS管会随机导通电机转速忽快忽慢这是新手最常见的问题。第三电机两端并联续流二极管。电机是感性负载PWM切断瞬间会产生反电动势电压尖峰能到几十伏直接反向灌进MOS管把它击穿。并联一个1N4007或SS34肖特基二极管注意极性负极接电源正极正极接电机供电负极端就能把这个尖峰吃掉。3.3 完整引脚分配参考表我最终版电路的引脚分配如下供参考Arduino Uno功能Arduino引脚说明上摩擦轮PWMD9可调频率的PWM输出下摩擦轮PWMD10双轮独立调速时使用送球电机PWMD6送球速度独立可调送球电机方向D7正反转控制用于解卡限位开关AD2送球漏斗料位检测限位开关BD3出球口异物检测启动按钮D4主启动/停止切换调速电位器A0球速粗调旋转电位器A1旋转强度粗调机械联动版无效4. 控制逻辑分层从送球节奏到摩擦轮闭环4.1 整体控制架构状态机优于线性流程发球机的控制逻辑如果不仔细设计很容易写成一堆“延时判断”的大杂烩程序能跑但调试起来非常头疼。我的建议是使用状态机架构把所有行为抽象成几个明确的状态待机、启动加速、送球、击球间隙、故障停止、手动调试。为什么状态机比线性流程好看一个实际场景球机正常运转时如果突然一颗球卡在送球漏斗里线性流程的代码可能还继续执行延时然后送下一颗球结果堵塞越来越严重。而状态机架构可以通过限位开关触发中断在任何状态都能跳转到“故障停止”状态执行反转解卡程序恢复正常后再跳回主流程。enum MachineState { STATE_IDLE, STATE_STARTUP, STATE_FEEDING, STATE_COOLDOWN, STATE_FAULT, STATE_MANUAL }; MachineState currentState STATE_IDLE; unsigned long stateEnterTime 0; void loop() { switch (currentState) { case STATE_IDLE: // 等待启动按钮 if (digitalRead(BUTTON_PIN) LOW) { currentState STATE_STARTUP; stateEnterTime millis(); } break; case STATE_STARTUP: // 先启动摩擦轮稳定后再进送球 analogWrite(WHEEL_PWM, currentSpeed); if (millis() - stateEnterTime 1500) { currentState STATE_FEEDING; } break; case STATE_FEEDING: // 送球电机以设定频率拨球 feedBall(); break; // ... 其余状态类似 } }状态机的另一个好处是调试路径清晰。哪个状态出问题就单独检查哪个状态的代码和硬件不用在一坨顺序逻辑里反复找“到底卡在哪一行”。4.2 送球节奏计算拨片转速与出球频率的关系送球频率决定发球频率而送球频率取决于送球电机的转数和拨片数量。我用的是N20减速电机1:30减速比输出轴转速大约是60RPM。假如拨片是单叶片结构一圈拨一颗球那么每分钟出球60颗也就是每秒1颗——这个频率偏社了一般业余练习适合的频率是30-50球/分钟职业选手训练可能到70-80球/分钟。所以送球电机需要用PWM调速。设PWM占空比为D电机最大转速R_max单位RPM拨片数N出球频率f则满足f (D / 255) * R_max / 60 * N举例R_max60RPMN1D180时f (180/255)60/601 ≈ 0.706球/秒 ≈ 42球/分钟。这是一个比较舒服的练习频率。实际使用中发现一个细节拨片角度很讲究。拨片和球接触时最好呈约30度切角这样球被拨出的初速度不仅向前还有一点竖直向上的分量刚好帮助球跃过摩擦轮中心进入轮隙。如果拨片太正接近90度球容易被拍平在斜面上滚动距离不够无法顺利进入摩擦轮表现为送球电机一直在转但球没有规律地从出口弹出而是隔三差五地漏一颗。4.3 摩擦轮的PID调速转速闭环的必要性当你开始追求出球速度和落点的稳定性时摩擦轮开环控制就是直接给定一个PWM占空比是不够的。原因有两个一是电池供电时电压会随负载跌落PWM占空比不变的情况下电机转速下降出球变慢二是摩擦轮压球瞬间负载突增转速急剧下降球弹出时的速度和目标值偏差很大。解决这个需要一个速度闭环用霍尔传感器或编码器测量电机实际转速PID调节器根据转速误差自动调PWM。我用的霍尔传感器是淘宝很常见的A3144霍尔开关贴在电机尾部给电机轴粘一个磁铁磁铁和电机轴同心每转一圈霍尔输出一个脉冲。通过测量脉冲间隔可以得到实时转速。标准PID代码框架如下double Setpoint, Input, Output; double Kp 2.0, Ki 5.0, Kd 0.5; PID myPID(Input, Output, Setpoint, Kp, Ki, Kd, DIRECT); void setup() { // ... myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0, 255); myPID.SetSampleTime(50); // 50ms采样一次 } void loop() { // 读取霍尔脉冲计算实时转速 Input readWheelRPM(); Setpoint targetSpeed; // 通过电位器或串口设置 myPID.Compute(); analogWrite(WHEEL_PWM, Output); }PID参数整定我踩过不少坑这里分享一套比较实用的手动整定流程先把Ki和Kd设为0Kp从小到大加从0.5开始每次加0.5观察转速响应。当转速出现等幅振荡时停止增加记下此时的Kp值为K_u。用Ziegler-Nichols经验公式算一组初始参数Kp0.6K_uKi1.2K_u/T_uKd0.075K_uT_uT_u是振荡周期。这组参数不一定最优但往往能直接进入稳定区间。微调先调Kp消除稳态误差再调Ki处理过冲。Kd在电机这类惯性环节中作用很小除非你要极快的响应否则Kd设0或者非常小都可以。值得注意的是摩擦轮系统的PID采样时间要有讲究。霍尔传感器在低转速下的脉冲时间非常长一个脉冲几百毫秒PID采样周期太短会导致测量值跳变PID输出抖动严重反而让电机发出“嗡嗡”的噪声。我的经验是采样时间设在50-100ms比较平衡。4.4 上旋球与下旋球的实现逻辑机械联动版的取舍如果你采用了上下轮机械联动方案那就失去了独立调转速的能力旋转球实现不了。但如果你用的是独立双轮驱动方案两个电机各带一个MOS桥旋转球的控制逻辑其实就是在双轮之间加一个转速差。核心原理是上摩擦轮转速高于下摩擦轮时球的上表面受到向前的摩擦力大于下表面球就会带上上旋反之下轮转速更高时球带下旋。转速差越大旋转越强。实现上只需要在PID目标速度上分开设置// 上轮目标转速 upperSetpoint baseSpeed spinOffset; // 下轮目标转速 lowerSetpoint baseSpeed - spinOffset;spinOffset通过电位器读取对应球的旋转强度baseSpeed对应出球速度。两个通道独立PID调节互不干扰。我实测下来的心得转速差的调节范围不需要很大。基础速度在2000RPM左右时转速差50RPM已经能明显感知到球的上旋效果100RPM的上旋球落台后前冲非常顶接球时明显感到球往前顶拍子。超过150RPM时球在空中的轨迹就开始不稳定来容易后坐出界练习价值反而降低。4.5 出球节奏可变可编程发球序列的实现纯匀速出球练久了太乏味而且实战中对手的回球节奏不可能一成不变。市售高端发球机可以编程出球序列比如“快-慢-快”、“左-右-左”我们自己做也可以实现一个简易版本。用两个数据数组来存储序列一个存储出球速度序列一个存储出球间隔序列。用一个索引变量在序列中循环遍历。int speedSequence[] {180, 120, 200, 120, 200, 150}; int delaySequence[] {800, 600, 800, 900, 700, 600}; int sequenceLength 6; int seqIndex 0; void feedBall() { // 设置摩擦轮速度 analogWrite(WHEEL_PWM, speedSequence[seqIndex]); // 拨球一颗 rotateFeedMotorOnce(); // 等待序列指定的间隔 unsigned long targetDelay delaySequence[seqIndex]; unsigned long startWait millis(); while (millis() - startWait targetDelay) { // 这里可以加状态机状态切换逻辑 } // 进入下一序列 seqIndex (seqIndex 1) % sequenceLength; }这个版本的进阶变体是把序列值通过串口或蓝牙动态下发这样你用手机就能临时改发球方案不用反复烧录程序。5. 全流程实测调试顺序、卡球处理与出球效果标定5.1 分层测试顺序先硬件后逻辑整机装好后千万别直接全速跑一定要分层测试。我吃过这种亏连续通电5分钟感觉球速忽快忽慢拆开检查才发现送球电机轴上的拨片安装角度偏了15度导致送球不稳定。这种问题如果分层测试会很快定位整体跑只会让你怀疑人生。推荐测试顺序是空载电机测试分别以不同PWM值驱动两个摩擦轮电机确认转速正常、无异响、转向正确。如果转向反了把两根电机线对调即可。限位开关测试在高速运转状态下按下限位开关确认中断响应立即生效电机能在500ms内停止。这个测试某种程度上决定了安全性必须做。送球结构测试不放球空转送球电机50次确认拨片无碰撞杂音、无卡涩。然后放10颗球观察球能否顺畅从漏斗依次送出记录卡球率。全速联调摩擦轮和送球同步启动观察出球轨迹的落点分布。如果落点左右偏差超过30cm检查摩擦轮面是否有异物或者两轮轮径是否一致。连续运行测试稳定出球200颗以上监测电机温度和Arduino供电稳定性。如果Arduino中途重启问题几乎可以断定在电源干扰上按第3节的方法重新布线。5.2 卡球故障的根因排查链路从“现象”到“根因”卡球是发球机最常见的故障各种原因的表现还不一样。我从实际故障中整理出下面这个排查链路照着走能节省大量时间现象1球卡在漏斗里不往下走第一步观察球堆中是否有明显“搭拱”的球。拱桥效应的本质是球之间的摩擦力形成了自锁受压的球堆中没有一颗球有向下的滑动力。这时检查漏斗斜面角度是否小于45度。如果斜面够陡但仍然搭拱问题出在漏斗壁材料——3D打印PLA表面比较糙球在下滑时摩擦阻力大。解决方法在漏斗内壁贴一层pet防滑膜或者直接贴特氟龙胶带非常有效。如果解决了卡住的问题后但球还是一颗接一颗地“黏”在一起出来说明送球电机的拨片转速太快后续已经送入轮隙的球还没出去新的球又顶上来形成了连续堆叠。把送球PWM调低10%-15%通常就能改善。现象2球到了摩擦轮处但弹不出被夹住这个现象的直接原因是中心距太小球被两轮压死电机扭矩不足以把球挤过去。但你量一下中心距发现也没小多少——那问题可能在摩擦轮橡胶表面。如果硅胶外圈老化打滑或者表面沾了灰摩擦系数下降轮子只能“抱着”球打滑而不能把它送出去。清洗轮面用酒精擦或者更换硅胶圈通常能解决。另一个根因是摩擦轮电机供电不足空载转速看起来正常但负载时转速暴跌。这多半是电源线太细或者MOS管散热不够进入了限流。用万用表量电机端电压负载下跌超过2V以上就是供电问题。现象3出球轨迹忽高忽低这是摩擦轮转速不稳的典型表现。如果开环PWM控制大概率是电源在负载波动下劣质解决方法是换成闭环PID。如果是闭环PID把霍尔传感器拆下来检查——磁铁安装是否松脱霍尔芯片是否被电机磁钢干扰导致误触发。A3144霍尔对磁场方向敏感安装时要选择正确的磁极面。5.3 出球速度与落点的标定方法做完排障后就需要把电位器读数和实际球速对应起来这个过程叫标定。我自己用的方法是用手机慢动作视频拍摄240fps从球出轮到落台记录帧数。已知球机到落点的距离用距离除以飞行时间得到平均速度。不同电压下测出来的球速可以画成一条“PWM值-球速”曲线。我实测的12V系统数据是PWM150约59%时出球速度约3.2m/sPWM220时约5.8m/sPWM255时约7.5m/s高速档。这个速度范围覆盖了业余爱好者大概的练习需求——低于4m/s适合初学者摆速训练5-6m/s适合中等强度对练超过7m/s的节奏已经接近职业训练的快速推挡了。落点标定需要配合出球角度调节。机械上在两个摩擦轮支架下方的连接轴上加一个螺丝调节机构可以手动调整发射头的仰角上下和偏角左右。仰角调整影响落点的前后位置偏角影响落点的左右位置。调节螺丝的螺距为0.8mm左右旋转一圈大概改变落点位置前后5-8cm所以精调时要小角度慢调。这里分享我的一个实测经验出球角度调节会在“仰角高、球速快”时带来非常夸张的抛物线效应。球以7m/s从40度仰角打出落台后会强烈上跳直接飞出对面底线。练习者如果接球时站位太靠前很容易被顶到。所以标定时一定要按“你在球台正手位发球机在对面球台边线”的常规使用场景调不要调到极端角度。5.4 连续运行稳定性与日常维护清单连续跑200颗球之后需要做几个常规检查项电机温度手摸外壳如果感觉“能握5秒”以上就算安全超过60度需要检查散热。轮面清洁硅胶轮面沾灰后摩擦系数下降明显建议每用5小时擦一次。轴承润滑打印件和轴的摩擦点如果出现吱吱响涂一点锂基油脂。电池电压如果使用锂电池供电单节电压低于3.5V时必须停止使用否则电池寿命会快速衰减。送球漏斗余量如果漏斗内球少于10颗送球稳定性会显著下降因为球堆的压力变了单球下落姿态不稳定。6. 写在最后从能用走向好用的几个方向当你把上面的所有内容都实现并调试到稳定状态后你会发现已经获得了一台“功能上接近市售中档发球机”的自制设备。我个人实际用下来的感受是自己做的发球机最大的价值不只是省钱而是你完全知道每个参数对应什么机械结构出了问题能几分钟定位并修复。如果有余力继续升级我建议按这个优先级投入精力加红外遥控或蓝牙控制不用跑回机器旁边调旋钮体验提升一个档次。加旋转球独立控制如果你的机器还是机械联动版下一步就是改成独立双轮驱动并加入转速差逻辑。加无线出球遥控器在球台对面挂一个遥控开关不用每次弯腰捡球练球效率大幅提升。优化漏斗容量和体积当前版漏斗只能装30颗球左右实战对练需要频繁加球扩容到80颗以上会舒服很多。最后分享一个我从整个项目里领悟到的小经验做这类机械电子结合的项目把机械部分做到“不用调试也能装起来”比把代码写到多高效更重要。代码逻辑不对顶多重新烧录机械公差不对那就是拆开重打时间成本完全不是一个量级。如果你正准备开工先在机械结构上多花点时间后面会省下大量时间。
返回列表