Devlog
article thumbnail

2019-1학기때 수강한 임베디드시스템에서 자율주행 로봇인 "오토봇"을 제작하였다.

학교 다니면서 되게 공을 많이 들인 프로젝트 였는데 원래 설정한 목표에 도달하지는 못했다.

 

차선을 인식하기 위해서 하프변환을 이용하였다.

차선을 인식하는데 직선을 검출하고 직선의 기울기에 따라 좌회전을 하는지 우회전을 하는지를 판단한다.

 

이 과정에서 무수한 문제점들이 발생하였는데 

첫 째, 하프변환이 모든 직선을 검출하는 문제점이 발생했다.

이는 카메라의 범위를 줄여 카메라가 인식하는 화면에 차선만 보이게 맞추어서 해결하였다.

차선에 해당하는 직선들을 검출 할 수 있었다.

 

둘 째, 카메라의 사양이 낮아서 로봇이 움직이는 속도와 카메라가 비추는 화면이 달라 실시간으로 받아오기 힘들었다.

이게 가장 큰 문제점이였는데 예를 들어 직선으로 가다가 좌측으로 꺾이는 주행도면이 있다고 가정하자

카메라가 직선을 검출하여 로봇이 직진을 하도록 카메라에서 받은 직선의 값을 로봇으로 값을 넘겨준다.

로봇은 직진을 다 수행한 상태이고 이제 좌회전을 해야하는 상황인데

카메라의 사양이 너무 낮아서 카메라는 이미 지나온 직선이 계속 나오고 있었던 것이다... (최소 5초 이상의 딜레이가 발생하였음) 

이 카메라의 사양 문제점은 신호등을 인식할 때도 발생하였는데 신호등은 색을 검출하여 판단하는거라 딜레이가 발생해도 어찌저찌 넘어갈 수 있었는데 차선을 인식하는 것은 해결할 수가 없었다.

 

결국 우리 팀은 차선을 검출하여 로봇을 제어하는 부분을 포기할 수 밖에 없었다. 

학교 다니면서 되게 공을 많이 들인 프로젝트 였는데 원래 설정한 목표에 도달하지는 못했다.

 

 

 

 

아두이노 수행코드 (시간을 단축하고자 창의공학설계입문 시간 때 사용했던 코드를 최대한 활용하였다)

include <Servo.h>

int MOTORL_PIN = 5;
int MOTORR_PIN = 9;

Servo IServo;
Servo RServo;

int left =1490;
int right =1490;

 

void setup() {
Serial.begin(115200);
IServo.attach(MOTORL_PIN);
RServo.attach(MOTORR_PIN);
}

void goForward() {
IServo.writeMicroseconds(left+70);
RServo.writeMicroseconds(right-70);
delay(1000);
}

void slow() {
IServo.writeMicroseconds(left+33);
RServo.writeMicroseconds(right-23);
delay(1000);
}

void turnright() {
IServo.writeMicroseconds(left+50);
RServo.writeMicroseconds(right-30);
delay(1000);
}

void turnleft() {
IServo.writeMicroseconds(left+20);
RServo.writeMicroseconds(right-50);
delay(1000);
}

void stop() {
IServo.writeMicroseconds(left);
RServo.writeMicroseconds(right);
}

void back() {
IServo.writeMicroseconds(1400);
RServo.writeMicroseconds(1590);
delay(400);

IServo.writeMicroseconds(1500);
RServo.writeMicroseconds(1490);
}

void loop() {
if (Serial.available()) {
    char value=Serial.read();
    Serial.println(value);
    
    if(value == 'R'){//빨간불
      stop();
      delay(5000);
    }
    if(value == 'Y'){//주황불
      slow();
      delay(100);
    }
    if(value == 'G'){//초록불
      goForward();
      delay(1000);
    }
  }
  else{
    slow();
  }
}

 

 

라즈베리파이 상세 코드

import cv2
import sys
import math
import video
import cv2 as cv
import numpy as np
import serial
import time
import math

 
ser = serial.Serial('/dev/ttyUSB0',115200) #아두이노와 시리얼 연동

if __name__ == '__main__':

    print(__doc__)

    try:
        fn = sys.argv[1]

    except IndexError:
        fn = 0

    def nothing(*arg):
        pass

    cap = video.create_capture(fn)


    i = 0
    counter = 0
    width = 0
    height = 0
    color = 0 

#영상 크기 받아오는 함수
    def check_img_info():
        while(True):
            ret, img = cap.read()

            if ret:
                x = img.shape[1] #영상의 가로 너비 크기
                y = img.shape[0] #영상의 세로 높이 크기
                break

        return x, y

#영상에서 RGB값 받아서 HSL 로 변환한 다음 출력 데이터 값 반환해주는 함수
    def check_color_pattern(src1):
        hls = cv2.cvtColor(src1, cv2.COLOR_BGR2HLS) # BGR color -> HSL 로 변환
        counter = 1
        sum_hue = 0

        # 평균 패치 측정   
        for i in range(50, width-50, 20):
            for j in range(50, height-50, 20):
                sum_hue = sum_hue + (hls[j, i, 0]*2)
                counter = counter + 1
        hue = sum_hue/counter #색상 값 추출
        print('Average Hue: ', hue)

        if ( 0 <= hue <= 30 ) or ( 280 <= hue <= 360): # RED
            print("R")
            str='R'
            ser.write(bytes(str.encode()))
            time.sleep(5)
            return 0

        elif( 90 <= hue <= 150): #GREEN
            print("G")
            str='G'
            ser.write(bytes(str.encode()))
            time.sleep(0.1)
            return 1

        elif( 40 <= hue <= 80): #YELLOW
            print("Y")
            str='Y'
            ser.write(bytes(str.encode()))
            time.sleep(0.1)
            return 2

        else:
            print(" Can't check color")
            time.sleep(1)
            return 3

    width, height = check_img_info()

    while (True):
        ret, src = cap.read() #실시간 영상 읽어오기
        src1 = np.copy(src)
        src = cv2.resize(src, (640, 380)) #영상의 윈도우 창 크기 조절   

        if ret:
            cv2.imshow('Video', src1)
            counter = counter + 1
            hls = cv2.cvtColor(src1, cv2.COLOR_BGR2HLS)
            color = check_color_pattern(src1) #함수의 반환 값을 받음

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

 

 

 

용량 문제로 영상이 바로 첨부가 되지를 않는다. 나중에 유튜브에 영상을 올리고 링크를 첨부 해야겠다

 

 

profile

Devlog

@덩이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그