산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

부품 및 소모품

부품수량비고
아두이노 나노 R31
HC-05 블루투스 모듈1
E18-D80NK 적외선 근접 센서1햇빛 간섭이 적은 타입 권장
Seeed Grove 진동 센서 (SW-420)1
DHT22 온습도 센서1
8mm RGB LED1
저항 10kΩ3
저항 100Ω3
저항 47Ω1
저항 1kΩ1
저항 2.21kΩ1
9V 배터리1

앱 및 온라인 서비스

프로젝트 소개

저는 정기적으로 농구 훈련을 하며 슛 횟수, 득점, 실책 등 통계를 기록합니다. 이를 수동으로 하기엔 지루하고 어렵습니다. 스마트 볼을 쓰면 되지만 단점이 있습니다:

이전 프로젝트(스마트 농구 스코어보드 프로토타입)에서는 Avnet SmartEdge 장치로 가속도 센서(슛 감지)와 근접 센서(득점 감지)를 테스트했습니다. 이번 프로젝트는 농구 스코어보드 작업을 위한 결정적인 솔루션을 구현하는 것입니다.

버전

초기에는 집에 있던 하드웨어로 1.1.0 버전을 개발해 잘 작동함을 확인했습니다. 이후 더 저렴한 부품으로 교체하고 소프트웨어를 개선한 2.0.0 버전을 만들었습니다.

1단계: 아두이노

하드웨어

버전 2.0.0의 부품 목록은 위 표를 참고하세요. 1.1.0에서 2.0.0으로의 주요 변경사항:

기타 부품 고려사항:

두 버전의 회로도는 회로도 섹션에 있습니다.

소프트웨어

아두이노 IDE로 개발했으며 전략은 다음과 같습니다:

  1. 초기화(변수, LED, 블루투스 등) 후 센서 상태를 지속적으로 모니터링
  2. 근접 센서가 공을 감지하면 득점으로 판정
  3. 진동 센서가 움직임을 감지하면 슛 발생으로 보고 2초간 대기하며 판정
  4. 대기 중 근접 센서가 공을 감지하면 즉시 득점 처리
  5. 2초 후에도 근접 센서가 감지하지 못하면 실책으로 판정
  6. 블루투스로 안드로이드 앱에 슛 결과(득점/실책) 전송
  7. 과정 반복

버전 2.0.0에서의 주요 소프트웨어 변경:

두 버전의 코드는 코드 섹션에 있습니다.

2단계: 안드로이드 앱

MIT App Inventor로 개발했으며 전략:

  1. 초기화(슛/득점/실책 카운트, 블루투스 등) 후 '시작' 버튼 대기
  2. '시작' 버튼 누르면 블루투스 연결 지속 모니터링
  3. 데이터 수신 시 스코어보드 업데이트 및 알림음 재생
  4. '일시정지' 버튼 누를 때까지 반복
  5. 블루투스 기기 선택, 카운트 리셋, 보드 수동 조정 버튼 포함

버전 2.0.0 변경사항:

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

두 버전의 안드로이드 코드는 코드 섹션에 있습니다.

3단계: 농구 골대 장착

제가 훈련에 쓰는 일반 농구 골대입니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

골대 아래 플라스틱 커버를 떼고 근접 센서용 구멍을 뚫었습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

진동 센서용 작은 구멍도 뚫었습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

플라스틱 커버가 곡면이라 센서를 직접 부착할 수 없어 MDF로 지지대를 만들었습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

볼트와 너트로 근접·진동 센서를 고정했습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

나머지 부품들을 연결했습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

연기 테스트(전원 투입 테스트)를 진행했습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

최종적으로 골대에 모두 장착했습니다.

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

4단계: 농구 훈련 테스트

이제 모든 것을 테스트할 차례입니다. 그리고 대망의 실전 테스트!

5단계: 최종 고찰

즐거운 훈련 되세요!

코드

아두이노 코드 (버전 1.1.0)

