ARTICLE DETAIL

资讯详情

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

ESP32保龄球计分系统实战:从硬件到算法全解析

ESP32保龄球计分系统实战:从硬件到算法全解析 做保龄球计分这类互动硬件时最容易被低估的往往不是代码而是“规则、传感器和状态机”三者怎么咬合的问题。ESP32 上能跑的计分方案很多但真正把球瓶检测、补投规则、LED 反馈、手机控制串成一套完整系统的教程很少。这篇文章围绕一个 ESP32 保龄球计分系统展开从硬件选型、环境搭建、计分算法、传感器采集到无线控制扩展把完整技术方案拆开讲清楚适合正在做 ESP32 项目、想从点灯进阶到完整交互系统的开发者参考。1. ESP32 保龄球系统概述与整体架构1.1 这个项目到底做什么一个 ESP32 保龄球系统本质上是把传统的保龄球记分流程自动化。传统场景里玩家掷球、球瓶倒下、人工计分、重新摆瓶整个过程依赖人眼判断。而 ESP32 方案要完成的工作包括检测球是否已经滚出触发一轮计分流程识别 10 个球瓶当前是站立还是倒下根据保龄球官方计分规则计算当前得分通过灯带、OLED 屏幕或手机 App 实时展示分数在每一轮结束后提醒玩家复位球瓶并开启下一轮。这类系统的应用场景很多比如桌面迷你保龄球台、商场互动游戏设备、创客教育项目甚至可以作为体育训练时的辅助计分设备。相比使用摄像头做视觉识别传感器方案的成本更低、实时性更好也更适合从 Arduino 或 ESP32 入门的新手学习和二次开发。1.2 系统整体架构整个系统可以分成三层来看层级负责内容典型硬件传感层检测发球、检测球瓶状态红外避障传感器、倾斜开关、MCP23017 I/O 扩展逻辑层计分规则、状态机、数据存储ESP32 主控、计分算法代码展示与控制层分数显示、灯光反馈、远程控制WS2812B 灯带、OLED、手机蓝牙或 WiFi这里的关键设计思路是不要把 10 个球瓶传感器直接接到 ESP32 的 GPIO 上。ESP32 虽然有较多引脚但接 10 路传感器后可用引脚已经很紧张而且后续还要接灯带、蜂鸣器、按键、无线模块。更好的做法是使用 MCP23017 这类 I2C I/O 扩展芯片用两根线扩展出 16 路数字输入只占用 ESP32 的 SDA 和 SCL。1.3 为什么选 ESP32 而不是 Arduino Uno 或树莓派相比 Arduino UnoESP32 的优势非常明显主频更高、内存更大、自带 WiFi 和蓝牙可以方便地实现手机控制、局域网数据上报。相比树莓派ESP32 成本更低、启动更快、没有操作系统负担适合做这种“传感器采集 简单展示”的嵌入式系统。另外ESP32 开发板型号很多比如常见的 ESP32 Dev Kit、ESP32-S2、ESP32-S3一般的计分系统使用双核 ESP32 就完全足够。2. 硬件选型与接线方案2.1 完整硬件清单下面是一套完整的硬件清单按功能模块分组模块型号/器件数量作用主控ESP32 DevKit 开发板1运行计分逻辑与控制逻辑I/O 扩展MCP23017 模块1扩展 16 路数字输入连接球瓶传感器倾斜传感器SW-520D 振动/倾斜开关10判断每个球瓶是否倒下发球检测红外避障传感器模块1检测球是否通过发球区显示WS2812B 灯带 或 8x8 LED 点阵若干计分板与灯光反馈可选显示SSD1306 0.96 英寸 OLED1显示帧数、分数、提示信息输入按键开关1复位球瓶、开始新一轮报警有源蜂鸣器1全中、补中等事件提示音电源5V 2A USB 电源1系统供电如果暂时没有 MCP23017也可以用 CD74HC4067 模拟开关多路复用器4 个选择引脚加 1 个信号引脚就能读 16 路开关但代码上需要用查表方式切换通道比 MCP23017 稍微麻烦一些。2.2 引脚分配参考不同 ESP32 开发板的引脚布局有差异以下是一份经过验证的参考分配方案实际制作时需要根据开发板丝印调整ESP32 GPIO连接对象GPIO21I2C SDA接 MCP23017 SDAGPIO22I2C SCL接 MCP23017 SCLGPIO4红外避障传感器数字输出GPIO5WS2812B 灯带数据输入GPIO15复位按键接一个 10kΩ 上拉电阻到 3.3VGPIO18蜂鸣器正极GND所有模块共地3.3V / 5V按模块要求分别供电MCP23017 的 A0、A1、A2 地址引脚全部接 GNDI2C 地址为 0x20。球瓶倾斜开关接入 MCP23017 的 GPA0 到 GPA7以及 GPB0 和 GPB1正好对应通道 0 到 9。2.3 接线与供电注意事项接线时需要注意以下几点电源不要走杜邦线串联到底。ESP32、灯带、传感器如果全部从一个 USB 口取电灯带全亮时电流很容易超过 500mA导致电压跌落、传感器误判。推荐使用 5V 2A 电源灯带单独供电ESP32 和传感器共用一组电源并且所有模块共地。倾斜开关需要上拉。SW-520D 这类机械式倾斜开关相当于一个开关量输出悬空时电平不稳定。MCP23017 内部有可配置的上拉电阻初始化时通过pullUp()开启即可不需要每个引脚外接上拉电阻。红外避障传感器要调节灵敏度。模块上通常有一个蓝色电位器用来调节检测距离。球从传感器前方经过时输出低电平如果检测距离太近或者太远会导致触发失败。3. 开发环境搭建Arduino IDE ESP323.1 Arduino IDE 安装 ESP32 支持Arduino IDE 默认不包含 ESP32 开发板需要先在“开发板管理器”中安装支持包。打开 Arduino IDE进入“文件 - 首选项”在“附加开发板管理器网址”中添加https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json然后进入“工具 - 开发板 - 开发板管理器”搜索esp32选择 Espressif Systems 官方提供的esp32包并安装。如果在线下载较慢或失败可以先把官方打包好的离线安装包下载到本地解压或放到 Arduino15 对应目录后重新打开 IDE也能完成安装。3.2 选择开发板与烧录设置安装完成后在“工具 - 开发板 - ESP32 Arduino”中选择ESP32 Dev Module。串口选择实际识别的 COM 口或/dev/ttyUSB0。上传速度建议设置为921600如果烧录不稳定可以降到115200。如果开发板无法识别通常是因为 USB 转串口芯片驱动没有安装。使用 CH340 芯片的开发板需要安装 CH340 驱动使用 CP2102 芯片的则安装 CP210x 驱动。烧录失败时可以按住开发板上的 BOOT 按键不放点击“上传”等待出现Connecting...提示后再松开 BOOT。ESP32 烧录后出现无法烧录的情况多数也是这个问题。3.3 项目所需 Arduino 库本系统需要安装以下第三方库库名安装来源用途Adafruit MCP23017库管理器搜索MCP23017操作 I2C I/O 扩展Adafruit NeoPixel库管理器搜索NeoPixel控制 WS2812B 灯带Adafruit SSD1306库管理器搜索SSD1306驱动 OLED 显示Adafruit GFX库管理器搜索GFXSSD1306 的图形依赖BluetoothSerial无需安装ESP32 经典蓝牙串口通信库管理器搜索时要注意Adafruit 的 MCP23017 库和 Adafruit SSD1306 库都依赖 Adafruit GFX后者会作为依赖自动安装。4. 保龄球计分规则与程序设计4.1 规则梳理保龄球标准计分规则有一些容易混淆的地方先把它整理清楚一局共 10 轮。前 9 轮每轮最多投两次球第 10 轮比较特殊。如果第一球就打倒全部 10 个球瓶称为全中这一轮立即结束不需要投第二球。如果两球打倒全部球瓶称为补中。全中的作用是“本次 10 分 之后两次投球的被击倒数”。补中的作用是“本次 10 分 之后一次投球的被击倒数”。第 10 轮如果投出全中或补中还可以额外追加投球最多允许三球。写计分代码时最容易出错的就是“当前这一轮还没结束不能把奖励分算进去”。所以计分函数不能只累加当前数据必须判断后续投球数据是否已经产生。4.2 计分引擎设计把计分逻辑独立成一个函数输入是每次投球击倒的球瓶数数组输出是某一轮结束后的累计分数。设计如下int computeScoreAt(const int rolls[], int rollCount, int frame) { int score 0; int roll 0; for (int f 0; f frame; f) { if (roll 1 rollCount) break; // 数据不足无法结算 if (rolls[roll] 10) { // 全中必须等后面两次投球数据才能累计 if (roll 2 rollCount) { score 10 rolls[roll 1] rolls[roll 2]; } roll; } else if (rolls[roll] rolls[roll 1] 10) { // 补中必须等后面一次投球数据才能累计 if (roll 2 rollCount) { score 10 rolls[roll 2]; } roll 2; } else { score rolls[roll] rolls[roll 1]; roll 2; } } return score; }rolls数组按顺序保存每一次实际投球的击倒数。比如玩家第 1 轮投出全中rolls[0] 10此时rollCount只有 1computeScoreAt(..., 1)会因为数据不足而返回 0。等第 2 轮第一球结束后rollCount变为 2仍然无法补采第 3 个数据直到第 2 轮第二球结束rollCount变为 3第 1 轮分数才能结算为10 rolls[1] rolls[2]。4.3 主循环状态机设计系统的主循环不能简单地“一检测到球就立即读传感器”。球滚动、碰撞、球瓶摇晃都需要时间所以这里使用状态机把流程拆开状态行为WAIT_BALL等待红外传感器检测到球通过WAIT_SETTLE球瓶摇晃等待1.2 秒后读取球瓶状态SHOW_RESULT显示本轮分数等待玩家复位球瓶并按键确认这个状态机的好处是把“检测事件”和“处理结果”解耦。如果
返回列表