일사분란착착착 - 영상인식을 통한 RVM 시스템 개발
프로젝트 소개
프로젝트 명
영상인식을 통한 RVM 시스템 개발
Developing Reverse Vending Machine Using Image Detection
프로젝트 기간
2020.3 ~ 2020.6
팀 소개
서울시립대학교 기계정보공학과 (20144300**) (유*영) (팀장)
서울시립대학교 기계정보공학과 (20144300**) (강*찬)
서울시립대학교 기계정보공학과 (20144300**) (박*석)
서울시립대학교 기계정보공학과 (20144300**) (심*헌)
서울시립대학교 기계정보공학과 (20144300**) (윤*상)
소스코드
https://github.com/YeonsangYoon/embedded-system-project
프로젝트 개요
프로젝트 요약
프로젝트의 배경 및 기대효과
페트병은 재활용 자원 중에서도 재활용 가능성이 높고 또 재활용 후에도 품질이 크게 떨어지지 않는다. 하지만 라벨 및 뚜껑이 있는 경우 재활용 전처리 과정에서 비용과 시간이 크게 늘어가게 된다. 하지만 페트병의 라벨 및 뚜껑을 제거하여 버림이 올바른 방법임을 모르는 경우 많다. 이를 위해 올바른 재활용 방법 홍보가 필요하지만 실용적으로 이루어지지 않는 상태이다. 우리는 사람들에게 조금 더 흥미로운 방법을 통해서 재활용 방법을 홍보하기 위해 독일 덴마크 등에서 활용되는 RVM을 모티브로 삼았다. 또한 제도적으로 RVM이 확립되어 있지않은 상태에서 더 많은 페트와 캔을 수거하기 위해 영상인식 RVM을 생각하였다. RVM(reverse vending machine)은 일반 자판기와는 다르게 돈을 넣고 물건을 받는 것이 아닌, 물건은 넣으면 돈이 나오는 구조이다. 페트나 캔을 넣으면 소정의 보상을 받게되고 이 과정에서 자연스럽게 흥미가 생긴다. 동시에 올바른 재활용 방법을 익히는 교육적인 효과도 불러올 것이다. 우리는 기존의 RVM과 달리 임베디드 시스템을 활용하여 더 경제적이고 이동식인 시스템을 구축함을 목표로 했다. 기존의 RVM이 크기 및 무게 문제로 인해 설치 장소에 고정이 되어있는것과 달리 우리가 개발한 시스템은 여러장소(초등학교, 주거단지 등)에 유연하게 배치하여 소량의 기기로 큰 교육효과를 누릴수 있을 것이다.
동작 시나리오
본 프로젝트에서 구현을 목표로 한 부분은 검은색 글씨로 표기하였다. 기존의 RVM 시스템은 사용자들의 적극적인 재활용쓰레기 수거를 위하여 투입한 쓰레기에 비례해 일정부분 현금이나 포인트로 보상을 주었다. 하지만 본 프로젝트에서 짧은 기간내 기본적인 RVM 기능 외 어플리케이션과 사용자 포인트 적립을 구현하는 것이 힘들다고 판단하여 부가기능은 추후에 개발하고 기본적인 RVM의 기능을 수행하는 시스템을 개발을 목표로 잡았다. 기본적인 사용자 시나리오는 다음과 같다. 사용자가 시작버튼을 누르면 내부적으로 기계의 상태가 ON으로 바뀌어 동작 시퀀스가 실행된다. 기본적으로 한번에 1개의 쓰레기를 처리하도록 동작을 하며 내부적으로 투입 -> 이동 -> 판별 -> 분류 의 순서로 동작한다. 사용자가 모든 재활용 쓰레기를 투입하여 종료버튼을 누르면 내부적으로 기계의 상태가 OFF로 바뀌어 동작 시퀀스가 완료된 후 idle 상태로 바뀌고 투입 결과가 UI에 표시된다.
구현 내용
시스템 구성
- RVM Controller
- Image Processing Server
- Rail Controller
RVM 시스템은 크게 3개의 프로세스로 구동된다. RVM Controller는 UI를 통해 사용자 이벤트를 처리하고 Status와 Main Cycle을 통해 시스템 상태를 관리하고 기계를 동작시키는 역할을 한다. RVM Controller는 하나의 프로세스로서 라즈베리파이에서 작동하며 Main Cycle과 UI를 2개의 Thread로 나누어 동시에 실행된다. UI는 사용자의 Event를 받아 Machine Status를 바꾸고 Main Cycle은 현재 status에 따라 전체 시스템을 동작시킨다. Rail Controller는 모든 모터를 제어하여 쓰레기를 판별하는 위치까지 이동시키고 각 결과에 따라 분류하도록 하는 프로세스이다. RVM Controller에게 Serial 통신을 통해 명령을 전달받아 아두이노에서 작동한다. Rail Controller는 총 4가지 동작 Case를 처리한다. 마지막으로 Image Processing Server는 판별부까지 이동한 쓰레기의 사진을 찍어 영상처리를 통해 판별하는 프로세스이다. RVM Controller와 Htttp 통신을 하기 위해 Web Server를 구축하였다. RVM Controller에서 판별 request를 보내면 Image Server에서는 사진을 찍고 영상처리를 하여 결과를 다시 보내준다.
하드웨어 설계 및 구현
RVM의 아두이노 메가 2560은 전반적인 모터제어 및 라즈베리파이와 시리얼 통신을 통해 동작 요청과 완료 신호를 송수신을 한다.
소프트웨어 설계 및 구현
RVM의 소프트웨어는 기본적으로 python, C, C++을 사용하여 프로그래밍하였다. 아래의 그림은 내부적으로 3개의 프로세스들이 동작하는 시퀀스를 나타낸다. 사용자가 시작 버튼을 누르면 기계 상태가 On으로 바뀌며 Main Cycle을 시작하게 된다.
RVMController
RVM Controller는 라즈베리파이에서 작동하는 프로세스이다. 파이썬으로 작성되었으며 pyqt5 파이썬 GUI 라이브러리를 사용하여 기본 골격을 만들었다. 거기에 현재 기계의 상태를 나타내주는 RVM Status Class와 각 동작을 실행하게 하는 Main Cycle을 구현하였다. 각 프로세스들이 여러가지 방법을 통해 통신하기 때문에 RVM Controller는 처음 시작할 때 여러가지의 통신 인터페이스를 초기화하고 각 센서 측정을 위한 GPIO setting을 해야한다. 아래의 코드는 RVM Controller의 main thread로서 기계를 처음 킬 때 Status class 인스턴스를 생성하고 각종 인터페이스를 초기화하고 로드셀 영점을 조절한다.
# stat class init
RVM_status = RVM_Stat()
if not debug:
# USB serial interface
port = '/dev/ttyACM0'
ser = serial.Serial(port, 9600, timeout = 2)
# Load Cell GPIO setting
GPIO.setwarnings(False)
hx711 = HX711(LC_DT_Pin, LC_SCK_Pin)
hx711.reset()
w = []
for i in range(20):
w.append(hx711._read())
if False in w:
w.remove(False)
w.remove(max(w))
w.remove(min(w))
init_avg = sum(w) / len(w)
# IR Sensor GPIO setting
GPIO.setup(IR_Pin1,GPIO.IN)
GPIO.setup(IR_Pin2,GPIO.IN)
GPIO.setup(IR_Pin3,GPIO.IN)
GPIO.setup(IR_Pin4,GPIO.IN)
# main Cycle init
t1 = threading.Thread(target = main_Cycle)
t1.daemon = False
t1.start()
# 유저 인터페이스 init
app = QApplication(sys.argv)
phone_window = phoneWindow()
main_window = mainWindow()
main_window.showFullScreen()
app.exec_()
RVM Controller는 전체 시스템을 관리하는 python 프로세스로서 UI, Main cycle, stat class의 인스턴스를 가지고 있다. Main cycle에서 단계별로 각 모듈을 함수 형태로 호출하며, 현재 stat을 관리한다. RVM Status는 기계의 온오프를 나타내는 Machine Status, 현재 실행 상태를 나타내는 Execute Status, 현재 투입된 재활용 쓰레기 정보인 Recycling Status, 에러 발생 여부를 나타내는 Error Status를 맴버로 가지고 있다. 또한 Main Cylce은 총 7단계의 실행 단계를 가지며 각 단계를 모두 실행해야 한개의 쓰레기가 처리된다.
def main_Cycle():
# main cycle
while 1:
#0 machine stat check
if RVM_status.machine_stat != RVM_STATE_ON:
time.sleep(0.1)
else :
#1 Check IR sensor
if checkObjectCond() < 0:
if RVM_status.machine_stat == RVM_STATE_OFF :
resultD = 0;
else :
errorExit()
#2 Check Load cell
elif checkLoadCell() < 0:
errorExit()
#3 rail move command
elif moveCommand('Dzone') < 0:
errorExit()
#4 Request discrimination
else :
resultD = requestD()
print(resultD)
#5 rail move command
if moveCommand(resultD)<0:
errorExit()
if RVM_status.error_stat == retValOK:
# Update Status
RVM_status.updateStatus(resultD)
main_window.can_pet()
main_window.button_text()
elif RVM_status.error_stat == Error :
#debug msg
while RVM_status.error_stat == Error :
continue
printU("Error fixed.. restart")
main_window.button_text()
RailController
ImageServer
영상인식 구현
본 프로젝트에서 투입 물건은 카메라로 촬영할 수 있는 장소에 페트병, 캔 두 종류가 오게된다. 페트병과 캔의 분류는 실시간 물체 감지 시스템인 YOLOv3를 사용한다. 물건의 분류는 크게 3가지 단계로 이루어진다. 사진촬영 및 전처리, YOLOv3 실행, 파싱을 통한 결과값 확인
1단계 - 사진촬영 및 전처리
우선 카메라를 통해 촬영되는 이미지를 그대로 사용하기에는 문제가 있었다. 카메라를 통해 보이는 물체는 분류를 하려는 물건만 있는 것이 아니고 모터와 기어박스 등 여러가지 물체들이 존재했다. 때문에 일말의 오류를 방지하고자 오픈소스인 OpenCV를 사용하여 이미지를 필요한 부분만 추출하는 전처리 과정을 넣었다.
import os
import cv2
def imagepreprocess():
"""
확장자가 jpg인 파일을 찾아서 불러오고 원하는 크기로 이미지를 자른다.
자른 이미지는 기존 이미지를 덮어씌워서 저장한다.
"""
path = "./"
filenames = os.listdir(path)
image_name = ""
for filename in filenames:
full_filename = os.path.join(path, filename)
ext = os.path.splitext(full_filename)[-1]
if ext == '.jpg': # find jpg
image_name = full_filename[2:]
image = cv2.imread(image_name, cv2.IMREAD_COLOR) # image load
image_cut = image[76:390, :, :] # image cut
cv2.imwrite(image_name, image_cut)
2단계 - YOLOv3
YOLOv3의 실행은 파이썬의 subprocess를 이용하였다. 그동안 학습시킨 가중치를 사용하여 전처리가 끝난 이미지를 불러와서 페트병과 캔이 검출이 되었는지 확인을 한다.
cmd_yolo = "./darknet detector test data/obj.data cfg/yolov3.cfg backup/yolov3_last.weights rvm/image/*.jpg >> detect.txt"
# Run Yolo
try:
subprocess.call(cmd_yolo, shell=True, timeout=10)
except subprocess.TimeoutExpired:
print("Timeout during execution")
return -1
3단계 - 파싱을 통한 결과값확인
일정패턴으로 나오는 텍스트를 통해서 원하는 문자를 파싱하여 결과값을 확인하였다.
UI구현
프로젝트 결과
최종 결과물
시연영상
페트병 처리
<iframe width="560" height="315" src="https://www.youtube.com/embed/aANCY5QO0gc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>