산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino가 있는 LEGO Wall-E

구성품 및 소모품

LEGO Wall-E
더 이상 만들지 않기 때문에 중고로 구입해야 했습니다.
× 1
Arduino Nano R3
× 1
DC 모터(일반)
× 2
L298N 듀얼 모터 컨트롤러
× 1
2색 LED
핀 3개 포함
× 1
적외선 센서
× 1
부저
다양한 음색을 재생할 수 있는 것
× 1
9V 배터리
× 1
저항 330옴
× 3
점퍼 와이어(일반)
× 20

필요한 도구 및 기계

납땜 인두(일반)

앱 및 온라인 서비스

Arduino IDE

이 프로젝트 정보

영화 월-E(만약 그렇지 않다면 지금 바로 보러 가세요!)와 지구를 청소하려는 노란 영웅을 모두 알고 있습니다. 이 프로젝트에서 저는 작은 친구의 레고 버전을 사용하여 장애물을 피하는 방법을 가르쳤습니다. 이것은 나의 첫 번째 프로젝트이자 전자공학의 기초를 이해하기 위한 훌륭한 학습 경험이었습니다.

1단계 - 코드

소프트웨어 개발자로서 나는 그에게 무엇을 해주기를 바라는지 생각하고 코드로 시작했습니다.

 // 이 프로그램은 Wall-E 레고 로봇을 제어하기 위한 프로그램입니다. // Wall-E가 주변을 운전하고 있습니다. 장애물이 보이면 멈추고 주위를 둘러보고 다른 경로를 선택합니다. // Arduino Nano에는 digitalRead 및 digitalWrite에 사용할 수 있는 21개의 핀이 있습니다. // PWM 핀 3, 5, 6, 9, 10, 11은 다음 용도로 사용할 수 있습니다. analogWrite// 핀 0 및 1은 TTL에 사용할 수 있습니다.// 핀 2 및 3은 외부 인터럽트에 사용할 수 있습니다.// 핀 10, 11, 12, 13은 SPI 통신을 지원합니다.// 핀 13은 내부 LED가 될 수 있습니다.// 핀 14는 21은 또한 아날로그 핀 A0 ~ A7이며 analogRead#define INFRA_RED 9 // 모든 핀이 될 수 있음#define GREEN_LED 7 // 모든 핀이 될 수 있지만 저항이 필요합니다. 아마도 220 Ohm - 또는 접지 핀이 1 kOhm을 얻습니다. 정의 RED_LED 8 // 핀이 될 수 있지만 저항이 필요함, 아마도 220 Ohm - 또는 접지 핀이 1 kOhm을 얻습니다.#define BUZZER 10 // 주파수를 설정하려면 PWM 핀이 필요하고 저항이 필요합니다. 아마도 1 kOhm// MR은 다음과 같습니다. 오른쪽 모터, ML은 왼쪽 모터입니다#define MR_1 A1 // 핀이 될 수 있으므로 L289N shield#define MR_2 A2의 핀 번호에 해당하도록 합시다. 피 L289N shield#define MR_ENABLE 5 // 속도 제어를 위해 PWM 핀이 필요합니다#define ML_1 A3 // 모든 핀이 될 수 있으므로 L289N shield#define ML_2 A4의 핀 번호에 해당하도록 합시다 // 모든 핀이 될 수 있으므로 L289N shield#define ML_ENABLE 6의 핀 번호에 해당하도록 합시다. // 속도 제어를 위해서는 PWM 핀이어야 합니다. // 정상 속도를 maximum으로 설정합니다. const int NORMAL_SPEED =255;void setup() { // 리셋 버튼을 누른 직후에 전압 스파이크를 통해 구성 요소를 손상시키지 않고 끌 수 있도록 잠시 기다리십시오. delay(2000); // LED 및 부저 초기화 pinMode(GREEN_LED, OUTPUT); 핀모드(RED_LED, 출력);// 핀모드(BUZZER, 출력); // 필요하지 않음 // LED를 녹색으로 재설정 digitalWrite(RED_LED, LOW); 디지털 쓰기(GREEN_LED, 높음); // DC 모터 핀 설정 pinMode(MR_ENABLE, OUTPUT); // 모터 오른쪽 pinMode(MR_1, OUTPUT); 핀모드(MR_2, 출력); 핀모드(ML_ENABLE, 출력); // 모터 왼쪽 pinMode(ML_1, OUTPUT); 핀모드(ML_2, 출력); // 적외선 초기화 pinMode(INFRA_RED, INPUT); // 무작위 회전을 위한 난수 생성기 초기화 randomSeed(analogRead(0)); // 인사합니다 playHello();}void loop() { // 일반 작업 driveForwards(NORMAL_SPEED); // LED를 녹색으로 설정 digitalWrite(RED_LED, LOW); 디지털 쓰기(GREEN_LED, 높음); // 장애물 확인 if (digitalRead(INFRA_RED) ==LOW) { //LOW는 장애물 감지됨 // LED를 빨간색으로 변경 digitalWrite(GREEN_LED, LOW); 디지털 쓰기(RED_LED, 높음); // 모터 정지 stopDriving(); // 엉엉 소리 재생 playUhOh(); // 좌회전 확인 turnLeft(500); 부울 장애물Left =거짓; if (digitalRead(INFRA_RED) ==LOW) { 장애물 왼쪽 =true; } // 중앙으로 되돌리기 delay(100); 우회전(500); // 조금 기다리세요. 서두르는 것처럼 보이고 싶지 않습니다. delay(500); // 우회전 확인(500); 부울 장애물Right =거짓; if (digitalRead(INFRA_RED) ==LOW) { 장애물 오른쪽 =true; } // 중앙으로 되돌리기 delay(100); 좌회전(500); // 이제 여기서 나가는 방법을 확인합니다. if (obstacleLeft &&barrierRight) { driveBackwards(NORMAL_SPEED / 3); // 뒤로 5초간 삐 소리 for (int i =0; i <5; i++) { tone(BUZZER, 1000, 500); 지연(1000); } // 어딘가에 갇히는 것을 방지하기 위해 여행을 계속하기 전에 무작위로 방향을 변경 randomTurn(800, 1600); } else if (obstacleLeft) { turnRight(1000); } else if (obstacleRight) { turnLeft(1000); } 그렇지 않으면 { randomTurn(1000, 1800); } } // 더 많은 상호 작용을 위해 임의 작업 수행 int number =random(100); // 0과 99 사이의 난수를 생성 if (number ==0) { randomTurn(200,2000); }}void driveForwards(int speed) { // 모터가 같은 방향으로 가도록 설정합니다. digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, 높음); 디지털 쓰기(ML_1, 높음); 디지털 쓰기(ML_2, LOW); setSpeed(speed);}void driveBackwards(int speed) { // 모터가 반대 방향으로 가도록 설정 digitalWrite(MR_1, HIGH); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, 높음); setSpeed(speed);}void turnLeft(int duration) { // 오른쪽 바퀴로 전진하고 왼쪽 바퀴로 후진하여 좌회전 digitalWrite(MR_1, HIGH); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, 높음); 디지털 쓰기(ML_2, LOW); // 속도를 낮추기 위해 setSpeed(NORMAL_SPEED / 2); 지연(지연); stopDriving();}void turnRight(int duration) { // 오른쪽 바퀴로 후진하고 왼쪽 바퀴로 앞으로 이동하여 우회전 digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, 높음); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, 높음); // 속도를 낮추기 위해 setSpeed(NORMAL_SPEED / 2); 지연(지연); stopDriving();}void stopDriving() { // 모든 모터 핀을 끕니다. digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, LOW); // ENABLE 핀으로 무엇을 해야할지 잘 모르겠지만, 핀을 끄는 것도 나쁘지 않습니다. digitalWrite(MR_ENABLE, LOW); digitalWrite(ML_ENABLE, LOW);}void setSpeed(int speed) { // 속도는 0에서 255 사이여야 합니다. speed =constrain(speed, 0, 255); // 모터를 켜기 위한 속도 설정 analogWrite(MR_ENABLE, speed); analogWrite(ML_ENABLE, 속도);} void randomTurn(int 최소값, int 최대값) { 부호 없는 긴 시간 =millis(); int 지속 시간 =random(최소, 최대); if (시간 % 2) { 우회전(지속시간); } else { 좌회전(지속시간); }} 무효 playHello() { 톤(BUZZER, 262, 250); // C4 재생 지연(300); 톤(부저, 330, 250); // E4를 재생합니다. delay(300); 톤(BUZZER, 392, 250); // G4 재생 지연(300); 톤(부저, 523, 500); // C5 재생 delay(550);}void playUhOh() { tone(BUZZER, 523, 250); // C5 재생 지연(300); 톤(부저, 415, 500); // Gis4 재생 지연(600);} 

