백승아_자율주행 RC카 제작 결과 보고서
활동 보고서
백*아
2024-07-26
[프로젝트 개요] 아두이노와 파이썬 이용한 rc카 제작 활동임. 센서와 액추에이터를 이용해 자율 주행이 가능하게 만드는 것이 목표. [설계 및 계획] -아두이노와 제작에 필요한 장비들의 개념 이해 후 기본 셋팅. ESP CAM과 아두이노를 연동 시켜 색을 구별할 수 있도록 만듦. [제작 과정] -나무 레이저컷팅을 통해 외관을 만들고 앞쪽에 캠을 기울게 달아 길에 있는 파란 선을 잘 인식할 수 있도록 달고 두 개의 동력 바퀴와 하나의 보조 바퀴를 달아 제작. [코드 구조 및 설명] -import cv2 import urllib.request import numpy as np import time IP_ADDR = '192.168.0.50' def go_backward(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=a') #time.sleep(0.05) def turn_left(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=c') #time.sleep(0.1) def turn_right(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=b') #time.sleep(0.1) def calibrate_left(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=c') #time.sleep(0.04) def calibrate_right(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=b') #time.sleep(0.04) def go_forward(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=d') #time.sleep(0.7) def stop(): urllib.request.urlopen('http://'+IP_ADDR+':80/command?cmd=e') def onMouse(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: print(x, y) cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE) stop_cnt = 0 while True: img_resp = urllib.request.urlopen('http://'+IP_ADDR+'/cam-hi.jpg') imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8) frame = cv2.imdecode(imgnp, -1) (h1, w1) = frame.shape[:2] frame = frame[600:h1, :] (h, w) = frame.shape[:2] topLeft = (118, 18) # x+y가 가장 값이 좌상단 좌표 topRight = (1400, 21) # x+y가 가장 큰 값이 우하단 좌표 bottomLeft = (34, 555) # x-y가 가장 작은 것이 우상단 좌표 bottomRight = (1511, 585) pts1 = np.float32([topLeft, topRight, bottomRight, bottomLeft]) w1 = abs(bottomRight[0] - bottomLeft[0]) w2 = abs(topRight[0] - topLeft[0]) h1 = abs(topRight[1] - bottomRight[1])+600 h2 = abs(topLeft[1] - bottomLeft[1])+600 width = int(max([w1, w2])) # 두 좌우 거리간의 최대값이 서류의 폭 height = int(max([h1, h2])) # 두 상하 거리간의 최대값이 서류의 높이 pts2 = np.float32([[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]]) # 변환 행렬 계산 mtrx = cv2.getPerspectiveTransform(pts1, pts2) # 원근 변환 적용 frame = cv2.warpPerspective(frame, mtrx, (width, height)) # 파란색, 빨간색, 초록색 채널 추출 blue_channel = frame[:, :, 0] green_channel = frame[:, :, 1] red_channel = frame[:, :, 2] # 조건에 맞는 픽셀 필터링 blue_filtered = np.zeros_like(blue_channel, dtype=np.uint8) blue_mask = np.logical_and(blue_channel >= 190, np.logical_and(red_channel <= 170, green_channel <= 200)) blue_filtered[blue_mask] = 255 # 이진화를 위해 255로 설정 kernel = np.ones((5, 5), np.uint8) blue_filtered = cv2.morphologyEx(blue_filtered, cv2.MORPH_OPEN, kernel) edges = cv2.Canny(blue_filtered, 10, 100, apertureSize=3) (w, h) = blue_filtered.shape[:2] points = cv2.findNonZero(blue_filtered) if points is not None: meaned_point = np.mean(points, axis=0)[0] meaned_point_x = int(meaned_point[0]) meaned_point_y = int(meaned_point[1]) cv2.circle(frame, (meaned_point_x, meaned_point_y), 5, (255, 255, 255), -1) cv2.line(frame, (h//3, 0), (h//3, w), (255, 255,255), 5) cv2.line(frame, (h//3*2, 0), (h//3*2, w), (255, 255,255), 5) if meaned_point_x < (h//3): calibrate_left() elif meaned_point_x > (h//3*2): calibrate_right() else: go_forward() else: go_backward() frame = cv2.resize(frame, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) cv2.imshow("live transmission", frame) cv2.setMouseCallback("live transmission", onMouse) key = cv2.waitKey(5) if key == ord('q'): #stop() break #stop() print() cv2.destroyAllWindows() 주행 도로에 있는 파란 선을 캠으로 찍어 색 기반 픽셀 필터링을 해 길을 인식할 수 있게 만든 뒤 이 코드를 실행시키면 길을 따라 움직이는 코드. 앞, 뒤, 회전, 후진 값을 변경해가며 속도나 디테일을 조절. [성능 테스트 및 평가] - 기본적으로 주어진 코드는 네트워크 문제로 잘 가다가 갑자기 급발진을 하는 등 오류가 심해 변경된 코드를 재시행 시킴. 이전처럼 급발진은 하지 않으나 움직인 뒤 네트워크 연결이 느려 반응 속도가 전보다 느려지는 단점이 생김. [결과 및 결론] - 3D프린팅을 위한 디자인 과정에서 나무 레이저 컷팅으로 바꿔 프린팅을 해보지 못해 좀 아쉬웠음. 하지만 rc카가 움직이기 위해 어떤 과정을 거쳐야 하고 어떤 방식으로 코드를 짜야 하는 지 수업을 들어 유익했음. 생각보다 자연스럽게 움직이는 것이 어려웠음. 걱정한 것보다 재밌고 더딘 부분들은 선생님들이 나서서 도와주셔 큰 어려움 또한 없었음.