메뉴 전체보기

회원메뉴

폐품으로 만드는 3D 조에트로프 > 게시판

본문 바로가기

쇼핑몰 검색

NO. 3164
제목 : 폐품으로 만드는 3D 조에트로프
2026-09-03 10:46

소개: 폐품으로 만드는 3D 조에트로프


소개: 폐품으로 만드는 3D 조에트로프


이 프로젝트는 작업장 지붕에 설치된 대형 LED 조명 중 하나가 고장 나면서 시작되었습니다. 전기 기술자가 그것을 교체한 뒤 쓰레기통에 버리려고 했습니다. 고칠 수 있을지 확신은 없었지만 일단 챙겨 두었고, 몇 달 동안 방치되어 있었습니다. 그러다 드라이버를 분해해 보니 수지로 가득 차 있어 수리할 수 없다는 것을 알게 되었습니다. 또한 다른 프로젝트를 위해 분해한 오래된 이동성 스쿠터에서 나온 48volt 배터리 충전기도 하나 굴러다니고 있었습니다. 알고 보니 둘이 아주 잘 맞았고, 이제 대형 LED 램프가 생겼습니다. 이걸로 무엇을 할 수 있을까요? 부품을 몇 개 더 추가하면 3D 조에트로프를 만들고, 미술 학생들에게 작은 조각상을 만들게 하여, 약간의 WOW 요소가 있는 무언가를 만들 수 있겠다고 생각했습니다.

3D 조에트로프란 무엇인가요?

3D 조에트로프는 TV나 컴퓨터 없이도 볼 수 있는 작은 3D 영화와 같습니다.

여러 개의 작은 3D 모형을 원형으로 배치합니다. 각 모형은 동작의 약간씩 다른 한 단계를 나타냅니다.

그렇다면 어떻게 작동할까요?

중요한 부분은 다음과 같습니다:

3D 모형은 영화의 개별 프레임과 같습니다. 각각의 모형은 움직임의 다음 단계를 보여 줍니다.

모터가 플랫폼을 매우 빠르게 회전시켜 각 모형이 차례로 눈앞을 지나가게 합니다.

일반적인 조에트로프에는 들여다볼 수 있는 슬롯이나 구멍이 있습니다. 이것들은 카메라 셔터와 비슷한 역할을 하여 각 모형 사이에서 잠시 시야를 가립니다. 이 조에트로프는 비슷한 효과를 내기 위해 스트로브 램프를 사용합니다.

뇌는 연속해서 나타나는 그림들을 연결하는 데 매우 능숙합니다. 서로 분리된 여러 모형을 보는 대신, 하나의 모형이 움직이는 것처럼 보게 됩니다.




STEP 1. 준비물


준비물


준비물


사용한 것은 다음과 같습니다. 제가 가지고 있던 부품과 준비물 대부분은 오래된 프로젝트에서 나온 것이거나 버려질 예정이던 물건이었습니다.

폐기된 LED 램프

작동하지만 쓸모가 없었던 48v volt 배터리 충전기

병뚜껑: 정말 정말 많은 병뚜껑!

Arduino

스테퍼 모터

스테퍼 컨트롤러

LED 스위칭용 MOSFET

스테퍼와 Arduino용 전원 공급 장치

3D 프린팅 부품

레이저 커팅 디스크

강철 프레임

3D 프린팅 조각상 또는 수제 조각상

페인트, 전선, 나사 등




STEP 2. 램프 작동시키기


램프 작동시키기


램프 작동시키기


첫 단계는 꽤 순조롭게 진행되었습니다. 램프를 작동시키는 일이었습니다. 램프의 드라이버는 수리할 수 없었고, 노트북 충전기도 몇 개 사용해 보았지만 전압이 LED를 켜기에는 너무 낮았습니다. 정크 박스에서 오래된 이동성 스쿠터에 쓰던 48-volt 배터리 충전기를 찾았고, 포장에서 꺼내자마자 완벽하게 작동했습니다.




STEP 3. 3D 프린팅 마운트


3D 프린팅 마운트


3D 프린팅 마운트


3D 프린팅 마운트


3D 프린팅 마운트


