반응형
결과물
기술개발의 개요
- 아두이노 GPS Tracker와 충격센서를 접목시켜 응급상황에 신속히 대처할 수 있는 IOT 제품 개발.
- Gps Tracker와 충격센서를 자동차에 내장시키고 특정 기준치 이상의 충격이 발생했을 때 운전자(환자)의 심박수 센서, 또는 적외선 온도 센서 등을 작동시켜 각종 센서 데이터를 사전에 구축한 사이트(긴급 구조 시스템)에 전송하여 사고 현황과 응급상황에 신속하게 대처할 수 있는 시스템.
- 사용 기술 : HTML, CSS, JS(jquery, ajax), PHP(CURL, Google Map API), MySQL, C(아두이노)
- 서버 : CAFE24 Web Hosting
시나리오
스토리 가정(서비스 상용화)
- 차량이 충돌사고가 났을 때 일정 이상의 충격량을 감지하면 차량에 탑재되어 있는 Gps Tracker가 작동
- 작동 후 운전자의 상태를 파악할 수 있는 Gps Tracker에 연결된 심박수 센서 또는 적외선 온도 센서, 차량의 위치(위도, 경도), 사고난 시간 등의 정보들을 사전에 구축한 사이트(긴급구조시스템)에 데이터 전송
- 사고 데이터를 받은 긴급구조 시스템은 사고 지점을 알 수 있으며 사고 지점으로부터 반경 5000m의 119 구급센터를 모두 검색하고 그 중에서 가장 가깝게 측정되는 구급센터로 경로 표시, 동시에 걸리는 시간과 거리도 실시간으로 표시
- 경로가 표시되는 동시에 표시된 119 구급센터로 자동으로 사고 관련 모든 데이터를 전송
- 즉 119 구급센터 또한 사고현황에 대해 바로 파악이 가능(전송된 데이터를 확인할 수 있는 119 구급센터 사이트로도 접속 가능)
- 운전자가 이 서비스를 이용하기 위해 등록한 자신의 인적사항을 충돌 사고가 났을 시 가져와 보다 더 신속한 조치를 취할 수 있음(병원 등록, 지인 연락 등등)
- 적외선 또는 심박수 센서를 통해 받아온 데이터를 통해 운전자의 상태 정보를 실시간으로 확인 가능(그래프 형식으로도 제작)
- 또한 119 구급센터에서 출발한 구급차의 위치도 알 수 있음(이 부분도 Gps Tracker가 필요하지만 비용적인 부담이 있어 그냥 임의로 위치 지정)
Hardware
- 아두이노 보드 중 ESP8266이라는 보드를 사용
- 와이파이 모듈이 탑재 되어있는 보드이기에 주변 AP 신호를 스캔하여 연결되어 있는 센서들의 데이터를 내가 원하는 곳에 전송 가능 (센서 : 충격감지 센서, 적외선 온도 센서 등)
- 해당 보드에서 사용하고 있는 버전과 심박수 센서의 기본 라이브러리가 호환되지 않아 적외선 온도센서로 대체
- 실제로 상용화 된다면 LTE 데이터 신호를 사용할 수 있음
- 케이스는 3D 프린터로 맞춤 제작
Source
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Adafruit_MLX90614.h>
#include <Wire.h>
const int SHOCK_PIN = 16; // 충격 센서 핀 설정
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
const int LED_PIN = 5;
byte ledStatus = LOW;
int status = WL_IDLE_STATUS;
// 와이파이 클라이언트 이용;
HTTPClient client;
const char mapHost[] = "http://gps.foolblack.com/api/index.php";
const int port = 80;
// GPS device SoftwareSerial 설정
static const int RXPin = 12, TXPin = 13;
static const uint32_t GPSBaud = 115200;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
enum eStates
{
EScan,
EConnect,
ESend
};
eStates state = EScan;
// DHT sensor.
const char* ssid = "jaymon";
const char* password = "93848234";
String host = "http://gps.foolblack.com";
const long interval = 5000;
unsigned long previousMillis = 0;
int shockValue = LOW; // 초기값 설정
const long wifiScanCooldown = 0; // Wi-Fi 스캔 쿨다운 시간 (0초)
unsigned long lastWifiScanMillis = 0;
WiFiServer server(80);
HTTPClient http;
void setup() {
Serial.begin(115200);
ss.begin(GPSBaud);
pinMode(LED_PIN, OUTPUT);
pinMode(SHOCK_PIN, INPUT);
digitalWrite(LED_PIN, HIGH); // Write LED high/low
delay(1000);
digitalWrite(LED_PIN, LOW); // Write LED high/low
Serial.println("Setup done");
// DHT sensor
Wire.begin(4, 5);
mlx.begin();
}
void loop() {
// main statechart loop
delay(1000);
// 충격 센서의 입력을 읽어옴
shockValue = digitalRead(SHOCK_PIN);
unsigned long currentMillis = millis();
switch (state)
{
case EScan:
if (shockValue == HIGH) {
Serial.println("Shock detected! Scanning for WiFi...");
if (currentMillis - lastWifiScanMillis >= wifiScanCooldown) {
if (scan_Wifi()) {
state = ESend;
lastWifiScanMillis = currentMillis;
}
}
}
break;
case EConnect:
if (connectServer())
state = ESend;
break;
case ESend:
// gpsdata를 가져와서 서버로 보냄
if (!SendToServer())
state = EScan;
break;
}
}
bool dhtserver() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
double ambientTemp = mlx.readObjectTempC();
String phpHost = host + "/api/insert2.php?temp=" + mlx.readObjectTempC();
Serial.print("Connect to ");
Serial.println(phpHost);
Serial.print(ambientTemp);
Serial.println("*C");
client.begin(phpHost);
client.setTimeout(1000);
int httpCode2 = client.POST(phpHost);
if (httpCode2 > 0) {
Serial.printf("GET code : %d\n\n", httpCode2);
if (httpCode2 == HTTP_CODE_OK) {
String payload = client.getString();
Serial.println(payload);
}
} else {
Serial.printf("POST failed, error: %s\n", client.errorToString(httpCode2).c_str());
}
}
client.end();
}
bool connectServer() {
Serial.print("connecting to ");
Serial.println(mapHost);
Serial.println("Connected");
return true;
}
bool scan_Wifi() {
const char android[] = "jaymon"; // AP SSID
const char pwd[] = "93848234"; // SSID PASS
// WiFi를 스테이션 모드로 설정하고 이전에 연결된 AP가 있는 경우 연결 해제
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("scan start");
// WiFi.scanNetworks will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0)
Serial.println("no networks found");
else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
char ssid[100];
WiFi.SSID(i).toCharArray(ssid, sizeof(ssid));
if (WiFi.encryptionType(i) == ENC_TYPE_NONE || strcmp(ssid, android) == 0) {
delay(100);
if (WiFi.encryptionType(i) == ENC_TYPE_NONE) {
Serial.print("Connecting to open SSID:");
Serial.println(ssid);
WiFi.begin(ssid);
} else
WiFi.begin(android, pwd);
int connectLoop = 0;
yield();
while (WiFi.status() != WL_CONNECTED) {
digitalWrite(LED_PIN, ledStatus);
ledStatus = (ledStatus == HIGH) ? LOW : HIGH;
delay(100);
if (connectLoop > 100) {
Serial.print("Timeout connecting to: ");
Serial.println(ssid);
digitalWrite(LED_PIN, LOW);
break;
}
connectLoop++;
}
delay(1000);
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Connected to ");
Serial.println(ssid);
return true;
} else {
Serial.println("Connection failed.");
return false;
}
}
}
}
Serial.println("");
return false;
}
bool SendToServer() {
// start feeding gps
while (true) {
smartDelay(100);
String PostData = Send_Location_Time();
client.begin(mapHost);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
unsigned long start = millis();
int interval = 3000;
yield();
int httpCode = client.POST(PostData);
if (millis() - start > interval) {
// no response from server
client.end();
return false;
}
Serial.print("Server response: ");
Serial.println(httpCode);
smartDelay(100);
Serial.println(PostData);
delay(100);
start = millis();
client.POST(PostData);
dhtserver();
yield();
}
client.end();
return true;
}
String Send_Location_Time() {
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
String macAddress = "";
for (int i = 0; i < WL_MAC_ADDR_LENGTH; i++)
macAddress += String(mac[i], HEX);
String retval = "device_id=";
retval += macAddress;
retval += "&date_and_time=";
if (gps.date.isValid()) {
retval += gps.date.year();
retval += "-";
retval += gps.date.month();
retval += "-";
retval += gps.date.day();
retval += " ";
} else
retval += "invalid ";
if (gps.time.isValid()) {
retval += gps.time.hour();
retval += ":";
retval += gps.time.minute();
retval += ":";
retval += gps.time.second();
} else
retval += "invalid";
if (gps.location.isValid()) {
char buf[12];
retval += "&latitude=";
dtostrf(gps.location.lat(), 4, 6, buf);
retval += buf;
retval += "&longitude=";
dtostrf(gps.location.lng(), 4, 6, buf);
retval += buf;
} else
retval += "&latitude=invalid&longitude=invalid";
return retval;
}
static void smartDelay(unsigned long ms) {
unsigned long start = millis();
do {
while (ss.available())
gps.encode(ss.read());
yield(); // give others some time..
} while (millis() - start < ms);
}
// 1초에 한 번 GPS 데이터를 읽고 추출
void gps_loop() {
while (ss.available()) {
gps.encode(ss.read());
delay(1000);
yield();
}
}
*코드가 살짝 난잡할 수 있음
Software
- 데이터를 모니터링 할 수 있는 시스템
- 대기화면
- 충돌 사고가 나면 데이터가 긴급구조시스템에 전송되면서 해당 화면 메시지 폼을 띄움
- 메시지 폼 : Mac 주소 / 사고 시간 / 사고 위치(위도, 경도)
- 사고가 난 제품의 Mac 주소가 자동으로 'Device Number' 에 기입
- 동시에 차량을 모니터링 할 수 있는 사이트로 리다이렉트
- 해당 차량 제품의 Mac 주소를 기점으로 사고 난 날짜와, 사고 관련 데이터를 불러옴
- 사고지점 B 마커가 GPS 모듈을 통해 받아온 위치
- 사고 난 위치를 기점으로 반경 5000m 안에 있는 119 구급센터를 모두 검색하고 Haversine Formula(하버사인 공식)을 통해 가장 가깝게 측정되는 구급 센터로 동선 표기
- 표기됨과 동시에 걸리는 시간과 거리를 실시간으로 표시 (Google Map API를 사용하였기에 국내에서는 대중교통 수단밖에 지원 안됨)
- 오른쪽에 있는 정보는 운전자의 인적사항 정보
- Body Temp 부분이 운전자의 상태를 실시간을 보여주는 데이터
- 왼쪽 하단에 Status 버튼을 눌러 두 번째 폼으로 변환
- 동선이 표기됨과 동시에 데이터를 받은 119 구급센터는 구급차를 이송
- 이송된 구급차의 위치를 확인 할 수 있음(구급차의 위치는 임의로 지정)
- 지정된 구급차의 위치부터 사고난 지점까지의 남은 거리와 시간을 실시간으로 표시
- 왼쪽 하단의 로그 기록은 구급차의 지나온 위치 로그 기록
- 오른쪽은 운전자의 적외선 온도 상태 변화를 좀 더 상세히 보기 위해 제작된 그래프 폼
- 119 구급센터에 전송된 사고 관련 현황 데이터를 볼 수 있음(119 구급센터 전산망)
- 클라이언트와 서버 관리자 간의 채팅
개선할 점
- 상용화 할 시 트래픽이 많이 몰릴 것이 예상되어 고가용성과, 로드밸런싱 솔루션을 추가(AWS로 서버 이전)
- 해당 Google Map API는 정보보호 법 때문에 대중교통 이외의 수단(자동차, 걷기)은 지원 불가 Naver map API로 사용
- 구급차 Gps Tracker까지 구현
- 보드 버전을 올려 심박수 센서까지 추가
활용 방안
- 스마트워치와 연동하여 더 많은 센서의 데이터를 종합할 수 있음
- 정상적인 차량 운행 중에도 운전자의 상태를 파악하여 과도한 스트레스나 피로감을 느끼고 있을 때 경고 알림을 보낼 수 있음
- 다양한 센서에서 수집되는 데이터를 활용해 차량의 안전성과 편의성을 향상시키는 연구 및 개발에 활용될 수 있음
반응형
'포트폴리오 > 개인 자작' 카테고리의 다른 글
[학기 프로젝트] 유니티 WebGL을 활용한 웹 게임 개발 (0) | 2024.06.11 |
---|---|
철권8 자동 스코어 봇 개발 (Feat. AWS) (4) | 2024.04.02 |
[2022] Hackathon AI 졸음 운전 검문소 (0) | 2023.12.01 |
music.foolblack.com(음악 플레이어 소개 사이트) (0) | 2023.11.29 |
[GTA5 온라인] 방화벽 인바운드/아웃바운드 차단 프로그램 배포 (0) | 2023.04.21 |
댓글