이 프로젝트 정보
그림과 같이 두 개의 스크랩 DVD 드라이브를 정렬하십시오.
1. Arduino IDE 다운로드
2. 처리 IDE 다운로드
3. Arduino IDE를 열고 에서 다운로드한 코드를 로드합니다. 여기 .
4. 처리 IDE를 열고 에서 다운로드한 코드를 로드합니다. 여기 .
스크랩 DVD 드라이브를 열고 내부 이동 트레이를 제거합니다. 스테퍼 메커니즘이 있는 이 트레이는 X축 및 Y축 역할을 합니다. 기계를 조립하는 방법을 이해하려면 첨부된 사진을 참조하십시오. 빈 DVD 드라이브 케이스에 구멍을 뚫고 너트 볼트를 사용하여 각 DVD 케이스에 X축과 Y축을 장착합니다.
이제 서로 수직으로 놓습니다.
G 코드
이 CNC 기계와 호환되는 g-code 파일을 만들려면 Inkscape를 사용해야 합니다.
Inkscape는 Windows, Mac OS X 및 Linux에서 실행되는 전문적인 품질의 벡터 그래픽 소프트웨어입니다. 일러스트레이션, 아이콘, 로고, 다이어그램, 지도 및 웹 그래픽과 같은 다양한 그래픽을 만들기 위해 전 세계의 디자인 전문가와 애호가가 사용합니다. Inkscape는 W3C 개방형 표준 SVG(Scalable Vector Graphics)를 기본 형식으로 사용하며 무료 및 오픈 소스 소프트웨어입니다. 여기에서 Inkscape를 다운로드하여 설치하십시오.
(중요 :0.48.5 버전 다운로드) 이제 이미지를 g-code 파일로 내보낼 수 있는 애드온을 설치해야 합니다. 이 추가 기능은 설치 정보와 함께 여기에서 찾을 수 있습니다.
G-code 파일 생성 방법은 유튜브 영상을 참고해주세요.
<울> 처리 IDE에 gctrl 파일을 업로드하고 처리 창에서 PLAY 버튼을 클릭합니다.
<울> 먼저 'p'를 눌러 통신 포트를 선택하세요.
<울> 원하는 경우 키보드에서 1,2 또는 3 버튼을 눌러 조그 속도를 설정할 수 있습니다.
<울> 'g'를 눌러 G 코드 파일을 로드합니다.
<울> G 코드 파일을 선택하여 Enter 키를 누르는 즉시 시스템이 플롯할 준비가 된 것입니다.
이제 플로터가 준비되었습니다. 일부 준비된 G 코드 파일 다운로드 링크:
<울> https://www.dropbox.com/s/bazynxife4k1trv/Hisoka.gcode?dl=0
<울> https://www.dropbox.com/s/h6bkdr5lhegbj6a/papay.gcode?dl=0
<울> https://www.dropbox.com/s/ueku5ckt6m4cmg4/spong1.gcode?dl=0
주목 해 주셔서 감사합니다! 완전한 그림을 보려면 이 링크를 방문하십시오.
기계를 라이브로 볼 수 있는 비디오:
섹션> <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드"> 코드
<울> Arduino CNC 코드
코드 처리
Arduino CNC 코드Arduino
이 코드를 Arduino에 업로드하십시오.#include #include #define LINE_BUFFER_LENGTH 512char STEP =MICROSTEP;// 상하 서보 위치 const int penZUp =95;const int penZDown =83; // PWM 핀 10번의 서보 const int penServoPin =10;// DVD 스테퍼에 적합해야 하지만 여기에서는 그다지 중요하지 않습니다. const int stepsPerRevolution =48; // 서보를 제어하기 위한 서보 객체 생성 Servo penServo; // L293D H-bridgeAF_Stepper용 Arduino 핀을 사용하여 X축 및 Y축용 스테퍼를 초기화합니다. myStepperY(stepsPerRevolution,1); AF_Stepper myStepperX(stepsPerRevolution,2); /* 구조체, 전역 변수 */struct point { float x; 플로트 y; 플로트 z; };// plotheadstruct point actuatorPos;// 도면 설정은 OK여야 합니다. 스케치를 테스트하여 100단계를 이동합니다. 선의 길이를 측정합니다. // mm당 걸음 수를 계산합니다. 여기에 입력하십시오.float StepsPerMillimeterX =100.0;float StepsPerMillimeterY =100.0;// 로봇 한계를 mm 단위로 그리기// 시작하는 것이 좋습니다. 잘 보정하면 최대 50mm까지 올라갈 수 있습니다. float Xmin =0;float Xmax =40;float Ymin =0;float Ymax =40;float Zmin =0;float Zmax =1;float Xpos =Xmin;float Ypos =Ymin;float Zpos =Zmax; // 디버그 출력을 얻으려면 true로 설정합니다.boolean verbose =false;// 해석 필요 // G1 이동// G4 P300(150ms 대기)// M300 S30(펜다운)// M300 S50(펜업)/ / (// 다른 명령을 모두 버리십시오!/********************** * void setup() - 초기화 ******* ****************/void setup() { // 설정 Serial.begin( 9600 ); penServo.attach(penServoPin); penServo.write(penZUp); delay(100); // 필요한 경우 감소 myStepperX.setSpeed(600); myStepperY.setSpeed(600); // 초기 기본 위치로 설정 및 이동 // 미정 // 알림!!! Serial.println("미니 CNC 플로터가 살아있고 킥! "); Serial.print("X 범위는 "); Serial.print(Xmin); Serial.print("에서 "); Serial.print(Xmax); Serial.println(" mm."); Serial. print("Y 범위는 "); Serial.print(Ymin); Serial.print("에서 "); Serial.print(Ymax); Serial.println(" mm."); }/***** ***************** * 무효 루프() - 메인 루프 ***********************/void 루프() { 지연(100); 문자 라인[ LINE_BUFFER_LENGTH ]; 문자 c; int 라인 인덱스; bool lineIsComment, lineSemiColon; 라인 인덱스 =0; 라인세미콜론 =거짓; lineIsComment =거짓; while (1) { // 직렬 수신 - 대부분 Grbl에서, 세미콜론 지원 추가 while ( Serial.available()>0 ) { c =Serial.read(); if (( c =='\n') || (c =='\r') ) { // 줄 끝에 도달함 if ( lineIndex> 0 ) { // 줄이 완료되었습니다. 그럼 실행! 라인[ lineIndex ] ='\0'; // 문자열 종료 if (verbose) { Serial.print( "Received :"); Serial.println(줄); } processIncomingLine( 라인, 라인 인덱스 ); 라인 인덱스 =0; } else { // 비어 있거나 주석 행. 블록 건너뛰기. } lineIsComment =거짓; 라인세미콜론 =거짓; Serial.println("확인"); } else { if ( (lineIsComment) || (lineSemiColon) ) { // 모든 주석 문자를 버립니다. if ( c ==')' ) lineIsComment =false; // 주석 끝. 이력서 라인. } else { if ( c <=' ' ) { // 공백 및 제어 문자를 버립니다. } else if ( c =='/' ) { // 블록 삭제가 지원되지 않습니다. 문자를 무시합니다. } else if ( c =='(' ) { // 주석 플래그를 활성화하고 ')' 또는 EOL 때까지 모든 문자를 무시합니다. lineIsComment =참; } else if ( c ==';' ) { lineSemiColon =true; } else if ( lineIndex>=LINE_BUFFER_LENGTH-1 ) { Serial.println( "오류 - lineBuffer 오버플로" ); lineIsComment =거짓; 라인세미콜론 =거짓; } else if ( c>='a' &&c <='z' ) { // 대문자 소문자 line[ lineIndex++ ] =c-'a'+'A'; } else { 라인[ lineIndex++ ] =c; } } } }} 무효 processIncomingLine( char* line, int charNB ) { int currentIndex =0; 문자 버퍼[ 64 ]; // 64가 1개의 매개변수에 충분하기를 바랍니다. struct point newPos; newPos.x =0.0; newPos.y =0.0; // 해석이 필요함 // 이동을 위한 G1 // G4 P300(150ms 대기) // G1 X60 Y30 // G1 X30 Y50 // M300 S30(펜다운) // M300 S50(펜업) // ( // 다른 모든 명령을 버리십시오! break; case 'G':buffer[0] =line[ currentIndex++ ]; // /!\ Dirty - 2자리 명령에서만 작동 // buffer[1] =line[ currentIndex++ ]; // buffer[2] =' \0'; buffer[1] ='\0'; switch ( atoi( buffer ) ){ // G 명령 선택 case 0:// G00 &G01 - 이동 또는 빠른 이동. 여기도 마찬가지 case 1:// /! \ Dirty - X가 Y 앞에 있다고 가정합니다. char* indexX =strchr( line+currentIndex, 'X' ); // 문자열에서 X/Y 위치를 가져옵니다(있는 경우) char* indexY =strchr( line+currentIndex, 'Y ' ); if ( indexY <=0 ) { newPos.x =atof( indexX + 1); newPos.y =액추에이터Pos.y; } else if ( indexX <=0 ) { newPos.y =atof( indexY + 1); newPos.x =액츄에이터Pos.x; } else { newPos.y =atof(인덱스Y + 1); indexY ='\0'; newPos.x =atof( indexX + 1); } drawLine(newPos.x, newPos.y); // Serial.println("확인"); 액츄에이터Pos.x =newPos.x; 액츄에이터Pos.y =newPos.y; 부서지다; } 부서지다; case 'M':buffer[0] =line[ currentIndex++ ]; // /!\ Dirty - 3자리 명령에서만 작동합니다. buffer[1] =line[ currentIndex++ ]; 버퍼[2] =라인[ 현재 인덱스++ ]; 버퍼[3] ='\0'; switch ( atoi( buffer ) ){ case 300:{ char* indexS =strchr( line+currentIndex, 'S' ); float Spos =atof( indexS + 1); // Serial.println("확인"); if (Spos ==30) { penDown(); } if (Spos ==50) { penUp(); } 부서지다; } case 114:// M114 - 보고 위치 Serial.print( "절대 위치 :X =" ); Serial.print(actuatorPos.x); Serial.print( " - Y =" ); Serial.println(actuatorPos.y); 부서지다; 기본값:Serial.print( "명령이 인식되지 않음 :M"); Serial.println(버퍼); } } }}/******************************** * (x0;y0)에서 ( x1;y1). * https://www.marginallyclever.com/blog/2013/08/how-to-build-an-2-axis-arduino-cnc-gcode-interpreter/의 Bresenham 알고리즘 * int (x1;y1) :시작 좌표 * int (x2;y2) :끝 좌표 **********************************/void drawLine(float x1 , float y1) { if (verbose) { Serial.print("fx1, fy1:"); Serial.print(x1); Serial.print(","); Serial.print(y1); Serial.println(""); } // 명령을 제한 내로 가져옵니다. if (x1>=Xmax) { x1 =Xmax; } if (x1 <=Xmin) { x1 =Xmin; } if (y1>=Ymax) { y1 =Ymax; } if (y1 <=Ymin) { y1 =Ymin; } if (자세한 정보) { Serial.print("Xpos, Ypos:"); Serial.print(Xpos); Serial.print(","); Serial.print(Ypos); Serial.println(""); } if (자세한 정보) { Serial.print("x1, y1:"); Serial.print(x1); Serial.print(","); Serial.print(y1); Serial.println(""); } // 좌표를 단계로 변환 x1 =(int)(x1*StepsPerMillimeterX); y1 =(int)(y1*StepsPerMillimeterY); float x0 =Xpos; float y0 =Ypos; // 좌표의 변화를 알아봅시다. long dx =abs(x1-x0); 긴 dy =abs(y1-y0); 정수 sx =x0 dy) { for (i=0; i=dx) { over-=dx; myStepperY.onestep(sy,STEP); } 지연(StepDelay); } } else { for (i=0; i=dy) { over-=dy; myStepperX.onestep(sx,STEP); } 지연(StepDelay); } } if (상세) { Serial.print("dx, dy:"); Serial.print(dx); Serial.print(","); Serial.print(dy); Serial.println(""); } if (verbose) { Serial.print("(")로 이동; Serial.print(x0); Serial.print(","); Serial.print(y0); Serial.println(")"); } // 다음 줄이 제출되기 전 지연 delay(LineDelay); // 위치 업데이트 Xpos =x1; Ypos =y1;}// penvoid penUp() { penServo.write(penZUp); 지연(펜지연); Zpos=Zmax; 디지털 쓰기(15, 낮음); 디지털 쓰기(16, 높음); if (verbose) { Serial.println("펜 업!"); } }// penvoid penDown() { penServo.write(penZDown); 지연(펜지연); Zpos=Zmin; 디지털 쓰기(15, 높음); 디지털 쓰기(16, 낮음); if (verbose) { Serial.println("펜 아래로."); } }
처리 코드자바
이 코드를 Processing IDE에 업로드합니다.import java.awt.event.KeyEvent;import javax.swing.JOptionPane;import processing.serial.*;Serial port =null;// 운영 체제에 적합한 라인을 선택하고 수정합니다. / 대화형 포트를 사용하려면 null로 둡니다(프로그램에서 'p' 누르기)String portname =null;//String portname =Serial.list()[0]; // Mac OS X//문자열 포트 이름 ="/dev/ttyUSB0"; // Linux//문자열 포트 이름 ="COM6"; // Windowsboolean 스트리밍 =false;float speed =0.001;String[] gcode;int i =0;void openSerialPort(){ if (portname ==null) return; if (포트 !=null) port.stop(); 포트 =새 직렬(이, 포트 이름, 9600); port.bufferUntil('\n');}void selectSerialPort(){ String result =(String) JOptionPane.showInputDialog(frame, "아두이노 보드에 해당하는 직렬 포트를 선택하세요.", "직렬 포트 선택", JOptionPane. QUESTION_MESSAGE, null, Serial.list(), 0); if (결과 !=null) { 포트 이름 =결과; 오픈시리얼포트(); }} 무효 설정(){ 크기(500, 250); openSerialPort();}무승부 그리기(){ 배경(0); 채우기(255); 정수 y =24, dy =12; text("지침", 12, y); y +=다이; text("p:직렬 포트 선택", 12, y); y +=다이; text("1:조그당 0.001인치(1mil)로 속도 설정", 12, y); y +=다이; text("2:조그당 0.010인치(10mil)로 속도 설정", 12, y); y +=다이; text("3:조그당 속도를 0.100인치(100mil)로 설정합니다.", 12, y); y +=다이; text("화살표 키:x-y 평면에서 조그", 12, y); y +=다이; text("페이지 업 &페이지 다운:z축으로 조그", 12, y); y +=다이; text("$:grbl 설정 표시", 12, y); y+=다이; text("h:집에 가세요", 12, y); y +=다이; text("0:0 머신(현재 위치로 홈 설정)", 12, y); y +=다이; text("g:g 코드 파일 스트리밍", 12, y); y +=다이; text("x:스트리밍 g-코드 중지(즉시 적용되지 않음)", 12, y); y +=다이; y =높이 - dy; text("현재 조그 속도:" + 속도 + " 단계당 인치", 12, y); y -=다이; text("현재 직렬 포트:" + 포트 이름, 12, y); y -=dy;}무효 keyPressed(){ if (key =='1') 속도 =0.001; if (키 =='2') 속도 =0.01; if (키 =='3') 속도 =0.1; if (!streaming) { if (keyCode ==LEFT) port.write("G91\nG20\nG00 X-" + 속도 + " Y0.000 Z0.000\n"); if (keyCode ==RIGHT) port.write("G91\nG20\nG00 X" + 속도 + " Y0.000 Z0.000\n"); if (keyCode ==UP) port.write("G91\nG20\nG00 X0.000 Y" + 속도 + " Z0.000\n"); if (keyCode ==DOWN) port.write("G91\nG20\nG00 X0.000 Y-" + 속도 + " Z0.000\n"); if (keyCode ==KeyEvent.VK_PAGE_UP) port.write("G91\nG20\nG00 X0.000 Y0.000 Z" + 속도 + "\n"); if (keyCode ==KeyEvent.VK_PAGE_DOWN) port.write("G91\nG20\nG00 X0.000 Y0.000 Z-" + 속도 + "\n"); if (키 =='h') port.write("G90\nG20\nG00 X0.000 Y0.000 Z0.000\n"); if (키 =='v') port.write("$0=75\n$1=74\n$2=75\n"); //if (키 =='v') port.write("$0=100\n$1=74\n$2=75\n"); if (키 =='') port.write("$3=10\n"); if (키 =='e') port.write("$16=1\n"); if (키 =='d') port.write("$16=0\n"); if (키 =='0') openSerialPort(); if (키 =='p') selectSerialPort(); if (키 =='$') port.write("$$\n"); } if (!스트리밍 &&키 =='g') { gcode =null; 나는 =0; 파일 파일 =null; println("파일 불러오기..."); selectInput("처리할 파일을 선택하세요:", "fileSelected", 파일); } if (key =='x') 스트리밍 =false;}void fileSelected(파일 선택) { if (selection ==null) { println("창이 닫혔거나 사용자가 취소를 눌렀습니다."); } else { println("사용자 선택" + selection.getAbsolutePath()); gcode =loadStrings(selection.getAbsolutePath()); if (gcode ==null) 반환; 스트리밍 =사실; 개울(); }}void stream(){ if (!streaming) return; while (true) { if (i ==gcode.length) { 스트리밍 =false; 반품; } if (gcode[i].trim().length() ==0) i++; 그렇지 않으면 휴식; } println(g코드[i]); port.write(gcode[i] + '\n'); i++;}무효 serialEvent(시리얼 p){ 문자열 s =p.readStringUntil('\n'); println(s.trim()); if (s.trim().startsWith("ok")) 스트림(); if (s.trim().startsWith("오류")) 스트림(); // XXX:정말요?}
섹션> 회로도
그림과 같이 모든 구성 요소를 연결하십시오