다음으로 스테퍼 모터와 디스크를 고정할 3D 프린팅 부품을 몇 개 출력했습니다. 이어서 레이저 커팅 디스크를 준비했고, 이 부품들은 문제없이 조립되었습니다. 스테퍼 마운트는 35mm SHS 안으로 밀어 넣을 수 있도록 설계했습니다.




STEP 4. 강철 프레임


강철 프레임


강철 프레임


강철 프레임


강철 프레임


장치를 함께 고정할 프레임을 설계하고 제작했으며, 지금까지는 순조롭습니다. 프레임은 두께 35 mm x 2.5 mm이고, 3D 프린팅 모터 마운트가 강철 부재 끝부분 안으로 들어갑니다. 허브는 스테퍼 모터에 끼워지고, 디스크는 3 mm 나사로 허브에 고정됩니다.




STEP 5. AI를 사용해 Arduino 코딩하기


AI를 사용해 Arduino 코딩하기


저는 코딩을 잘하지 못해서 Perplexity AI를 사용해 Arduino용 코드를 작성했습니다. 첫 시도에 작동했으며, 제가 사용한 프롬프트는 다음과 같습니다.

"스테퍼 모터, Arduino, 대형 LED 램프를 사용해 대형 3D 조에트로프를 만들고 싶습니다. 세그먼트가 20개 있으므로 램프는 1회전마다 20번 깜박여야 합니다. 디스크의 지름은 500mm입니다. 포텐셔미터로 스테퍼 모터의 속도를 변경할 수 있으면 좋겠습니다. 드라이버는 회전당 400 microsteps로 설정되어 있습니다. 램프는 디스크의 세그먼트와 동기화되어 깜박여야 합니다. Arduino용 코드를 작성해 주실 수 있나요?"

#include <AccelStepper.h>


const byte STEP_PIN = 2;

const byte DIR_PIN = 3;

const byte EN_PIN = 8;

const byte SSR_PIN = 9;

const byte POT_PIN = A0;


const long STEPS_PER_REV = 400; // your driver setting

const int SEGMENTS = 20;

const int STEPS_PER_SEGMENT = STEPS_PER_REV / SEGMENTS;


const float MIN_RPM = 1.0;

const float MAX_RPM = 120.0;


const unsigned int PULSE_US = 300; // lamp on-time pulse

const int POT_DEADBAND = 3;


AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);


long nextFlashStep = 0;

bool lampOn = false;

unsigned long lampOffTime = 0;

int lastPot = -1000;


void setup() {

pinMode(EN_PIN, OUTPUT);

pinMode(SSR_PIN, OUTPUT);

digitalWrite(EN_PIN, LOW); // 드라이버 활성화(사용 중인 드라이버가 active HIGH라면 변경)

digitalWrite(SSR_PIN, LOW);


stepper.setMaxSpeed(3000);

stepper.setAcceleration(3000);

}


void loop() {

int pot = analogRead(POT_PIN);


if (abs(pot - lastPot) > POT_DEADBAND) {

lastPot = pot;

}


float rpm = MIN_RPM + (MAX_RPM - MIN_RPM) * (pot / 1023.0);

float stepsPerSecond = (rpm * STEPS_PER_REV) / 60.0;

stepper.setSpeed(stepsPerSecond);


stepper.runSpeed();


long pos = stepper.currentPosition();


if (pos >= nextFlashStep) {

digitalWrite(SSR_PIN, HIGH);

lampOn = true;

lampOffTime = micros() + PULSE_US;

nextFlashStep += STEPS_PER_SEGMENT;

}


if (lampOn && (long)(micros() - lampOffTime) >= 0) {

digitalWrite(SSR_PIN, LOW);

lampOn = false;

}

}




STEP 6. AI 배선도 실패


AI 배선도 실패


AI는 코드 작성은 훌륭하게 해냈고, 4단계에서 우스꽝스러운 그래픽을 만들고 제목 페이지도 편집했지만, 배선도를 만드는 작업은 안타깝게도 이것이 AI가 할 수 있는 최선이었습니다. 거의 사용할 수 없는 수준입니다. 도면에 일부 정보는 있지만 오류도 있으므로, 너무 그대로 따라 하지는 마세요. 프로젝트가 작동하지 않을 것입니다.