작동 중인 모터를 분리하면 전압 스파이크가 발생하여 전자 장치가 손상될 수 있습니다. 그러므로 나는 월-E가 아무것도 하기 전에 2초 동안 기다리게 한다. 즉, Arduino의 재설정 버튼을 누르고 아무 것도 손상시키지 않고 배터리를 빠르게 분리할 수 있습니다.

그는 일어나서 운전을 시작할 때 약간의 멜로디를 연주합니다. 그는 장애물이 보이면 멈추고 "으-오" 소리를 내며 최선의 방법을 결정하기 위해 주위를 둘러봅니다. 내가 사용한 적외선 센서 유형은 뒤쪽에 작은 나사가 있어 신호를 생성하는 거리를 결정할 수 있습니다. 이것이 코드에 거리 계산이 없는 이유입니다. (초음파 센서를 먼저 써보고 싶었는데 눈에 안들어옴.)

Wall-E는 먼저 왼쪽이 깨끗한지 확인한 다음 오른쪽이 깨끗한지 확인합니다. 양쪽이 막히면 건설현장의 중장비처럼 삐 소리를 내며 후진하다가 무작위 방향으로 방향을 틀고 계속한다. 한 쪽만 막히면 다른 쪽으로 계속 진행합니다. 양쪽이 모두 자유로우면 무작위로 하나를 선택하고 계속 진행합니다.

