尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ESP32保龄球计分系统实战:传感器检测与状态机设计全解析

ESP32保龄球计分系统实战:传感器检测与状态机设计全解析 ESP32 保龄球计分系统技术解析从硬件选型到实时检测落地保龄球馆里那套计分系统看起来只是一块屏幕和几个传感器背后其实涉及红外检测、按键矩阵、状态机、无线通信和低功耗设计。这次我们来看一个基于 ESP32 的开源保龄球计分系统项目它把整条球道的检测、计分、显示和重置流程全部跑在 ESP32 上。如果你正在做 ESP32 相关的嵌入式项目或者想了解“传感器数据怎么变成一套可用的业务逻辑”这篇文章可以直接收藏。这个项目最值得关注的几个点一是它对硬件成本的控制绕开了商用保龄球计分系统里常见的专用控制器二是它把“传感器触发 - 状态判定 - 分数计算 - 界面刷新”的完整链路放在单片机上完成不需要上位机持续参与三是它保留了扩展接口后续接蓝牙 App、局域网通信都有改造空间。本文会用一套通用且可落地的思路带你把整个系统的硬件架构、软件状态机、踩坑点和扩展方向理清楚。1. 核心能力速览能力项说明项目类型基于 ESP32 的运动场景实时检测与计分系统核心功能保龄球滚动检测、球瓶倒落判定、计分逻辑、回合切换、显示输出主控芯片ESP32推荐选型见正文通用开发板即可传感器方案红外对射 / 激光反射 / 震动检测三种方案可组合显示方案OLED / LCD / 串口屏 / 上位机 Web 页面可选启动方式烧录固件后上电自启动无需外部电脑持续运行开发环境Arduino IDE 或 PlatformIO推荐 PlatformIO 管理依赖是否支持 API可以通过串口或 WiFi 暴露计分结果接口需自行定义是否支持批量任务适合多球道并行部署但单颗 ESP32 只处理一条球道推荐硬件门槛主控加传感器加显示屏总成本较低具体按实际配置估算适合场景开源硬件学习、保龄球馆辅助计分、运动数据采集原型验证从材料看整个系统的定位不是一套商用成品而是可复现、可二次开发的技术方案。它的价值在于把传感器检测、事件判定、计分逻辑这些典型嵌入式问题集中在一个足够小的硬件平台上跑通非常适合做 ESP32 项目练手或改造。2. 适用场景与使用边界这个项目适合三类人。第一类是嵌入式爱好者想找一个“不是点灯”的完整项目来练手这里面有 GPIO 中断、定时器消抖、状态机、I2C/SPI 显示驱动全部能用到。第二类是 ESP32 开发板的入门用户想从零做一个能对真实物理事件做出反应的系统而不是只跑 Hello World。第三类是保龄球馆或运动场馆的技术人员想评估低成本辅助计分的可行性这个项目能提供一套原型参考。它能解决的问题很明确用传感器替代人工目测计分把球道上的物理事件转化成数字信号再通过软件逻辑完成计分和展示。整个过程不依赖云服务也不依赖 PC 持续运行数据链路短、延迟低、可控性强。但不适合什么场景首先它不适合作为商用保龄球馆的正式计分设备直接上线因为商用场景对传感器故障冗余、赛事规则完整性、多球道并发可靠性都有更高要求这套方案在原型阶段更合适。其次它不适合没有硬件基础的纯软件开发者直接上手至少需要会接线、会看原理图、会用串口监视器。最后如果球道环境有强光干扰、灰尘较大、传感器安装位置不当检测稳定性会受影响这些问题需要在安装环节做针对性处理。特别提醒一点如果这个项目后续要在真实球馆部署涉及场地改造、传感器安装、数据采集和使用必须先取得场馆方授权不要私自拆装设备采集到的打球数据涉及用户行为信息也要按当地隐私法规处理。所有测试建议在自己的实验环境或获得授权的场地进行。3. 系统整体架构先梳理整个系统的数据流这会帮助你理解后面的每一段代码和接线。球滚动 - 传感器检测 - 信号调理 - GPIO 中断 - 消抖与状态判定 - 计分逻辑更新 - 显示刷新 - 回合/局结束处理从架构上看这是一个典型的事件驱动型嵌入式系统。ESP32 不轮询传感器而是靠 GPIO 中断被唤醒。这样做的直接好处是 CPU 占用低功耗也低传感器没有触发时系统可以进入轻量休眠。中断触发后软件进入一个短窗口做消抖、事件类型判断和状态更新。整个系统可以拆成五个模块传感器模块负责把物理事件转换成电信号。信号处理模块负责把传感器的模拟/数字信号整理成 ESP32 能安全读取的电平。主控模块ESP32 负责读取事件、维护状态机、执行计分逻辑。显示模块把当前分数、回合、球瓶状态展示出来。通信模块可选通过串口、WiFi 或蓝牙把数据传给外部设备。模块之间尽量解耦。例如传感器类型如果从红外改成激光反射只需要替换传感器模块和对应的初始化代码计分逻辑和显示逻辑不用改。这也是这个项目值得学习的地方硬件选型会变但业务逻辑应该是稳定的。4. 硬件选型与环境准备4.1 主控选型ESP32 系列从相关热搜词来看ESP32、ESP32 C3、ESP32 S3 都是目前关注度很高的型号选型时可以从这几点考虑。型号推荐场景理由ESP32 经典款通用开发、入门学习社区资料多、引脚丰富、双核跑业务逻辑更从容ESP32 S3需要屏幕界面、需要更多 GPIOAI 加速和 PSRAM 对显示友好适合做可视化界面ESP32 C3追求低功耗、低价格RISC-V 内核体积小适合传感器节点但 GPIO 较少ESP32 C6需要 WiFi 6 / 802.15.4 等新特性适合做无线组网扩展但当前生态资料相对少一些如果只是复现这个保龄球项目经典 ESP32 开发板就够了。如果你想把显示界面做得更流畅或者需要更丰富的 GPIO 接多路传感器ESP32 S3 会更合适。要评估具体用哪颗芯片建议先列清自己需要多少路输入、多少个显示接口、是否要 WiFi 通信再对着选型表定。4.2 传感器选型保龄球计分系统最核心的环节是判断“球是否滚过”和“球瓶是否被击倒”。从成本、安装难度和稳定性三个维度看有几种常见方案。方案一红外对射传感器在球道两侧安装红外发射管和接收管球滚过时遮挡光线接收管电平发生变化触发 GPIO 中断。这是成本最低、最容易实现的方案。缺点是对安装位置敏感发射管和接收管必须严格对齐强光环境下需要加遮光罩。方案二激光反射传感器用激光模块发射光束配合反射板或漫反射目标检测球瓶区域的变化。相比红外对射激光束更集中抗干扰能力更强但成本稍高对安装角度要求较高。适合需要更高检测精度的场景。方案三震动/压力传感器在球瓶区域底部安装震动传感器或压电传感器球瓶倒落时产生震动信号。这种方案能直接检测“球瓶倒落”这个事件但误报率取决于传感器安装的物理位置和球道本身的震动环境。更稳妥的做法是组合使用一组传感器检测“球滚过”另一组检测“球瓶倒落”。两颗传感器都触发才判定当前回合完成。这样能把单传感器误报的概率降低一个量级。4.3 开发环境准备推荐使用 PlatformIO因为它对项目依赖的管理比 Arduino IDE 清晰。如果你不熟悉 PlatformIO用 Arduino IDE 也完全可以跑通只是需要手动下载 ESP32 开发板支持包。这里分别给两套环境准备方式。方式一Arduino IDE 安装 ESP32 支持Arduino IDE 里安装 ESP32 支持包最常见的坑是下载速度慢或失败。如果在线安装失败可以考虑使用离线安装包把下载好的 ESP32 包解压到 Arduino 的硬件目录下。安装完成后在“工具 - 开发板”里选择对应的 ESP32 型号。方式二PlatformIO 创建项目创建项目时选对开发板型号然后让 PlatformIO 自动下载框架和工具链。建议把第三方库依赖写在 platformio.ini 里这样换电脑后重新编译不会缺库。下面是一个通用的 platformio.ini 示例[env:esp32dev] platform espressif32 board esp32dev framework arduino monitor_speed 115200这里使用经典的 ESP32 DevKit 开发板配置。如果你用的是 ESP32 S3 或 C3把board改成对应型号即可例如esp32-s3-devkitc-1或esp32-c3-devkitm-1。4.4 硬件接线清单接线是第一个容易出问题的环节。建议先画一张接线表再动手。模块引脚说明红外对射传感器输出GPIO 13配置为输入启用内部上拉或下拉球瓶区震动传感器输出GPIO 14配置为输入建议加 RC 滤波OLED/SDAGPIO 21I2C 数据线OLED/SCLGPIO 22I2C 时钟线按键重置/新局GPIO 0 或 GPIO 27注意避开下载模式引脚不同的开发板引脚映射不同接线前必须核对对应开发板的引脚图。特别注意GPIO 0 在部分开发板上是下载模式引脚按键接在这里可能会在上电时触发下载流程导致无法正常启动。更稳妥的做法是避开 GPIO 0使用 GPIO 27 这类普通 IO。如果项目使用串口屏或 LCD接口差异更大需要按屏幕 datasheet 单独接线。5. 软件状态机与计分逻辑设计5.1 为什么用状态机保龄球计分系统的业务流程是线性的但中间有各种边界情况一颗球都没打中的“洗沟”、第二次补中、第十格的额外投球、上一回合未结束时的分数等待。如果用一堆 if-else 硬写代码会越来越难维护。状态机是更合适的建模工具。系统状态大致如下IDLE 等待开始 - READY 等待发球 - BALL_ROLLING 检测到球滚动 - PIN_FALL 检测到球瓶变化 - SCORING 计分计算 - DISPLAY_UPDATE 刷新显示 - 回到 READY / 进入 GAME_OVER每次传感器触发程序只做两件事判断当前状态是否合法执行状态对应的处理函数。非法事件会被丢弃。这套逻辑能天然过滤掉很多传感器噪声产生的误触发。5.2 状态机代码示意下面给出一套可编译的通用状态机伪代码用于展示核心逻辑。实际项目中传感器读取、消抖、显示刷新需要替换成你自己的驱动代码。#include Arduino.h enum GameState { IDLE, READY, BALL_ROLLING, PIN_FALL, SCORING, DISPLAY_UPDATE, GAME_OVER }; GameState currentState IDLE; void handleBallSensor() { if (currentState READY) { currentState BALL_ROLLING; Serial.println([EVENT] Ball detected, waiting for pin fall...); } } void handlePinSensor() { if (currentState BALL_ROLLING) { currentState PIN_FALL; Serial.println([EVENT] Pin sensor triggered.); } } void updateScore() { if (currentState PIN_FALL) { randomSeed(millis()); int pinsDown random(0, 11); Serial.printf([SCORE] Pins down: %d\n, pinsDown); currentState SCORING; } } void setup() { Serial.begin(115200); pinMode(13, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(13), handleBallSensor, FALLING); currentState READY; } void loop() { updateScore(); delay(5); }这段代码不是完整的计分系统但演示了状态机的核心思想中断回调只改状态真正的事务逻辑在主循环里处理。这么做有一个重要原因——attachInterrupt回调函数里不应该执行耗时操作比如 I2C 显示刷新否则会阻塞中断丢失后续事件。正确做法是中断里置状态位主循环轮询状态并执行具体任务。在实际项目中传感器中断回调和主循环代码需要隔离这是 ESP32 项目里非常关键的代码设计习惯。5.3 计分逻辑注意事项保龄球计分逻辑比看起来要复杂原因在于“补中”和“全中”会影响后续投球的分数。一套最简单的计分规则是每回合最多投两次。第一次全中则跳过第二次投球。补中或全中会导致分数递延到下回合计算。第十格需要处理额外投球。如果第一次实现不想被计分规则拖住可以先只记录“每回合倒瓶数”和“是否补中/全中”显示当前累计倒瓶数把标准保龄球规则作为第二步再接进去。先打通传感器链路再优化业务逻辑这个顺序更稳妥。6. 传感器检测与信号处理细节传感器接入 ESP32 时直接接 GPIO 往往不够稳定。信号调理这一步不能省。6.1 电平匹配与保护如果传感器模块输出 5V 电平而 ESP32 的 GPIO 只能承受 3.3V直接接线可能烧坏引脚。正确的做法是使用电平转换模块或者选择 3.3V 供电的传感器模块。若传感器是集电极开路输出可以在 ESP32 侧接上拉电阻到 3.3V这样既能保证电平正确也能利用内部上拉简化接线。6.2 消抖与防误触发传感器信号在触发瞬间往往存在抖动。软件消抖的两种常见方法时间窗口消抖中断触发后记录当前时间在 20ms 到 50ms 内忽略同引脚的新中断。连续采样确认触发后在主循环里连续读 5 次电平都满足条件才确认事件。第一种方法实现简单适合响应要求高的场景第二种方法更可靠但会占用更多主循环时间。保龄球场景中球的滚动速度不算极快20ms 的消抖窗口不会漏检。另一个值得做的优化是做“事件时间戳”日志。每个传感器触发事件都记录millis()这样在调试阶段可以回看事件的先后顺序和时间间隔判断是软件逻辑问题还是传感器位置问题。这个习惯能省下大量排错时间。6.3 传感器布局建议传感器安装位置是整个项目成败的关键。红外对射管建议安装在球道末端靠近球瓶区的位置球滚过时必然遮挡光束。球瓶区传感器安装在球瓶底部附近检测球瓶倒下时产生的震动或位移。如果安装位置离球瓶区太远传感器可能检测不到倒瓶事件太近又可能被球滚过的震动直接触发。具体距离要根据实际球道结构测试没有统一标准值。7. 显示与用户交互方案计分系统必须有一个直观的输出界面。常见三种方案7.1 OLED 屏幕方案小尺寸 SSD1306 OLED 适合原型开发显示当前回合、倒瓶数和累计分数。连接方式使用 I2C接线只有两根信号线代码量小。缺点是屏幕尺寸有限难以展示复杂计分表。驱动库推荐用U8g2它对多种 OLED 和 LCD 控制器兼容性较好。7.2 串口屏方案串口屏通过 UART 与 ESP32 通信ESP32 只需要发送格式化好的控制指令不需要直接驱动像素。适合对界面美观度有要求的场景。缺点是串口屏成本比 OLED 高协议手册需要花时间读。7.3 Web 页面方案ESP32 自带 WiFi可以启动一个轻量 HTTP 服务打球者用手机浏览器访问同一局域网内的 IP看到实时计分页面。这个方案的好处是交互界面可以做得很丰富不需要额外硬件成本。缺点是 WiFi 环境下存在一定的连接延迟和断连风险。如果要做这个方向ESP32 适合只做数据采集和计分计算通过 WebSocket 推送结果给浏览器展示。7.4 蓝牙 App 方案从热搜词看很多人在做“蓝牙 App 控制 ESP32”的项目。这个保龄球系统也可以加蓝牙把计分结果推送到手机 App。ESP32 内置 BLE用 BLE Notify 特征值广播当前分数即可。手机端用任意 BLE 调试工具就能接收数据不一定需要专门开发 App。这个扩展比较适合做毕设或者作品展示。8. 功能测试与效果验证8.1 分模块测试清单项目落地前建议按模块逐项测试不要一上来就整套联调。测试模块测试方法通过标准LED 指示灯测试给传感器通路接 LED手动遮挡传感器LED 能随遮挡动作亮灭GPIO 电平测试串口打印 GPIO 电平变化遮挡时电平翻转正确中断触发测试中断回调里打印日志每次遮挡只触发一次事件状态机测试模拟传感器信号串口观察状态变化状态切换符合预期计分逻辑测试手动注入倒瓶数观察分数计算基础计分结果正确显示刷新测试触发计分后看屏幕分数更新及时无残影整机稳定性测试连续运行 2 小时以上无死机、误触发率可接受8.2 第一批测试用例测试一单次击球检测输入手动遮挡球滚动传感器再触发球瓶区传感器。预期状态机从 READY 到 BALL_ROLLING 再到 PIN_FALL最终计分并刷新显示。判断串口日志里能看到完整的事件链。测试二重复击球误触发输入同一时间段内连续遮挡同一个传感器 5 次。预期只有第一次触发被接受后续 4 次被消抖逻辑过滤。判断串口没有重复日志状态没有错乱。测试三非法事件处理输入未发球时直接触发球瓶区传感器。预期状态机忽略该事件。判断当前状态不切换分数不变。8.3 失败排查方向如果传感器触发没有反应先查三处。第一GPIO 中断有没有正确注册可以用digitalPinToInterrupt()返回值是否为负判断。第二传感器的输出电平是否真的发生了翻转用万用表或串口打印确认。第三代码里有没有在中断回调里执行了阻塞操作如果有立刻移到主循环。如果显示不正确先查 I2C 地址是否匹配再用 I2C 扫描代码找出实际设备地址。OLED 常见地址是 0x3C 或 0x3D确认后修改驱动初始化参数即可。9. 接口 API 与数据扩展虽然这个项目本身没有暴露一套标准 REST API但 ESP32 的开发方式决定了你很容易把计分结果对外暴露。两种常见做法9.1 串口输出协议最简单的做法是定义一套稳定的串口文本协议任何上位机软件都能读取。{event:score,frame:3,throw:1,pins:7,total:42}每触发一次计分事件就输出一行 JSON上位机按行解析即可。这个方案零依赖适合和 PC、树莓派或者其他单片机对接。9.2 HTTP API把 ESP32 作为 HTTP 服务端运行一个轻量 Web 服务。使用WebServer库示例代码如下#include WebServer.h WebServer server(80); void handleScore() { String json {\score\: 42, \frame\: 3}; server.send(200, application/json, json); } void setupWiFiServer() { WiFi.mode(WIFI_STA); WiFi.begin(SSID, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); } server.on(/api/score, handleScore); server.begin(); }实际使用时需要把 SSID 和密码替换成你所在局域网的信息。接口路径和返回字段也需要按你的业务定义调整。有了这个接口外部系统就能按需轮询当前分数也能和记录系统、显示大屏对接。9.3 批量任务与多球道管理单颗 ESP32 适合处理一条球道。如果场馆有多条球道比较合理的架构是每条球道一颗 ESP32 采集数据 | 局域网 | 一台中心服务器汇总中心服务器按球道 ID 区分数据来源把计分结果写入数据库或转发到显示器。这个架构下每一颗 ESP32 都是独立的数据采集节点单点故障不会影响其他球道。10. 资源占用与性能观察ESP32 是双核处理器性能上跑这个项目完全够用但要注意任务划分。推荐把传感器事件读取放在 Core 0计分逻辑和显示刷新放在 Core 1避免逻辑互相干扰。具体实现时可以在loopTask之外启动一个独立任务。需要重点观察的性能指标有三个中断响应时延从传感器触发到 GPIO 回调执行的时间用micros()记录。主循环周期两次 loop() 之间的间隔避免因为显示刷新阻塞导致事件丢失。内存余量ESP32 的 RAM 不算大不要把 JSON 解析、日志输出等操作做得太重。可以使用ESP.getFreeHeap()监控堆内存剩余量。如果遇到堆内存持续下降优先排查是否在循环里反复创建String对象没释放。ESP32 的内存碎片问题在小内存设备上比想象中更常见。关于 CPU 推理和 GPU 推理这里先说明一下这个保龄球项目本质上不涉及模型推理没有显存相关需求。如果你之后想给系统加“基于摄像头画面的球瓶识别”那才需要考虑使用 ESP32-S3 的向量加速能力或者将图像推送到带 GPU 的服务端处理。这两条路径的性能参数差异很大需要按实际模型确定不在本文的假设范围内。11. 常见问题与排查方法问题现象可能原因排查方式解决方案烧录失败提示连接超时开发板没有进入下载模式按住 BOOT 键再点击烧录参考开发板说明书进入下载模式Arduino 下载 ESP32 库失败网络原因或源速度慢检查网络、换镜像源使用离线安装包手动安装传感器触发但串口无日志GPIO 中断未注册 / 电平接反打印 GPIO 状态确认电平变化检查attachInterrupt参数和触发边沿中断连续触发多次传感器信号抖动串口打印时间戳观察间隔增加软件消抖或 RC 硬件滤波按下按键导致开发板重启按键误接下载/复位引脚查看引脚图确认换用普通输入引脚OLED 显示花屏/无显示I2C 地址错误或接线松动运行 I2C 扫描程序修正地址或重新接线系统运行一段时间后卡死内存泄漏或 WiFi 重连异常监控ESP.getFreeHeap()优化字符串操作增加看门狗球瓶区传感器频繁误报安装位置太靠近球道震动区查看事件时间戳规律调整传感器位置或增加检测阈值WiFi 连接不稳定信号弱或供电不足检查电源适配器电流改用 5V/2A 独立供电供电问题要单独强调。ESP32 的瞬时电流可能到几百毫安如果使用开发板的 USB 口供电且同时带传感器和 OLED电压跌落会导致重启或传感器误触发。建议外部供电时选择电流余量充足的适配器并在 ESP32 电源输入脚并联一个 100uF 或更大容量的电容。12. 最佳实践与使用建议项目要稳定运行建议从一开始就做好几件事。第一目录结构保持清晰。把src、lib、include分离传感器驱动、显示驱动、计分逻辑拆成独立模块避免所有代码堆在main.cpp里。第二日志分级。开发阶段用Serial.println输出详细调试信息稳定运行阶段把日志级别调低或者加开关避免日志输出拖慢主循环。可以把日志输出做成宏封装编译时裁剪。第三每次修改硬件接线后先做最小验证再上完整逻辑。不要一次性把传感器、显示、WiFi 全部接好再调试遇到问题很难定位。第四接口服务如果开放到局域网要限制访问范围。至少做到两点接口只监听局域网地址而不是直接把端口暴露到公网如果后续把 ESP32 接入物联网平台要使用安全的连接凭证不要在代码里硬编码明文密码。第五涉及人脸、声音、位置等个人数据的采集场景必须提前获得当事人或场地管理方授权测试数据不要用于公开演示。第六批量部署时每一颗 ESP32 都要有唯一编号。可以通过按键设置、WiFi SSID 后缀或烧录时写死的配置来区分球道。建议在启动日志里打印设备 ID方便后期运维。13. 总结与下一步这个 ESP32 保龄球计分系统最值得尝试的点不是它实现了多复杂的算法而是它把一套完整的事件检测链路压缩到了单颗 MCU 上。从传感器信号到业务逻辑再到界面显示全部闭环。对于想深入 ESP32 开发的人这是一个比点灯、比读温湿度完整得多的练手项目。如果你想自己复刻建议按照这个顺序推进先把开发环境和 GPIO 中断跑通用串口打印传感器状态。再接 OLED 或串口屏完成最基本的分数显示。然后实现状态机把传感器事件和业务逻辑串成闭环。最后再加 WiFi 或蓝牙把数据外发到手机或服务器。最容易踩的坑有三处传感器信号抖动导致的误触发、GPIO 接线错误导致开发板无法烧录、状态机设计不合理导致的分数错乱。这三类问题在开发阶段一定会遇到提前有心理准备会省很多时间。后续可以扩展的方向不少用 ESP32-S3 加摄像头做视觉识别球瓶、用 BLE 对接手机 App 显示历史战绩、用 WiFi 把多球道数据汇总到中心服务器、加语音播报当前分数。最直接的路径是先跑通这套“传感器 - 状态机 - 计分 - 显示”的基础链路再往里面加你需要的功能模块。建议收藏备用动手的时候按组装顺序一步步来。
返回列表