쓸모없는 상자(Useless Box) 프로젝트

쓸모없는 상자 프로젝트:

이번 Digi-DIY 프로젝트에서는 쓸모없는 상자를 만들 것입니다. 이전에 만든 박스가 더 이상 동작 하지도 않고 추가적인 프로그램 가능성과 사용 편의성을 위해 ATMEGA328P-PU 칩에서 아두이노 나노로의 업데이트가 필요하다고 판단했습니다.

쓸모없는 상자를 조사하고 다른 DIY나 제작법 강좌가 있는 지부터 찾아보기 시작했습니다. Vagelis Chantzis로부터 많은 영감을 얻었으며 프로젝트의 기본을 다지는데 도움이 되었습니다.

이 DIY 가이드를 위해 쓸모없는 상자 제작 과정을 다루고 있으니 여러분도 이런 재미난 프로젝트를 만들 수 있을 것입니다. 이번 프로젝트는 저자에게는 좋은 학습 프로젝트였으며, 중간중간 몇 가지 조정이 있었던 것도 확인할 수 있을 것입니다. 다른 많은 프로젝트와 마찬가지로, 미처 알아차리지 못한 문제들도 있었습니다.

다음과 같은 문제였습니다.

서보 모터 장착하기: 서보 모터를 그대로 장착할 수 있는 좋은 방법을 찾지 못했습니다. 암이 계속해서 물체를 누르고 있기 때문에 핫 글루(hot glue)로는 충분치 않을 것이라고 판단했습니다. 시간이 지나면 토크에 의해 핫 글루는 평평한 표면에서 떨어져 나갈 것입니다. 그래서 두 개의 서보 모터에 사용할 고유 브래킷을 스케치하기 위해 온쉐이프(OnShape)를 사용했습니다. 아래에서 도면을 확인할 수 있습니다.

전원 문제: 사용했던 6V 전원에 문제가 좀 있었습니다. 아두이노 나노는 5V 핀에 사용하는 5V 전압을 내부적으로 정류하기 위해 최소 7-12V의 전압을 필요로 합니다. 6V로 공급하고 있었기 때문에 5V가 제대로 나오지 않았습니다. 서보 모터의 동력으로는 부족해서 아무것도 작동하지 않았습니다. 마이크로 USB 포트의 전원은 정류하지 않고 그대로 사용하기 때문에 대처방안으로 USB 포트에 전원을 공급할 수 있도록 전원 케이블을 직접 만들었습니다. 그 대신에, 6개의 AA 배터리 팩을 사용해서 최대 9V를 사용할 수도 있습니다.

일반적인 제작 과정에 따라, 보드를 서로 납땜하고 동작시키는 것으로부터 시작했습니다. 샘플 코드로 보드가 동작하면 다음으로 상자를 만들었습니다. 서보 모터와 상자가 동작하면, 암의 이동 거리에 맞는 암 길이를 스케치했습니다. 암은 온쉐이프에서 스케치한 후 3D로 인쇄했습니다. 사용 가능한 3D 프린터가 없다면 나무로 비슷한 모양을 만들 수도 있습니다. 최종 조립 후에 전력 문제를 해결해야 했습니다.

아두이노 나노: (1050-1001-ND)
크기가 작고 프로그래밍이 쉬워서 아두이노 나노를 선택했습니다. 작은 보드 공간을 계획했는데 아두이노 우노의 전체 크기는 원하던 것에 비해 꽤나 컸습니다.

보드 선택: (1528-1195-ND)
보드 레이아웃(부품 목록은 아래)을 계획할 때 풀 사이즈의 브레드보드로 시작했는데, 공간이 너무 많이 남았습니다. 작은 공간에 대한 생각을 고수해 결국엔 풀 사이즈의 보드를 반으로 잘라 보다 작은 보드 사이즈로 만들었습니다. 작은 드레멜(Dremel)공구와 절단휠로 잘랐습니다. 여기에 딱 맞는 1/2 크기의 브레드보드가 있습니다(부품 번호는 위에). 작은 크기의 아두이노 나노에 딱 맞을 것이며 다른 나머지 부품들을 위한 공간도 충분할 것입니다. 여러분이 더 작은 크기로 만들려 한다면, 할 수 있을 것이라고 확신합니다.

배선: (BKWK-3-ND)
브레드보드에 사용할 수 있는 전선의 종류는 많습니다. 브레드보드에 맞게 잘려 있고, 여러 색이며 앞 부분이 미리 벗겨져 있어서 '점퍼 와이어 키트’를 사용하기로 결정했습니다.

