Виртуальный теннис на Arduino
Компоненты и расходные материалы
![]() |
| × | 2 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 |
Необходимые инструменты и машины
![]() |
|
Приложения и онлайн-сервисы
![]() |
|
Об этом проекте
Этот проект состоит из 3 частей:игрового поля / дисплея, контроллера и главного маршрутизатора (скрипт Python).
Часть 1 - Дисплей
Дисплей представляет собой неопиксельную матрицу 15x10, которая работает от Arduino Nano. Он обрабатывает логику игры и вводит скрипт Python, запущенный на главном компьютере. Он отображает мяч, который растет и движется дальше по матрице, создавая иллюзию глубины и полета мяча на вас. Если он обнаруживает, что мяч поражен, мяч будет перерисован, уходя «в сторону» от вас.

Очки
Направление мяча (влево или вправо) меняется с каждым ударом. Если вы пропустите мяч, COM получает очко, но если COM промахивается (вероятность 25%), вы получаете очко. Этот игровой дизайн похож на версию тенниса для Wii Sports. Очки отображаются всякий раз, когда СОМ забивает игроку.

Высокая оценка
Текущий рекорд хранится в I2C EEPROM по адресу 0x04. Он хранит байт, в котором хранится высокий балл. Если вы набрали больше, чем предыдущий рекорд, адрес будет перезаписан. Если COM набирает 10 баллов, игра окончена ... Если это сбивает с толку, я сделал логическую схему:

Сделайте матрицу
Создание матрицы займет некоторое время, поэтому следуйте руководству, которое я сделал здесь.


Часть 2 - Контроллер
Контроллер - это еще один Arduino Nano, к которому прикреплен стик 9DoF (только 3v3!) И модуль HC-05 BLE. Если ускорение оси x или y превышает заданный порог, он отправляет «1» через последовательный порт на главный компьютер, где он передается на дисплей. Nano снимает показания акселерометра x и y с заданным интервалом, после чего проверяет, падают ли значения выше или ниже 1,5 грамма. Чтобы получить доступ к флешке I2C 9 DoF, вы должны установить библиотеку Sparkfun, которую можно скачать здесь. Здесь также есть руководство о том, как подключить датчик и запускать с ним базовые программы.
Для создания ракетки я использовал коробку, а затем вырезал форму ракетки на куске картона. Оттуда это было просто - просто накройте картонный вырез листом белой бумаги и нарисуйте узор на бумаге. Я использовал батарею 9 В для питания установки, просто убедитесь, что батарея подключена к контакту Vin на Nano, иначе это будет нерегулируемый 9 В! Вот изображение внутреннего устройства ракетки:

Общайтесь через Bluetooth
Итак, теперь вам может быть интересно, что контролирует эту сложную операцию? Как ракетка взаимодействует с дисплеем? Вот секрет:они не разговаривают друг с другом! Существует простой сценарий Python, который использует входящий COM-порт Bluetooth и COM-порт матрицы для передачи информации между ними. Это также помогает синхронизировать две системы, поскольку они обе сбрасываются при инициализации последовательных портов. Ракетка отправляет «1» скрипту Python через Bluetooth, а затем скрипт Python отправляет «1» в матрицу. Имеется задержка в 1 секунду, поэтому последовательные порты не переполняют свои буферы (у них есть только 32-битные буферы).
Ракетка
Просмотрите изображения, чтобы узнать, как я построил ракетку:






