Создаем умное баскетбольное кольцо на основе Ардуино и Андроид-приложения для отслеживания прогресса игры в баскетбол. Я регулярно тренируюсь в баскетбол и всегда отслеживаю статистику - количество бросков, результативность, промахи, время тренировки и т.д. Отслеживать эти цифры довольно скучно и сложно. Кто-то может сказать, что для этого можно использовать умные мячи, но у них есть ряд недостатков:
- Если вы хотите тренироваться с несколькими мячами, то нужно купить несколько довольно дорогих умных мячей.
- Точность таких мячей довольно сомнительна.
- Долговечность мяча также не долгая.
В своем проекте интеллектуального баскетбольного кольца ранее, я использовал устройство Avnet SmartEdge, чтобы протестировать процесс отслеживания тренировок по баскетболу. Мы будем использовать датчик ускорения, чтобы обнаруживать броски и датчик приближения, чтобы определять результаты. На этот раз идея этого проекта заключается в разработке окончательного решения для задачи реализации умного баскетбольного кольца на основе Ардуино. Сразу скажу, что наш проект состоит из двух основных частей - разработка на Arduino и на Android.
Шаг 1. Комплектующие
Для того, чтобы нам реализовать умное баскетбольное кольцо с использованием Ардуино, нам нужно достаточное количество комплектующих:
- Arduino Mega 2560 или Genuino Mega 2560 × 1
- Bluetooth Shield (шилд) × 1
- Инфракрасный датчик приближения E18-D80NK × 1
- Датчик вибрации Seeed Grove (SW-420) × 1
- 8 мм RGB LED × 1
- Резистор 10 кОм × 1
- Резистор 100 Ом × 3
- Резистор 47 Ом (резистор выводной (through hole resistors) - для навесного монтажа, а также монтажа в отверстия платы (объемный монтаж) × 1
- Перезаряжаемая литий-ионная аккумуляторная батарея 15000 мАч × 1
Из программного обеспечения нам понадобятся:
- Arduino IDE
- MIT App Inventor Android IDE
Шаг 2. Arduino
Некоторые соображения по поводу оборудования, используемого в этом проекте:
- Arduino Mega 2560. Я использовал эту плату, просто потому что она была в наличии, но вы можете использовать любую другую плату и менее дорогую, например, Arduino Uno или Arduino Nano.
- Bluetooth Shield. Здесь то же самое, что и выше про плату. Эта штука валялась у меня дома. Но, например, Bluetooth-модуль HC-05 является более дешевым вариантом.
- E18-D80NK инфракрасный датчик приближения. В этом проекте можно использовать несколько других датчиков приближения, но имейте в виду, что лучше использовать тот, который не подвержен влиянию солнечного света.
- Перезаряжаемая литий-ионная батарея. Используйте любой доступный источник питания.
Схема соединений нашего проекта ниже.
Я использовал Arduino IDE для разработки кода на Arduino, запрограммированного по следующей стратегии:
- После инициализации (переменные, светодиод, Bluetooth и т.д.) плата постоянно отслеживает состояние датчиков.
- Если датчик приближения обнаруживает присутствие мяча, - это означает, что бросок только что произошел, и это попадание.
- Если датчик вибрации обнаруживает какое-либо движение, - это означает, что бросок только что произошел, но он ждет 3 секунды (максимум), чтобы принять решение.
- В это время, если датчик приближения обнаруживает присутствие мяча, он (сразу) понимает, что это попадание.
- По истечении 3 секунд, если датчик приближения не обнаружил присутствие мяча, он понимает, что это промах.
- Arduino информирует Android через Bluetooth о том, что бросок (попадание или промах) только что был выполнен.
- Процесс возобновляется.
Код проект вы можете скачать или скопировать ниже:
//----------------------------------------------------------------------------// // DEFINITIONS // //----------------------------------------------------------------------------// // TURN ON DEBUG MODE // #define DEBUG // #define DEBUG_PROX // #define DEBUG_VIBR //----------------------------------------------------------------------------// // CONSTANTS // //----------------------------------------------------------------------------// // PINS const int prox_pin = 2; const int vibr_pin = 3; const int led_r_pin = 4; const int led_g_pin = 5; const int led_b_pin = 6; // TIME const unsigned long wait_interval = 3000; // MATH const float percent_to_bright_factor = 100 * log10(2) / log10(255); //----------------------------------------------------------------------------// // VARIABLES // //----------------------------------------------------------------------------// // TIME unsigned long wait_time; // STATUS boolean prox = false; boolean vibr = false; boolean wait = false; //----------------------------------------------------------------------------// // FUNCTIONS (SETTINGS) // //----------------------------------------------------------------------------// void setup() { // INITIATE PINS pinMode(prox_pin, INPUT); pinMode(vibr_pin, INPUT); pinMode(led_r_pin, OUTPUT); pinMode(led_g_pin, OUTPUT); pinMode(led_b_pin, OUTPUT); set_led(5, 100); // INITIATE SERIAL COMMUNICATION Serial.begin(9600); // INITIATE BLUETOOTH COMMUNICATION setup_bluetooth(); set_led(4, 100); #ifdef DEBUG Serial.println("Board is alive"); Serial.println(); #endif } void setup_bluetooth() { #ifdef DEBUG Serial.println("Setting Bluetooth"); Serial.println(); #endif Serial1.begin(38400); // Set baud rate Serial1.print("\r\n+STWMOD=0\r\n"); // Set to work in slave mode Serial1.print("\r\n+STNA=Arduino\r\n"); // Set name Serial1.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me Serial1.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here delay(2000); // This delay is required. Serial1.print("\r\n+INQ=1\r\n"); // Make the slave inquirable delay(2000); // This delay is required. while (Serial1.available()) { // Clear data delay(50); Serial1.read(); } } //----------------------------------------------------------------------------// // FUNCTIONS (LIGHT) // //----------------------------------------------------------------------------// int percent_to_bright(int percent) { // PERCENT: // 0..100 // RETURN BRIGHT // 255..0 return 256 - pow(2, percent / percent_to_bright_factor); } void set_led(int color, int bright) { // COLOR: // 0 = GREEN // 1 = YELLOW // 2 = RED // 3 = CYAN // 4 = BLUE // 5 = MAGENTA // 6 = WHITE // // BRIGHT: // 0 = OFF // .. // 100 = MAX #ifdef DEBUG Serial.println("Setting LED"); Serial.println(); #endif if (color < 0 || color > 6 || bright < 0 || bright > 100) { return; } int led_r_bright = 255; int led_g_bright = 255; int led_b_bright = 255; int bright_aux = percent_to_bright(bright); switch (color) { case 0: // GREEN led_g_bright = bright_aux; break; case 1: // YELLOW led_r_bright = bright_aux; led_g_bright = bright_aux; break; case 2: // RED led_r_bright = bright_aux; break; case 3: // CYAN led_g_bright = bright_aux; led_b_bright = bright_aux; break; case 4: // BLUE led_b_bright = bright_aux; break; case 5: // MAGENTA led_r_bright = bright_aux; led_b_bright = bright_aux; break; case 6: // WHITE led_r_bright = bright_aux; led_g_bright = bright_aux; led_b_bright = bright_aux; break; } analogWrite(led_r_pin, led_r_bright); analogWrite(led_g_pin, led_g_bright); analogWrite(led_b_pin, led_b_bright); return; } //----------------------------------------------------------------------------// // FUNCTIONS (CHECK) // //----------------------------------------------------------------------------// void check_prox() { if (!prox) { if(digitalRead(prox_pin) == LOW) { #ifdef DEBUG_PROX Serial.println("Proximity detected"); Serial.println(); #endif prox = true; if (!vibr) { wait = true; wait_time = millis() + wait_interval; } set_shot(1); } } } void check_vibr() { if (!prox && !vibr) { if(digitalRead(vibr_pin) == HIGH) { #ifdef DEBUG_PROX Serial.println("Vibration detected"); Serial.println(); #endif vibr = true; wait = true; wait_time = millis() + wait_interval; set_led(1, 100); } } } void check_wait() { if (wait && millis() > wait_time) { if (!prox) { set_shot(0); } reset(); } } //----------------------------------------------------------------------------// // FUNCTIONS (MIS) // //----------------------------------------------------------------------------// void set_shot(int mode) { // MODE: // 0 = WRONG SHOT (MISS) // 1 = RIGHT SHOT (SCORE) if (mode == 0) { set_led(2, 100); } else { set_led(0, 100); } Serial1.print(mode); delay(1000); } void reset() { vibr = false; prox = false; wait = false; set_led(4, 100); } //----------------------------------------------------------------------------// // MAIN // //----------------------------------------------------------------------------// void loop() { check_prox(); check_vibr(); check_wait(); }
Шаг 3. Android
Я использовал MIT App Inventor для разработки кода Android, запрограммированного по следующей стратегии:
- После инициализации (броски, попадания, промахи, Bluetooth и т.д.) оно ожидает нажатия кнопки «Пуск».
- Когда кнопка «Пуск» нажата, она постоянно отслеживает соединение Bluetooth.
- Каждый раз, когда оно получает информацию о броске, оно увеличивает соответствующий счетчик (попадание или промах) и воспроизводит нужный звук уведомления.
- Затем оно рассчитывает проценты и обновляет табло.
- Процесс повторяется до тех пор, пока не будут нажаты кнопки «Пауза» или «Сброс».
Код можно скачать ниже:
Шаг 4. Создание баскетбольного кольца
Это моё оригинальное баскетбольное кольцо, которое я регулярно использую для тренировок по баскетболу.
Сначала я снял пластиковую крышку под обручем и сделал отверстие для датчика приближения.
Затем я сделал маленькое отверстие для крепления датчика вибрации.
Я не мог прикрепить датчик непосредственно к пластиковой крышке из-за его кривизны, поэтому я сделал внутреннюю опору датчика, используя МДФ.
Я зафиксировал датчики приближения и вибрации, используя несколько болтов и гаек.
Затем я поместил остальную электронику в корпус.
Время протестировать устройство умного кольца.
Наконец я установил все на основу баскетбольного кольца.
Теперь пришло время всё проверить.
Шаг 5. Заключительные соображения
Система оказалась очень точной, с очень небольшим количеством ложных срабатываний и действительно редкими ложными отрицаниями.
Очень приятно играть с системой. Можно узнать статистику тренировок в режиме реального времени и после тренировки. Можно дальше проработать некоторые улучшения, добавить некоторые функции, такие как:
- Тайм-менеджмент.
- Функция памяти.
- Больше данных (бросков в минуту, температура и т.д.)
- Уведомление о достижении цели.
На этом всё. Желаю вам хорошей тренировки.