서보 모터: (1528-1084-ND)
아두이노 나노의 출력 전력에 알맞고 상자에 사용한 무겁고 단단한 오크 목재를 들어올릴 수 있어서 5V 하이토크 서보 모터를 사용하기로 결정했습니다. 플라스틱이나 발사 나무와 같은 가벼운 물체로 만든다면 일반 서보 모터를 사용해도 문제가 없을 것입니다. 단, 연속 회전 모터가 아닌 각도 제한 회전 모터를 사용하려는 지 확인하시기 바랍니다.

서보 모터 핀 배치:
전원: 빨간색
접지: 갈색
제어: 노란색

커패시터: (399-6602-ND)
검토하던 원래 도면에는 서보 모터의 전류 소모를 상쇄하기 위해 두 개의 100uF 커패시터가 달려있었습니다.

헤더 핀: (S9258-ND)
서보 모터에 3핀 암 커넥터가 달려있어서 브레드보드에 헤더 핀을 꽂으면 훨씬 쉽게 커넥터를 연결할 수 있습니다.

USB A(수) – 미니 B(수) 케이블: (WM14083-ND)
자작 전원 케이블을 만들기 위해 케이블에서 USB A(수) 부분을 잘라내서 양극 및 음극선을 9V 스냅 배터리 커넥터에 연결하였습니다. 이 케이블을 배터리 팩에 연결한 후 아두이노 나노의 미니 B(암) 부분에 케이블의 미니 B(수)를 체결합니다. 이렇게 한 이유는, 아두이노 나노의 내부 정류기는 배터리 팩의 6V를 5V 전원 핀에 사용할 5V로 올바르게 정류하지 못하기 때문에 이를 우회하기 위함 입니다. 아두이노 내부에서 올바르게 5V로 강압하기 위해 필요한 입력 전압 범위는 7~12V입니다.
만약 여러분이 6개의 AA 배터리 팩을 사용하고 있다면, 이렇게 할 필요가 없습니다. 배터리 팩을 Vin과 접지에 연결하기만 하면 됩니다.

9V 스냅 배터리 커넥터: (36-232-ND)
AA 배터리 팩을 빠르게 연결하거나 분리할 수 있어서 이 부품을 사용하기로 결정했습니다.

AA 4구 배터리 홀더: (BH24AASF-ND)
아두이노 나노에 6V의 전원을 공급하기위해 필요한 4개의 AA 배터리를 넣을 수 있어서 이 부품을 선택했습니다. 만약 6개의 AA 배터리를 AA 6구 배터리 홀더(BH26AASF-ND)에 사용한다면 9V가 출력될 것이며, Vin 입력 핀에 연결해 알맞는 5V로 낮춰 정류될 수 있도록 해야 합니다.

단일 폴 듀얼 스로우(Single Pole Double Throw, SPDT) 스위치: (EG2350-ND)
기존 상자의 스위치를 그대로 사용했지만, 새로 다른 것을 사야 한다면 EG2350-ND를 선택할 것입니다.

온/오프 로커 스위치: (EG5619-ND)
배터리를 절약하기 위해 온/오프 전원 스위치를 넣고 싶을 경우, 이 스위치를 배터리 팩과 Vin 핀 사이에 넣으면 됩니다.

10 kΩ 저항: (CF14JT10K0CT-ND)
이 저항은 SPDT 스위치로부터의 신호를 바이어스(풀다운)하기 위함입니다. 이 신호를 통해 보드는 언제 스위치 암과 도어 암을 움직여야 하는지를 알 수 있습니다.

인두: (243-1267-ND)
땜납: (473-1128-ND)
전선 스트리퍼: (K598-ND)
플라이어: (K633-ND)

상자 치수:
상자 치수는 전적으로 여러분에게 달려 있습니다. 저자가 사용했던 아이디어를 공유해드리겠습니다. 유념해야 할 단 한 가지는 스위치에서 상자 뚜껑 가장자리까지의 이동 거리입니다. 스위치가 멀리 떨어져 있을수록 스위치에 도달하기 위한 스위치 암의 길이도 증가해야 하며, 이는 상자 내부에서의 이동 문제를 야기할 수 있습니다.
(2x) 7" x 5 ½" (양 끝)
(3x) 12" x 5 ½" (벽2 + 바닥1)
(1x) 5 ½" x 5" (상단, 뚜껑)
(1x) 5 ½" x 6 ¾" (상단, 고정)