STEP 7. MOSFET 배선


MOSFET 배선


MOSFET 배선


이 MOSFET 모듈은 잡동사니 상자에 있던 것입니다. 어디서 가져왔는지는 전혀 모르지만 잘 작동합니다. MOSFET에 방열판도 달았는데, 과열되어 소손될 수 있기 때문입니다.

  1. VIN 및 GRD 핀은 램프용 전원 공급 장치에 연결합니다. 제 경우에는 약 60볼트입니다.
  2. V+ 및 V- 핀은 LED 램프에 연결합니다.
  3. VCC는 Arduino의 5V 핀에 연결합니다.
  4. 작은 GRD 핀은 Arduino의 GND에 연결합니다.
  5. SIG 핀은 Arduino의 9번 핀에 연결합니다.




STEP 8. Potentiometer 배선


Potentiometer 배선


RPM을 조절해 보고 싶다면 potentiometer를 사용하면 됩니다. 저는 zoetrope가 높은 RPM에서 잘 작동하는 것을 확인했습니다. 그림은 낮은 RPM에서 더 잘 작동하는 것 같습니다.

  1. pot의 가운데 핀은 Arduino의 A0에 연결합니다.
  2. pot의 왼쪽 핀은 Arduino의 GND에 연결합니다.
  3. pot의 오른쪽 핀은 Arduino의 5V 핀에 연결합니다.
  4. GND와 5V 핀의 연결을 서로 바꾸면 RPM 변화 방향을 반대로 바꿀 수 있습니다.




STEP 9. Stepper Motor를 Driver에 연결하기


Stepper Motor를 Driver에 연결하기


Stepper Motor에는 전선이 4개 있고, 모터 내부에는 코일 세트가 2개 있습니다. 저는 multimeter로 확인하여 한 코일에 연결되는 두 전선을 식별했습니다. 그러면 나머지 두 전선은 다른 코일에 연결됩니다.

  1. Stepper Motor 전선 한 쌍은 A+와 A-에 연결합니다.
  2. 나머지 한 쌍은 B+와 B-에 연결합니다.
  3. GND와 VCC는 Stepper Motor 전원 공급 장치에 연결합니다. 저는 12볼트를 사용했습니다.
  4. DIR-는 Arduino의 8번 핀에 연결합니다.
  5. DIR+는 Arduino의 3번 핀에 연결합니다.
  6. DIR+는 Stepper Driver의 PUL+ 핀에도 연결합니다.
  7. PUL-는 Arduino의 2번 핀에 연결합니다.




STEP 10. Driver 설정


Driver 설정


Driver 측면에는 DIP 스위치가 몇 개 있습니다. 처음 3개는 microstep을 제어하며, 이 프로젝트에서는 400을 선택했습니다. 합리적인 속도에서 소음이 너무 크지 않으면서 Stepper가 부드럽게 작동하기 때문입니다.

설정은 1번 ON, 2번 OFF, 3번 ON입니다.

다음 3개의 스위치는 모터에 공급되는 전류를 제어합니다. 열이 축적되는 것을 줄이기 위해 모터가 안정적으로 작동하는 가장 낮은 전류를 원했습니다.

설정은 4번 ON, 5번 ON, 6번 OFF입니다.

전류는 1.5암페어가 됩니다.





STEP 11. Bottle Cap 설치


Bottle Cap 설치


Bottle Cap 설치


Bottle Cap 설치


Bottle Cap 설치


Bottle Cap 설치


Bottle Cap 설치


먼저 굶주린 너구리처럼 쓰레기통 안으로 기어 들어가 bottle cap 60개를 찾아야 했습니다. 설치가 가장 어렵고 시간이 많이 걸리는 작업이었습니다. 애니메이션을 설정하는 가장 쉬운 방법은 먼저 12시, 3시, 6시, 9시 위치의 bottle cap을 배치한 다음 각 위치 사이를 채워 나가는 것이라고 생각합니다. 한 위치에서 시작해 처음부터 끝까지 작업하면 금방 엉망이 되었습니다.




