본문 바로가기

메이커 프로젝트

음성으로 로봇 팔 제어하기

 

2023 과학전시관 ai메이커 직무연수 자료 업데이트 

작성자 : 경기기계공업고 교사 성원경

 

메인 강의 자료 (canva ppt) 

https://www.canva.com/design/DAFlNYbcKY0/GCol7mQF3O6IL4aJ85Iulw/view?utm_content=DAFlNYbcKY0&utm_campaign=designshare&utm_medium=link&utm_source=publishsharelink

- 목차.

1. 아두이노 서보모터 제어하기

2. 로봇팔 프로토 타입 모델링하기

3. 파이썬 음성 인식하기

4. 파이썬 음성인식 코드와 아두이노 서보모터 제어 연결하기

 

 

사전 작업 : 프로그램 설치

1. 아두이노 프로그램 설치

 

[IoT] 아두이노 통합 개발 환경(Arduino IDE) 설치하는 방법

IT is True 블로그에 들어와 주셔서 감사합니다. 이번엔 아두이노 통합 개발 환경(Arduino IDE)을 설치하는 방법에 대해서 알아보겠습니다. 1. 아두이노 IDE 다운로드 먼저, 아두이노 홈페이지에 접속하

ittrue.tistory.com

 

2. vs코드 설치

 

Visual Studio Code 설치하는 방법( Windows / Ubuntu )

Visual Studio Code를 Windows와 Ubuntu에 각각 설치하는 방법을 설명합니다. 설치를 진행해본 운영체제 버전은 Windows 10과 Ubuntu 20.04 /Ubuntu 18.04 입니다.           1. 윈도우에 설치하는 방법..

webnautes.tistory.com

 

3. 아나콘다 설치

 

[Python] 아나콘다[Anaconda] 설치하기

이번 시간에는 아나콘다[Anaconda]를 설치하는 방법을 포스팅 해보도록 하겠습니다. 추후 올릴 블로그 내용에 Google Tensorflow.js를 이용하여 인공지능 딥러닝을 통한 웹앱형태의 프로젝트를 개발

codepathfinder.com


 

참고자료.

 

[모듈 1-3] 아두이노 서보모터 제어하기 (feat. For 구문)

● 모듈 구성 안내 1-3-1. 서보모터란 무엇인가 1-3-2. 서보모터 기본 제어 1-3-3. for 구문으로 서보모터 제어하기 1-3-4. 포텐셜미터(가변저항)으로 서보모터 제어하기 ● 1-3-1. 서보모터란 무엇인가?

ai0.kr

 

 

[모듈 1-4] 아두이노 시리얼통신 제어(Feat. 로봇팔 만들기)

● 모듈 구성 안내 1-4-1. 시리얼 통신으로 가변 저항값 받아오기 1-4-2. 시리얼 통신으로 서보모터 제어하기 1-4-3. 시리얼 통신으로 로봇팔 만들기 ● 1-4-1. 시리얼 통신으로 가변저항값 받아오기

ai0.kr

 

 

 

 

 


 

 

1.  아두이노 서보모터 제어하기

 실습 1.   서보모터 1개 제어하기

 - 회로

 

- 코드 설명

 

- 코드 원본

#include <Servo.h>

Servo servo;                                                    
int value = 0;    

void setup() {
  servo.attach(7);          
}

void loop() {
    value = 0;
    servo.write(value); 
    delay(500);

    value = 90;
    servo.write(value);
    delay(500);

    value = 179;
    servo.write(value);
    delay(500);
}

 

 실습 2.  시리얼 통신으로 서보모터 제어하기

 

(이론적 배경) 시리얼통신이란?

 

 

 

- 회로

 

- 코드 1 - 시리얼 통신 테스트

 

- 코드 1 원본

void setup() {
  Serial.begin(9600);                               // Serial 통신을 설정합니다.
}

void loop() {

      Serial.println("hello World");                            //Serial 모니터에 a에 저장된 값을 타이핑 합니다.
      delay(500);
  }

 

코드 2 - 시리얼 통신으로 서보모터 제어하기

코드2 원본

#include <Servo.h>
Servo servo;
int value = 0;

void setup() {
  servo.attach(7);
  Serial.begin(9600);                               // Serial 통신을 설정합니다.
  while(!Serial);                                           
  Serial.println("Servor Mortor");
}

void loop() {

  if(Serial.available()){                             //Serial 모니터창에 어떤 값이 들어오면 실행을 합니다.
    value = Serial.parseInt();                           //Serial 모니터창에서 받은 값을 a라는 변수로 넘겨줍니다.

      Serial.print("각도 : ");
      Serial.println(value);

      servo.write(value);
      delay(15);
  }

}

 

 

 

실습3. 서보모터 2개 시리얼 통신으로 제어하기.

- 회로

 

- 코드 설명

 

 