상자 정보:
목재: 저자의 경우 상자에 오크를 사용했지만, 일반 서보 모터의 경우 보다 가벼운 목재가 낫습니다.
구성: 안에 작은 부품들이 들어 있는 큰 상자입니다. 만약 여러분이 상자를 설계한다면, 더 작은 크기로 만들 수 있을 것입니다.

기타 부품:
2 x 소형 힌지(박스 끝에 먼저 나사로 고정한 다음 뚜껑에 고정합니다)
4 x 소형 ½" 나사(길이는 사용 중인 재료의 두께에 따라 다름)
12 x 2" 나사 (나무가 쪼개지지 않도록 나사 코어와 동일한 크기의 드릴 비트로 나무에 미리 구멍을 뚫습니다)
드릴
드릴 비트(일반 가게의 표준 팩도 괜찮습니다. 나무와 플라스틱은 부드러워서 드릴로 쉽게 구멍을 뚫을 수 있습니다.)
사포(거친 사포(40-50)로 시작해서, 다음으로 중간: 100, 그리고 마지막으로 고운 사포(220-240)로 마무리)
연필
목재 끌(선택사항, 나무에 스위치를 올려놓을 공간을 깎아내야 했습니다)

도어 암:
온쉐이프를 사용해 프로젝트에 사용할 3D로 인쇄 가능한 도어 암을 만들었습니다. 디자인은 “여기”에서 확인할 수 있습니다.

자작 도어 브라켓:
온쉐이프를 사용해 프로젝트에 사용할 3D로 인쇄 가능한 도어 암 브라켓을 만들었습니다. 디자인은 “여기”에서 확인할 수 있습니다.

스위치 암:
온쉐이프를 사용해 프로젝트에 사용할 3D로 인쇄 가능한 스위치 암을 만들었습니다. 디자인은 “여기”에서 확인할 수 있습니다.

자작 스위치 암 브라켓:
온쉐이프를 사용해 프로젝트에 사용할 3D로 인쇄 가능한 스위치 암 브라켓을 만들었습니다. 디자인은 “여기”에서 확인할 수 있습니다.

배선도:

코드:

#include <Servo.h>

Servo doorServo;
Servo fingerServo;

int swPin = 2;                    // Switch on pin 2
int pos = 0;                      // Sets initial arm positions.
int selectedMove = 0;             // Move selector

void setup() {
  pinMode(swPin, INPUT);          // Sets pin 2 as input.
  doorServo.attach(9);            // Sets door servo on Pin 9 
  fingerServo.attach(10);         // Sets finger servo on Pin 10 
  doorServo.write(0);             // Sets door to position
  fingerServo.write(80);          // Sets finger to position
}


void loop() {                     // If the switch is on, move door and finger to switch it off
  if (digitalRead(swPin) == HIGH) {
    if (selectedMove > 9) {       // If greater than 9 count, reset to 0.
      selectedMove = 0;           // ^
    }
    if (selectedMove == 0) {      // If count = 0 then perform this function / Same logic for the following.
      simpleClose();
    }
    else if (selectedMove == 1) {
      simpleClose();
    }
    else if (selectedMove == 2) {
      simpleClose2();
    }
    else if (selectedMove == 3) {
      crazydoor();
    }
    else if (selectedMove == 4) {
      slow();
    }
    else if (selectedMove == 5) {
      serious();
    }
    else if (selectedMove == 6) {
      trollClose();
    }
    else if (selectedMove == 7) {
      simpleClose();
    }
    else if (selectedMove == 8) {
      matrix();
    }
    else if (selectedMove == 9) {
      sneak();
    }
    selectedMove += 1;                       // Add's 1 to "selectMove" count.
  }
}



void simpleClose() {
    for (pos = 0; pos < 140; pos += 3) {  // Defines starting postition for door
      doorServo.write(pos);               // Executes starting position for door
      delay(20);                          // Delay before next action
    }
    for (pos = 0; pos < 200; pos += 4) {  // Defines starting position for finger
      fingerServo.write(pos);             // Executes position position for finger
      delay(10);                          // Delay before next action
    }
    for (pos = 200; pos >= 0; pos -= 4) { // Defines next position for finger
      fingerServo.write(pos);             // Executes next position for finger
      delay(20);                          // Delay before next action 
    }
    for (pos = 140; pos >= 0; pos -= 3) { // Defines next position for door
      doorServo.write(pos);               // Executes next position for door
      delay(10);                          // Delay before next action
  }
}

// The following code follows the same schema. Play around with the code to get the correct travel distance. Watch out for doorServo vs. fingerServo, to know which one you are using.