STEP 12. 병뚜껑 테스트


병뚜껑 테스트


GIF는 프로젝트의 테스트와 진행 상황을 보여 줍니다. GIF가 작동하도록 이미지를 클릭해야 할 수도 있습니다.

영상의 선은 카메라 셔터와 스트로브의 동기화가 어긋나서 생긴 아티팩트입니다. 이걸 촬영하려고 하니 머리도 아팠습니다. 따라서 번쩍이는 빛에 민감하다면 편두통이나 그보다 심한 증상이 생길 수 있습니다.

영상도 GIF로 바꿔야 했는데, 조금 까다로웠습니다. 영상이 정확히 20번째 프레임에서 끝나고 반복되어야 합니다. 그렇지 않으면 오류가 생기고 약간 이상하게 보입니다.




STEP 13. "캡" 완성


"캡" 완성


"캡" 완성


설정을 이리저리 많이 조정한 끝에 만족스러운 결과를 얻었고, 애니메이션도 꽤 괜찮아 보입니다. 학생들도 상당히 좋아하고 자신만의 버전을 만들고 싶어 합니다.




STEP 14. 레고맨 테스트


레고맨 테스트


시험 삼아 레고맨 20개를 3D 프린터로 출력해 블루택으로 디스크 위에 붙였습니다. 어떻게 될지 보려고 거미 팩맨 같은 것도 그려 보았습니다. 디스크 가장자리를 따라 움직이는 블루택 점도 보일 것입니다. 각 구간에서 물체를 조금 더 앞이나 뒤로 옮기기만 해도 디스크 주위를 달리는 것처럼 보이게 만들 수 있습니다. 꽤 만족스럽고, 몇몇 학생들은 작동 원리에 매우 관심을 보였으며 바라보다가 약간 최면에 걸린 듯한 반응을 보였습니다.

영상의 선은 카메라 셔터와 스트로브의 동기화가 어긋나서 생긴 아티팩트입니다. 이걸 촬영하려고 하니 머리도 아팠습니다. 따라서 번쩍이는 빛에 민감하다면 편두통이나 그보다 심한 증상이 생길 수 있습니다.




STEP 15. AI로 시작 버튼 추가하기


AI로 시작 버튼 추가하기


이번에도 Arduino 코드와 함께 Perplexity AI에 다음과 같이 프롬프트를 입력했습니다. "스테퍼 모터를 켜는 시작 버튼을 추가하고, 3초 후에 LED를 켜고 싶습니다. 조에트로프가 30초 동안 작동한 다음 LED를 끄고, 다시 3초 후에 스테퍼 모터를 끄고 싶습니다. 또한 조에트로프가 꺼질 때까지 시작 버튼이 무시되도록 해야 합니다. 아이들이 사이클이 끝나기 전에 버튼을 반복해서 누를 가능성이 높기 때문입니다."

이것이 AI가 제시한 결과이며, 처음부터 작동했습니다.

장치Arduino 핀비고

스테퍼 드라이버 STEP D2

스테퍼 드라이버 DIR D3

스테퍼 드라이버 ENABLE D8

다음을 가정함 LOW = 활성화; 반대라면 상수를 변경하세요

MOSFET 게이트 / LED 트리거 D9 게이트 드라이버 회로를 통해 사용

시작 푸시버튼 D7 다른 단자는 GND

포텐셔미터 와이퍼A0 외부 단자는 5 V 및 GND에 연결

#include <AccelStepper.h>


// ---------------- 핀 할당 ----------------

const byte STEP_PIN = 2;

const byte DIR_PIN = 3;

const byte ENABLE_PIN = 8;

const byte LED_PIN = 9;

const byte START_PIN = 7;

const byte POT_PIN = A0;


// ---------- 조에트로프 / 모터 설정 ----------

const long STEPS_PER_REV = 400; // 드라이버 설정: 디스크 1회전당 마이크로스텝 수

const byte SEGMENTS = 20;

const long STEPS_PER_SEGMENT = STEPS_PER_REV / SEGMENTS; // 400 / 20 = 20