무작위 턴을 하게 하려고 했으나 아직 그 부분이 완성되지 않았습니다. 내장된 Arduino 타이머를 사용하려고 합니다. 최적화 방법에 대한 아이디어가 있으면 댓글로 알려주세요!

2단계 - 연결하기

첫 번째는 적외선 센서를 눈에 내장하여 눈이 너무 뚜렷해 보이지 않도록 하는 것이었습니다. 나는 그것을 분해하고 (그의 눈이 위아래로 움직일 수 있도록) 레고 핀을 센서에 글루건으로 붙인 다음 파란색 압정을 사용하여 레고 조각을 센서 주위에 다시 끼웠습니다.

모터에서 가장 중요한 것은 충분한 토크가 있다는 것이었습니다. Wall-E의 바퀴 설정이 움직이려면 꽤 많은 힘이 필요하기 때문입니다. 모터에 와이어를 납땜하고 레고에 단단히 연결되도록 부착해야 했습니다. 그래서 나는 그의 바퀴를 분해하고, 레고 테크닉 핀으로 가득 찬 가방 전체를 주문하고, 모터 샤프트 주위에 석고 테이프(이게 어떻게 부르나요? 피부에 붙을 수 있는 부드러운 테이프와 같습니다)를 감싼 다음 두 개의 핀에 붙였습니다. 각 바퀴의 주축이 되었습니다. 이것은 몇 분 동안 효과가 있었지만 마찰이 너무 높아서 테이프의 접착제가 붙을 수 없었습니다. 다행히 테크닉 핀은 측면에 작은 홈이 있어서 테이프를 고정할 수 있는 곳이 있었고, 접착력이 좋은 접착제에 흠뻑 젖어서 다행이었습니다.

나는 또한 LED를 통과시키기 위해 그의 가슴을 약간 떼어 냈습니다. 그런 다음 모든 부품과 Arduino를 연결했습니다.

모터 실드 그냥 그의 배에 맞게:

