.. Cover Letter

ㅇ 프로젝트/TEAM_스마트 팩토리

4. 원을 검출하고 이를 시리얼 통신으로 아두이노 LCD에 기록하자.

BrainKimDu 2022. 12. 29. 11:24

조원이 LCD에 관해 연구를 해왔다.

이를 통해
시리얼 통신의 코드와 opencv원검출 코드를 활용하여
원을 검출할때 LCD에 띄우는 작업을 하고자 한다.


먼저 아두이노에서 LCD를 사용하기 위해서는
모듈을 하나 설치해야 한다.

LiquidCrystal_I2C.h
를 깃헙에서 다운로드 하여 적용하여야한다.
https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library.git

GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino board

Library for the LiquidCrystal LCD display connected to an Arduino board. - GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino...

github.com

여기에서 다운로드를 진행합니다.

깃클론 아닙니다!


zip으로 다운로드 받습니다.
그리고 아두이노에서 sketch -> include 라이브러리 -> add zip 뭐시기


https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kaiserkhan21&logNo=221042019483

[아두이노] I2C LCD 사용하기

LCD(Liquid Crystal Display)는 전기적 신호를 가해 액정을 원하는 방향으로 배열하여 빛을 투과 또...

blog.naver.com

해당블로그에서
다음의코드를 사용할 것입니다.

//#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f, 16, 2);

void setup() {
  // put your setup code here, to run once:
  lcd.begin();
  lcd.backlight();
  lcd.print("Hello world!");
}

void loop() {
  // put your main code here, to run repeatedly:

}

VCC = 5V
GND = GND
SDA = A4
SCL = A5에 연결하고

만약 출력이 잘안되면
뒤에있는 저항을 조절합니다.


응용

//#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3f, 16, 2);

void setup() {
  // put your setup code here, to run once:
  lcd.begin();
  lcd.backlight();
  
}

void loop() {
  // put your main code here, to run repeatedly:
  lcd.setCursor(0, 0);
  lcd.print("Hello world!  ");
  lcd.setCursor(0, 1);
  lcd.print("Hi im name  ");
  delay(5000);

  lcd.setCursor(0, 0);
  lcd.print("bye world   ");
  lcd.setCursor(0, 1);
  lcd.print("Hi your name");
  delay(5000);

}





그러면 이제 진행할 것은
원을 검출하는 코드에서 시리얼 통신을 구현하자.
openCV를 활용하여 동전을 검출해보자. - https://kimbrain.tistory.com/m/341

openCV를 활용하여 동전을 검출해보자.

이 글은 PinkLab의 PinkWink 강사님의 강의자료를 참고하여 작성되었습니다. 프로젝트에서 컨베이어 벨트를 통과하는 도형들을 검출해야한다. YOLO를 사용하지 않고 openCV만을 사용하여 검출해주었으

kimbrain.tistory.com

(코드설명)

import sys
import numpy as np
import cv2

import serial
import time

cap = cv2.VideoCapture(0)
if not cap.isOpened():
    print("열리지 않아요")
    sys.exit()

ser = serial.Serial('/dev/ttyACM0', 9600)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    #src = cv2.resize(frame, dsize=(900, 959))
    # 이미지의 사이즈를 조절한다.

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blr = cv2.GaussianBlur(gray, (0, 0), 1.0)
    # 이미지의 잡음을 제거한다.


    # 실질적인 허프변환이 시작되는 부분
    circles = cv2.HoughCircles(blr, cv2.HOUGH_GRADIENT, 1, 50, param1=120, param2=40, minRadius=10, maxRadius=80)
    # 반지름과 threshold를 조절하면서 확인해볼 분이다.

    dst = frame.copy()
    # 이미지를 복사해서 dst에 저장한다.

    cv2.imshow('img', frame)
    
    # 원을 검출할 때 실행된다.
    if circles is not None:
        #for i in range(circles.shape[1]):
        # 검출된 원의 개수만큼 돌아서 원을 그린다.
        cx, cy, radius = circles[0][0]
        cv2.circle(dst, (int(cx), int(cy)), int(radius), (255, 0, 0), 2, cv2.LINE_AA)
        cv2.putText(dst, str(radius), org=(int(cx), int(cy)), 
        fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, 
        color=(0,0,255),thickness=3, lineType=cv2.LINE_AA)
 

        val = "circle," + str(radius)
        val = val.encode('utf-8')
        ser.write(val)
        print("circle detect and success communicate")
        time.sleep(0.25)
    
    

    cv2.imshow('img', dst)
    key = cv2.waitKey(1)

    if key == 27:
        break
    