Удачи в новой игре в теннис!
Видео игры в теннис:
Код
- Матричный код
- Код ракетки
- Код Python
Матричный код C / C ++
Идет на Arduino, прикрепленном к матрице.#include#include #include #include #include #define PIN 6 // Вывод данных для матрицы # define EEPROM_ADR 0x50 // I2C-адрес EEPROM # define HS_ADR 0x02 // Адрес байта рекорда в EEPROM # define NOTE_C1 33 # define SPKR_PIN 3Adafruit_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; // Координата мяча по оси X ball_y =2; // Координатный радиус шара по оси Y =1; // Радиус шара int r_incr =1; // Насколько увеличить радиус bybool isSwung =false; // Размах ракетки ball_x_dir =1; // Направление мяча по оси Xint ball_y_dir =1; // Направление мяча по оси Y isDirRight =true; int score =0; // Оценка текущей игры int COM_score =0; int 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}; int tempo [] ={0}; static unsigned long lastFrame =0; void setup () {Serial.begin (9600); matrix.begin (); matrix.fillScreen (0); matrix.setTextColor (цвета [1]); randomSeed (analogRead (A2)); display_scores (); рекорд =read_HS (); Serial.println (рейтинг, DEC); matrix.setCursor (0,1); matrix.print ("HS:"); matrix.show (); задержка (1000); matrix.fillScreen (0); matrix.setCursor (0,1); matrix.print (рейтинг, DEC); matrix.show (); задержка (1000); score_string ="";} void loop () {if ((lastFrame + framerate) =5 &&ball_y <7 &&isSwung) {if (isDirRight) {ball_x_dir =-1; ball_y_dir =-1; } иначе, если (! isDirRight) {ball_x_dir =1; ball_y_dir =-1; } r_incr =-1; } иначе, если (ball_y> =8) {COM_score + =1; end_round (); } иначе, если (ball_y <=2) {isDirRight =! isDirRight; int randNum =случайный (4); Serial.println (randNum); if (randNum ==2) {// 25% шанс пропуска ошибки COM + =1; если (оценка> рекорд) {write_HS (); } end_round; } else {if (isDirRight) {ball_x_dir =1; ball_y_dir =1; } иначе, если (! isDirRight) {ball_x_dir =-1; ball_y_dir =1; } r_incr =1; }} ball_x + =ball_x_dir; мяч_y + =мяч_y_dir; радиус + =r_incr; matrix.fillScreen (0); matrix.fillCircle (ball_x, ball_y, radius, colors [2]); matrix.show ();} void end_round () {если (COM_score> =10) {end_game (); } isDirRight =true; r_incr =1; ball_x_dir =1; ball_y_dir =1; ball_x =7; ball_y =2; радиус =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 (цвета [0]); matrix.drawLine (3,0,12,9, цвета [0]); matrix.drawLine (11,0,2,9, цвета [0]); matrix.show (); задержка (500); в то время как (1) {}} void display_scores () {matrix.fillScreen (0); matrix.setTextColor (цвета [1]); matrix.setCursor (0,1); Score_string =Строка (оценка) + «-» + Строка (COM_score); scrollText (Score_string); matrix.fillScreen (0); задержка (2000); matrix.show ();} void scrollText (текст строки) {int pass =0; int x =matrix.width (); для (int я =0; я <24; я ++) {matrix.fillScreen (0); matrix.setCursor (x, 2); matrix.print (текст); х - =1; matrix.show (); задержка (150); }} void write_HS () {EEPROM.write (0x04, int (оценка));} int read_HS () {byte HS =EEPROM.read (0x04); // Считываем с адреса 4 return HS;}
Код ракетки C / C ++
#include#include #include LSM9DS1 imu; #define LSM9DS1_M 0x1E // Будет 0x1C, если SDO_M LOW # определить LSM9DS1_AG 0x6B // Будет 0x6A SDO_AG is LOW # define PRINT_SPEED 10 // 10 мс между проверками статическое значение без знака long lastPrint =0; // Отслеживайте время печати Accelx =0; Float 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) =1,5) {Serial.print (1); задержка (600); } else if (Accely <=-1,5 || Accely> =1,5) {Serial.print (1); задержка (600);}}
Код Python Python
import serialimport timematrix_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 ( ) распечатать данные, если data =="1":напечатать "hit" matrix.write ("1") time.sleep (1) time.sleep (.05)
Схема


Производственный процесс
- Детектор языка TinyML на основе Edge Impulse и Arduino
- Игра с гироскопом Arduino с MPU-6050
- Цифровые игральные кости Arduino
- Железный человек
- Найди меня
- Управление увлажнителем Arduino
- Сонар с использованием Arduino и отображение при обработке IDE
- MobBob:самостоятельный робот Arduino, управляемый смартфоном Android
- Реактивный настольный светильник для звука Arduino
- NeoMatrix Arduino Pong