亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

组件与材料

组件数量
Arduino Nano R32
SparkFun 9DoF Sensor Stick (LSM9DS1)1
杜邦线若干
NeoPixel 灯条 (15x10 矩阵)1
HC-05 蓝牙模块1
9V 电池1

所需工具

应用与在线服务

项目简介

项目包含三部分:游戏显示板(矩阵)、控制器(球拍)、主路由(Python 脚本)。

第一部分:显示板

15x10 NeoPixel 矩阵由一块 Arduino Nano 驱动,运行游戏逻辑并接收 Python 脚本指令。矩阵显示一个“球”,通过逐渐变大并向下移动产生立体感(球向你飞来)。检测到挥拍后,球会反向重绘(飞离你)。

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

得分机制

每次击球球的左右方向翻转。漏球则 COM 得分;COM 有 25% 概率漏球,此时玩家得分。类似 Wii Sports 网球。COM 得分时会在矩阵上滚动显示比分。

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

最高分记录

最高分存储在 I2C EEPROM 地址 0x04 处(单字节)。破纪录时自动覆盖。COM 达 10 分游戏结束。逻辑流程图如下:

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

制作矩阵

矩阵制作耗时,可参考作者制作指南。

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

第二部分:控制器(球拍)

另一块 Arduino Nano 接 9DoF 传感器(仅支持 3.3V)和 HC-05 蓝牙模块。当 X 或 Y 轴加速度超过阈值(±1.5g),通过串口发送 1 给主机 Python 脚本,再由脚本转发给显示板。需安装 SparkFun LSM9DS1 库。

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

球拍外壳用纸箱剪裁,贴白纸绘制图案。供电用 9V 电池接 Nano 的 Vin 引脚(勿直供 9V 到 5V 引脚)。

蓝牙通信与 Python 中转

球拍与显示板不直接通信,由 Python 脚本中转:读取蓝牙串口(球拍)数据,写入显示板串口。脚本还负责同步两端复位(串口初始化会复位 Arduino)。设置 1 秒防抖,防止 32 字节缓冲区溢出。

球拍制作步骤

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

代码

显示板代码

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <EEPROM.h>

#define PIN 6
#define EEPROM_ADR 0x50
#define HS_ADR 0x02
#define NOTE_C1 33
#define SPKR_PIN 3

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(15, 10, PIN,
  NEO_MATRIX_BOTTOM + NEO_MATRIX_LEFT + NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
  NEO_GRB + NEO_KHZ800);

int ball_x = 7, ball_y = 2, radius = 1, r_incr = 1;
bool isSwung = false;
int ball_x_dir = 1, ball_y_dir = 1;
bool isDirRight = true;
int score = 0, COM_score = 0, highscore = 0;
int framerate = 50;
int serial_data;
String score_string = "";
uint16_t colors[] = {matrix.Color(255,0,0), matrix.Color(0,255,0), matrix.Color(150,200,0)};
int melody[] = {0}, tempo[] = {0};
static unsigned long lastFrame = 0;

void setup() {
  Serial.begin(9600);
  matrix.begin();
  matrix.fillScreen(0);
  matrix.setTextColor(colors[1]);
  randomSeed(analogRead(A2));
  display_scores();
  highscore = read_HS();
  Serial.println(highscore, DEC);
  matrix.setCursor(0,1); matrix.print("HS: "); matrix.show(); delay(1000);
  matrix.fillScreen(0); matrix.setCursor(0,1); matrix.print(highscore,DEC); matrix.show(); delay(1000);
  score_string = "";
}

void loop() {
  if ((lastFrame + framerate) < millis()) {
    update_frame();
    lastFrame = millis();
  }
}

void update_frame() {
  serial_data = Serial.parseInt();
  isSwung = (serial_data != 0);

  if (ball_y >= 5 && ball_y < 7 && isSwung) {
    if (isDirRight) { ball_x_dir = -1; ball_y_dir = -1; }
    else { ball_x_dir = 1; ball_y_dir = -1; }
    r_incr = -1;
  } else if (ball_y >= 8) {
    COM_score++; end_round();
  } else if (ball_y <= 2) {
    isDirRight = !isDirRight;
    int randNum = random(4);
    Serial.println(randNum);
    if (randNum == 2) { // 25% COM miss
      score++;
      if (score > highscore) write_HS();
      end_round();
    } else {
      if (isDirRight) { ball_x_dir = 1; ball_y_dir = 1; }
      else { ball_x_dir = -1; ball_y_dir = 1; }
      r_incr = 1;
    }
  }
  ball_x += ball_x_dir;
  ball_y += ball_y_dir;
  radius += r_incr;
  matrix.fillScreen(0);
  matrix.fillCircle(ball_x, ball_y, radius, colors[2]);
  matrix.show();
}