- 코드(2축 서보모터 시리얼 통신 제어)

#include <Servo.h> //헤더파일 포함

Servo servo1; //servo1 변수 선언
Servo servo2; //servo2 변수 선언

int motor1 = 3; //motor1을 입출력 3번 핀에 연결
int motor2 = 5; //motor2을 입출력 5번 핀에 연결
int angle1 = 90; //초기 각도값 설정  
int angle2 = 90; //초기 각도값 설정

void setup() {
  servo1.attach(motor1); //servo1에 입출력 3번 핀을 지정
  servo2.attach(motor2); //servo2에 입출력 5번 핀을 지정
  Serial.begin(9600); //시리얼 모니터 사용
  Serial.println("Enter the w,a,s,d ");
}
void loop() {
  if(Serial.available()) //시리얼 통신이 가능할 경우
  {
    char input = Serial.read(); //시리얼 모니터 입력 값을 읽어옴
    if(input =='w') //입력값이 W일 경우
    {
      Serial.print("+30");
      for(int i = 0; i <30; i++) // 30번 반복
      {
        angle1 = angle1 + 1; // angle1의 값에 1씩 30번을 더함
        if(angle1 >=180) // angle1이 180보다 커지거나 같아질 경우 
        angle1 = 180; // angle1을 180으로 고정
        servo1.write(angle1); // servo1을 angle1 값에 맞추어 동작
        delay(10);
      }
      Serial.print("\t\t");
      Serial.println(angle1);
    }
    else if(input =='a') //입력값이 a일 경우
    {
      Serial.print("+30");
      for(int j = 0; j <30; j++)
      {
        angle2 = angle2 + 1;
        if(angle2 >=180)
         angle2 = 180;
        servo2.write(angle2);
        delay(10);
      }
      Serial.print("\t\t");
      Serial.println(angle2);
    }
     else if(input == 's') //입력값이 s일 경우
     {
      Serial.print("\t-30\t");
      for(int i = 0; i <30; i++) // 30번 반복
      {
        angle1 = angle1 -1; // angle1의 값에 1씩 30번을 빼기
        if(angle1 <= 0) // angle1이 0보다 작아지거나 같을 경우
        angle1 = 0; // angle1을 0으로 고정
        servo1.write(angle1); // servo1을 angle 값에 맞추어 동작
        delay(10);
      }
      Serial.println(angle1);
     }
     else if(input == 'd')  //입력값이 d일 경우
     {
      Serial.print("\t-30\t");
      for(int j = 0; j <30; j++)
      {
        angle2 = angle2 -1;
        if(angle2 <= 0)
        angle2 = 0;
        servo2.write(angle2);
        delay(10);
      }
      Serial.println(angle2);
     }
  }
}

 

- 코드(3축 서보모터 시리얼 통신 제어)

#include <Servo.h> //헤더파일 포함

Servo servo0; //servo0 변수 선언
Servo servo1; //servo1 변수 선언
Servo servo2; //servo2 변수 선언

int motor0 = 6; //motor1을 입출력 3번 핀에 연결
int motor1 = 3; //motor1을 입출력 3번 핀에 연결
int motor2 = 5; //motor2을 입출력 5번 핀에 연결
int angle0 = 90; //초기 각도값 설정  
int angle1 = 90; //초기 각도값 설정
int angle2 = 90; //초기 각도값 설정

