基于Arduino的双轮摩擦驱动乒乓球发球机DIY全解析
2026/9/24 7:45:21 网站建设 项目流程

1. 整体设计思路与方案选型

先说结论:一台靠谱的乒乓球发球机,核心不在于电机多贵、架子多 fancy,而在于“双轮对旋摩擦驱动”这个物理方案,以及一套能稳定控制轮速和出球节奏的逻辑。Arduino 在这里扮演的角色,就是整个系统的大脑——它不负责发力,但负责让发力变得可控。

我在动手之前,其实纠结过一段时间的方案选型。市面上现成的发球机,从几百块到上万的都有,拆开看原理大同小异:两个摩擦轮高速对转,乒乓球从中间被挤压甩出,方向由轮子的角度和你持机的姿态决定。真正拉开差距的,是出球频率是否均匀、转速是否稳定、调整是否方便。自己 DIY 的出发点,不是为了省钱,而是为了能完全掌控这套逻辑,想调出球弧线就调轮速,想改频率就改代码,自由度是成品机比不了的。

选型上,最终定了 Arduino Uno R3 作为主控。为什么不选 ESP32?原因很实在:这个项目里没有复杂的网络通信需求,也不需要跑音频、视觉之类的重负载任务,Uno 的 16MHz 主频和 32KB Flash 完全够用,而且它的 PWM 输出、中断引脚都很好用,资料多到搜不完。ESP32 的优势在 Wi-Fi 和蓝牙,如果之后想加手机 App 遥控,再平滑过渡到 ESP32 也不迟。另外,Uno 的 5V 逻辑电平对舵机和电机驱动模块非常友好,不用做电平转换,少一个坑。

机械部分的核心结构是这样的:储球漏斗负责存球,漏斗底部开口通向一条倾斜的落球通道,通道末端是一对相向旋转的摩擦轮。球落到轮间缝隙时,被两个轮的摩擦力带飞出去。这个方案最大的好处是结构简单、出球速度快,而且通过调整两个轮的转速差,可以实现侧旋、上旋等不同旋转效果,后面控制逻辑部分会细讲。

还有一个重要决策:供电方案。舵机、电机驱动模块、Arduino 三者对电压和电流的需求不一样,绝对不能共用一个供电口。我用了两路电源:一路 5V/3A 给 Arduino 和舵机,一路 12V/5A 给电机驱动模块。分开供电一个是出于稳定性的考虑,另一个是保护主控板,电机启动的瞬间电流冲击很大,如果和主控共地不做好,很容易造成单片机复位重启,表现就是发球发着发着突然“死机”一下。

2. 核心细节解析与实操要点

2.1 摩擦轮驱动的物理原理与关键参数

先讲透摩擦轮驱动这个核心机制。两个轮子面对面安装,间距略小于乒乓球直径,标准乒乓球直径 40mm,所以两轮间距大概要做到 36-38mm,让球能陷进去一点但又不会被卡死。轮子以相反方向旋转,球进入两轮之间后,轮子外缘对球表面产生摩擦力,摩擦力方向与轮子旋转方向相同,于是球被加速并从另一侧甩出。

出球速度取决于两个因素:轮子的线速度和球与轮子的接触面积。轮子线速度不是简简单单等于电机转速乘以轮子周长,因为球在两轮之间会存在滑动,实际出球速度低于理论值,这个损耗系数通常在 0.7-0.85 之间,取决于轮子的材质和表面纹路。我之前用实心橡胶轮和最普通的 PVC 轮做过对比,橡胶轮表面抓球更稳,出球速度也更接近理论值,但橡胶轮更贵,而且用久了表面会老化发滑,需要定期清洁或更换。

轮径和电机转速的搭配也有讲究。我用的轮子是直径 50mm 的橡胶轮,电机是 12V 的直流减速电机,空载转速约 3000 RPM。不用减速箱的话,轮子线速度就是 3.14 × 0.05 × 3000 / 60,约等于 7.85 m/s,这个速度打出去还不够快,实际配上 3:1 减速后,轮子转速约 1000 RPM,线速度约 2.6 m/s,加上滑动损耗,实际出球速度大概在 5-8 m/s 之间,刚好适合业余爱好者对练使用。如果需要更快的球速,就把减速比调小或者换更高转速的电机。