다이어그램도 명확하지 않지만 더 나은 개요를 위해 전선에 색상을 지정하려고 했습니다.

관례에 따라 모든 빨간색 전선은 양극(전기를 "전달")이고 모든 검은색 전선은 음극(전기를 "수신")입니다. 오른쪽 상단의 노란색 와이어는 적외선 센서에 대한 신호를 전달합니다. 주황색과 녹색 와이어는 3핀 2색 LED용이고, 보라색 와이어는 모터 실드에 모터를 돌릴 방향을 알려주기 위한 것이며, 파란색 케이블은 모터 실드에 얼마나 빨리 회전시켜야 하는지 알려줍니다.

모터 실드에는 연결하고 사용하기 쉽게 만든 매우 좋은 튜토리얼이 있었습니다. 불행히도 Fritzing 부품에는 속도를 설정하기 위한 두 개의 핀이 없었기 때문에 파란색 케이블이 다이어그램의 모터 쉴드에 무작위로 연결됩니다.

이 모든 것을 결합하는 동안 직면한 또 하나의 문제는 전압 및 접지 핀이 없다는 것이었습니다. 최대한 많은 전력을 공급할 수 있도록 모터 실드를 통해 직접 모터에 전원을 공급하고 싶었지만 어떻게든 Arduino와 적외선 센서에도 5V를 공급해야 했습니다. 그래서 나는 웹상의 거의 모든 사람들이 내가 해서는 안 된다고 말한 일을 했습니다. 모터 실드의 5V 출력을 Arduino의 5V 핀에 입력으로 연결했습니다. 이제 내가 사용하는 쉴드를 사용하여 Arduino를 손상시킬 수 있는 불쾌한 스파이크 없이 조절된 5V를 출력한다는 것을 절대적으로 확신할 수 있습니다. 조정되지 않은 전원을 해당 핀에 연결하면 아마도 무언가를 튀길 것입니다. 처음에는 Vin 핀을 사용하고 싶었지만 모든 것을 조절하는 메커니즘이 내장되어 있어 5V가 3.8V 정도가 되어 Arduino가 제대로 작동하기에 충분하지 않습니다. 대신에 무료 Vin을 사용하여 5V의 적외선 센서에 전원을 공급(!)했습니다. 왜냐하면 저는 케이블 스플리터가 없었고 거기에서도 5V가 나올 것이라는 것을 알고 있었기 때문입니다. 네, 이때부터 프랑켄슈타인 같은 느낌이 들기 시작했습니다. 하지만 효과가 있었습니다!

3단계 - Wall-E 작동

다음은 그의 행동을 보여주는 몇 가지 동영상입니다.

그리고 여기에서 그가 구석에 갇힌 경우 어떻게 할 것인지 테스트했습니다.

그래서 이것은 나의 첫 번째 작은 프로젝트였습니다. 나는 이제 케이블 연결을 최적화하고 그가 머리를 돌릴 수 있도록 서보 모터를 추가할 계획입니다. 스플리터와 더 작은 모터 실드와 보드를 사서 그의 배에 모든 것을 넣을 수도 있습니다.

그리고 그래서 월-E 살았다 기쁘게 항상 후. 끝.

<섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

코드

