제조공정
이 튜토리얼에서는 아두이노 기반 3D 와이어 벤딩 머신을 만드는 방법을 보여드립니다. 이는 기계, 전기, 컴퓨터 공학이 결합된 전형적인 메카트로닉스 시스템으로, 공학도나 메카트로닉스 입문자에게 흥미로운 프로젝트라 생각합니다.
아래 비디오를 시청하거나 작성된 튜토리얼을 읽어보세요.
이 3D 와이어 벤딩 머신의 작동 원리입니다. 먼저 와이어가 일련의 롤러(스트레이트너)를 통과합니다. 스테퍼 모터로 와이어를 벤딩 메커니즘으로 정밀하게 공급하는데, 벤딩 메커니즘도 스테퍼 모터와 작은 서보를 사용합니다.

또 다른 스테퍼 모터(Z축)가 있어 벤딩 메커니즘이 와이어 주위를 회전하며 3차원 형상을 만들 수 있습니다. 물론 머신의 두뇌는 아두이노 보드이며, 다른 전자부품들과 함께 맞춤 설계된 PCB에 장착됩니다.

프로그램으로는 별, 정육면체, 간단한 스탠드 등 다양한 형상 제작용 커스텀 함수들과, 시리얼 모니터로 명령어를 입력해 수동으로 와이어 형상을 만드는 수동 모드를 만들었습니다.
여느 때처럼 3D 모델링 소프트웨어로 프로젝트를 설계했습니다. 아래에서 3D 모델을 다운로드할 수 있습니다.

설계 영감: YouTube 영상
이 3D 모델은 Thangs에서 찾아 다운로드하거나 브라우저에서 탐색할 수 있습니다.

3D 프린팅용 STL 파일: 다운로드
기어, 베어링 필로우 블록, 샤프트 커플러 등 일부 부품은 3D 프린터로 제작했습니다. 이 부품들의 STL 파일은 위 파일에서 다운로드 가능합니다.
새 3D 프린터 Creality CR-10이 훌륭한 품질로 부품을 출력했습니다. 이 3D 프린터 링크도 참고하세요.

나머지 부품은 MDF와 합판으로 제작했습니다. 3D 모델에서 모든 치수를 가져와 원형 톱으로 재단했습니다. 8mm MDF와 18mm 합판을 사용했습니다. 준비된 부품으로 조립을 시작합니다. 먼저 두 장의 MDF 플레이트와 4개의 합판 기둥으로 베이스를 만듭니다. 목공 본드와 나사로 고정하고, 90도 앵글 클램프로 패널을 고정했습니다. 무선 드릴로 파일럿 홀을 뚫고 카운터싱크 후 3mm 나사를 조였습니다. 모든 패널을 같은 방식으로 조립했고, 일부에는 F-클램프도 사용했습니다.

이 시점에서 레일 시스템을 만듭니다. 알루미늄 튜브를 금속 손톱으로 잘라 사용합니다. 수평 레일 튜브 직경 16mm, 수직 레일 튜브 직경 20mm. 18mm 두꺼운 원목 판에 포스너 비트로 튜브용 슬롯을 내고 튜브를 고정합니다.

수평 레일은 27cm 튜브 2개, 수직 레일은 45cm 튜브 3개로 구성합니다.
슬라이더 제작 방법입니다. 21x21cm 목재 판에 8mm 구멍을 뚫습니다.

8mm 나사봉을 구멍에 통과시키고 와셔/너트로 22mm 베어링을 고정합니다. 수평 슬라이더는 같은 방식이나 16mm 외경 베어링을 사용합니다.
슬라이더를 튜브 레일 사이에 끼워보니 좀 헐거웠습니다. 두 레일 간격을 좁혀 해결했습니다. 튜브 슬롯을 확장하고 튜브에 수직 슬롯을 낸 후 나사봉으로 두 튜브 레일을 당겨 간격을 좁혔습니다. 이후 슬라이더가 헐겁지 않고 잘 작동했습니다.

