안드로이드 앱으로 제어하는 스마트 인원 카운터 제작
부품 및 소모품
| 부품 |
수량 |
| Arduino UNO |
1 |
| HC-06 블루투스 모듈 |
1 |
| 브레드보드 (일반) |
2 |
| 포토레지스터 (LDR) |
3 |
| 레이저 모듈 |
3 |
| 부저 |
1 |
| RGB LED 모듈 |
1 |
| LED (일반) |
3 |
| 저항 1k 옴 |
3 |
| 저항 221 옴 |
3 |
| 배터리 |
1 |
| 점퍼 와이어 (일반) |
1 |
앱 및 온라인 서비스
- Arduino IDE
- MIT App Inventor
프로젝트 소개
설명
인원 카운터는 출입구를 통과하는 사람의 수를 감지하는 장치입니다. 2주간 휴가를 갈 때 방을 안전하게 지키기 위해 인원 카운터를 만들기로 했습니다. 또한 허가 없이 방에 들어오는 사람에게 경고하는 알람 기능도 원했습니다. 레이저는 속도 특성상 LDR과 함께 무언가를 정확하게 세는 데 최적의 선택이어서 레이저와 LDR을 카운팅용으로 사용했습니다. 방에 출입구가 세 곳(문 2개, 창문 1개)이 있어 레이저 3개와 LDR 3개를 사용했습니다.
하지만 원격으로 장치를 제어해 어떤 출입구의 레이저를 활성화할지, 알람을 켤지 끌지 선택하려면 블루투스 통신이 필요했습니다. 그래서 HC-06 블루투스 모듈을 추가하고 직접 만든 안드로이드 앱으로 통신하도록 했습니다. 앱에서는 관찰하려는 출입구의 통과 인원 수도 표시됩니다.
앱 만들기
안드로이드 앱을 만드는 방법은 HTML을 자바로 변환하거나 파이썬으로 프로그래밍하는 등 다양합니다. 하지만 MIT App Inventor는 드래그 앤 드롭 구조 덕분에 가장 쉽게 만들 수 있습니다. 다만 아직 iOS는 지원하지 않습니다.
앱 이름은 "People Counter!"이며 Screen1과 Screen2 두 화면으로 구성됩니다.
Screen1 (홈 화면)
메인 화면으로 넘어가기 전, MIT App Inventor에서 설정한 비밀번호를 정확히 입력해야 합니다(기본 비밀번호: "counter").
Screen2 (메인 화면)
아두이노 보드를 제어하는 메뉴이자 아두이노가 보낸 인원 카운터 결과를 표시하는 화면입니다. 어떤 레이저를 켤지, 알람을 켤지 끌지 선택할 수 있고, 카운터 결과를 확인하고 0으로 리셋할 수도 있습니다.
레이저와 LDR로 인원 카운터 만들기
레이저(Light Amplification by Stimulated Emission of Radiation)는 기본적으로 빛의 패키지를 매우 직선으로 타겟에 보냅니다. LDR(Light-Dependent Resistor)은 레이저가 직접 향할 때 빛 강도 증가를 쉽게 감지합니다. 레이저와 LDR 사이에 장애물이 생기면 LDR은 빛 강도 감소를 감지합니다. 이 감소가 최적 범위 내에서 몇 번 발생했는지 세면 인원 카운터가 됩니다. 실험 결과 LDR의 최적 범위는 150~350 사이로 설정해야 합니다.
연결 방법
- Arduino Uno - 모듈
- Pin 2 ──── Laser Module 1
- Pin 3 ──── Laser Module 2
- Pin 4 ──── Laser Module 3
- Pin 5 ──── Buzzer
- Pin 6 ──── HC-06 블루투스 모듈 (TX)
- Pin 7 ──── HC-06 블루투스 모듈 (RX)
- Pin 8 ──── Control LED 1
- Pin 12 ──── Control LED 2
- Pin 13 ──── Control LED 3
- Pin 9 ──── RGB 모듈 (R)
- Pin 10 ──── RGB 모듈 (G)
- Pin 11 ──── RGB 모듈 (B)
- A0 ──── LDR 1
- A1 ──── LDR 2
- A2 ──── LDR 3
모든 부품 연결을 마무리하기 전에 레이저가 LDR을 정확히 향하도록 해야 합니다. 테스트 후 장치를 세 부분으로 나누어 세 출입구에 각각 설치했습니다. 이후로 방 보안에 대한 걱정이 없습니다.
코드
PeopleCounter_with_Lasers.ino (아두이노)
// 레이저와 안드로이드 기기로 인원 카운터 만들기
// Kutluhan Aktar 제작
#include <SoftwareSerial.h>
int LaserPin_1 = 2;
int LaserPin_2 = 3;
int LaserPin_3 = 4;
int BuzzerPin = 5;
int Control_RX = 6;
int Control_TX = 7;
int RedPin = 9;
int GreenPin = 10;
int BluePin = 11;
int Control_Led_1 = 8;
int Control_Led_2 = 12;
int Control_Led_3 = 13;
int LDR_1 = A0;
int LDR_2 = A1;
int LDR_3 = A2;
int LDR_1_Read, LDR_2_Read, LDR_3_Read;
int Counter = 0;
volatile boolean Alarm_is_Activated = false;
volatile boolean Alarm_Initial = false;
volatile boolean Counter_Detect = false;
SoftwareSerial Control(Control_RX, Control_TX);
String Name = "Control";
int Password = 1111;
String Uart = "9600,0,0";
void setup() {
Serial.begin(9600);
Control.begin(9600);
pinMode(LaserPin_1, OUTPUT);
pinMode(LaserPin_2, OUTPUT);
pinMode(LaserPin_3, OUTPUT);
pinMode(RedPin, OUTPUT);
pinMode(GreenPin, OUTPUT);
pinMode(BluePin, OUTPUT);
pinMode(Control_Led_1, OUTPUT);
pinMode(Control_Led_2, OUTPUT);
pinMode(Control_Led_3, OUTPUT);
}
void loop() {
get_Data_From_LDR();
if (Control.available()) {
char c = Control.read();
Serial.println(c);
Commands(c);
}
Set_Alarm();
Set_Counter();
}
void Commands(char i) {
switch(i) {
case '1': Control.print(Counter); break;
case '2': Alarm_is_Activated = true; break;
case '3': Alarm_is_Activated = false; break;
case '4': digitalWrite(LaserPin_1, HIGH); digitalWrite(Control_Led_1, HIGH); break;
case '5': digitalWrite(LaserPin_1, LOW); digitalWrite(Control_Led_1, LOW); break;
case '6': digitalWrite(LaserPin_2, HIGH); digitalWrite(Control_Led_2, HIGH); break;
case '7': digitalWrite(LaserPin_2, LOW); digitalWrite(Control_Led_2, LOW); break;
case '8': digitalWrite(LaserPin_3, HIGH); digitalWrite(Control_Led_3, HIGH); break;
case '9': digitalWrite(LaserPin_3, LOW); digitalWrite(Control_Led_3, LOW); break;
case 'r': Counter = 0; break;
}
}
void get_Data_From_LDR() {
LDR_1_Read = analogRead(LDR_1);
LDR_2_Read = analogRead(LDR_2);
LDR_3_Read = analogRead(LDR_3);
}
void Set_Counter() {
if (LDR_1_Read < 150 || LDR_2_Read < 150 || LDR_3_Read < 150) {
Counter_Detect = true;
} else {
Counter_Detect = false;
}
if (Counter_Detect) {
Counter++;
delay(500);
}
}
void Set_Alarm() {
if (Alarm_is_Activated) {
if (LDR_1_Read < 150 || LDR_2_Read < 150 || LDR_3_Read < 150) {
Alarm_Initial = true;
} else {
Alarm_Initial = false;
}
if (Alarm_Initial) {
tone(BuzzerPin, 500);
Color_Change(255, 0, 0); delay(50);
Color_Change(0, 255, 0); delay(50);
Color_Change(0, 0, 255); delay(50);
Color_Change(255, 255, 0); delay(50);
Color_Change(80, 0, 80); delay(50);
Color_Change(0, 255, 255); delay(50);
Color_Change(255, 255, 255); delay(50);
}
}
if (!Alarm_is_Activated || !Alarm_Initial) {
noTone(BuzzerPin);
Color_Change(0, 0, 0);
}
}
void Color_Change(int red, int green, int blue) {
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
analogWrite(RedPin, red);
analogWrite(GreenPin, green);
analogWrite(BluePin, blue);
}
void Change_BluetoothModule_Defaults() {
Control.print("AT+NAME"); Control.println(Name);
delay(2000);
Control.print("AT+PSWD"); Control.println(Password);
delay(2000);
Control.print("AT+UART"); Control.println(Uart);
delay(2000);
Serial.println("Task is completed.");
}
회로도 및 커스텀 파트
프로젝트에는 프리칭 회로도, 앱 소스 파일(.aia), APK 파일(.apk)이 포함되어 있습니다.