헬멧 착용 여부와 어린이 보호구역 진입 여부 탐지를 통한 킥보드 최대 속력 제어 모듈

YeongUk·2022년 7월 20일
3

Edge Computing

목록 보기
2/3
post-thumbnail

개발 목적

최근 킥보드 사고에 대한 기사가 많이 나왔다. 심지어 킥라니라고 한다.

처음엔 이륜차 전부의 헬멧 착용 여부를 제 3의 관점에서 체크하여 사진을 찍는 프로그램을 만들었었다.
만들면서 느꼈지만 킥보드는 안전관리 측면에서 너무 심각했다.
이런 문제를 내가 할 수 있는 한 해결할 수 있는 방법을 내놓는 것은 재밌으니 한 번 만들어 보기로 했다.

헬멧을 탐지하기 위해서 YOLOv5

학습데이터에 필요한 사진 모으기

헬멧을 착용하고 있는 데이터와 미착용 데이터가 필요했다.
하지만 이 프로젝트에서 필요한 데이터들은 킥보드 운전대의 각도에서 찍은 사진이 필요했고
당연히 그런 데이터는 없었다.

간단히 opencv로 사진을 찍는 프로그램을 만들었고 사진을 찍고 어노테이션 하여 데이터를 만들었다.

YOLOv5 학습

왜 YOLOv5

YOLO 알고리즘에 대한 설명은 YOLO, Object Detection Network 이곳에 설명이 아주 잘 되어있다.

내가 YOLO 알고리즘을 이 프로젝트에 사용하게 된 이유는 크게 두 가지가 있다.

  1. R-CNN 계열에 비해 말도 안되는 빠른 속도
  2. 꽤나 좋은 정확도

그럼 학습을 시켜보자

학습 데이터셋 형태

.{data}
├── images
│   ├── train
│   └── val
├── labels
│   ├── train
│   └── val
└── class.yml

학습

git clone https://github.com/ultralytics/yolov5

cd yolov5
pip install -r requirements.txt

python train.py --img 640 --batch 8 --epochs 200 --data {class.yml 경로} --weights yolov5s.pt --cache

GPS 데이터 가져오기

아센 코리아의 gps모듈을 사용하였다.
중요한 부분은 gps를 가져오는 부분과 다른 기능이 병렬처리가 되어야 하므로
멀티 스레드를 구성하여 gps값을 받아와서 파싱해주었다.
gps값을 가져 오는 것은 이전 글에 설명해놓았으니 이곳에선 생략하도록 하겠다.

어린이 보호구역 진입 여부 확인

어린이 보호구역은 유치원, 초등학교, 어린이집, 학원 등의 출입문을 중심으로 300미터 이내의 도로 중 일정구간을 보호구역으로 지정한다.

이처럼 어린이 보호구역 gps좌표를 중점으로 반지름이 300m인 원이 그려져야하고 킥보드의 gps값이 원 안에 진입시 제어되어야한다.

from haversine import haversine

BOHO = (36.374108, 127.365723)

def check_boho(self):
  cur_area = (self.lat, self.lon)
  if haversine(cur_area, BOHO) * 1000 <= 300:
    self.inBoho = 1
  else:
    self.inBoho = 0

어떻게 최대 속력를 조절할 것인가?

나의 목표는 최대 속력를 제어하는데 있다.
이 부분에서는 사용자가 만약 17의 속력로 가고 있을 때,
어린이 보호구역에 가게 된다면 갑자기 최대 속력가 10이 되어 사용자가 위험해진다.

이를 해결하기 위해선 시간을 두고 천천히 감속시켜야 했다.
그리고 속력의 증가와 감소에 한계가 있어야 했다.
최대 속력는 20이상 올라가면 안되었고 0 이하로 떨어지면 안되었다.
즉, 기본 속력가 10이면 위로는 10이상 올라가면 안되었고 아래로는 10이하 떨어지면 안된다.

그래서 생각해낸 것이 시그모이드 형태의 함수이다.


위의 형태의 함수를 사용한다면 앞의 부호가 +이면 천천히 속력를 증가시킬 수 있고 부호가 -이면 천천히 속력를 감소 시킬 수 있다.

현재까지 내가 생각해낼 수 있는 최선이라 나중에 더 좋은 함수를 생각해낸다면 수정할 예정이다.

import math

var_speed = 10 / (1 + math.exp(-0.3 * (sec%36) + 5))
max_speed = max_speed + var_speed

(fix: 이런 조건을 가진 모듈을 만든다고 말했더니 왜 최대 속력을 0으로 만드냐는 피드백을 받았다. 고맙게도 발걸음의 평균 속력이 4정도 이므로 0이 아니라 4로 되야하는게 아닌가?라는 솔루션까지 제공해주셔서 바로 적용시켰다.)

시리얼 통신을 통해 아두이노에 출력

젯슨에서 받아온 gps값과 다른 기능을 통해 처리한 최대 속력이 아두이노 디스플레이에 출력되어야한다. 젯슨과 ESP36을 직결한다음 데이터 값을 시리얼로 연결해주었다.
하지만 시리얼 통신 특성상 데이터가 손실될 가능성이 크다.
따라서 아래와 같은 방법으로 해결해 주었다.

if (inChar == 'E') {
  Serial.println(inputString);
      
  inds=inputString.indexOf('S');
  sub=inputString.substring(inds+1,inputString.length());
  for(int i=0;i<5;i++){
    ind=sub.indexOf(',');
    if(ind!=-1){
      indata[i]=sub.substring(0,ind).toFloat();
      if(isnan(indata[i]))indata[i]=0;
      	sub=sub.substring(ind+1,sub.length());
      }
   	}
    ...
  }
}

이미지

아쉬운 점

  1. 실제로 밖에서 테스트를 해보지 못했어서 입출력 값을 임의로 찍어보면서 만들어서 현실에서 어느정도 괴리가 있을지 확인을 해보지 못했다.
  2. 2주도 안되는 기간에 심지어 다른 일이 섞여 있었어서 6시간도 투자하지 못해서 코드도 효율적이지 못한 면이 있고, 아직 아쉬운 부분도 해결하지 못했다.
profile
소통과 배움을 통해 개인이 가진 맹점을 극복하려 노력하고 있습니다.

0개의 댓글