from grove_rgb_lcd import setText, setRGB
import grovepi
import RPi.GPIO as GPIO
import time
import cv2
import numpy as np

# GPIO 핀 설정

# LED 부분
LED_RED = 4  # 빨간색 LED 핀
LED_GREEN = 18  # 초록색 LED 핀

# DC모터 부분(GPIO)
ENA = 22  # 모터 1 속도 제어 (PWM 핀)
ENB = 23  # 모터 2 속도 제어 (PWM 핀)
IN1 = 17  # 모터 1 방향 제어 핀 (단방향 고정)
IN3 = 24   # 모터 2 방향 제어 핀 (단방향 고정)

# 초음파 센서 부분(GROVEPI)
ULTRASONIC_PIN_1 = 4  # 초음파 센서 1 (입구 감지용)
ULTRASONIC_PIN_2 = 3  # 초음파 센서 2 (카메라 위치 감지용)

# 서보 모터 부분(GPIO)
SERVO_PIN1 = 27  # 서보 모터 1 제어 핀
SERVO_PIN2 = 2  # 서보 모터 2 제어 핀

# GPIO 초기화
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)  # GPIO 핀 번호를 BCM 모드로 설정
GPIO.setup(LED_RED, GPIO.OUT)  # 빨간색 LED 출력 모드 설정
GPIO.setup(LED_GREEN, GPIO.OUT)  # 초록색 LED 출력 모드 설정
GPIO.setup(SERVO_PIN1, GPIO.OUT)  # 서보 모터 1 출력 모드 설정
GPIO.setup(SERVO_PIN2, GPIO.OUT)  # 서보 모터 2 출력 모드 설정

GPIO.setup(ENA, GPIO.OUT)  # 모터 1 속도 제어 핀 출력 모드 설정
GPIO.setup(ENB, GPIO.OUT)  # 모터 2 속도 제어 핀 출력 모드 설정
GPIO.setup(IN1, GPIO.OUT)  # 모터 1 방향 제어 핀 출력 모드 설정
GPIO.setup(IN3, GPIO.OUT)  # 모터 2 방향 제어 핀 출력 모드 설정

GPIO.output(IN1, GPIO.LOW)
GPIO.output(IN3, GPIO.LOW)

# PWM 초기화
pwm1 = GPIO.PWM(ENA, 100)  # 모터 1 속도 제어용 PWM 생성 (100Hz)
pwm2 = GPIO.PWM(ENB, 100)  # 모터 2 속도 제어용 PWM 생성 (100Hz)

servo1 = GPIO.PWM(SERVO_PIN1, 50)  # 서보 모터 1 PWM 생성 (50Hz)
servo2 = GPIO.PWM(SERVO_PIN2, 50)  # 서보 모터 2 PWM 생성 (50Hz)

pwm1.start(0)  # 모터 1 초기 속도 0%
pwm2.start(0)  # 모터 2 초기 속도 0%
servo1.start(7)  # 서보 모터 1 초기 위치 (0도)
servo2.start(7)  # 서보 모터 2 초기 위치 (0도)

# 기준 이미지 로드
reference_images = {
    'Plastic': cv2.imread('/home/pi/image1.jpg'),  # 플라스틱 기준 이미지
    'Paper': cv2.imread('/home/pi/image2.jpg'),  # 종이 기준 이미지
    'PET': cv2.imread('/home/pi/image3.jpg'),  # PET 병 기준 이미지
    'Glass': cv2.imread('/home/pi/image4.jpg'),  # 유리 기준 이미지
}

# LCD 메시지 출력 함수
def lcd_string(message, line):
    """
    Grove RGB LCD에 메시지 출력.
    line: 출력할 줄 번호 (1 또는 2)
    """
    if line == 1:
        setText(message)
    elif line == 2:
        setText("\n" + message)

# 초음파 센서 거리 측정 함수
def get_distance(pin):
    """
    초음파 센서를 이용해 거리를 측정.
    pin: 초음파 센서 핀 번호
    """
    try:
        distance = grovepi.ultrasonicRead(pin)  # 거리 값 읽기
        return distance
    except TypeError:
        print("초음파 센서 오류")  # 오류 발생 시 출력
        return None

def operate_dc_motor(speed, state):
    """
    DC 모터를 제어하는 함수 (단방향 회전).
    speed: 모터 속도 (0~100)
    state: 모터 작동 상태 (1: 작동, 0: 정지)
    """
    if state == 1:  # 모터 작동
        GPIO.output(IN1, GPIO.HIGH)  # 모터 1 작동
        GPIO.output(IN3, GPIO.HIGH)  # 모터 2 작동
        pwm1.ChangeDutyCycle(speed)  # 모터 1 속도 제어
        pwm2.ChangeDutyCycle(speed)  # 모터 2 속도 제어
    else:  # 모터 정지
        GPIO.output(IN1, GPIO.LOW)  # 모터 1 정지
        GPIO.output(IN3, GPIO.LOW)  # 모터 2 정지
        pwm1.ChangeDutyCycle(0)  # 속도 0
        pwm2.ChangeDutyCycle(0)  # 속도 0