const float MIN_RPM = 1.0;

const float MAX_RPM = 120.0;


// 각 세그먼트 위치에서 이 시간 동안 LED를 스트로브합니다.

// 50 us로 테스트했습니다. 필요한 경우에만 조정하세요.

const unsigned long PULSE_US = 50;


// ---------- 시퀀스 타이밍 ----------

const unsigned long LED_START_DELAY_MS = 3000; // 먼저 모터가 3초 동안 작동

const unsigned long LED_RUN_TIME_MS = 30000; // LED가 30초 동안 스트로브

const unsigned long MOTOR_STOP_DELAY_MS = 3000; // LED가 멈춘 후 모터가 3초 동안 작동


// 하드웨어가 반대로 작동한다면 이 값을 변경하세요.

const byte DRIVER_ENABLED = LOW;

const byte DRIVER_DISABLED = HIGH;

const byte LED_ON = HIGH;

const byte LED_OFF = LOW;


// ---------- 상태 머신 ----------

enum RunState {

IDLE,

MOTOR_SPINUP,

LED_RUNNING,

MOTOR_COASTDOWN

};


RunState runState = IDLE;

unsigned long stateStartedAt = 0;


// ---------- 스테퍼 / 점멸 ----------

AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);


long nextFlashStep = 0;

bool ledPulseActive = false;

unsigned long ledOffAtUs = 0;


// ---------- 버튼 디바운스 ----------

bool lastRawButton = HIGH;

bool stableButton = HIGH;

unsigned long buttonChangedAt = 0;

const unsigned long DEBOUNCE_MS = 30;


bool startButtonPressed() {

bool raw = digitalRead(START_PIN);


if (raw != lastRawButton) {

lastRawButton = raw;

buttonChangedAt = millis();

}


if ((millis() - buttonChangedAt) >= DEBOUNCE_MS) {

if (raw != stableButton) {

stableButton = raw;


// 디바운스된 누름 전이에서만 true를 반환합니다.

if (stableButton == LOW) {

return true;

}

}

}


return false;

}


void setMotorSpeedFromPot() {

int potValue = analogRead(POT_PIN);


float rpm = MIN_RPM +

(MAX_RPM - MIN_RPM) * (potValue / 1023.0);


float stepsPerSecond = (rpm * STEPS_PER_REV) / 60.0;


stepper.setSpeed(stepsPerSecond);

}


void stopLED() {

digitalWrite(LED_PIN, LED_OFF);

ledPulseActive = false;

}


void startCycle() {

// 스테퍼를 활성화하고 3초간의 회전 가속 기간을 시작합니다.

digitalWrite(ENABLE_PIN, DRIVER_ENABLED);


// 사이클이 항상 예측 가능하게 시작되도록 위치와 점멸 기준을 초기화합니다.

stepper.setCurrentPosition(0);

nextFlashStep = 0;


stopLED();


runState = MOTOR_SPINUP;

stateStartedAt = millis();

}


void updateLEDStrobe() {

// 먼저 짧은 펄스 시간이 만료되었다면 이전 점멸을 종료합니다.

if (ledPulseActive && (long)(micros() - ledOffAtUs) >= 0) {

stopLED();

}


// 20스텝 세그먼트 위치마다 한 번씩 점멸합니다.

long currentStep = stepper.currentPosition();


if (!ledPulseActive && currentStep >= nextFlashStep) {

digitalWrite(LED_PIN, LED_ON);

ledPulseActive = true;

ledOffAtUs = micros() + PULSE_US;


nextFlashStep += STEPS_PER_SEGMENT;

}

}


void setup() {

pinMode(ENABLE_PIN, OUTPUT);

pinMode(LED_PIN, OUTPUT);

pinMode(START_PIN, INPUT_PULLUP);


digitalWrite(ENABLE_PIN, DRIVER_DISABLED);

digitalWrite(LED_PIN, LED_OFF);


stepper.setMaxSpeed(3000);

stepper.setAcceleration(3000);


// 방향을 한 번만 설정합니다. 디스크가 반대 방향으로 회전하면 HIGH/LOW를 서로 바꾸세요.

digitalWrite(DIR_PIN, HIGH);

}