이 시점에서 다른 요소를 추가하기 위해 레일을 분해해야 했습니다. 레일 좌측에 5mm 볼트를 달아 수평 타이밍 벨트용 풀리와 좌측 수직 레일을 슬라이드할 베어링 2개를 부착했습니다.

우측에는 수평 이동용 스테퍼 모터를 장착합니다. 모터를 8mm MDF 판에 고정하고 지지목과 슬롯 부분을 추가한 후 수직 슬라이더에 목공 본드와 나사 2개로 고정합니다.

수평 슬라이더에 컨테이너를 장착합니다. 작은 목재 조각을 목공 본드로 접합해 만들었습니다. 레일 시스템 조립 준비 완료. 레일 슬롯에 에폭시를 바르고 레일 측면에 추가 목재 판을 대 전체 레일 시스템을 더 견고하게 만들었습니다.

조립체를 수직 레일 사이에 끼우고 고정합니다. 슬라이더와 레일 시스템 최종 결과물이 훌륭하게 작동합니다.

수평 타이밍 벨트를 설치합니다. 필요한 길이 측정 후 재단, 지퍼 타이로 슬라이더에 고정. 수직 슬라이더용 스테퍼 모터를 기계 상단에 MDF 조각과 볼트로 고정. 하단에 풀리를 달고 같은 방식으로 타이밍 벨트 설치.

이제 와이어 벤딩 메커니즘을 만듭니다. MDF 조각에 벤더 모터를 장착합니다. 가진 MDF 조각이 가공이 필요해 손톱, 대패톱, 줄로 원하는 모양을 만들었습니다. 38mm 홀쏘로 큰 스테퍼(NEMA 23)용 구멍을 내고, 다른 부품 장착용 작은 구멍들도 뚫었습니다.

NEMA 23 스테퍼를 M4 볼트/너트로 고정하고 출력 샤프트에 모듈 2.5, 18톱니 기어를 장착. 이 기어는 30톱니 큰 기어와 맞물리는데, 이 큰 기어는 MG996R 서보 장착용 통합 플레이트가 있는 커스텀 설계 기어입니다. 이 서보가 랙 앤 피니언 메커니즘(기어에서 핀이 나와 와이어를 벤딩)을 움직입니다. 5분 에폭시로 기어에 베어링을 고정하고 랙에 구리 튜브 조각을 달아 벤딩 시 접촉면으로 사용합니다.

에폭시 경화 후 두 기어를 M8 볼트/너트로 고정해 맞물리게 합니다. 랙과 서보를 장착하고 서보 패키지 제공 나사로 고정. 피니언 기어를 서보 라운드 혼에 M3 볼트/너트 2개로 고정. 혼을 서보에 장착하면 벤딩 메커니즘 완성.


이제 벤더를 Z축에 부착합니다. 3D 프린트한 샤프트 클램프 2개 사용. 클램프를 벤더 플레이트에 M6 볼트/너트로 고정하고 Z축에 끼웁니다. 너트 2개 제자리에 넣고 볼트로 클램프를 샤프트에 조입니다. 이제 모든 움직이는 부품이 제대로 작동합니다.

작은 디테일 2개 추가: 와이어가 나오는 샤프트에 3mm 노즐, 벤더 하단에 마이크로 리미트 스위치(벤더 초기 위치 설정용).


3D 와이어 벤딩 머신이 거의 완성되었습니다. '거의'라고 한 건 이제 전자부품을 연결하고 프로그래밍해 생명을 불어넣어야 하기 때문입니다.