# 쓰레기 분류 함수
def classify_waste(input_image):
    """
    입력 이미지를 기준 이미지와 비교하여 쓰레기 종류를 분류.
    input_image: 입력 이미지
    """
    input_hist = cv2.calcHist([input_image], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])  # 입력 이미지 히스토그램 계산
    cv2.normalize(input_hist, input_hist, 0, 1, cv2.NORM_MINMAX)  # 히스토그램 정규화

    best_match = None
    highest_score = -1

    for label, ref_image in reference_images.items():  # 기준 이미지와 비교
        ref_hist = cv2.calcHist([ref_image], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
        cv2.normalize(ref_hist, ref_hist, 0, 1, cv2.NORM_MINMAX)
        score = cv2.compareHist(input_hist, ref_hist, cv2.HISTCMP_CORREL)

        if score > highest_score:
            highest_score = score
            best_match = label

    return best_match  # 가장 유사한 분류 반환

# 서보 모터 동작
def move_servo(result):
    """
    서보 모터를 동작시켜 쓰레기를 분류.
    result: 쓰레기 종류
    """
    if result == 'Paper':
        servo1.ChangeDutyCycle(3)  # 30도
        servo2.ChangeDutyCycle(12)  # 120도
    elif result == 'Plastic':
        servo1.ChangeDutyCycle(6)  # 60도
        servo2.ChangeDutyCycle(9)  # 90도
    elif result == 'PET':
        servo1.ChangeDutyCycle(9)  # 90도
        servo2.ChangeDutyCycle(6)  # 60도
    elif result == 'Glass':
        servo1.ChangeDutyCycle(12)  # 120도
        servo2.ChangeDutyCycle(3)  # 30도
    time.sleep(1)

# 메인 반복문
try:
    setRGB(0, 255, 0)  # LCD 색상 설정
    GPIO.output(LED_GREEN, GPIO.HIGH)

    while True:
        # 초음파 센서 1에서 물체 감지
        if get_distance(ULTRASONIC_PIN_1) < 10:
            lcd_string("ul 1 check", 1)
            GPIO.output(LED_GREEN, GPIO.LOW)
            GPIO.output(LED_RED, GPIO.HIGH)
            time.sleep(2)
            operate_dc_motor(speed=50, state=1)

        # 초음파 센서 2에서 물체 감지
        if get_distance(ULTRASONIC_PIN_2) < 10:
            lcd_string("2 check", 1)
            operate_dc_motor(speed=0, state=0)  # 모터 정지

            # 카메라로 이미지 캡처
            camera = cv2.VideoCapture(0)
            if not camera.isOpened():
                break
            ret, frame = camera.read()
            camera.release()

            if ret and frame is not None:
                # 쓰레기 분류
                result = classify_waste(frame)

                # LCD에 물체 종류 출력
                lcd_string(result, 1)

                # 서보 모터 동작
                move_servo(result)
                time.sleep(3)

                lcd_string("move", 1)

                operate_dc_motor(speed=50, state=1)
                time.sleep(3)
                operate_dc_motor(speed=0, state=0)

                GPIO.output(LED_RED, GPIO.LOW)
                GPIO.output(LED_GREEN, GPIO.HIGH)

                lcd_string("clear", 1)
                time.sleep(2)

                # LCD 초기화
                lcd_string("", 1)
                lcd_string("", 2)

            else:
                print("이미지를 캡처할 수 없습니다")

except KeyboardInterrupt:
    print("프로그램 종료")

finally:
    pwm1.stop()
    pwm2.stop()
    servo1.stop()
    servo2.stop()
    GPIO.cleanup()
    setRGB(0, 0, 0)
    setText("")

확인사항

sudo apt-get update sudo apt-get install python3-opencv

테스트

그냥 랜덤으로 분류

from grove_rgb_lcd import setText, setRGB  # Grove RGB LCD 모듈 추가
import grovepi  # GrovePi 모듈 제어 라이브러리
import RPi.GPIO as GPIO  # Raspberry Pi GPIO 핀 제어 라이브러리
import time  # 시간 지연을 위한 라이브러리
import random  # 랜덤 분류를 위한 라이브러리

# GPIO 핀 설정

# LED 부분
LED_RED = 4  # 빨간색 LED 핀
LED_GREEN = 18  # 초록색 LED 핀

# DC모터 부분(GPIO)
ENA = 22  # 모터 1 속도 제어 (PWM 핀)
ENB = 23  # 모터 2 속도 제어 (PWM 핀)
IN1 = 17  # 모터 1 방향 제어 핀 (단방향 고정)
IN3 = 24   # 모터 2 방향 제어 핀 (단방향 고정)

# 초음파 센서 부분(GROVEPI)
ULTRASONIC_PIN_1 = 4  # 초음파 센서 1 (입구 감지용)
ULTRASONIC_PIN_2 = 3  # 초음파 센서 2 (카메라 위치 감지용)

# 서보 모터 부분(GPIO)
SERVO_PIN1 = 27  # 서보 모터 1 제어 핀
SERVO_PIN2 = 25  # 서보 모터 2 제어 핀

# GPIO 초기화
GPIO.setmode(GPIO.BCM)  # GPIO 핀 번호를 BCM 모드로 설정

GPIO.setup(LED_RED, GPIO.OUT)  # 빨간색 LED 출력 모드 설정
GPIO.setup(LED_GREEN, GPIO.OUT)  # 초록색 LED 출력 모드 설정
GPIO.setup(SERVO_PIN1, GPIO.OUT)  # 서보 모터 1 출력 모드 설정
GPIO.setup(SERVO_PIN2, GPIO.OUT)  # 서보 모터 2 출력 모드 설정

# GPIO 초기화
GPIO.setup(ENA, GPIO.OUT)  # 모터 1 속도 제어 핀 출력 모드 설정
GPIO.setup(ENB, GPIO.OUT)  # 모터 2 속도 제어 핀 출력 모드 설정
GPIO.setup(IN1, GPIO.OUT)  # 모터 1 방향 제어 핀 출력 모드 설정
GPIO.setup(IN3, GPIO.OUT)  # 모터 2 방향 제어 핀 출력 모드 설정

GPIO.output(IN1, GPIO.LOW)
GPIO.output(IN3, GPIO.LOW)

# PWM 초기화
pwm1 = GPIO.PWM(ENA, 100)  # 모터 1 속도 제어용 PWM 생성 (100Hz)
pwm2 = GPIO.PWM(ENB, 100)  # 모터 2 속도 제어용 PWM 생성 (100Hz)

servo1 = GPIO.PWM(SERVO_PIN1, 50)  # 서보 모터 1 PWM 생성 (50Hz)
servo2 = GPIO.PWM(SERVO_PIN2, 50)  # 서보 모터 2 PWM 생성 (50Hz)

pwm1.start(0)  # 모터 1 초기 속도 0%
pwm2.start(0)  # 모터 2 초기 속도 0%
servo1.start(0)  # 서보 모터 1 초기 위치
servo2.start(0)  # 서보 모터 2 초기 위치

# 쓰레기 종류 리스트
categories = ['Plastic', 'Paper', 'PET', 'Glass']

# LCD 초기화 함수
def lcd_string(message, line):
    """
    Grove RGB LCD에 메시지 출력.
    line: 출력할 줄 번호 (1 또는 2)
    """
    if line == 1:
        setText(message[:LCD_WIDTH])  # 첫 줄에 텍스트 출력
    elif line == 2:
        setText("\n" + message[:LCD_WIDTH])  # 두 번째 줄로 출력

# 초음파 센서 거리 측정 함수
def get_distance(pin):
    """
    초음파 센서를 이용해 거리를 측정.
    pin: 초음파 센서 핀 번호
    """
    try:
        distance = grovepi.ultrasonicRead(pin)  # 거리 값 읽기
        return distance
    except TypeError:
        print("초음파 센서 오류")  # 오류 발생 시 출력
        return None

# 메인 반복문
try:
    setRGB(0, 255, 0)  # LCD 색상 설정 (초록)
    GPIO.output(LED_GREEN, GPIO.HIGH)

    while True:
        # 초음파 센서 1에서 물체 감지
        if get_distance(ULTRASONIC_PIN_1) < 10:
            lcd_string("물체 감지", 1)
            GPIO.output(LED_GREEN, GPIO.LOW)
            GPIO.output(LED_RED, GPIO.HIGH)
            time.sleep(2)
            lcd_string("컨베이어 벨트 작동", 1)

            # 모터 작동
            operate_dc_motor(speed=50, state=1)

        # 초음파 센서 2에서 물체 감지
        if get_distance(ULTRASONIC_PIN_2) < 10:
            lcd_string("카메라 아래", 1)
            lcd_string("물체 감지", 2)
            operate_dc_motor(speed=0, state=0)

            result = random.choice(categories)
            print(f"분류 결과: {result}")

            lcd_string("Classified as:", 1)
            lcd_string(result, 2)

            move_servo(result)
            time.sleep(3)

            lcd_string("컨베이어 벨트 작동", 1)

            operate_dc_motor(speed=50, state=1)
            time.sleep(3)
            operate_dc_motor(speed=0, state=0)

            GPIO.output(LED_RED, GPIO.LOW)
            GPIO.output(LED_GREEN, GPIO.HIGH)

            lcd_string("물체 분류 완료", 1)
            time.sleep(2)

            lcd_string("", 1)
            lcd_string("", 2)

            time.sleep(2)

except KeyboardInterrupt:
    pwm1.stop()
    pwm2.stop()
    servo1.stop()
    servo2.stop()
    GPIO.cleanup()
    print("프로그램 종료")
    
finally:
    pwm1.stop()
    pwm2.stop()
    servo1.stop()
    servo2.stop()
    GPIO.cleanup()
    setRGB(0, 0, 0)  # LCD 백라이트 끄기
    setText("")