cap.release()
cv2.destroyAllWindows()

도형(원) , 반지름을 시리얼 통신으로 전송한다.

혹시나 아두이노에서 시리얼모니터를 작동시키면 필히꺼주어야한다
그러면 파이썬 파일이 실행이안된다.

아두이노에서 문자열은 또 다르게 사용된다.
https://steemit.com/kr-arduino/@codingman/serial-string

Serial 통신 때 String 사용 (아두이노) — Steemit

Serial 통신 때 String 사용 (아두이노) 오늘은 간단히 Serial 통신을 할 때 String으로 접근하는 방법을 알아보고자 합니다. 지금까지는 간단히 Sensor의 값을 Serial 통신을 통해 값을 전송할 때는 하나의

steemit.com

String come;

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 16, 2);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
}

void loop() {

  while(Serial.available()){
    String come = Serial.readStringUntil('/');
    Serial.println(come);
    lcd.setCursor(0, 0);
    lcd.print(come);
    delay(500);
  }
  
}

일단 카메라에서 detecting한 원의 반지름을LCD에 출력하게 했다.
근데 점점 출력이 이상해기 시작해서 원일을 찾아야겠다.

LCD를 초기화했다.
https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library/blob/master/LiquidCrystal_I2C.h

GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino board

Library for the LiquidCrystal LCD display connected to an Arduino board. - GitHub - fdebrabander/Arduino-LiquidCrystal-I2C-library: Library for the LiquidCrystal LCD display connected to an Arduino...

github.com


해당 라이브러리는 init이 지원이 안된다.

String come;

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 16, 2);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
}

void loop() {

  while(Serial.available()){
    String come = Serial.readStringUntil('/');
    lcd.begin();
    lcd.setCursor(0, 0);
    lcd.print(come);
    delay(250);
  }
}


파이썬 코드와 아두이노 코드의 딜레이 오프셋을 맞춰주어야하는듯 하다
근데, 정확하게 맞추기는 어렵고
가끔 값이 튄다.





살짝 수정을 해서
1차 초안

import sys
import numpy as np
import cv2

import serial
import time

cap = cv2.VideoCapture(0)
if not cap.isOpened():
    print("열리지 않아요")
    sys.exit()

ser = serial.Serial('/dev/ttyACM0', 9600)
count = 0
de_count = 0 
radius_list = []

while True:
    ret, frame = cap.read()
    if not ret:
        break

    #src = cv2.resize(frame, dsize=(900, 959))
    # 이미지의 사이즈를 조절한다.

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blr = cv2.GaussianBlur(gray, (0, 0), 1.0)
    # 이미지의 잡음을 제거한다.


    # 실질적인 허프변환이 시작되는 부분
    circles = cv2.HoughCircles(blr, cv2.HOUGH_GRADIENT, 1, 50, param1=120, param2=40, minRadius=10, maxRadius=80)
    # 반지름과 threshold를 조절하면서 확인해볼 분이다.

    dst = frame.copy()
    # 이미지를 복사해서 dst에 저장한다.

    cv2.imshow('img', frame)
    
    # 원을 검출할 때 실행된다.
    if circles is not None:
        #for i in range(circles.shape[1]):
        # 검출된 원의 개수만큼 돌아서 원을 그린다.
        cx, cy, radius = circles[0][0]
        cv2.circle(dst, (int(cx), int(cy)), int(radius), (255, 0, 0), 2, cv2.LINE_AA)
        cv2.putText(dst, str(radius), org=(int(cx), int(cy)), 
        fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, 
        color=(0,0,255),thickness=3, lineType=cv2.LINE_AA)
        radius_list.append(radius)
        count += 1
        if count == 5:
            val_radius = np.average(radius_list)
            if val_radius >=38 and val_radius <= 42:
                val = "circle, "+ "yes, " + str(val_radius) +  "/"
            else:
                val = "circle, "+ "no, " + str(val_radius) +  "/"
            val = val.encode('utf-8')
            ser.write(val)
            radius_list.clear()
            count = 0   
        de_count = 0 
        time.sleep(0.1)
    
    else:
        de_count += 1
        if de_count == 5:
            val = "not detect           "
            val = val.encode('utf-8')
            ser.write(val)
            de_count = 0
            count = 0

        time.sleep(0.25)
        count = 0 
        
    
    

    cv2.imshow('img', dst)
    key = cv2.waitKey(1)

    if key == 27:
        break
    


cap.release()
cv2.destroyAllWindows()