2.2 关键部件选型清单与注意事项

舵机的选择是我踩过坑最多的地方。一开始我图便宜买了 SG90 这种 9g 微型舵机,结果发现扭矩完全不够——落球通道的挡板机构和发射倾角的调整机构都需要一定的扭矩,SG90 在负载稍大的时候会抖舵、发热,甚至直接烧掉。后来换了 MG996R 金属齿轮舵机,扭矩 9.4 kg·cm,用起来就稳多了。

MG996R 的工作电压是 4.8V-6.6V,用 Arduino 的 5V 输出供电没问题,但要注意的是它的瞬间启动电流可以达到 2A 以上,如果直接从 Arduino 的 5V 引脚取电,很容易把板子搞挂。正确的做法是舵机单独从电源模块取电,只把信号线接到 Arduino 的数字引脚上,同时共地。这一点新手特别容易忽略,共地这个概念可以这样理解:Arduino 说“我要你转到 90 度”,这句指令是通过信号线上的电压变化来告诉舵机的,但如果两个设备的地电平面不一样,信号线的电压变化就“传不到”舵机那里,于是舵机收不到指令,表现就是舵机不动或乱动。

电机驱动模块选择的 L298N,虽然效率不高、发热不小,但赢在皮实耐用、资料多,适合入门。后级也可以换成 TB6612FNG 这种效率更高的模块,但 L298N 的逻辑电压是 5V,输入高电平阈值 2.3V,所以 Arduino 的 5V 引脚直接怼上去就能驱动,不需要额外的电平转换芯片,省事。

传感器部分:落球通道里我加了一个对射式红外传感器,用来检测是否有球落到发射口。这个传感器非常便宜,几块钱一个,但作用很大——它让系统知道自己“手里有没有球”,没球的时候可以自动停轮,避免空转磨损,也可以据此统计发球数量。安装时要注意对射管的对准精度,两边的发射管和接收管必须严格处在同一条直线上,否则光路偏移会导致误判。

2.3 机械结构设计细节

结构设计上,我的建议是先建模再动手,哪怕不用专业的 CAD 软件,用纸笔画出尺寸图也比凭感觉打孔强。发球机的整体结构可以分为三个部分:底盘与支撑架、储球漏斗与落球通道、发射机构与角度调节。

底盘我用了 2020 铝型材搭建,加几块 3D 打印的 PLA 连接件。之所以选铝型材,是因为它强度够、重量轻、后期改造方便——想加一个高度调节杆,拧几颗螺丝就能装上。储球漏斗我最初用纸板糊了一个,结果球的流动性很差,堆在一起的球经常互相卡住,后来老老实实用 3D 打印做了个漏斗,内壁设计成 45 度以上的倾角,球的流动性立刻好了很多。

漏斗底部开口要控制在刚好让一个球通过的尺寸,如果开口太大,多个球会同时挤进落球通道,造成卡球。单球通道的内径比乒乓球直径大 2-3mm 左右就行,40.5-42mm,这样球能顺畅下滑但不会并列。

发射倾角的调节我做了两套方案。一套是手动调节——通过一个手拧螺丝锁紧机构,松开就能调整发射头在竖直方向的倾角(范围 15-50 度),适合定点练习;另一套是舵机自动调节——在发射头底部装一个 MG996R,用代码控制倾角,适合发球落点变化的训练。手动调节结构简单,可靠性高;舵机调节玩法多,但会增加系统复杂度,而且倾角改变会影响出球轨迹的稳定性,需要更仔细的调参。

3. 实操过程与核心环节实现

3.1 控制系统电路接线

这是完整的接线清单,照着接就不会乱:

  • Arduino Uno R3,负责主控逻辑。
  • L298N 电机驱动模块,接 Arduino 的 5、6 引脚(PWM 控制两个摩擦轮转速),12V 电源输入,两个电机输出分别接左右摩擦轮电机。
  • MG996R 舵机,信号线接 Arduino 的 9 引脚,电源单独从 5V/3A 电源模块取。
  • 对射式红外传感器,信号线接 Arduino 的 2 引脚,这里用到了外部中断功能,球到达发射口时能第一时间触发逻辑。
  • 1602 LCD 显示屏(I2C 接口),接 Arduino 的 A4 (SDA) 和 A5 (SCL) 引脚,用来实时显示轮速、发球计数、工作模式等参数。
  • 三个按键,分别接 7、8、10 引脚,功能是“模式切换”“速度加”“速度减”,按键另一端接 GND。
  • 电源:12V/5A 适配器给 L298N,另外用一个 DC-DC 降压模块把 12V 降到 5V/3A,给 Arduino、舵机和传感器供电。

