로봇팔 만들기 – 2. 관절 (Joint)
지난강좌
.
아두이노 로봇팔 만들기를 위해 필요한 내용들을 하나씩 알아보는 시리즈 강좌입니다. 지난번에 손 만드는 법에 대해서 알아봤으니 이번엔 관절을 한 번 만들어 보겠습니다. 아래와 같이 2개 축으로 상하좌우 회전하는 관절을 만듭니다.
1. 준비물
사용되는 부품은 아래와 같습니다.
- 관절 프레임 세트
- 서보모터 2개 (MG995)
- 서보모터에 포함된 악세사리
- M3 나사, 너트, 원형 베어링 1개
- 서보모터 회전축에 끼울 디스크 2개 (위 사진에 없음)
부품 세트 구매처는 aliexpress 에서 robot arm joint로 검색하면 볼 수 있습니다. (아래 링크에 있는 제품 구성을 참고)
2. 조립순서
2.1. 하부관절 조립
먼저 좌우 회전할 아래부분을 만듭니다.
서보모터 회전축에 디스크를 끼웁니다. 이 상태에서 디스크를 좌우로 돌려보고 정확히 중앙(90′ ) 위치에서 아래와 같이 십자 형태를 이루도록 조절해줍니다. 만약 손대중으로 맞추기 힘들다면 지난 Claw 만들기 강좌에서 썼던 예제를 실행해서 서보모터가 90′ 위치에 놓이도록 만들어 주는 것이 좋습니다. (2개의 서보모터 전부)
아래와 같이 관절 하부 프레임에 구멍을 맞추고
3개의 나사로 서보모터, 디스크, 프레임이 고정되도록 해줍니다. 로봇팔의 하중을 서보모터 축으로 모두 감당해야 하므로 단단히 조여줍니다.
2.2. 상부관절 조립
아래와 같이 서보모터를 하부관절에 대고 나사와 너트로 조여줍니다. 서보모터 회전축에 디스크를 끼웁니다. 서보모터가 90′ 위치에 있을 때 X 모양이 되어야 합니다.
서보모터 고정이 끝나면 상부 관절에 해당하는 부품들을 준비합니다. 아래 사진 참고.
이제 상부관절 프레임을 서보모터 디스크와 맞추고 나사로 고정합니다. 서보모터와 디스크도 고정되도록 나사로 조여줍니다.
이제 반대쪽으로 돌려보면 아래와 같이 될겁니다. 서보모터와 뒷면과 프레임 사이에 1cm 조금 안되는 간격이 있어야 합니다.
여기에 나사-너트-원형베어링-상부관절 프레임-너트 순서로 연결해 줍니다. 연결하면 아래 사진처럼 됩니다.
이제 조립이 모두 끝났습니다. 서보모터를 돌려보면서 헐거운 곳은 없는지 동작 범위가 잘 맞는지 확인해봅니다.
2.3. 손 조립
관절만 테스트하기 밋밋하니까 미리 조립해 둔 손을 같이 연결해 줍니다. 총 3개의 서보모터로 간단한 팔처럼 동작시킬 수 있습니다.
3. 테스트
지난 손 조립 과정에서 사용한 회로도에 2개의 서보모터를 더해줍니다. 새로 추가된 2개의 서보모터에 들어갈 신호선은 아두이노의 D5, D6 핀에 연결해주세요.
이제 소스코드를 올려 동작을 확인할 차례입니다.
손 조립할 때 사용했던 소스코드를 대거 수정했습니다.
#include <Servo.h> Servo servo_joint1; Servo servo_joint2; Servo servo_claw; int servo_joint1_pin = 5; int servo_joint2_pin = 6; int servo_claw_pin = 9; int cur_angle_joint1 = 0; // current servo position in degrees int cur_angle_joint2 = 0; int cur_angle_claw = 0; int current_servo_index; // [1: joint1], [2: joint2], [3: claw] int CENTER_SERVO = 90; // center servo position int joint1_min_angle = 55; // minimum servo position int joint1_max_angle = 125; // maximum servo position int joint2_min_angle = 55; // minimum servo position int joint2_max_angle = 125; // maximum servo position int claw_min_angle = 55; // minimum servo position int claw_max_angle = 125; // maximum servo position int turnRate = 5; // servo turn rate increment (larger value, faster rate) void setup() { Serial.begin(9600); Serial.println("Robot Arm Control"); Serial.println("By pressing 1, 2, 3 you can select servo"); Serial.println("Press a or s to move, spacebar to center"); Serial.println(); servo_joint1.attach(servo_joint1_pin); servo_joint2.attach(servo_joint2_pin); servo_claw.attach(servo_claw_pin); cur_angle_joint1 = CENTER_SERVO; cur_angle_joint2 = CENTER_SERVO; cur_angle_claw = CENTER_SERVO; servo_joint1.write(cur_angle_joint1); servo_joint2.write(cur_angle_joint2); servo_claw.write(cur_angle_claw); changeServo(1); // Set joint1 as current servo } void loop() { if (Serial.available() > 0) { char command = Serial.read(); // Servo control command: 'a'==97, 's'==115, ' '==32 if (command == 97) { moveServo(-1); } // move -1 step else if (command == 115) { moveServo(1); } // move 1 step else if (command == 32) { moveServo(0); } // 0 step means 'move to center position' // Select servo command: '1'==49, '2'==50, '3'==51 else if (command == 49) { changeServo(1); } // select joint1 servo else if (command == 50) { changeServo(2); } // select joint2 servo else if (command == 51) { changeServo(3); } // select claw servo } } void changeServo(int index) { if(index == 1) { current_servo_index = 1; Serial.println("# Joint1 servo selected"); } else if(index == 2) { current_servo_index = 2; Serial.println("# Joint2 servo selected"); } else { current_servo_index = 3; Serial.println("# Claw servo selected"); } } // Move servo to target angle void moveServo(int steps) { int c_angle = 0; int target_angle = 0; if(current_servo_index == 1) { c_angle = cur_angle_joint1; if(steps == 0) target_angle = CENTER_SERVO; else target_angle = cur_angle_joint1 + steps*turnRate; if(target_angle > joint1_max_angle) target_angle = joint1_max_angle; if(target_angle < joint1_min_angle) target_angle = joint1_min_angle; } else if(current_servo_index == 2) { c_angle = cur_angle_joint2; if(steps == 0) target_angle = CENTER_SERVO; else target_angle = cur_angle_joint2 + steps*turnRate; if(target_angle > joint2_max_angle) target_angle = joint2_max_angle; if(target_angle < joint2_min_angle) target_angle = joint2_min_angle; } else { c_angle = cur_angle_claw; if(steps == 0) target_angle = CENTER_SERVO; else target_angle = cur_angle_claw + steps*turnRate; if(target_angle > claw_max_angle) target_angle = claw_max_angle; if(target_angle < claw_min_angle) target_angle = claw_min_angle; } int step_angle = 1; if(target_angle < c_angle) { step_angle = -1; } // This code makes smooth movement for(int i = c_angle; i != target_angle; i+=step_angle) { //if((target_angle - i) < step_angle && (target_angle - i) > step_angle * -1) // close to target position, break this loop // break; if(current_servo_index == 1) { servo_joint1.write(i); } else if(current_servo_index == 2) { servo_joint2.write(i); } else { servo_claw.write(i); } delay(15); } if(current_servo_index == 1) { cur_angle_joint1 = target_angle; } else if(current_servo_index == 2) { cur_angle_joint2 = target_angle; } else { cur_angle_claw = target_angle; } }
소스코드 업로드 후 Serial Monitor 창을 켭니다. 시리얼 모니터 창으로 아래 명령어를 내리면 3개의 서보모터를 조절할 수 있습니다.
- 1 : 하부관절 서보모터를 선택 (좌우회전용)
- 2 : 상부관절 서보모터를 선택 (상하회전용)
- 3 : 손 서보모터를 선택 (열기, 닫기)
- a : 서보모터의 회전축 위치를 5′ 줄임
- s : 서보모터의 회전축 위치를 5′ 늘림
여러개의 명령어를 동시에 내릴수도 있습니다. [1aaaa] 이렇게 입력하고 전송하면 1번 서보모터의 회전각을 20′ 줄입니다.
손과 관절을 구성하는 방법을 배웠으니.. 이 내용을 응용하면 다양한 로봇팔을 만들 수 있습니다. 다음 강좌에서는 오픈소스로 프레임 디자인과 소스코드가 모두 제공되는 프로젝트를 실제 따라하면서 로봇팔을 만들어 보겠습니다.