세 개의 스테퍼 모터를 세 개의 DRV8825 스테퍼 드라이버로 제어합니다. 스테퍼와 전체 프로젝트 전원용으로 최소 3A 정격의 12V 파워 서플라이를 사용합니다.
서보 전원은 아두이노 5V를 쓸 수 있지만 MG996R 서보가 전력 소모가 커 아두이노 5V 레귤레이터가 감당 못 할 수 있습니다. 그래서 별도 5V 전압 레귤레이터 LM7805를 사용했는데 이 프로젝트엔 충분합니다. 벤더용 리미트 스위치는 풀업 저항과 함께 아두이노 디지털 핀에 연결.
배선 정리를 위해 EasyEDA로 맞춤 PCB를 설계했습니다. 연결이 많아 양면 기판을 사용해 정리했습니다. 스테퍼 해상도 선택 핀, 추가 리미트 스위치 연결, 아두이노에서 나오는 추가 디지털/아날로그 핀도 제공합니다.

거버 파일 생성 후 JLCPCB(이 프로젝트 후원사)에 주문.

거버 파일 업로드 후 뷰어 검토, 원하는 속성 선택 후 주문. 첫 주문 시 10장 $2.

도착한 PCB. 품질 훌륭, 설계와 일치.

전자부품을 PCB에 장착합니다. 핀 헤더를 납땜해 부품 탈부착 쉽게 만듭니다. 커패시터, 저항, 전압 레귤레이터, 터미널 블록 같은 소형 부품은 직접 납땜.

스테퍼 드라이버와 아두이노 장착. 파워 플러그와 스위치를 터미널 블록에 연결. 스테퍼 모터 케이블을 한쪽엔 모터, 다른 쪽엔 PCB에 연결. 서보는 디지털 핀 2번, LM7805 5V로 전원 공급. 마지막으로 드라이버 아래 해상도 핀 연결로 스테퍼 해상도 선택.

