스마트 아두이노 제어 로봇 팔 제작: 쉬운 DIY 튜토리얼
구성품 및 부품
| 부품 |
수량 |
| Arduino UNO |
1 |
| 마이크로 서보 |
5 |
| 포텐셔미터 (가변저항) |
5 |
| 브레드보드 |
1 |
프로젝트 소개
마스터 팔을 이용해 제어하는 심플한 로봇 팔을 만듭니다. 팔을 움직이면 동작을 기억했다가 순서대로 재생합니다. 컨셉은 'mini robotic arm - by Stoerpeak'에서 영감받았습니다. 오래전부터 만들고 싶었지만 당시 프로그래밍 지식이 없어 이제야 만들게 되었습니다. 단순하고 저렴하게, 여러분과 공유합니다.
1단계: 필요한 것들
- 서보 모터 ×5
- 포텐셔미터 ×5
- Arduino UNO
- 배터리 (5V 어댑터 사용)
- 브레드보드
- 골판지/목재/선보드/아크릴 등 구하기 쉬운 재료
- Arduino IDE 설치
2단계: 팔 만들기
아이스크림 막대(팝시클 스틱)로 팔을 만들었습니다. 사용 가능한 어떤 재료든 괜찮고, 더 나은 기계적 설계를 시도해보세요. 제 설계는 그리 안정적이지 않습니다.
양면 테이프로 서보를 막대에 붙이고 나사로 고정했습니다. 마스터 팔은 포텐셔미터를 막대에 접착해 만들었습니다. 사진을 참고하세요. 모든 것을 A4 캔버스 보드 베이스에 장착했습니다.
3단계: 연결하기
- 모든 서보를 전원 공급장치에 병렬 연결 (적색: +, 흑색/갈색: GND)
- 신호선(황색/주황색)을 아두이노 PWM 핀에 연결
- 포텐셔미터를 아두이노 +5V/GND에 병렬 연결, 중간 단자를 아날로그 핀에 연결
핀 배정:
- 디지털 3, 5, 6, 9, 10 → 서보 제어
- 아날로그 A0~A4 → 포텐셔미터 입력
- 핀 3 서보 ↔ A0 포텐셔미터, 핀 5 서보 ↔ A1 포텐셔미터... 순서대로 매핑
중요: 서보 전원을 아두이노에서 안 끌어다 써도 서보 GND를 아두이노 GND와 꼭 연결해야 합니다. 안 그러면 작동 안 합니다.
4단계: 코딩
로직은 단순합니다: 포텐셔미터 값을 배열에 저장 → 기록 순회하며 서보를 해당 위치로 이동. 참고 튜토리얼
전역 변수 선언
#include <Servo.h>
Servo Servo_0, Servo_1, Servo_2, Servo_3, Servo_4;
int Pot_0, Pot_1, Pot_2, Pot_3, Pot_4;
int Servo_0_Pos, Servo_1_Pos, Servo_2_Pos, Servo_3_Pos, Servo_4_Pos;
int Prev_0_Pos, Prev_1_Pos, Prev_2_Pos, Prev_3_Pos, Prev_4_Pos;
int Current_0_Pos, Current_1_Pos, Current_2_Pos, Current_3_Pos, Current_4_Pos;
int Servo_Position, Servo_Number;
int Storage[600]; // 데이터 저장 배열 (크기 늘리면 메모리 더 사용)
int Index = 0;
char data = 0;
setup()
void setup() {
Serial.begin(9600);
Servo_0.attach(3); Servo_1.attach(5); Servo_2.attach(6); Servo_3.attach(9); Servo_4.attach(10);
Servo_0.write(100); Servo_1.write(100); Servo_2.write(100); Servo_3.write(100); Servo_4.write(100);
Serial.println("Press 'R' to Record and 'P' to play");
}
Map_Pot() 함수 - 포텐셔미터 읽어 서보 제어
void Map_Pot() {
Pot_0 = analogRead(A0);
Servo_0_Pos = map(Pot_0, 0, 1023, 1, 179); // 0-179도 제한 (180도 쓰면 버징 발생)
Servo_0.write(Servo_0_Pos);
// ... Pot_1~Pot_4도 동일 처리 (A1~A4, 서보 1~4)
}
loop() - 메인 루프
void loop() {
Map_Pot();
while (Serial.available() > 0) {
data = Serial.read();
if (data == 'R') Serial.println("Recording Moves...");
if (data == 'P') Serial.println("Playing Recorded Moves...");
}
if (data == 'R') { // 'R' 입력 시 녹화 시작
// 이전 위치 저장
Prev_0_Pos = Servo_0_Pos; Prev_1_Pos = Servo_1_Pos;
Prev_2_Pos = Servo_2_Pos; Prev_3_Pos = Servo_3_Pos; Prev_4_Pos = Servo_4_Pos;
Map_Pot(); // 현재 위치 다시 읽기
// 각 서보별 위치 변화 감지해 배열에 저장 (+서보번호×100으로 구분)
if (abs(Prev_0_Pos - Servo_0_Pos) > 0) { // 위치 변경 시
Storage[Index] = Servo_0_Pos + 0; Index++; Current_0_Pos = Servo_0_Pos; }
if (abs(Prev_1_Pos - Servo_1_Pos) > 0) { Storage[Index] = Servo_1_Pos + 100; Index++; Current_1_Pos = Servo_1_Pos; }
if (abs(Prev_2_Pos - Servo_2_Pos) > 0) { Storage[Index] = Servo_2_Pos + 200; Index++; Current_2_Pos = Servo_2_Pos; }
if (abs(Prev_3_Pos - Servo_3_Pos) > 0) { Storage[Index] = Servo_3_Pos + 300; Index++; Current_3_Pos = Servo_3_Pos; }
if (abs(Prev_4_Pos - Servo_4_Pos) > 0) { Storage[Index] = Servo_4_Pos + 400; Index++; Current_4_Pos = Servo_4_Pos; }
// 시리얼 모니터에 현재 위치 출력
Serial.print(Servo_0_Pos); Serial.print("\t");
Serial.print(Servo_1_Pos); Serial.print("\t");
Serial.print(Servo_2_Pos); Serial.print("\t");
Serial.print(Servo_3_Pos); Serial.print("\t");
Serial.println(Servo_4_Pos);
Serial.print("Index = "); Serial.println(Index);
delay(50);
}
if (data == 'P') { // 'P' 입력 시 재생
for (int i = 0; i < Index; i++) {
Servo_Number = Storage[i] / 100; // 서보 번호 추출
Servo_Position = Storage[i] % 100; // 서보 위치 추출
switch (Servo_Number) {
case 0: Servo_0.write(Servo_Position); break;
case 1: Servo_1.write(Servo_Position); break;
case 2: Servo_2.write(Servo_Position); break;
case 3: Servo_3.write(Servo_Position); break;
case 4: Servo_4.write(Servo_Position); break;
}
delay(50);
}
}
}
코드 업로드 후 시리얼 모니터 열기(Tools → Serial Monitor). 아두이노 리셋 후 마스터 팔로 로봇 팔 제어 가능. 'R' 입력으로 녹화 시작, 원하는 동작 수행 후 'P' 입력으로 재생. 보드 리셋 전까지 계속 반복 재생됩니다.
5단계: 테스트
스토어피크 님 작품만큼 부드럽진 않지만 작동합니다. 코드 개선 제안이나 아이디어 있으시면 댓글로 알려주세요!
코드 파일
- Record-Play.ino (전체 코드)
- 코드 스니펫 #1~#4 (구간별 분할)
회로도
(회로도 이미지 참조)