void setup() {
  servo0.attach(motor0); //servo0에 입출력 3번 핀을 지정
  servo1.attach(motor1); //servo1에 입출력 3번 핀을 지정
  servo2.attach(motor2); //servo2에 입출력 5번 핀을 지정
  Serial.begin(9600); //시리얼 모니터 사용
  Serial.println("Enter the w,a,s,d,z,c");
}
void loop() {
  if(Serial.available()) //시리얼 통신이 가능할 경우
  {
    char input = Serial.read(); //시리얼 모니터 입력 값을 읽어옴
    if(input =='w') //입력값이 W일 경우
    {
      Serial.print("+30");
      for(int i = 0; i <30; i++) // 30번 반복
      {
        angle1 = angle1 + 1; // angle1의 값에 1씩 30번을 더함
        if(angle1 >=180) // angle1이 180보다 커지거나 같아질 경우 
        angle1 = 180; // angle1을 180으로 고정
        servo1.write(angle1); // servo1을 angle1 값에 맞추어 동작
        delay(10);
      }
      Serial.print("\t\t");
      Serial.println(angle1);
    }
    else if(input =='a') //입력값이 a일 경우
    {
      Serial.print("+30");
      for(int j = 0; j <30; j++)
      {
        angle2 = angle2 + 1;
        if(angle2 >=180)
         angle2 = 180;
        servo2.write(angle2);
        delay(10);
      }
      Serial.print("\t\t");
      Serial.println(angle2);
    }
     else if(input == 's') //입력값이 s일 경우
     {
      Serial.print("\t-30\t");
      for(int i = 0; i <30; i++) // 30번 반복
      {
        angle1 = angle1 -1; // angle1의 값에 1씩 30번을 빼기
        if(angle1 <= 0) // angle1이 0보다 작아지거나 같을 경우
        angle1 = 0; // angle1을 0으로 고정
        servo1.write(angle1); // servo1을 angle 값에 맞추어 동작
        delay(10);
      }
      Serial.println(angle1);
     }
     else if(input == 'd')  //입력값이 d일 경우
     {
      Serial.print("\t-30\t");
      for(int j = 0; j <30; j++)
      {
        angle2 = angle2 -1;
        if(angle2 <= 0)
        angle2 = 0;
        servo2.write(angle2);
        delay(10);
      }
      Serial.println(angle2);
     }
     else if(input == 'z')  //입력값이 d일 경우
     {
      Serial.print("\t-30\t");
      for(int j = 0; j <30; j++)
      {
        angle0 = angle0 +1;
        if(angle0 >= 180)
        angle0 = 180;
        servo0.write(angle0);
        delay(10);
      }
      Serial.println(angle0);
     }
     else if(input == 'c')  //입력값이 d일 경우
     {
      Serial.print("\t-30\t");
      for(int j = 0; j <30; j++)
      {
        angle0 = angle0 -1;
        if(angle0 <= 0)
        angle0 = 0;
        servo0.write(angle0);
        delay(10);
      }
      Serial.println(angle0);
     }
  }
}

- 코드(4축 서보모터 시리얼 통신 제어)

 

#include <Servo.h> //헤더파일 포함

Servo servo0; //servo0 변수 선언
Servo servo1; //servo1 변수 선언
Servo servo2; //servo2 변수 선언
Servo servo3; //servo3 변수 선언

int motor[4]={6, 3, 5, 9};  //servo motor와 연결된 digital pin 값을 설정

int angle[4]={90, 90, 90, 90};  //초기 각도값 설정

void setup() {
  servo0.attach(motor[0]); //servo0에 입출력 6번 핀을 지정_베이스 서보
  servo1.attach(motor[1]); //servo1에 입출력 3번 핀을 지정_상하1 서보
  servo2.attach(motor[2]); //servo2에 입출력 5번 핀을 지정_상하2 서보
  servo3.attach(motor[3]); //servo2에 입출력 9번 핀을 지정_그리퍼 서보
  Serial.begin(9600); //시리얼 모니터 사용
  Serial.println("Enter the w,a,s,d,z,c");
}

int delayTime(int i){ //지연값 변경
  return int(sq(abs(15-i))*0.1)+10;
  //return 10;
}

void move(int smotor, int dir){
  if(dir==1){
    Serial.print("+30");
  }else{
    Serial.print("-30");
  }
  
  for(int i = 0; i <30; i++) // 30번 반복
  {
    angle[smotor] = angle[smotor] + dir; // angle1의 값에 +-1씩 30번을 더함
    if(angle[smotor] >=180) // angle1이 180보다 커지거나 같아질 경우 
      angle[smotor] = 180; // angle1을 180으로 고정
    if(angle[smotor] <=0) // angle1이 180보다 커지거나 같아질 경우 
      angle[smotor] = 0; // angle1을 180으로 고정
    servo0.write(angle[0]); // servo1을 angle[0] 값에 맞추어 동작
    servo1.write(angle[1]); // servo2을 angle[1] 값에 맞추어 동작
    servo2.write(angle[2]); // servo3을 angle[2] 값에 맞추어 동작
    servo3.write(angle[3]); // servo4을 angle[3] 값에 맞추어 동작
    delay(delayTime(i));
  }
  Serial.print("\t\t");
  Serial.println(angle[smotor]);
}


void loop() {
  if(Serial.available()) //시리얼 통신이 가능할 경우
  {
    char input = Serial.read(); //시리얼 모니터 입력 값을 읽어옴
    
    if(input =='w') //입력값이 W일 경우
    {
      move(1, 1);
    }
    else if(input == 's') //입력값이 s일 경우
    {
      move(1, -1);
    }
    else if(input =='a') //입력값이 a일 경우
    {
      move(2, 1);
    }
    else if(input == 'd')  //입력값이 d일 경우
    {
      move(2, -1);
    }
    else if(input == 'z')  //입력값이 z일 경우
    {
      move(0, 1);
    }
    else if(input == 'c')  //입력값이 c일 경우
    {
      move(0, -1);
    }
    else if(input == 'q')  //입력값이 q일 경우
    {
      move(3, 1);
    }
    else if(input == 'e')  //입력값이 e일 경우
    {
      move(3, -1);
    }
  }

 

2.  로봇팔 프로토 타입 제작

- 로봇팔 모델링 참고자료

 

 

Search Thingiverse - Thingiverse

Download files and build them with your 3D printer, laser cutter, or CNC. Thingiverse is a universe of things.

www.thingiverse.com

 

https://www.tinkercad.com/dashboard

 

Tinkercad | From mind to design in minutes

Tinkercad is a free, easy-to-use app for 3D design, electronics, and coding.

www.tinkercad.com

 

- 제작 예시

 

 

 

 

 

3.  파이썬 음성 인식하기

1) 시작하며 : VS 코드 사용해 보기

 

 

