본문 바로가기

피지컬컴퓨팅/아두이노

#인공지능 AI 활용 - Mediapipe를 이용한 로봇 손 제어하기

반응형

MediaPipe는 구글에서 개발한 오픈 소스 라이브러리로, 다양한 운영체제와 프로그래밍 언어를 지원하며, API를 통해 쉽게 사용할 수 있습니다. 또한 이미지와 실시간 비디오 처리가 가능하며 계속해서 개발이 이루어지고 있어 다양한 분야에서 활용도가 높아지고 있습니다.

 

https://mediapipe.readthedocs.io/en/latest/solutions/hands.html

 

아래 링크를 눌러 해당 사이트로 이동하면 다양한 데모를 볼 수 있고 관련된 프로젝트의 내용을 볼 수 있으니 참고하시기 바랍니다.

https://developers.google.com/mediapipe

 

MediaPipe  |  Google for Developers

An open source, cross-platform, customizable ML solution for live and streaming media.

developers.google.com

 

1) 준비물

- 로봇 손

 

 

- 아두이노 우노보드와 우노보드용 실드를 사용하여 만들 수도 있고 실드 없이 브레드 보드를 사용하여 만들어도 됩니다.

- 점퍼선

 

2) 아두이노 서보모터 이용하기

- 회로도

복잡해보이지만 서보모터 5개를 각각 GND(음극), VCC(양극)에 연결하고 2, 4,6,8,10번 핀에 연결합니다.

프로토실드가 있다면 브레드 보드 없이 더 편리하게 연결할 수 있지만 없다면 그냥 브레드 보드에 연결해도 됩니다.

서보모터를 여러개 작동하기 때문에 보조 전원이 필요합니다.

 

 

- 소스코드

아두이노에 소스코드를 업로드할 때 포트 번호를 기억해주세요.

#include<Servo.h> 
Servo servo_1;
Servo servo_2;
Servo servo_3;
Servo servo_4;
Servo servo_5;      


void setup() {
  Serial.begin(9600);
  servo_1.attach(10); 
  servo_2.attach(8);
  servo_3.attach(6);
  servo_4.attach(4);
  servo_5.attach(2);
  delay(500);
  servo_1.write(0);
  servo_2.write(165);
  servo_3.write(165);
  servo_4.write(165);
  servo_5.write(165);
  delay(5000);
}

void loop() {
  while (Serial.available() > 0) {
    char data = Serial.read();
    if (data == '1') {
     servo_1.write(165);   
    }
    if (data == '2') {
     servo_1.write(0); 
    }
     if (data == '3') {
      servo_2.write(0);
    }
    if (data == '4') {
     servo_2.write(165);
    }
    if (data == '5') {
      servo_3.write(0);
    }
     if (data == '6') {
      servo_3.write(165);
    }
    if (data == '7') {
     servo_4.write(0);
    }
    if (data == '8') {
      servo_4.write(165);
    }
     if (data == '9') {
      servo_5.write(0);
    }
    if (data == '0') {
     servo_5.write(165);
    }
    delay(5); 
  }
}

 

 

3) Mediapipe를 이용하여 손가락 위치 정보 찾아 아두이노로 전송하기

- cmd 창을 열어 라이브러리를 설치합니다.

 

- cmd 창에서  명령어를 입력하여 라이브러리를 설치합니다.

- cmd 창을 열어 라이브러리를 설치합니다.

 

- cmd 창에서  명령어를 입력하여 라이브러리를 설치합니다.

- pip install mediapipe

 

- Visual Studio Code를 이용해 새로운 파일('finger.py')을 만들어 아래 소스코드를 붙여넣기 합니다.

import cv2
import mediapipe as mp
import pyautogui
import serial
import math

finger0_x = finger4_x = finger8_x = finger9_x = finger12_x = finger16_x = finger20_x = 0
finger0_y = finger4_y = finger8_y = finger9_y = finger12_y = finger16_y = finger20_y = 0

webcam=cv2.VideoCapture(0)
mp_hands = mp.solutions.hands
my_hands = mp.solutions.hands.Hands()
drawing_utils = mp.solutions.drawing_utils

arduino = serial.Serial('COM9', 9600)
arduino.timeout = 1

while True:   
    _, image = webcam.read()
    image = cv2.flip(image, 1)
    frame_height, frame_width, _ = image.shape
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    output = my_hands.process(rgb_image)
    hands = output.multi_hand_landmarks

    if hands:
        for hand in hands:
            drawing_utils.draw_landmarks(image, hand, mp_hands.HAND_CONNECTIONS)
            landmarks = hand.landmark
            for id, landmark in enumerate(landmarks):
                x = int(landmark.x * frame_width)
                y = int(landmark.y * frame_height)
                if id == 0:
                    finger0_x = x
                    finger0_y = y
                if id == 4:
                    finger4_x = x
                    finger4_y = y
                if id == 8:
                    finger8_x = x
                    finger8_y = y
                if id == 9:
                    finger9_x = x
                    finger9_y = y
                if id == 12:
                    finger12_x = x
                    finger12_y = y
                if id == 16:
                    finger16_x = x
                    finger16_y = y
                if id == 20:
                    finger20_x = x
                    finger20_y = y
                    
                dist_1 = int(math.sqrt((finger4_x - finger9_x)**2 + (finger4_y - finger9_y)**2))
                dist_2 = int(math.sqrt((finger8_x - finger0_x)**2 + (finger8_y - finger0_y)**2))
                dist_3 = int(math.sqrt((finger12_x - finger0_x)**2 + (finger12_y - finger0_y)**2))
                dist_4 = int(math.sqrt((finger16_x - finger0_x)**2 + (finger16_y - finger0_y)**2))
                dist_5 = int(math.sqrt((finger20_x - finger0_x)**2 + (finger20_y - finger0_y)**2))

                cv2.putText(
                    image, text='dist1=%d dist2=%d dist3=%d dist4=%d dist5=%d' % (dist_1,dist_2,dist_3,dist_4,dist_5), org=(10, 30),
                    fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.6,
                    color=(255,0,0), thickness=2)

                if dist_1<=100:
                    arduino.write(b'1')
                else:
                    arduino.write(b'2')
                    
                if dist_2<=200:
                    arduino.write(b'3')
                else:
                    arduino.write(b'4')
                if dist_3<=200:
                    arduino.write(b'5')
                else:
                    arduino.write(b'6')
                if dist_4<=200:
                    arduino.write(b'7')
                else:
                    arduino.write(b'8')
                if dist_5<=200:
                    arduino.write(b'9')
                else:
                    arduino.write(b'0')
                    
        else:
            arduino.write(b'2')
            arduino.write(b'4')
            arduino.write(b'6')
            arduino.write(b'8')
            arduino.write(b'0')
                 

    cv2.imshow("Img", image)
    key = cv2.waitKey(10)

    if key == 27: #esc key
        break

webcam.release()
cv2.destroyAllWindows()

 

4) 실행결과

 

반응형