//----------------------------------------------------------------------------//
// Filename : Scoreboard.ino
// Description : Smart Basketball Scoreboard
// Version : 1.1.0
// Author : Marcelo Avila de Oliveira <marceloavilaoliveira@gmail.com>
//----------------------------------------------------------------------------//
// DEFINITIONS
//----------------------------------------------------------------------------//
// #define DEBUG
// #define DEBUG_PROX
// #define DEBUG_VIBR
//----------------------------------------------------------------------------//
// CONSTANTS
//----------------------------------------------------------------------------//
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;
const unsigned long wait_interval = 3000;
const float percent_to_bright_factor = 100 * log10(2) / log10(255);
//----------------------------------------------------------------------------//
// VARIABLES
//----------------------------------------------------------------------------//
unsigned long wait_time;
boolean prox = false;
boolean vibr = false;
boolean wait = false;
//----------------------------------------------------------------------------//
// FUNCTIONS (SETTINGS)
//----------------------------------------------------------------------------//
void setup() {
  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);
  Serial.begin(9600);
  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);
  Serial1.print("\r\n+STWMOD=0\r\n");
  Serial1.print("\r\n+STNA=Arduino\r\n");
  Serial1.print("\r\n+STOAUT=1\r\n");
  Serial1.print("\r\n+STAUTO=0\r\n");
  delay(2000);
  Serial1.print("\r\n+INQ=1\r\n");
  delay(2000);
  while (Serial1.available()) {
    delay(50);
    Serial1.read();
  }
}
//----------------------------------------------------------------------------//
// FUNCTIONS (LIGHT)
//----------------------------------------------------------------------------//
int percent_to_bright(int percent) {
  return 256 - pow(2, percent / percent_to_bright_factor);
}
void set_led(int color, int bright) {
  #ifdef DEBUG
  Serial.println("Setting LED");
  Serial.println();
  #endif
  if (color < 0 || color > 6 || bright < 0 || bright > 100) return;
  int led_r_bright = 255, led_g_bright = 255, led_b_bright = 255;
  int bright_aux = percent_to_bright(bright);
  switch (color) {
    case 0: led_g_bright = bright_aux; break; // GREEN
    case 1: led_r_bright = bright_aux; led_g_bright = bright_aux; break; // YELLOW
    case 2: led_r_bright = bright_aux; break; // RED
    case 3: led_g_bright = bright_aux; led_b_bright = bright_aux; break; // CYAN
    case 4: led_b_bright = bright_aux; break; // BLUE
    case 5: led_r_bright = bright_aux; led_b_bright = bright_aux; break; // MAGENTA
    case 6: led_r_bright = bright_aux; led_g_bright = bright_aux; led_b_bright = bright_aux; break; // WHITE
  }
  analogWrite(led_r_pin, led_r_bright);
  analogWrite(led_g_pin, led_g_bright);
  analogWrite(led_b_pin, led_b_bright);
}
//----------------------------------------------------------------------------//
// FUNCTIONS (CHECK)
//----------------------------------------------------------------------------//
void check_prox() {
  if (!prox && 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 && digitalRead(vibr_pin) == HIGH) {
    #ifdef DEBUG_VIBR
    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) {
  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();
}

안드로이드 코드 (버전 1.1.0)

MIT App Inventor 프로젝트 파일 (다운로드 필요)

아두이노 코드 (버전 2.0.0)

//----------------------------------------------------------------------------//
// Filename : Scoreboard.ino
// Description : Smart Basketball Scoreboard
// Version : 2.0.0
// Author : Marcelo Avila de Oliveira <marceloavilaoliveira@gmail.com>
//----------------------------------------------------------------------------//
// LIBRARIES
//----------------------------------------------------------------------------//
#include "DHT.h"
#include "SoftwareSerial.h"
//----------------------------------------------------------------------------//
// DEFINITIONS
//----------------------------------------------------------------------------//
// #define DEBUG
// #define DEBUG_BLUE
// #define DEBUG_PROX
// #define DEBUG_VIBR
// #define DEBUG_DHT
#define DHTPIN 7
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
SoftwareSerial Bluetooth(10, 11); // RX, TX
//----------------------------------------------------------------------------//
// CONSTANTS
//----------------------------------------------------------------------------//
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;
const unsigned long wait_interval = 2000;
const unsigned long dht_interval = 10000;
const float percent_to_bright_factor = 100 * log10(2) / log10(255);
//----------------------------------------------------------------------------//
// VARIABLES
//----------------------------------------------------------------------------//
unsigned long wait_time, dht_time;
float humi, temp, heat;
boolean prox = false, vibr = false, wait = false;
//----------------------------------------------------------------------------//
// FUNCTIONS (SETTINGS)
//----------------------------------------------------------------------------//
void setup() {
  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); // MAGENTA
  Serial.begin(9600);
  setup_bluetooth();
  dht.begin();
  set_led(4, 100); // BLUE
  #ifdef DEBUG
  Serial.println("Board is alive");
  Serial.println();
  #endif
}
void setup_bluetooth() {
  #ifdef DEBUG_BLUE
  Serial.println("Setting Bluetooth");
  Serial.println();
  #endif
  Bluetooth.begin(9600);
  while (Bluetooth.available()) { delay(50); Bluetooth.read(); }
}
//----------------------------------------------------------------------------//
// FUNCTIONS (LIGHT) - 1.1.0과 동일
//----------------------------------------------------------------------------//
int percent_to_bright(int percent) {
  return 256 - pow(2, percent / percent_to_bright_factor);
}
void set_led(int color, int bright) {
  #ifdef DEBUG
  Serial.println("Setting LED");
  Serial.println();
  #endif
  if (color < 0 || color > 6 || bright < 0 || bright > 100) return;
  int led_r_bright = 255, led_g_bright = 255, led_b_bright = 255;
  int bright_aux = percent_to_bright(bright);
  switch (color) {
    case 0: led_g_bright = bright_aux; break;
    case 1: led_r_bright = bright_aux; led_g_bright = bright_aux; break;
    case 2: led_r_bright = bright_aux; break;
    case 3: led_g_bright = bright_aux; led_b_bright = bright_aux; break;
    case 4: led_b_bright = bright_aux; break;
    case 5: led_r_bright = bright_aux; led_b_bright = bright_aux; break;
    case 6: 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);
}
//----------------------------------------------------------------------------//
// FUNCTIONS (CHECK)
//----------------------------------------------------------------------------//
void check_prox() {
  if (!prox && digitalRead(prox_pin) == LOW) {
    #ifdef DEBUG_PROX
    Serial.println("Proximity detected");
    Serial.println();
    #endif
    set_led(0, 100); // GREEN
    send_data(2);
    prox = true;
    if (!vibr) { wait = true; wait_time = millis() + wait_interval; }
  }
}
void check_vibr() {
  if (!prox && !vibr && digitalRead(vibr_pin) == HIGH) {
    #ifdef DEBUG_VIBR
    Serial.println("Vibration detected");
    Serial.println();
    #endif
    set_led(1, 100); // YELLOW
    vibr = true;
    wait = true;
    wait_time = millis() + wait_interval;
  }
}
void check_wait() {
  if (wait && millis() > wait_time) {
    if (!prox) { set_led(2, 100); send_data(1); } // RED, MISS
    reset();
  }
}
void check_dht() {
  if (!prox && !vibr && millis() > dht_time) {
    humi = dht.readHumidity();
    temp = dht.readTemperature();
    heat = dht.computeHeatIndex(temp, humi, false);
    #ifdef DEBUG_DHT
    Serial.print("Humidity : "); Serial.print(humi); Serial.println("%");
    Serial.print("Temperature: "); Serial.print(temp); Serial.println("C");
    Serial.print("Heat Index : "); Serial.print(heat); Serial.println("C");
    Serial.println();
    #endif
    send_data(0);
    dht_time = millis() + dht_interval;
  }
}
//----------------------------------------------------------------------------//
// FUNCTIONS (MIS)
//----------------------------------------------------------------------------//
void send_data(int shot) {
  // shot: 0=데이터 없음, 1=실책, 2=득점
  Bluetooth.print(humi);
  Bluetooth.print(temp);
  Bluetooth.print(heat);
  Bluetooth.print(shot);
  #ifdef DEBUG_BLUE
  Serial.println("Bluetooth sent");
  Serial.println();
  #endif
}
void reset() {
  vibr = false; prox = false; wait = false;
  delay(1000);
  set_led(4, 100); // BLUE
}
//----------------------------------------------------------------------------//
// MAIN
//----------------------------------------------------------------------------//
void loop() {
  check_prox();
  check_vibr();
  check_wait();
  check_dht();
}