接线的一个关键操作是共地:L298N 的 GND 和 DC-DC 降压模块的 GND 必须连在一起,再一起接到 Arduino 的 GND 引脚。这样所有设备才有统一的电压参考点,信号传输才可靠。如果不共地,舵机和电机经常会出现随机抖动的怪异现象。

3.2 Arduino 控制逻辑与代码实现

控制逻辑是这台发球机的灵魂。我用三段式代码结构来组织,分别是初始化、主循环、调参函数。核心逻辑包括:轮速控制(PWM)、出球节奏控制(定时器)、倾角控制(舵机)、状态显示与按键响应。

出球频率的控制逻辑是:红外传感器检测到球落到位后,系统启动一个可调的时间窗口(比如每 500ms 发一个球),窗口内控制两个摩擦轮各转一个预设的脉冲数,把球“踢”出去。这个方案的优点是逻辑简单、实时性好,缺点是球的初速度完全取决于轮速的稳定性,所以 PWM 控制要做得平滑,不能直接让轮子 0-100% 猛加速,要加一个“软启动”渐变过程。

下面是我写的一个简化的示例代码,可以直接烧录测试(这是核心逻辑,完整版还需要加入按键消抖和 LCD 驱动,代码结构我做了精简方便解释):

#include <Servo.h> // 引脚定义 const int PIN_MOTOR_LEFT = 5; // 左摩擦轮电机 PWM const int PIN_MOTOR_RIGHT = 6; // 右摩擦轮电机 PWM const int PIN_SERVO = 9; // 舵机信号 const int PIN_IR_SENSOR = 2; // 落球红外传感器(中断引脚) Servo tiltServo; volatile bool ballDetected = false; // 工作参数 int leftSpeed = 180; // 左轮 PWM 值 0-255 int rightSpeed = 180; // 右轮 PWM 值 0-255 int tiltAngle = 30; // 发射倾角 15-50 int intervalMs = 500; // 出球间隔 void setup() { pinMode(PIN_MOTOR_LEFT, OUTPUT); pinMode(PIN_MOTOR_RIGHT, OUTPUT); pinMode(PIN_IR_SENSOR, INPUT_PULLUP); tiltServo.attach(PIN_SERVO); tiltServo.write(tiltAngle); // 外部中断:红外传感器下降沿触发 attachInterrupt(digitalPinToInterrupt(PIN_IR_SENSOR), onBallDetected, FALLING); Serial.begin(9600); softStart(100); // 电机软启动到 100 PWM } void loop() { if (ballDetected) { ballDetected = false; launchBall(); delay(intervalMs); // 控制出球间隔 } // 这里可以加按键检测、串口指令处理等 // 例如通过串口发送 "L200 R220 T35" 来调整参数 handleSerialCommand(); } void onBallDetected() { ballDetected = true; } void launchBall() { // 启动摩擦轮,保持 currentSpeed 到目标转速 softStart(leftSpeed); softStart(rightSpeed); // 短暂延时等待球被甩出 delay(120); // 摩擦轮持续转动,等待下一个球 } void softStart(int targetSpeed) { // 渐变加速,防止瞬间冲击 for (int i = 0; i <= targetSpeed; i += 5) { analogWrite(PIN_MOTOR_LEFT, i); analogWrite(PIN_MOTOR_RIGHT, i); delay(5); } } void handleSerialCommand() { if (Serial.available() > 0) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); if (cmd.startsWith("L")) { leftSpeed = cmd.substring(1).toInt(); } // 类似地解析 R 和 T 指令 } }

这段代码体现了几个控制要点:一是用外部中断响应落球信号,避免主循环轮询的延迟;二是软启动机制让电机转速渐变,避免瞬间大电流冲击和球被甩飞;三是提供串口调试口,方便在电脑上实时调整转速和倾角参数。在实际测试中基本指哪打哪,调整参数后立刻就能看到出球轨迹的变化。