2) 파이썬 음성인식 환경 구성 및 코드 작성

- 음성인식 코드

import speech_recognition as sr

# 인스턴스 생성
r = sr.Recognizer()

# 마이크 설정
microphone = sr.Microphone(sample_rate=16000)

# 마이크 소음 수치 반영
with microphone as source:
    r.adjust_for_ambient_noise(source)
    print("주변 소음 수치 {}".format(r.energy_threshold))

# 음성 수집해서 텍스트로 변환
with microphone as source:
    print("말씀하세요.")
    result = r.listen(source)
    text = r.recognize_google(result, language='ko')

#변환된 텍스트 출력
print(text)

4.  로봇팔 음성제어

- 코드

import speech_recognition as sr

import time
import serial
ser = serial.Serial('COM4',9600)

r = sr.Recognizer()

microphone = sr.Microphone(sample_rate=16000)

try:
    while True:
        with microphone as source:
            r.adjust_for_ambient_noise(source)
            print("소음수치 {}".format(r.energy_threshold))

        with microphone as source:
                print("말씀하세요.")
                result = r.listen(source)
                text = r.recognize_google(result, language='ko')

        if '위' in text: 
            ser.write(b'w')
            print('로봇팔을 올립니다.')

        elif '아래' in text: ser.write(b's')
        elif '좌' in text: ser.write(b'a')
        elif '우' in text: ser.write(b'd')

except KeyboardInterrupt:
    print('ctrl + c 중지 메세지 출력')

print('프로그램을 종료합니다')

- 코드2

import speech_recognition as sr
import time
import serial
ser = serial.Serial('COM4',9600)
r = sr.Recognizer()
microphone = sr.Microphone(sample_rate=16000)
try:
    while True:
        with microphone as source:
            r.adjust_for_ambient_noise(source)
            print("소음수치 {}".format(r.energy_threshold))
        with microphone as source:
            print("말씀하세요.")
            result = r.listen(source)
            text = r.recognize_google(result, language='ko')
            print(text)
        if '왼' in text: 
            ser.write(b'a')
            print('왼쪽으로.')
        elif '오' in text: 
            ser.write(b'd')
            print('오른쪽으로.')
        elif '불' or 'led' in text: 
            ser.write(b's')
            print('led ON/OFFd')

except KeyboardInterrupt:
    print('ctrl + c 중지 메세지 출력')
    print('프로그램을 종료합니다')

 

방법  : 기존 아두이노 로봇팔 프로토타입 회로를 윈도우 PC에 연결해서 시리얼통신으로 제어한다.

import speech_recognition as sr
import time
import serial
ser = serial.Serial('COM7',9600)
r = sr.Recognizer()
microphone = sr.Microphone(sample_rate=16000)
try:
    while True:
        with microphone as source:
            r.adjust_for_ambient_noise(source)
            print("소음수치 {}".format(r.energy_threshold))
        with microphone as source:
            text=None
            print("말씀하세요.")
            result = r.listen(source)
            try:                    #음성 인식이 잘 안될 경우 UnknownValueError 예외가 발생, 예외 처리 추가(시작)
                text = r.recognize_google(result, language='ko') #UnknownValueError 발생 코드
                print(text)
                if '왼' in text: 
                    ser.write(b'z')
                    print('왼쪽으로.')
                elif '오' in text: 
                    ser.write(b'c')
                    print('오른쪽으로.')
                elif '위' in text: 
                    ser.write(b'w')
                    print('위로')
                elif '아래' in text: 
                    ser.write(b's')
                    print('아래로')
                elif '올려'in text:  
                    ser.write(b'd')
                    print('더 위로')
                elif '내려'in text:  
                    ser.write(b'a')
                    print('더 아래로')
                elif '잡아' in text or '자' in text or '바' in text: 
                    ser.write(b'e')
                    print('물건 잡아')
                elif '풀어'in text or '놔' in text: 
                    ser.write(b'q')
                    print('물건 풀어')
            except sr.UnknownValueError: #UnknownValueError 예외 발생할 경우 메시지 출력
                print("다시 말씀하세요")

except KeyboardInterrupt:
    print('ctrl + c 중지 메세지 출력')
    print('프로그램을 종료합니다')

 

- 동작영상(4축)

끝.