void loop() {

// 버튼을 계속 읽고 디바운스합니다.

bool buttonPressed = startButtonPressed();


// 시작 버튼은 시스템이 유휴 상태일 때만 인식합니다.

if (runState == IDLE && buttonPressed) {

startCycle();

}


// 활성 사이클 중에만 스테퍼를 구동하고 속도를 업데이트합니다.

if (runState != IDLE) {

setMotorSpeedFromPot();

stepper.runSpeed();

}


switch (runState) {


case IDLE:

// 모든 장치는 꺼진 상태로 유지됩니다. 버튼은 이 상태에서만 인식됩니다.

stopLED();

digitalWrite(ENABLE_PIN, DRIVER_DISABLED);

break;


case MOTOR_SPINUP:

// 모터는 작동하지만 처음 3초 동안 LED는 꺼져 있습니다.

stopLED();


if (millis() - stateStartedAt >= LED_START_DELAY_MS) {

// 새로 설정된 기준 스텝 수에 첫 스트로브 시퀀스를 맞춥니다.

nextFlashStep = stepper.currentPosition();

runState = LED_RUNNING;

stateStartedAt = millis();

}

break;


case LED_RUNNING:

// 모터가 작동하고 LED가 세그먼트마다 한 번씩 점멸합니다.

updateLEDStrobe();


if (millis() - stateStartedAt >= LED_RUN_TIME_MS) {

// LED는 즉시 끄되 모터는 3초 동안 계속 작동시킵니다.

stopLED();

runState = MOTOR_COASTDOWN;

stateStartedAt = millis();

}

break;


case MOTOR_COASTDOWN:

// LED는 꺼진 상태로 유지되고 모터는 3초 더 작동합니다.

stopLED();


if (millis() - stateStartedAt >= MOTOR_STOP_DELAY_MS) {

digitalWrite(ENABLE_PIN, DRIVER_DISABLED);

runState = IDLE;

}

break;

}

}




STEP 16. 최종 배선 정리 및 도색


최종 배선 정리 및 도색


최종 배선 정리 및 도색


최종 배선 정리 및 도색


이제 Zoetrope가 제가 원하는 방식으로 작동하지만, 배선이 약간 엉망이고 도색도 필요해 보였습니다. MakerWorld에서 다운로드한 상자를 3D 프린팅하고 프레임에 검은색 페인트를 칠했습니다. 이렇게 해서 완성된 Zoetrope가 만들어졌습니다.

학생들은 이것을 가지고 놀며 애니메이션을 만드는 것을 즐깁니다. 다시 만든다면 12볼트 LED 조명을 사용할 것입니다. 별도의 전원 공급 장치로 60볼트 LED를 구동하는 것이 조금 번거롭기 때문입니다.

또한 코딩에 AI를 사용한 것도 잘 됐습니다. 저는 Arduino 코딩이 어렵다고 느끼고 코딩에 별로 관심도 없어서, 애초에 직접 시도하지 않았을 것입니다. 빈 페이지에서 시작해 코딩하는 일이 지루하고 답답하게 느껴지기 때문에, 저에게 AI는 큰 도움이 되었습니다.




STEP 17. 더 많은 GIF와 실패작


더 많은 GIF와 실패작


더 많은 GIF와 실패작


더 많은 GIF와 실패작


몇몇 학생들이 직접 애니메이션을 만들었고, 관심 있는 사람이 있다면 여기에 업로드하겠습니다. 잘게 잘라 만든 Lego 인형은 그다지 잘 작동하지 않아 실패작이 되었지만, 해골은 괜찮게 작동했습니다. 앞으로 더 많은 작품이 나올 것이라고 확신합니다.


원문: https://www.instructables.com/3D-Zoetrope-From-Junk/

좋아요 0
게시판

회사명 공방유니언 주소 각 공방 주소 참조
사업자 등록번호 0000 대표 공방유니언 전화 019-60105846 팩스 0000 이메일 gongbangunion@gmail.com
통신판매업신고번호 0000 개인정보관리책임자 공방유니언
Copyright © 2017 공방유니언. All Rights Reserved.