3.3 调试流程与参数整定

组装完成后不要急着上满速调试,按这个流程来:

第一步是“空转测试”:不装球,手动给电机通电,观察两个摩擦轮是否相向旋转、转速是否均匀、有没有异响。注意检查轮子的夹紧程度——如果两轮间距太小,电机会因为负载过大而发热甚至堵转;间距太大,球又会从中间漏下去,根本没有摩擦力能把球甩出去。理想的间距是:用手指轻轻捏住两个轮子,能转动但能感受到明显的阻力。

第二步是“送球测试”:放一颗球进漏斗,观察球能否顺利滑落到发射口,红外传感器能否正确检测到球。我在这步遇到过球落下去但传感器没反应的情况,排查发现是传感器安装位置不正,发射管和接收管的光路被球架遮挡了一部分,微调位置后就好了。

第三步是“定点发射测试”:固定倾角,调整轮速,发射 20 个球,观察落点的分布。一个好的系统,落点应该集中在一个半径 30cm 左右的圆圈内,如果落点散得满桌子都是,多半是轮子打滑或者两轮转速不一致。两轮转速不一致的表现很有趣:球会往慢轮一侧旋转偏转,转速差越大,球的侧旋越明显。实际操作中,我经常故意用这个特性来制造侧旋球,训练接侧旋的应对能力。

第四步是“调节参数标定”:给系统加上按键或串口指令,快速调整左右轮速差和倾角,记录每档参数对应的出球轨迹特征,形成一张自己的“参数-轨迹映射表”。这张表非常有用,比如我可以存几组预设:低速近台球练单项技术、高速远台球练步法、侧旋球练接发球判断,一按键就能切换训练模式。

4. 常见问题与排查技巧实录

项目做到后面,真正值钱的经验都在排查故障的过程里。整理了一份我踩过的坑,直接照着快速对齐就行:

故障现象可能原因排查与解决方案
舵机抖动或不转供电不足、信号线接触不良确认舵机单独供电、电流≥2A;用万用表量信号线是否有 3.3V/5V 电平跳动
电机不转或无力驱动模块使能端没拉高、电源功率不够、PWM 引脚接错检查 L298N 的 ENA/ENB 跳线帽是否插上;确认 12V 电源实际输出电流;核对代码里的引脚号
球进入两轮间被卡住轮间距过小、轮子表面太光滑、球不是标准 40mm调整轮间距至 37mm 左右;更换摩擦系数更大的橡胶轮;换新球
出球乱出、时快时慢轮速不稳定、球在漏斗中堆积受力不均检查供电波动,给 Arduino 加稳压电容;优化漏斗倾角;检查两轮磨损程度是否一致
红外传感器误触发环境光干扰、传感器安装松动、接线过长给传感器加遮光罩;用热熔胶固定安装位置;信号线用双绞线,减少电磁干扰
发球间隔不稳定delay() 阻塞主循环、定时器配置不当不要用 delay() 控制出球节奏,改用 millis() 非阻塞定时;或者用 Timer1 产生定时中断
LCD 显示乱码或不亮I2C 地址不对、数据线接反先运行 I2C 扫描程序确认地址(常见 0x27 或 0x3F);检查 SDA/SCL 是否接反

一个比较隐蔽的坑是 L298N 模块的 5V 输出问题。很多教程会让你直接用 L298N 板上的 5V 输出去给 Arduino 供电,我一开始也这么干,结果发现系统偶尔会重启。原因在于 L298N 的 5V 是逻辑供电,电流能力有限,而 Arduino 带动 LCD、传感器之后电流需求增大了,两者互相抢电,导致电压跌落触发 Arduino 的欠压复位。后面我改成独立的 DC-DC 降压模块供电,问题立刻消失了。这个经验可以用一句话总结:电源设计不是“能响就行”,要算电流余量,各功能模块的供电尽量隔离。

还有一个经验是关于舵机安装位置的选择。发射头的倾角调整舵机,如果安装在靠近摩擦轮的位置,工作时的震动会很大,长期下来舵机的齿轮会有明显磨损。我把舵机改到远离发射头、靠近底盘的转轴处,用一根连接杆传递角度,虽然结构复杂了一点,但震动对舵机的伤害小了很多,寿命明显延长。DIY 项目里,结构上的每个选择都要考虑到“这个零件在什么环境下工作、会不会因为环境而提前损坏”这个维度。