안드로이드 코드 (버전 2.0.0)

MIT App Inventor 프로젝트 파일 (다운로드 필요)

회로도

블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드
블루투스·센서·실시간 업데이트 지원 고급 스마트 농구 스코어보드

제조공정

  1. 농구: 네이스미스의 1891년 발명에서 현대 생산 기술까지
  2. 오픈소스 스마트 팜 시스템 구축: 저렴하고 상호운용 가능한 IoT로 농민 역량 강화
  3. ECM3532: 에타 컴퓨트의 첫 통합 초저전력 AI 센서 보드, 에지 개발 가속화
  4. MCP9808, InfluxDB, Grafana로 라즈베리 파이 홈 온도 모니터 구축하기
  5. 스마트 쓰레기통: 자동화된 폐기물 관리를 위한 셀룰러 IoT 솔루션
  6. 스마트 바텐더: 라즈베리파이 기반 나만의 칵테일 스테이션 만들기
  7. 감정 센서 & EEG: 실시간 감정 감지를 위한 저비용 하드웨어
  8. 스마트 텍스타일용 초고감도·내구성 변형 센서 혁신
  9. 혁신적 초박막 센서, 스마트 콘택트렌즈 기능 강화
  10. 센서 생산 혁신: 센사타(Sensata), 스마트 메카트로닉스 활용