<울>
  • 벽_e_control
  • Wall_e_controlArduino
    Wall-E의 중앙 제어 파일입니다. 기본이지만 지금 당장 필요한 건.
    // 이 프로그램은 월-E 레고 로봇을 제어하는 ​​프로그램입니다.// 월-E가 이리저리 운전하고 있습니다. 장애물이 보이면 멈추고 주위를 둘러보고 다른 경로를 선택합니다. // Arduino Nano에는 digitalRead 및 digitalWrite에 사용할 수 있는 21개의 핀이 있습니다. // PWM 핀 3, 5, 6, 9, 10, 11은 다음 용도로 사용할 수 있습니다. analogWrite// 핀 0 및 1은 TTL에 사용할 수 있습니다.// 핀 2 및 3은 외부 인터럽트에 사용할 수 있습니다.// 핀 10, 11, 12, 13은 SPI 통신을 지원합니다.// 핀 13은 내부 LED가 될 수 있습니다.// 핀 14는 21은 또한 아날로그 핀 A0 ~ A7이며 analogRead#define INFRA_RED 9 // 모든 핀이 될 수 있음#define GREEN_LED 7 // 모든 핀이 될 수 있지만 저항이 필요합니다. 아마도 220 Ohm - 또는 접지 핀이 1 kOhm을 얻습니다. 정의 RED_LED 8 // 핀이 될 수 있지만 저항이 필요함, 아마도 220 Ohm - 또는 접지 핀이 1 kOhm을 얻습니다.#define BUZZER 10 // 주파수를 설정하려면 PWM 핀이 필요하고 저항이 필요합니다. 아마도 1 kOhm// MR은 다음과 같습니다. 오른쪽 모터, ML은 왼쪽 모터입니다#define MR_1 A1 // 핀이 될 수 있으므로 L289N shield#define MR_2 A2의 핀 번호에 해당하도록 합시다. 피 L289N shield#define MR_ENABLE 5 // 속도 제어를 위해 PWM 핀이 필요합니다#define ML_1 A3 // 모든 핀이 될 수 있으므로 L289N shield#define ML_2 A4의 핀 번호에 해당하도록 합시다 // 모든 핀이 될 수 있으므로 L289N shield#define ML_ENABLE 6의 핀 번호에 해당하도록 합시다. // 속도 제어를 위해서는 PWM 핀이어야 합니다. // 정상 속도를 maximum으로 설정합니다. const int NORMAL_SPEED =255;void setup() { // 리셋 버튼을 누른 직후에 전압 스파이크를 통해 구성 요소를 손상시키지 않고 끌 수 있도록 잠시 기다리십시오. delay(2000); // LED 및 부저 초기화 pinMode(GREEN_LED, OUTPUT); 핀모드(RED_LED, 출력);// 핀모드(BUZZER, 출력); // 필요하지 않음 // LED를 녹색으로 재설정 digitalWrite(RED_LED, LOW); 디지털 쓰기(GREEN_LED, 높음); // DC 모터 핀 설정 pinMode(MR_ENABLE, OUTPUT); // 모터 오른쪽 pinMode(MR_1, OUTPUT); 핀모드(MR_2, 출력); 핀모드(ML_ENABLE, 출력); // 모터 왼쪽 pinMode(ML_1, OUTPUT); 핀모드(ML_2, 출력); // 적외선 초기화 pinMode(INFRA_RED, INPUT); // 무작위 회전을 위한 난수 생성기 초기화 randomSeed(analogRead(0)); // 인사합니다 playHello();}void loop() { // 일반 작업 driveForwards(NORMAL_SPEED); // LED를 녹색으로 설정 digitalWrite(RED_LED, LOW); 디지털 쓰기(GREEN_LED, 높음); // 장애물 확인 if (digitalRead(INFRA_RED) ==LOW) { //LOW는 장애물 감지됨 // LED를 빨간색으로 변경 digitalWrite(GREEN_LED, LOW); 디지털 쓰기(RED_LED, 높음); // 모터 정지 stopDriving(); // 엉엉 소리 재생 playUhOh(); // 좌회전 확인 turnLeft(500); 부울 장애물Left =거짓; if (digitalRead(INFRA_RED) ==LOW) { 장애물 왼쪽 =true; } // 중앙으로 되돌리기 delay(100); 우회전(500); // 조금 기다리세요. 서두르는 것처럼 보이고 싶지 않습니다. delay(500); // 우회전 확인(500); 부울 장애물Right =거짓; if (digitalRead(INFRA_RED) ==LOW) { 장애물 오른쪽 =true; } // 중앙으로 되돌리기 delay(100); 좌회전(500); // 이제 여기서 나가는 방법을 확인합니다. if (obstacleLeft &&barrierRight) { driveBackwards(NORMAL_SPEED / 3); // 뒤로 5초간 삐 소리 for (int i =0; i <5; i++) { tone(BUZZER, 1000, 500); 지연(1000); } // 어딘가에 갇히는 것을 방지하기 위해 여행을 계속하기 전에 무작위로 방향을 변경 randomTurn(800, 1600); } else if (obstacleLeft) { turnRight(1000); } else if (obstacleRight) { turnLeft(1000); } 그렇지 않으면 { randomTurn(1000, 1800); } } // 더 많은 상호 작용을 위해 임의 작업 수행 int number =random(100); // 0과 99 사이의 난수를 생성 if (number ==0) { randomTurn(200,2000); } }void driveForwards(int speed) { // 모터가 같은 방향으로 가도록 설정 digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, 높음); 디지털 쓰기(ML_1, 높음); 디지털 쓰기(ML_2, LOW); setSpeed(speed);}void driveBackwards(int speed) { // 모터가 반대 방향으로 가도록 설정 digitalWrite(MR_1, HIGH); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, 높음); setSpeed(speed);}void turnLeft(int duration) { // 오른쪽 바퀴로 전진하고 왼쪽 바퀴로 후진하여 좌회전 digitalWrite(MR_1, HIGH); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, 높음); 디지털 쓰기(ML_2, LOW); // 속도를 낮추기 위해 setSpeed(NORMAL_SPEED / 2); 지연(지연); stopDriving();}void turnRight(int duration) { // 오른쪽 바퀴로 후진하고 왼쪽 바퀴로 앞으로 이동하여 우회전 digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, 높음); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, 높음); // 속도를 낮추기 위해 setSpeed(NORMAL_SPEED / 2); 지연(지연); stopDriving();}void stopDriving() { // 모든 모터 핀을 끕니다. digitalWrite(MR_1, LOW); 디지털 쓰기(MR_2, LOW); 디지털 쓰기(ML_1, LOW); 디지털 쓰기(ML_2, LOW); // ENABLE 핀으로 무엇을 해야할지 잘 모르겠지만, 핀을 끄는 것도 나쁘지 않습니다. digitalWrite(MR_ENABLE, LOW); digitalWrite(ML_ENABLE, LOW);}void setSpeed(int speed) { // 속도는 0에서 255 사이여야 합니다. speed =constrain(speed, 0, 255); // 모터를 켜기 위한 속도 설정 analogWrite(MR_ENABLE, speed); analogWrite(ML_ENABLE, 속도);} void randomTurn(int 최소값, int 최대값) { 부호 없는 긴 시간 =millis(); int 지속 시간 =random(최소, 최대); if (시간 % 2) { 우회전(지속시간); } else { 좌회전(지속시간); }} 무효 playHello() { 톤(BUZZER, 262, 250); // C4 재생 지연(300); 톤(부저, 330, 250); // E4를 재생합니다. delay(300); 톤(BUZZER, 392, 250); // G4 재생 지연(300); 톤(부저, 523, 500); // C5 재생 delay(550);}void playUhOh() { tone(BUZZER, 523, 250); // C5 재생 지연(300); 톤(부저, 415, 500); // Gis4 재생 지연(600);}

    회로도

    케이블 색상의 의미:
    빨간색 =전압(양)
    검은색 =접지(음수)
    노란색 =적외선 센서용 신호
    주황색 및 녹색 =빨간색 및 녹색 LED 입력 연결
    보라색 =모터 방향 제어
    파란색 =모터 속도 제어(불행히도 Fritzing 부품에는 이러한 연결을 위해 내 모터 브리지에 있는 두 개의 핀이 없었으므로 현재 느슨한 전선처럼 보입니다) wall-e2_3P6X71BCnP.fzz

    제조공정

    1. K30 센서로 CO2 모니터링
    2. 1Sheeld/Arduino를 사용한 청각 장애인용 통신
    3. Arduino로 코인 억셉터 제어
    4. 자동 레고 슈터
    5. 서보 모터로 로봇을 피하는 장애물
    6. Bluetooth가 탑재된 Arduino로 LED 제어!
    7. Arduino 또는 ESP8266이 있는 정전 용량 지문 센서
    8. 라인 팔로워 로봇
    9. Nextion 디스플레이로 재생
    10. Nunchuk 제어 로봇 팔(Arduino 포함)