5. 功能扩展与进阶升级思路

基础版本跑通之后,这个项目的扩展空间非常可观,而且难度是循序渐进的。

首先是“无线控制”方向。把主控从 Arduino Uno 换成 ESP32,就能通过手机浏览器直接调整所有参数——轮速、倾角、发球频率、预设模式。ESP32 自带 Wi-Fi 和蓝牙,可以直接用 Arduino IDE 编程,代码迁移成本极低。加上现在热门的 BLE 遥控方式,手机靠近发球机就能连上,实际体验和成品机差不多了。如果不想换主控,也可以给 Uno 加一个 HC-06 蓝牙串口模块,用手机 App 发送串口指令来控制,接线和代码改造成本都很小,是最快能玩出花的扩展方案。

其次是“自动落点训练”方向。现在的版本靠倾角调节改变落点,但只能手动切换。我们可以预设一套“训练模式”:发球机自动按“左-中-右-中-左”的节奏改变倾角,同时搭配轮速变化出不同旋转,模拟实战中的多球训练场景。这个逻辑不复杂,本质就是把倾角的舵机控制和定时器结合起来,提前规划好一组角度序列即可。我自己做了这个功能之后,练习效率明显提升,因为不用频繁弯腰捡球、调整落点。

再次是“球速测量”方向。两个摩擦轮之间的缝隙处,加上一对光电测速传感器,精确测量球飞出的实际速度。有了这位数据,就能形成一套“轮速-实际球速”的标定曲线,控制精度能再上一个台阶。这对进阶选手非常有价值,尤其是练习接弧圈球的时候,需要知道每个球大概的速度和旋转强度。

最后是“Wokwi 仿真验证逻辑”的方向。如果你不想每次调试都动硬件,可以在 Wokwi 这类在线仿真平台里,把 Arduino 的接线、传感器和电机逻辑先跑一遍。我在做代码大改时,都会先在仿真平台上验证逻辑正确性,再烧录到真实设备上。这个习惯帮我省掉了大量反复写烧、烧了再改的时间。

6. 写在最后的实操体会

最后分享两个经验,一个关于调试心态,一个关于让项目更耐用的细节。

调试心态方面,这个项目最考验人的是“参数之间的耦合”。轮速会影响出球速度,出球速度会影响球的轨迹,轨迹又受到倾角的影响,而倾角的调整又会反过来影响球进入摩擦轮的角度——所有变量都互相牵扯。我调试的时候习惯一次只动一个变量,比如固定倾角不变,只调轮速,观察落点变化;固定轮速不变,只调倾角,再观察。这样能建立一张精确的“参数→结果”映射表,而不是靠感觉乱试。如果你发现怎么调都不对,大概率不是调参的问题,而是某个机械结构松了或传感器数据不对,先排查硬件再回头调参。

设备耐用性方面,给所有螺丝连接处加上防松垫圈或螺纹胶,这个细节非常关键。发球机工作时的震动比想象中大得多,普通螺丝用几天就会松动,最怕的是摩擦轮的固定螺丝松动——轻则影响出球稳定性,重则轮子飞出来砸到人。我最初没注意这一点,结果在一次高速测试中摩擦轮连接器松脱,轮子带着螺丝直接飞了出去,还好没伤到人。此后我所有关键连接都用螺纹胶加固,每次使用前也养成了检查螺丝紧固状态的习惯。

防潮防尘方面,乒乓球馆环境相对干燥但粉尘不少,舵机和电机这类精密部件需要做好保护。我给舵机输出轴加了防尘盖板,电机接线端子用硅胶密封,主板放在一个带透明视窗的亚克力盒里,既方便观察 LED 状态灯,又能挡灰。

这个项目做下来,带给我最大的收获不是“我会做发球机了”这个标签,而是建立了一套从机械设计、电路搭建、嵌入式编程到现场调试的完整工程思维。如果你也想做一个,我的建议是:先把机械结构做简单做稳,再上控制逻辑和花哨功能;先把基础出球跑通,再琢磨自动落点、无线遥控这些进阶玩法。一步一步来,每一步都能看到反馈,这种持续获得正反馈的感觉,才是 DIY 最上头的部分。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询