// The following code has extra delays (200+) to make the arms more expresive. Mess with these also to get different timings for movement.

void simpleClose2() {
  for (pos = 0; pos < 140; pos += 3) {
    doorServo.write(pos);
    delay(15);
  }
  delay(800);
  for (pos = 0; pos < 140; pos += 4) {
    fingerServo.write(pos);
    delay(15);
  }
  delay(1000);
  for (pos = 140; pos < 180; pos += 4) {
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 180; pos >= 0; pos -= 5) {
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 140; pos >= 0; pos -= 3) {
    doorServo.write(pos);
    delay(15);
  }
}


void crazydoor(){
  for (pos = 0; pos < 120; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 120; pos >= 0; pos -= 5){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 0; pos < 120; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 120; pos >= 0; pos -= 15){
    doorServo.write(pos);
    delay(15);
  }
  delay(700);
  for (pos = 0; pos < 120; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  delay(700);
  for (pos = 120; pos >= 0; pos -= 5){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 0; pos < 140; pos += 8){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 0; pos < 180; pos += 3){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 180; pos >= 0; pos -= 3){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 140; pos >= 0; pos -= 15){
    doorServo.write(pos);
    delay(15);
  }
}


void slow(){
  for (pos = 0; pos < 130; pos += 1){
    doorServo.write(pos);
    delay(100);
  }
  for (pos = 80; pos < 160; pos += 1){
    fingerServo.write(pos);
    delay(100);
  }
  for (pos = 160; pos >= 80; pos -= 1){
    fingerServo.write(pos);
    delay(100);
  }
  for (pos = 130; pos >= 0; pos -= 1){
    doorServo.write(pos);
    delay(100);
  }
}


void serious() {
  for (pos = 0; pos < 130; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 80; pos < 120; pos += 1){
    fingerServo.write(pos);
    delay(15);
  }
  delay(800);
  for (pos = 120; pos >= 100; pos -= 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 100; pos < 130; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 130; pos >= 90; pos -= 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 90; pos < 150; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  fingerServo.write(80);
  delay(1000);
  for (pos = 80; pos < 160; pos += 4){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 160; pos >= 80; pos -= 4){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 150; pos >= 0; pos -= 1){
    doorServo.write(pos);
    delay(15);
  }
}


void trollClose() {
  for (pos = 0; pos < 155; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 0; pos < 160; pos += 4){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 155; pos >= 100; pos -= 3){
    doorServo.write(pos);
    delay(15);
  }
  delay(10000);
  for (pos = 160; pos >= 0; pos -= 4){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 100; pos >= 0; pos -= 3){
    doorServo.write(pos);
    delay(15);
  }
}


void matrix(){
  for (pos = 0; pos < 120; pos += 3){
    doorServo.write(pos);
    delay(15);
  }
  for (pos = 80; pos < 100; pos += 4){
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 100; pos < 160; pos += 1){
    fingerServo.write(pos);
    delay(30);
  }
  delay(300);
  for (pos = 160; pos >= 0; pos -= 4){
    fingerServo.write(pos);
    delay(10);
  }
  for (pos = 120; pos >= 0; pos -= 3){
    doorServo.write(pos);
    delay(15);
  }
}


void sneak(){
  for (pos = 0; pos < 100; pos += 1) {
    doorServo.write(pos);
    delay(30);
  }
  delay(2000);
  for (pos = 80; pos < 100; pos += 1) {
    fingerServo.write(pos);
    delay(30);
  }
  delay(500);
  for (pos = 100; pos < 120; pos += 4) {
    doorServo.write(pos);
    delay(15);
  }
  delay(100);
  for (pos = 100; pos < 130; pos += 4) {
    fingerServo.write(pos);
    delay(15);
  }
  delay(500);
  for (pos = 130; pos >= 100; pos -= 4) {
    fingerServo.write(pos);
    delay(15);
  }
  delay(100);
  for (pos = 100; pos < 130; pos += 4) {
    fingerServo.write(pos);
    delay(15);
  }
  delay(100);
  for (pos = 130; pos >= 100; pos -= 4) {
    fingerServo.write(pos);
    delay(15);
  }
  delay(100);
  for (pos = 100; pos < 160; pos += 4) {
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 160; pos >= 80; pos -= 4) {
    fingerServo.write(pos);
    delay(15);
  }
  for (pos = 120; pos >= 0; pos -= 3) {
    doorServo.write(pos);
    delay(15);
  }
}


영문 원본: Useless Box Project