-
아두이노 프로젝트 | 마이크로 서보 로봇Technology/Arduino 2024. 1. 26. 18:00
1. 마이크로 서보 로봇
마이크로 서보 로봇 제조 공장에서 흔하게 볼 수 있는 로봇과, 로봇을 제어하기 위한 모형을 아두이노 플랫폼으로 구현해보자. 구현하고자 하는 로봇은 서보모터 4개로, 로봇을 제어하기 위한 모형은 가변저항 4개로 구성되어 있다. 모형을 움직이면 로봇이 움직임을 따라가도록 프로그램을 작성해보자. 추가로, 모형의 움직임을 차례대로 저장한 뒤 저장된 움직임을 로봇이 반복하는 기능을 구현해보자. 모형의 움직임을 저장하고 재생하는 신호는 택트 스위치 1개로 제어하며, 택트 스위치를 한 번 누르면 모형의 움직임이 저장되고, 택트 스위치를 빠르게 두 번 누르면 로봇이 아두이노에 전원이 공급되지 않을 때까지 저장된 움직임을 반복하도록 프로그램을 작성해보자.
2. 프로젝트
2.1. 회로 구성
회로 구성 아두이노 가변 저항 10KΩ (다이얼 타입)
10K옴 / 싱글턴 가변저항 포텐션미터 너트 와샤 포함 , 일반 가변 저항과 달리 돌리면 틱틱틱 걸리는 느낌이 있는 다이얼 타입의 저항 입니다. 일반 가변저항은 돌리면 저항감이 없어서 조정하는
www.devicemart.co.kr
브레드보드용 4핀 택트스위치 6x6 breadboard friendly switch 4p [SZH-TH0018]
TACT 스위치 / DIP TYPE / 4PIN / 빵판에 바로 연결사용하는 특별한 택트스위치입니다. 부품다리가 휘어져있는 다른 제품들과 다르게 브레드보드에 알맞은 길이로 곧게 뻗어있습니다.
www.devicemart.co.kr
1/2W 1% Axial Resistor 221F (220Ω)
일반막대저항 / 탄소피막 / 1/2W / F급(±1%) / 220옴
www.devicemart.co.kr
TowerPro 호환 9g 미니 서보모터 SG-90
대표 미니 서보모터, 토크 : 1.8kg/cm(4.8V), Operating speed : 0.1sec/60degree(4.8v)
www.devicemart.co.kr
2.2. 프로그램 작성
#include <Servo.h> Servo myServo1; // myServo1라는 이름의 서보모터 개체를 생성 Servo myServo2; Servo myServo3; Servo myServo4; int Angle[4] = {90, 90, 90, 90}; // 정수형 배열 선언 후 초기 각도 90도로 초기화 int Memory1[100]; // myServo1의 각도 정보를 100개까지 저장할 수 있는 정수형 배열 선언 int Memory2[100]; int Memory3[100]; int Memory4[100]; int IndexCounter = 0; // 저장된 정보 수를 저장할 정수형 변수 선언 후 0으로 초기화 float InputAngle[4]; // 서보모터에 입력할 각도 정보를 저장할 실수형 배열 선언 int Resolution = 10; // 정수형 변수 선언 후 10으로 초기화 int Potentiometer1 = A3; // 정수형 변수 선언 후 아날로그 핀 번호 A0로 초기화 int Potentiometer2 = A2; int Potentiometer3 = A1; int Potentiometer4 = A0; int Switch = 7; // 정수형 변수 선언 후 디지털 핀 번호 7로 초기화 bool State = false; // 택트 스위치의 상태 정보를 저장할 불린 변수 선언 후 false로 초기화 // 택트 스위치가 연속으로 눌린 횟수 정보를 저장할 정수형 변수 선언 후 0으로 초기화 int PushCount = 0; // 택트 스위치가 마지막으로 눌린 시간 정보를 저장할 정수형 변수 선언 후 0으로 초기화 long LastChange = 0; void setup() { myServo1.attach(9); // myServo1을 12번 핀에 연결 myServo1.write(Angle[0]); // myServo1의 각도를 90도로 초기화 myServo2.attach(10); myServo2.write(Angle[1]); myServo3.attach(11); myServo3.write(Angle[2]); myServo4.attach(12); myServo4.write(Angle[3]); delay(1000); // 1000 ms 대기 pinMode(Switch, INPUT); // 디지털 7번 핀을 출력(INPUT) 모드로 설정 pinMode(Potentiometer1, INPUT); // 아날로그 A3번 핀을 출력(INPUT) 모드로 설정 pinMode(Potentiometer2, INPUT); pinMode(Potentiometer3, INPUT); pinMode(Potentiometer4, INPUT); Serial.begin(9600); // 시리얼 통신 시작 (통신 속도: 9600 bps) Serial.println("*** Recording ***"); // 시리얼 모니터에 문자열을 출력한 뒤 줄 바꿈 } void loop() { // 아날로그 핀으로부터 받은 아날로그 신호값의 범위를 0~1023에서 0~255로 조정한 뒤 // 정수형 배열에 저장 Angle[0] = map(analogRead(Potentiometer1), 0, 1023, 0, 180); Angle[1] = map(analogRead(Potentiometer2), 0, 1023, 0, 180); Angle[2] = map(analogRead(Potentiometer3), 0, 1023, 0, 180); Angle[3] = map(analogRead(Potentiometer4), 0, 1023, 0, 180); // 정수형 배열에 저장된 각도 정보만큼 서보모터를 회전 myServo1.write(Angle[0]); myServo2.write(Angle[1]); myServo3.write(Angle[2]); myServo4.write(Angle[3]); delay(10); // 택트 스위치가 연속으로 눌린 횟수에 따라 프로그램 실행 switch (MultiPressRead(Switch)) { // 택트 스위치가 한 번만 눌린 경우 case 1: // 모든 서보모터의 현재 각도 정보를 메모리 배열에 각각 저장 Memory1[IndexCounter] = myServo1.read(); Memory2[IndexCounter] = myServo2.read(); Memory3[IndexCounter] = myServo3.read(); Memory4[IndexCounter] = myServo4.read(); // 메모리 배열에 저장된 각도 정보를 시리얼 모니터에 출력 Serial.print("[ "); Serial.print(Memory1[IndexCounter]); Serial.print(" | "); Serial.print(Memory2[IndexCounter]); Serial.print(" | "); Serial.print(Memory3[IndexCounter]); Serial.print(" | "); Serial.print(Memory4[IndexCounter]); Serial.println(" ]"); // 메모리 배열에 저장된 정보 수를 저장 IndexCounter += 1; delay(100); break; // switch문 종료 // 택트 스위치가 두 번 연속으로 눌린 경우 case 2: Serial.println("*** Repetition Start ***"); delay(1000); // 전원이 공급되지 않을 때까지 무한 반복 while(1) { // 모든 서보모터의 현재 각도 정보를 실수형 배열에 저장 InputAngle[0] = Angle[0]; InputAngle[1] = Angle[1]; InputAngle[2] = Angle[2]; InputAngle[3] = Angle[3]; // 현재 각도에서 다음 각도까지 회전 for (int i = 1; i <= Resolution; i++) { // 현재 각도에서 다음 각도까지 최소 회전 단위로 회전하도록 최소 회전 단위 연산 InputAngle[0] += (Memory1[0] - Angle[0]) / Resolution; InputAngle[1] += (Memory2[0] - Angle[1]) / Resolution; InputAngle[2] += (Memory3[0] - Angle[2]) / Resolution; InputAngle[3] += (Memory4[0] - Angle[3]) / Resolution; // 연산한 최소 회전 단위를 정수형으로 변경한 뒤 모든 서보모터에 입력 myServo1.write((int)InputAngle[0]); myServo2.write((int)InputAngle[1]); myServo3.write((int)InputAngle[2]); myServo4.write((int)InputAngle[3]); delay(10); } // 연산에 의한 오차를 보정하기 위해 모든 서보모터에 최종 회전 각도 입력 myServo1.write(Memory1[0]); myServo2.write(Memory2[0]); myServo3.write(Memory3[0]); myServo4.write(Memory4[0]); // 현재 서보모터의 각도 정보를 시리얼 모니터에 출력 Serial.print("[ "); Serial.print(myServo1.read()); Serial.print(" | "); Serial.print(myServo2.read()); Serial.print(" | "); Serial.print(myServo3.read()); Serial.print(" | "); Serial.print(myServo4.read()); Serial.println(" ]"); delay(1000); // 메모리 배열에 저장된 정보에 맞게 차례대로 동작 for (int i = 1; i < IndexCounter; i++) { // 모든 서보모터의 현재 각도 정보를 실수형 배열에 저장 InputAngle[0] = Memory1[i - 1]; InputAngle[1] = Memory2[i - 1]; InputAngle[2] = Memory3[i - 1]; InputAngle[3] = Memory4[i - 1]; for (int j = 1; j <= Resolution; j++) { InputAngle[0] += (Memory1[i] - Memory1[i - 1]) / Resolution; InputAngle[1] += (Memory2[i] - Memory2[i - 1]) / Resolution; InputAngle[2] += (Memory3[i] - Memory3[i - 1]) / Resolution; InputAngle[3] += (Memory4[i] - Memory4[i - 1]) / Resolution; myServo1.write((int)InputAngle[0]); myServo2.write((int)InputAngle[1]); myServo3.write((int)InputAngle[2]); myServo4.write((int)InputAngle[3]); delay(10); } myServo1.write(Memory1[i]); myServo2.write(Memory2[i]); myServo3.write(Memory3[i]); myServo4.write(Memory4[i]); Serial.print("[ "); Serial.print(myServo1.read()); Serial.print(" | "); Serial.print(myServo2.read()); Serial.print(" | "); Serial.print(myServo3.read()); Serial.print(" | "); Serial.print(myServo4.read()); Serial.println(" ]"); delay(1000); } } break; } } // 택트 스위치 연속 동작 판별 함수 int MultiPressRead(int Switch) { if (digitalRead(Switch) == HIGH) // 택트 스위치가 눌린 경우 실행 { if (State == false) // 택트 스위치의 이전 상태가 눌리지 않은 상태일 경우 실행 { PushCount += 1; // 택트 스위치가 눌린 횟수를 정보를 정수형 변수에 저장 State = true; // 택트 스위치가 눌린 상태를 불린 변수에 저장 LastChange = millis(); // 현재 시간 정보를 정수형 변수에 저장 return 0; // 함수 실행 결과로 0을 반환하고 함수 종료 } } if (digitalRead(Switch) == LOW) // 택트 스위치가 눌리지 않은 경우 실행 { State = false; // 택트 스위치가 눌리지 않은 상태를 불린 변수에 저장 // 택트 스위치가 연속으로 눌렸는지 판별 // 택트 스위치가 마지막으로 눌린 시간과 현재 눌린 시간의 차이가 500 ms 이상이면 실행 if ((millis() - LastChange) > 500) { int NumberOfPresses = PushCount; PushCount = 0; // 택스 스위치가 눌린 횟수 정보를 초기화 // 함수 실행 결과로 정수형 변수에 저장된 값을 반환하고 함수 종료 return NumberOfPresses; } } }
[함께 읽으면 좋은 페이지]
아두이노 디지털 신호 입력 | 택트 스위치
1. 디지털 신호 입력 아두이노 소프트웨어에서 디지털 신호를 받을 핀을 설정하고 함수를 작성하여 아두이노 하드웨어에 업로드하면, 앞서 설정한 핀을 통해 디지털 신호를 입력 받을 수 있다.
vedacube.tistory.com
아두이노 | 가변저항
1. 가변저항 저항값을 임의로 바꿀 수 있는 물리 소자이다. 극성이 없는 3개의 단자를 가지고 있으며, 손잡이를 돌리면 각 단자 사이의 저항값을 조절할 수 있다. 손잡이를 시계방향으로 돌리면 A
vedacube.tistory.com
아두이노 라이브러리 | 서보모터
1. 아두이노 라이브러리 LED나 택트 스위치와 같이 간단한 전자 소자는 아두이노 플랫폼에서 지원하는 함수를 이용하여 쉽게 제어할 수 있지만, 초음파 센서와 서보모터와 같이 특별한 기능을 가
vedacube.tistory.com
참고문헌
- Kuantronic. (2021). JC_Button. GitHub. https://github.com/Kuantronic/JC_Button. 2023.10.28.
- Pinaut. (2014). Micro Servo Robot. YouTube. https://www.youtube.com/watch?v=bLnAJ-mSElE. 2023.10.26.
반응형'Technology > Arduino' 카테고리의 다른 글
아두이노 프로젝트 | 현관 센서등 (1) 2024.02.09 아두이노 | PIR 센서 모듈 HC-SR501 (0) 2024.02.02 아두이노 라이브러리 | 서보모터 Servo.h (0) 2024.01.19 아두이노 | DC모터 드라이버 L298N 모듈 (0) 2024.01.12 아두이노 | DC모터 드라이버 L293D 모듈 (1) 2024.01.05