16스텝 해상도(마이크로스테핑 1/16) 사용하려 사진과 같이 오른쪽 핀들을 연결했습니다(가운데가 아닌). 전자부품 준비 완료, 이제 와이어 벤딩 머신 프로그래밍으로 넘어갑니다.
코드가 길어 섹션별로 설명하고 마지막에 전체 코드 제공.
스테퍼 제어용 Mike McCauley의 AccelStepper 라이브러리와 서보 제어용 Servo 라이브러리 포함. 스테퍼 연결 핀과 필요 변수 정의.
#include <AccelStepper.h>
#include <Servo.h>
#define limitSwitch 11
// 스테퍼 모터 및 핀 정의 (Type:driver, STEP, DIR)
AccelStepper feederStepper(1, 5, 6);
AccelStepper zAxisStepper(1, 7, 8);
AccelStepper benderStepper(1, 9, 10);
Servo servo01;
String dataIn = "";
String manualStatus = "";
int count = 0;
int dist;
setup에서 서보/벤딩 핀 초기 위치 설정, 리미트 스위치로 벤더 기어 초기 위치 설정(호밍). 스테퍼가 스위치 쪽으로 회전하다 스위치 눌리면 0 스텝부터 카운트해 0도 위치(벤딩 준비)로 이동.
void setup() {
Serial.begin(9600);
pinMode(limitSwitch, INPUT_PULLUP);
servo01.attach(2);
servo01.write(40); // 초기 위치, 벤딩 핀 업
// 스테퍼 최대 속도
feederStepper.setMaxSpeed(2000);
zAxisStepper.setMaxSpeed(2000);
benderStepper.setMaxSpeed(2000);
// 호밍
while (digitalRead(limitSwitch) != 0) {
benderStepper.setSpeed(1200);
benderStepper.runSpeed();
benderStepper.setCurrentPosition(0); // 스위치 눌리면 위치를 0으로
}
delay(40);
// 리미트 스위치에서 1400 스텝 이동해 시작 위치로
while (benderStepper.currentPosition() != -1400) {
benderStepper.setSpeed(-1200); // 음수면 반시계 방향
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
}
loop에서 시리얼 모니터 명령 대기. "manual" 입력 시 수동 벤딩 모드, "star" 입력 시 star() 함수 실행해 자동으로 별 모양 제작 등.
void loop() {
String mode = Serial.readString();
if (mode.startsWith("manual")) { manual(); }
if (mode.startsWith("star")) { star(); }
if (mode.startsWith("cube")) { cube(); }
if (mode.startsWith("stand")) { stand(); }
}
void star() {
while (count != 5) { // 별은 5개 포인트
int feed = 38; // mm
int feedDistance = feed * 48; // mm를 스텝 수로 변환(48 상수)
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.currentPosition(0); // 현재 위치 0으로 리셋
servo01.write(40); // 벤더 핀 업
delay(200);
int angleConst = 18; // 각도 상수
// 와이어 52도 벤딩
while (benderStepper.currentPosition() != -52 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// 초기 위치로 52도 복귀
while (benderStepper.currentPosition() != 52 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// 같은 길이 다시 공급
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
servo01.write(130); // 벤더 핀 다운
delay(200);
// 반대 방향 벤딩용 새 초기 위치
while (benderStepper.currentPosition() != -42 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(200);
servo01.write(40); // 벤더 핀 업
delay(200);
while (benderStepper.currentPosition() != 105 * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(50);
while (benderStepper.currentPosition() != -63 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
delay(100);
servo01.write(130);
benderStepper.setCurrentPosition(0);
count++;
}
}
while 루프 5회 실행(별 5개 포인트). 공급 길이(feed) 설정 후 48 곱해 스텝 수로 변환. run() 함수로 피더 모터 회전, setSpeed()로 속도 설정. 목표 거리 도달 시 정지 후 현재 위치 0으로 리셋.
int feed = 38; // mm
int feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
다음으로 와이어 52도 벤딩. 위와 유사하게 angleConst 곱해 목표 스텝 계산. 도달 시 정지, 위치 0 리셋, 반대 방향 같은 스텝 수 실행해 초기 위치 복귀.
// 와이어 52도 벤딩
while (benderStepper.currentPosition() != -52 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// 초기 위치로 52도 복귀
while (benderStepper.currentPosition() != 52 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
다시 같은 길이 공급, 핀 다운으로 벤더를 반대 방향 벤딩용 새 초기 위치로 이동. 핀 업 후 반대 방향으로 105도 벤딩. 명령을 5회 반복해 별 모양 완성.
위와 같은 방식으로 정육면체 등 원하는 어떤 형상이든 만들 수 있습니다. 수동 모드도 원리는 같으나 시리얼 모니터 명령 읽기 라인 추가. 예: 와이어 공급 "f" + 거리(mm), 벤딩 "b" + 각도(도), Z축 회전 "z" + 각도(도).
if (dataIn.startsWith("f")) {
dataInS = dataIn.substring(1, dataIn.length());
dist = dataInS.toInt();
Serial.print("Feed "); Serial.print(dist); Serial.println("mm wire.");
dist = dist * 48;
while (feederStepper.currentPosition() != dist) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
}
이게 제가 만든 프로그램 작동 방식이지만, 물론 코딩 방법은 다양합니다. 전체 아두이노 코드입니다.
/* Arduino 3D Wire Bending Machine by Dejan Nedelkovski www.HowToMechatronics.com
Library - AccelStepper by Mike McCauley: https://www.airspayce.com/mikem/arduino/AccelStepper/index.html */
#include <AccelStepper.h>
#include <Servo.h>
#define limitSwitch 11
AccelStepper feederStepper(1, 5, 6);
AccelStepper zAxisStepper(1, 7, 8);
AccelStepper benderStepper(1, 9, 10);
Servo servo01;
String dataIn = "";
String manualStatus = "";
int count = 0;
int dist;
void setup() {
Serial.begin(9600);
pinMode(limitSwitch, INPUT_PULLUP);
servo01.attach(2);
servo01.write(40);
feederStepper.setMaxSpeed(2000);
zAxisStepper.setMaxSpeed(2000);
benderStepper.setMaxSpeed(2000);
while (digitalRead(limitSwitch) != 0) {
benderStepper.setSpeed(1200);
benderStepper.runSpeed();
benderStepper.setCurrentPosition(0);
}
delay(40);
while (benderStepper.currentPosition() != -1400) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
}
void loop() {
String mode = Serial.readString();
if (mode.startsWith("manual")) { manual(); }
if (mode.startsWith("star")) { star(); }
if (mode.startsWith("cube")) { cube(); }
if (mode.startsWith("stand")) { stand(); }
}
void star() {
while (count != 5) {
int feed = 38;
int feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
servo01.write(40);
delay(200);
int angleConst = 18;
while (benderStepper.currentPosition() != -52 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 52 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
servo01.write(130);
delay(200);
while (benderStepper.currentPosition() != -42 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(200);
servo01.write(40);
delay(200);
while (benderStepper.currentPosition() != 105 * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(50);
while (benderStepper.currentPosition() != -63 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
delay(100);
servo01.write(130);
benderStepper.setCurrentPosition(0);
count++;
}
}
void cube() {
int feed = 40;
int feedDistance = feed * 48;
int angleConst = 16;
// Step 1
while (count != 3) {
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
count++;
}
count = 0;
// Step 2
while (zAxisStepper.currentPosition() != 88 * angleConst) {
zAxisStepper.setSpeed(500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
// Step 3
while (count != 2) {
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
count++;
}
count = 0;
// Step 4
while (zAxisStepper.currentPosition() != 85 * angleConst) {
zAxisStepper.setSpeed(500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
// Step 5
servo01.write(130);
delay(200);
while (benderStepper.currentPosition() != -42 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
while (count != 3) {
delay(100);
servo01.write(40);
delay(200);
// Step 6
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
count++;
}
count = 0;
}
void stand() {
int feed = 20;
int feedDistance = feed * 48;
int angleConst = 16;
// Step 1
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 2
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -70 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 70 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 3
feed = 80;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
// Step 4
servo01.write(130);
delay(200);
while (benderStepper.currentPosition() != -42 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
servo01.write(40);
delay(200);
while (benderStepper.currentPosition() != 108 * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -66 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
// Step 5
servo01.write(130);
delay(200);
// Step 6
feed = 80;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
servo01.write(40);
delay(200);
// Step 7
while (zAxisStepper.currentPosition() != -90 * angleConst) {
zAxisStepper.setSpeed(-500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
// Step 8
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 6 (반복)
feed = 45;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
// Step 10
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 48 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 11
while (zAxisStepper.currentPosition() != 90 * angleConst) {
zAxisStepper.setSpeed(500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
feed = 80;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
// Step 12
while (benderStepper.currentPosition() != 110 * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != -68 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
// Step 13
servo01.write(130);
delay(200);
feed = 80;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
servo01.write(40);
delay(200);
// Step 14
while (benderStepper.currentPosition() != -70 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 70 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 15
feed = 25;
feedDistance = feed * 48;
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
// Step 16
while (benderStepper.currentPosition() != -90 * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != 90 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
// Step 17
while (feederStepper.currentPosition() != feedDistance) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
}
void manual() {
int sign;
String dataInS;
int angle;
int angleConst;
Serial.println(" // MANUAL MODE //");
while (!dataIn.startsWith("end")) {
servo01.write(130);
delay(200);
dataIn = Serial.readString();
if (dataIn.startsWith("f")) {
dataInS = dataIn.substring(1, dataIn.length());
dist = dataInS.toInt();
Serial.print("Feed "); Serial.print(dist); Serial.println("mm wire.");
dist = dist * 48;
while (feederStepper.currentPosition() != dist) {
feederStepper.setSpeed(1200);
feederStepper.run();
}
feederStepper.setCurrentPosition(0);
delay(100);
}
if (dataIn.startsWith("b")) {
if (dataIn.charAt(1) == '-') {
dataInS = dataIn.substring(2, dataIn.length());
angle = dataInS.toInt();
Serial.print("Bend -"); Serial.print(angle); Serial.println(" degrees.");
angleConst = 16;
while (benderStepper.currentPosition() != -43 * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
servo01.write(40);
delay(200);
while (benderStepper.currentPosition() != angle * angleConst) {
benderStepper.setSpeed(700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != (-1) * angle * angleConst) {
benderStepper.setSpeed(-1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
servo01.write(130);
delay(200);
while (benderStepper.currentPosition() != 43 * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
} else {
dataInS = dataIn.substring(1, dataIn.length());
angle = dataInS.toInt();
Serial.print("Bend "); Serial.print(angle); Serial.println(" degrees.");
angleConst = 16;
servo01.write(40);
delay(200);
while (benderStepper.currentPosition() != (-1) * angle * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != angle * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
}
dataInS = dataIn.substring(2, dataIn.length());
angle = dataInS.toInt();
angleConst = 16;
while (benderStepper.currentPosition() != sign * angle * angleConst) {
benderStepper.setSpeed(-700);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
while (benderStepper.currentPosition() != sign * angle * angleConst) {
benderStepper.setSpeed(1200);
benderStepper.run();
}
benderStepper.setCurrentPosition(0);
delay(100);
}
// Z축 제어
if (dataIn.startsWith("z")) {
if (dataIn.charAt(1) == '-') {
dataInS = dataIn.substring(2, dataIn.length());
angle = dataInS.toInt();
Serial.print("Move Z-Axis -"); Serial.print(angle); Serial.println(" degrees.");
angleConst = 16;
while (zAxisStepper.currentPosition() != angle * angleConst) {
zAxisStepper.setSpeed(500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
} else {
dataInS = dataIn.substring(1, dataIn.length());
angle = dataInS.toInt();
Serial.print("Move Z-Axis "); Serial.print(angle); Serial.println(" degrees.");
angleConst = 16;
while (zAxisStepper.currentPosition() != (-1) * angle * angleConst) {
zAxisStepper.setSpeed(-500);
zAxisStepper.run();
}
zAxisStepper.setCurrentPosition(0);
delay(100);
}
}
manualStatus = dataIn;
}
}
마지막으로 와이어 벤딩 머신의 와이어 스트레이트닝 시스템이 제대로 작동하지 않는다는 점을 지적하고 싶습니다. 더 조이면 피더가 그립을 잃어 와이어가 움직이지 않기 때문입니다.

이 문제 해결을 위해 구리 튜브보다 강한 다른 재료를 쓰거나 다른 피더 시스템을 시도해보세요.
이상으로 튜토리얼을 마칩니다. 즐겁게 보셨고 새로운 걸 배우셨길 바랍니다. 질문은 댓글로, 제 아두이노 프로젝트 모음도 확인해보세요.
제조공정
부품 및 소모품 부품 수량 비고 나무 상자/크레이트 1 직접 제작 또는 구매 아두이노 우노 (Arduino UNO) 1 메인 컨트롤러 아다프루트 웨이브 쉴드 (Adafruit Wave Shield) 1 오디오 재생용 SainSmart 4채널 릴레이 모듈 1 모터, 조명, 연무기 제어 자동차 와이퍼 모터 1 뚜껑 개폐용 (12V, 고토크) 빨간 LED 크리스마스 라이트 (100구) 1 내부 조명 효과 연무기 (Smoke Machine) 1 연기 효과용 파워 앰프/스피커 1 사운드 출력용 프
이 튜토리얼에서는 아두이노 기반 CNC 폼 커팅 머신을 만드는 방법을 배웁니다. 단순하고 저렴한 재료, 일부 3D 프린팅 부품, 아두이노 컨트롤러로 만든 전형적인 DIY CNC 머신입니다. 다음 영상을 시청하거나 아래 작성된 튜토리얼을 읽어보세요. 개요 비트나 레이저 대신 이 머신의 주 도구는 열선(핫 와이어)입니다. 전류가 흐르면 매우 뜨거워지는 특수 저항선을 사용합니다. 열선이 폼을 통과하며 녹이거나 기화시켜 원하는 형상을 정밀하고 쉽게 얻을 수 있습니다. 쉽다고 말한 이유는 CNC 머신 제작이 사실 그리 어렵지 않기 때