void end_round() {
  if (COM_score >= 10) end_game();
  isDirRight = true; r_incr = 1;
  ball_x_dir = 1; ball_y_dir = 1;
  ball_x = 7; ball_y = 2; radius = 1;
  display_scores();
  matrix.fillScreen(0);
  matrix.fillCircle(ball_x, ball_y, radius, colors[2]);
  matrix.show();
}

void end_game() {
  matrix.fillScreen(0);
  matrix.setCursor(0,1); matrix.setTextColor(colors[0]);
  matrix.drawLine(3,0,12,9,colors[0]);
  matrix.drawLine(11,0,2,9,colors[0]);
  matrix.show(); delay(500);
  while(1); // halt
}

void display_scores() {
  matrix.fillScreen(0);
  matrix.setTextColor(colors[1]);
  matrix.setCursor(0,1);
  score_string = String(score) + "-" + String(COM_score);
  scrollText(score_string);
  matrix.fillScreen(0); delay(2000); matrix.show();
}

void scrollText(String text) {
  int x = matrix.width();
  for (int i=0; i<24; i++) {
    matrix.fillScreen(0);
    matrix.setCursor(x,2);
    matrix.print(text);
    x--;
    matrix.show();
    delay(150);
  }
}

void write_HS() { EEPROM.write(0x04, int(score)); }
int read_HS() { return EEPROM.read(0x04); }

球拍代码

#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>

LSM9DS1 imu;
#define LSM9DS1_M 0x1E
#define LSM9DS1_AG 0x6B
#define PRINT_SPEED 10

static unsigned long lastPrint = 0;
float accelx = 0, accely = 0;

void setup() {
  Serial.begin(9600);
  imu.settings.device.commInterface = IMU_MODE_I2C;
  imu.settings.device.mAddress = LSM9DS1_M;
  imu.settings.device.agAddress = LSM9DS1_AG;
  if (!imu.begin()) while(1);
}

void loop() {
  if ((lastPrint + PRINT_SPEED) < millis()) {
    if (imu.accelAvailable()) imu.readAccel();
    lastPrint = millis();
  }
  accelx = imu.calcAccel(imu.ax);
  accely = imu.calcAccel(imu.ay);
  if (accelx <= -1.5 || accelx >= 1.5) {
    Serial.print(1); delay(600);
  } else if (accely <= -1.5 || accely >= 1.5) {
    Serial.print(1); delay(600);
  }
}

Python 中转脚本

import serial, time
matrix_port = "COM3"
raquet_port = "COM9"
matrix = serial.Serial(matrix_port, 9600)
racquet = serial.Serial(raquet_port, 9600)
time.sleep(10)
while 1:
  data = racquet.read()
  print(data)
  if data == "1":
    print("hit")
    matrix.write("1")
    time.sleep(1)
  time.sleep(0.05)

原理图

Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验
Arduino 网球游戏:NeoPixel + 9DoF 传感器 + 蓝牙打造虚拟球拍体验

制造工艺

  1. 基于 Edge Impulse 的 TinyML 语言检测器:Arduino Nano 33 BLE Sense 实战
  2. Arduino Nano 与 MPU-6050 构建实时陀螺仪游戏
  3. Arduino 数字骰子:LCD 显示随机点数的电子骰子
  4. DIY 钢铁侠人偶:Arduino 控制超声波触发音效与灯光
  5. Find Me:基于 Arduino 与蓝牙的智能寻物器制作指南
  6. DIY Arduino 加湿器控制器:继电器安全控制高压电路
  7. Arduino 声纳实时测距与 Processing 可视化
  8. MobBob:3D 打印智能机器人,Android 手机无缝控制,语音视觉一体
  9. 声控氛围灯:Arduino Nano + 麦克风模块 + WS2812B 灯珠
  10. Arduino Nano 驱动 NeoPixel 矩阵:自制霓虹乒乓游戏
  11. DIY Arduino 手柄方向盘 - 游戏竞速模拟器自制指南
  12. Arduino 101 计步器:集成 DHT11 温湿度 + LCD 显示步数/距离/卡路里