Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Компоненты и материалы

Arduino Nano R3 2 шт.
SparkFun 9DoF Sensor Stick (LSM9DS1) 1 шт.
Провода-перемычки 1 комплект
NeoPixel лента (матрица 15x10) 1 шт.
Bluetooth-модуль HC-05 1 шт.
Крона 9В 1 шт.

Необходимые инструменты

Приложения и сервисы

О проекте

Проект состоит из трёх частей: игровая доска/дисплей, контроллер (ракетка) и мастер-маршрутизатор (Python-скрипт на хост-компьютере).

Часть 1 — Дисплей

Дисплей — матрица 15×10 на NeoPixel, управляемая Arduino Nano. Она обрабатывает игровую логику и команды от Python-скрипта. Отображает мяч, который растет и движется по матрице, создавая иллюзию глубины и приближения. При обнаружении удара мяч перерисовывается «улетающим» от игрока.

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Очки

Направление мяча (влево/вправо) меняется при каждом ударе. Если игрок промахнулся — очко компьютеру (COM). Если COM промахивается (25% шанс) — очко игроку. Похоже на Wii Sports Tennis. Счёт отображается при очках COM.

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Рекорд

Рекорд хранится в I2C EEPROM по адресу 0x04 (один байт). При побитии перезаписывается. Если COM набирает 10 очков — конец игры. Логика на диаграмме:

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Сборка матрицы

Сборка матрицы занимает время, следуйте руководству:

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Часть 2 — Контроллер (Ракетка)

Второй Arduino Nano с 9DoF стиком (только 3.3В!) и HC-05 BLE. Если ускорение по X или Y превышает порог (1.5g), отправляет «1» по Serial на хост-ПК, где Python-скрипт пересылает его дисплею. Nano опрашивает акселерометр с заданным интервалом. Для работы с LSM9DS1 нужна библиотека SparkFun (ссылка) и туториал по подключению (ссылка).

Ракетка сделана из коробки: вырезан картонный силуэт, поверх — бумага с рисунком. Питание — крона 9В через Vin Nano (не подавайте 9В на 5V пин!). Внутренности:

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Обмен по Bluetooth

Ракетка и дисплей не общаются напрямую. Python-скрипт использует два COM-порта (Bluetooth ракетки и USB дисплея) для ретрансляции данных. Также синхронизирует системы при инициализации портов. Дебаунс 1 сек предотвращает переполнение буферов (32 байта).

Ракетка — пошагово

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Приятной игры! Видео геймплея: (вставьте ссылку)

Код

Код матрицы (C/C++)

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

#define PIN 6           // Data pin для матрицы
#define EEPROM_ADR 0x50 // I2C адрес EEPROM
#define HS_ADR 0x02     // Адрес байта рекорда в EEPROM
#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();
  if (serial_data) isSwung = true;
  else isSwung = false;

  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 += 1; end_round();
  } else if (ball_y <= 2) {
    isDirRight = !isDirRight;
    int randNum = random(4);
    Serial.println(randNum);
    if (randNum == 2) { // 25% шанс промаха COM
      score += 1;
      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) {}
}

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 -= 1;
    matrix.show();
    delay(150);
  }
}

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

Код ракетки (C/C++)

#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 True:
    data = racquet.read()
    print(data)
    if data == "1":
        print("hit")
        matrix.write("1")
        time.sleep(1)
    time.sleep(0.05)

Схемы

Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth
Arduino Tennis Game — Виртуальный теннис на NeoPixel, датчиках и Bluetooth

Производственный процесс

  1. TinyML-детектор языка на Arduino Nano 33 BLE Sense с Edge Impulse
  2. Создание игры в реальном времени на Arduino Nano с гироскопом MPU-6050 и OLED-дисплеем
  3. Цифровые кости на Arduino: генератор случайных чисел с LCD-дисплеем и кнопкой
  4. Строим Iron Man на Arduino: компоненты, сенсоры и пошаговый гайд
  5. Find Me: Умный поисковик вещей на Arduino и Bluetooth
  6. DIY-контроллер увлажнителя на Arduino с реле: безопасная работа с высоким напряжением
  7. Измерение расстояния в реальном времени: Ардуино-сонар с визуализацией в Processing
  8. MobBob: Самостоятельная сборка Arduino-робота под управлением Android-смартфона
  9. Сборка аудиореактивной настольной лампы на Arduino Nano
  10. NeoPixel Matrix Pong на Arduino Nano: неоновая игра Pong на матрице 15×10