2018년 10월 28일 일요일

gcode Slicer 만들어 보기 - 일명 구라(Gura) 슬라이서

자주가는 3D 프린터 카페에서 무한 출력되는 3D 프린터의 gcode slicer 를 어떻게 만들지에 대해 궁금하다는 글이 올라왔다.

궁금하면 한번 해 봐야 하는 성격 때문에, 급 삘~을 받아 24시간 전력 질주를 한번 해 봤다.
blog 에 적지 않고 직접 카페에 글을 써서 경어체로 적었는데 6편으로 나눠 적은 글을 이곳에 모아 둔다.

============================1편====================================



영상의 45도 기울어진 Z 축을 보면서 생각을 해 보니,
X/Y 축 이동은 동일한데, Z 축은 올라갈때 마다 Y 축이 - 되어 가는 것처럼 보였습니다.
그럼 얼마나 Y 축이 줄어들까 생각하는 중에

언제인지 한번 배웠던 이 그림이 떠 올랐습니다.

그렇단 얘기는 ...


이렇다는 거겠죠? ㅋㅋ. 산수에 약하니.. 일단 제 생각을 쭈욱 써 내려 가겠습니다.
틀린 부분이 있으면 댓글로 알려 주세요~~

이 도표도 배운 기억이.. 아니 외운 기억이.. 어렴풋합니다.

그렇다면 Y 는??
Y = Z * 0.707
겠죠?

Z 가 1 mm 움직이면 Y 는 0.707 mm 만큼 줄어 든다고 생각할 수 있을것 같습니다.
그렇다면 똑바른 Z 를 쌓아가려면 Z 가 1 mm 올라 갈 때 마다 Y 를 0.707 mm 만큼 증가 시켜줘야 할 것 같습니다.
맞을까요??

일단 이 이론이 맞는지 카페 회원분들께서 검증을 해 주시면, 2편에서 이 이론에 맞는 슬라이서를 제작해 보겠습니다.

============================2편====================================

1편에서 충분한 시간을 거쳐서 검증을 받아야 하는게 마땅하지만,
주말이 지나기 전에 마무리 하고 싶어서 무모하지만 일단 2편을 진행해 보겠습니다.
검증은 계속해서 해 주시면 공부 하면서 정정해 나가겠습니다.



슬라이서를 만들어 보기로 마음을 먹었으니, 일단 적을 알고 나를 알아야 백전백승이라는 말을 곱씹으며 슬라이서를 이해해 보기로 합니다. 저는 무엇을 이해 할때 정의 부터 확인하는 습관이 있습니다. 용어의 정의를 확인할 때는 Wikipedia 만한게 없죠.

그럼 위키 내용을 옮겨 보겠습니다. (https://en.wikipedia.org/wiki/Slicer_(3D_printing))
우리에겐 구글 번역신도 있으니까요~

The slicer, also called slicing software, is a computer software used in the majority of 3D printing processes for the conversion of a 3D object model to specific instructions for the printer. 
"슬라이서 혹은 슬라이싱 소프트웨어는 주로 3D 물체를 프린터를 위한 특정 명령어로 변환하기 위해 3D 프린팅 과정에서 사용되는데  컴퓨터 소프트웨어이다."

여기 까지는 문제 없이 이해가 됩니다.

In particular, the conversion from a model in STL format to printer commands in g-code format in fused filament fabrication and other similar processes [1] [2] [3] [4] [5] .
"특히 FFF(필라멘트를 쌓아서 제작하는 방식) 및 기타 유사한 과정에서, STL 형식의 모델에서 gcode 형식의 프린터 명령으로 변환한다."

딱히 문제가 없는 설명이라 받아 들입니다. ㅋ, 그런데.. 이제 부터가 문제 입니다. ㅠㅜ

The slicer first divides the object as a stack of flat layers,
1. "슬라이서는 먼저 대상물을 평평한 층의 스택으로 나누고,"

followed by describe these layers as linear movements of the 3D printer extruder, fixation laser or equivalent.
2. "이 층들을 3D 프린터 압출기, 고정 레이저 또는 동급의 직선 운동으로 설명합니다."

All these movements, together with some specific printer commands like the ones to control the extruder temperature or bed temperature, are finally written in the g-code file, that can after be transferred to the printer.
3. "압출기 온도 나 베드 온도를 제어하는 ​​것과 같은 특정 프린터 명령과 함께 이러한 모든 동작은 최종적으로 프린터로 전송 된 후 g 코드 파일에 기록됩니다."


역시 여기까지가 한계인가.. 하면서 멍 때리며 문장을 읽고 또 읽어 봅니다.

1 단계 보스 >> 평평한 층의 스택.... 평평한 층의 스택...
가끔은 번역이 이난 영어자체로 이해하는게 더 직관적일 때가 많습니다. 지금이 딱 그때 인 것 같습니다.

도저히 유식한 말로 이해가 안되니.. 제 특유의 초딩 이해방식으로 전환 하겠습니다.
슬라이싱은 칼로 무를 써는 과정도 슬라이싱이라고 할 수 있으니까, 무를 썬 다음에는 얇은 무가 쌓입니다.
바로 이 얇은 무가 flat layer 일테고 에게 쌓이는걸 stack 이라고 하는 것 같습니다.

그렇다면 우리가 그렇게 많이 출력해 왔던 xyz Calibration 큐브를 예로 들어 생각하면 20 mm 높이의 큐브를 칼로 2 mm 단위로 썰어서 10개의 조각으로 쌓아두는 과정을 말하는 것 같습니다.

네네. 이정도면 1 단계  보스는 깬것 같습니다.. 그렇다면 2 단계 보스는?

2 단계 보스 >> 직선의 운동으로 설명합니다...
무를 썰었는데 선으로?????
음.. 선으로 만들려면 무 한장을 다시 칼로 채를 쳐야 할까요?
아니면 사과 깎듯이 돌려 깎아야 할까요?

음........... Cura 같은 슬라이서를 미리 써보지 않았다면 이 부분에서 포기했을 수도 있을 것 같습니다.
Cura 를 예로 들어서 생각하면, 무 채를 써는건 line infill 이고 사과 깎듯이 돌려 깎는것은 concentric infill 같습니다.
오호라.. 맞는지 틀리는지는 모르겠지만, 일단 제 방식으로 이해는 갑니다.

찝찝하지만 2 단계 보스는 퍼펙트로 깨지 못하고 3단계로 넘어 가겠습니다.

3 단계 보스 >> 온도 정보와 함께 gcode 로 저장한다.
ㅋㅋ. 이거야 뭐 껌이죠. 마지막 보스가 이리 쉬워서야... 3 단계 퍼펙트!

그럼 이 과정을 한 문장으로 정리하고 슬라이서 뜻 이해는 마무리 하겠습니다.
"무, 사과, 배 중에 맘에 드는 것을 골라서, 일정한 간격으로 썰고, 그것을 다시 채를 썰거나 돌려 깎아서 길게 늘어 늘어 놓고 설탕이나 시럽과 함께 접시에 담는다.

그럴싸 하쥬?

그럼 3편에서는 이 정의를 컴퓨터 프로그래밍으로 바꿔 보겠습니다.


============================3편====================================

2편에서 슬라이서 정의를 알아 봤습니다.

슬라이서의 정의를..
"무, 사과, 배 중에 맘에 드는 것을 골라서, 일정한 간격으로 썰고, 그것을 다시 채를 썰거나 돌려 깎아서 길게 늘어 늘어 놓고 설탕이나 시럽과 함께 접시에 담는다.
이렇게 했더랬죠.

우잉??  무슨 채소 과일 얘기냣!! 하시는 분들은 아래 2편을 살짝 읽어 주세요 ㅋㅋㅋ

그럼 2편에서 약속한대로 저 한줄을 코딩 해 보겠습니다.

음.... 음..... 그러니까.. 코딩....음.......... 어떻게 하지????? ㅠㅜ

큰소리를 쳤는데 막상 하려니 막막한 이 기분. 하지만 당황하지 않고~~ 찬찬히 생각을 해 봅니다.
저 한줄의 정의가 나오기 까지 3단계의 보스를 물리쳤습니다. 그렇다면 그 3 단계 보스를 물리치는 과정을 적어봅니다.
그 결과물을 '알고리즘' 이라고 부릅니다. 알고리즘을 컴퓨터가 아는 말로 적는게 '코딩' 이겠죠.

왜 갑자기 딴길로 새느냐?? 네.. 겁먹은거 맞습니다. ㅋㅋㅋㅋㅋ

흠흠.. 다시 한번 용기를 내서 도전!
원래 정식(FM) 대로 하려면 이쯤에서 프로그래밍 언어와 문법을 선택하고 설명하고 3단계 보스의 특징을 살펴보며
다분히 학구적인 설명을 해야 하나!! 전 항상 그래왔듯이 간단하게 초딩 코딩으로 가 보겠습니다.
제가 하는 초딩 코딩은, 검색과 상당히 유사합니다. 무엇을 모를때 전 '오케이 구글' 을 외칩니다.
그런데 코딩을 해야 할때는 '오케이 github' 를 외치죠. ㅎㅎㅎㅎ

저를 따라 github 로 이동하겠습니다. (https://github.com/). 그곳에서 'sclicing algorithm' 을 검색해 봅니다.
그럼 아래 그림처럼, 무려 63개나 되는 알고리즘과 관련된 코드가 검색이 됩니다.

ㅎㅎㅎ. 오픈소스의 힘이죠. 제가 맨바닥 부터 이것을 다 코딩해야 한다면, 전 2편에서 '해보겠습니다!' 라고 자신있게 말을 꺼낼 수가 없었겠죠.

음. 무엇을 먹어볼까....
전 이름이 100% 일치하는 Nehri/slicing_algorithm (https://github.com/Nehri/slicing_algorithm) 을 선택해 보겠습니다.


오호. 공부하기 딱 좋게 소스 코드가 딱 하나 입니다. (slicing.py)

그럼. 코드를 살짝 살펴 볼까요? 717 라인의 코드를 다 볼 필요 없고, main () 함수만 들여다 봐서 전체적인 흐름을 파악 합니다.

defmain():
filename = sys.argv[1]
layerThickness = float(sys.argv[2])
infillPercent = float(sys.argv[3])
triangles =fileToTriangles(filename)
slices_ = separateSlices(triangles, layerThickness)
supportSlices = generateSupports(triangles, layerThickness)
slices = list()
for s in slices_:
slices += [cleanPerimeter(s)]
for s in slices:
if s.isSurface:
s.infill = infill(s.perimeter, 1)
else:
s.infill = infill(s.perimeter, infillPercent)
for shape in supportSlices:
for s in range(len(shape)):
slices[s].support += infill(shape[s].perimeter,supportInfill)
writeGcode(slices,filename)
엇? 1편에서 보스는 3개 뿐이었는데, 여긴 보스가 좀 더 많네요?
fileToTriangles () >>> separateSlices () >>> generateSupports () >>> infill () >>> writeGcode()

오오!!! 그래도 1편에서 살펴본 보스와 성격이 비슷해 보입니다.
1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시과 함께 접시에 담는다)

깔끔합니다. 이 다섯 단계가 슬라이싱을 하는 대충대충 초딩 알고리즘 입니다.  2편의 목표는 달성 한거 맞죠??
그럼 이쯤에서 정리를 하겠습니다. ㅋ

그런데..........
뜬금 Triangle 은 뭘까요? 나머지는 다 한번씩 들어 봤었는데 삼각형은 갑자기 왜?
이 삼각형의 실체를 4편에서 알아 보겠습니다.

============================4편====================================


전편에서 슬라이싱 초딩 알고리즘을 정리 해 봤었습니다.

복습하면, 
1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시럽과 함께 접시에 담는다)

여기서 뜬금없이 나온 Triangle 에 대한 글을 이 편에서 이어 가 보겠습니다.


글을 이어 가는 과정에서 무한 출력 프린터의 슬라이서에 대한 정보를 Mini3DLab 님께서 공유해 주셔서
이 글을 다 쓰고 참고서 정답 맞춰 보는 식으로 확인해 볼 수 있는 좋은 정답지가 생긴것 같습니다.
ㅋ. .하지만 전 커닝은 안 하고 써 나가던 주제를 계속 이어가 보겠습니다~

main () 을 다시 한번 살펴 볼까요?

defmain():
filename = sys.argv[1]
layerThickness = float(sys.argv[2])
infillPercent = float(sys.argv[3])
triangles = fileToTriangles(filename)
이 프로그램을 실행 하는 예제는 이렇습니다.

$ python slicing.py cube.stl 0.2 0.2

첫번째 filename 은 cube.stl,
두번째 layerThinckness 는 출력 높이로 0.2 mm 로 넣습니다.
세번째 infillPercent 는 infill 을 20% 로 출력하기 위해 마찬가지로 0.2 를 넣습니다.

이 프로그램은 실행할때 넣는 옵션은 이 3개 지만, 이 외에도 설정값을 소소코드에서 바꿀 수 있습니다.
여튼 우리가 이번편에 삼각형 (fileToTriangles) 의 비밀을 알려면 cube.stl 이 열쇠가 됩니다.
말 그대로 file 을 Triangles 로 바꾼다는 의미인데, file 은 STL 파일이고 Triangles 는 삼각형들이라는 말이죠.

cube.stl 은 3D 프린터를 하는 사람들에게는 정말 익숙한 큐브 입니다. 그런데 이 파일을 직접 메모장으로 열어서 본 사람이 몇이나 있을까요? ㅋㅋ. 제가 그 몇 중에 한명이 한번 되어 보겠습니다.

일단 cube.stl 이 어떻게 생겼는지 볼까요? meshlab 으로 열어 본 모습입니다.


xyz 가 새겨진 cube 는 아니군요. 아래 부분을 보면 정보가 있습니다.
Vertices : 8, Faces : 12

Vertex 는 점이고 Face 는 면인데, 정육면체의 끝 점이 8개 라는 것은 이해가 되는데...
Face 는 왜 12일까요? 6면체 니까 6 이어야 하지 않을까요? 이걸 확인하기 위해서 면을 선택해 보겠습니다.

빨갛게 선택 된 부분의 정보가 아래에 Selection v:0 f:2 로 나옵니다.
오호라. face는 삼각형이군요? 그렇다면 '6면 * 2개 삼각형 = 12' 가 이해가 됩니다.

그런데 왜 삼각형이죠? 똑같은 질문을 계속하는데.. 그렇단 건 모른다는 거죠 ㅋㅋㅋㅋㅋ
오케이 구글이 등장해야 할 때가 된겁니다. 검색 키워드는 '컴퓨터 그래픽스 삼각형' 입니다. ㅎㅎㅎㅎㅎ 정말 무식하군요 ㅠㅜ..
그런데 개떡같이 얘기해도 찰떡같이 알아 듣고 알려주는 구글신께서 저에게 길을 열어 주셨습니다.


링크의 본문 중에 이런 내용이 있습니다.
* 표면 메시로 사용되는 다각형
- 일반적으로 표면 메시에 사용되는 다각형은 '사각형' 또는 '삼각형'
사각형 메시(Rectangular Mesh)는 삼각형 메시(Triangular Mesh)에 비해 정밀도가 떨어진다.
- 3차원 공간상에서 임의의 4점을 연결하여 이루어진 면은 평면이 아닌 휜 면이 된다.
  삼각형 메시는 공간상의 3점이 반드시 평면이기 때문에 정밀도가 증가한다.
 -> 다각형 메시 단위로 색상을 계산하는 렌더링 단계에서 메시 자체를 평면으로 가정하여, 사각형 메시에서 정확한 렌더링을 기대하기 힘듦
 -> 삼각형 메시로 표현하면 사각형에 비해 메시 수가 2배로 증가, 연산 속도는 느려진다.

굵은 글씨로 표시한 부분만 봐도 왜 삼각형을 사용하는지 이해가 갑니다.
아하!! 그래서 mesh 를 triangles 로 다루는 구나!!!!

그렇다면 cube.stl 을 텍스트로 열어 볼까요?


하나의 solid 가 12 개의 facet 으로 구성되고, 각각의 facet 은 3개의 vertex (점) 으로 이루어진 삼각형 입니다.
아름답군요! 이제 알았습니다. stl 파일에 들어있는 이 삼각형들을 모두 수집하는 것이 슬라이싱의 맨 첫 단추라는 것을요.

얏호!! 뭔가 알게 되니 중간에서 이야기의 끝을 못 내겠네요. 그렇다면 수미상관법..
1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시과 함께 접시에 담는다)

맨 처음에 복습한 내용중에 1번 보스를 물리쳤으니 5편에서 나머지 보스를 물리쳐 보겠습니다.

============================5편====================================

전편에서는 슬라이싱의 가장 기본인 삼각형에 수집? 에 대해서 공부 했습니다.
먼길 오시느라 수고 하셨습니다. 이제 최종 보스까지 한방에 가시죠~

1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시럽과 함께 접시에 담는다)


역시나 main () 함수에서 다시 시작 합니다.

def main(): filename = sys.argv[1]
layerThickness = float(sys.argv[2])
infillPercent = float(sys.argv[3])
triangles = fileToTriangles(filename)
slices_ = separateSlices(triangles, layerThickness)
supportSlices = generateSupports(triangles, layerThickness)
slices = list()
for s in slices_:
slices += [cleanPerimeter(s)]
for s in slices:
if s.isSurface:
s.infill = infill(s.perimeter, 1)
else:
s.infill = infill(s.perimeter, infillPercent)
for shape in supportSlices:
for s in range(len(shape)):
slices[s].support += infill(shape[s].perimeter,supportInfill)
writeGcode(slices,filename)

separateSlices ()  부터 살펴 봐야 합니다.
이게 결국 핵심인 슬라이싱 입니다.


# given a list of triangles and a thickness per layer,# computes the total number of layers and checks which
# line segments need to be drawn in each layer,
# returns the list of slices with the list of line segments
# to draw per slice, as a tuple with a bool for if the slice
# is a bottom or top
def separateSlices(triangleslayerThickness):


주석문을 번역해 볼까요? 구글 번역기에 던지면 이번에는 외계어 비슷하게 번역을 해 주기 때문에 약간 조미료를 쳐야 합니다.

given a list of triangles and a thickness per layer, computes the total number of layers and 
전편에서 읽어들인 삼각형들과 프로그램 실행할때 두번째 인자로 받아들인 0.2 mm 높이를 갖고 몇번을 쌓아 올려야 하는지 계산하고

checks which line segments need to be drawn in each layer, returns the list of slices with the list of line segments to draw per slice, as a tuple with a bool for if the slice is a bottom or top.
각 레이어에서 어떤 선을 그려야 하는지 체크 해서 그려야할 것들을 되돌려주는 역할을 하는게 separateSlices () 이다

음.. "아저씨! 저 영어나 우리말이나 다 무슨말인지 모르겠어요~" 라고 할 수도 있을 듯 하죠 ㅋㅋㅋ

자 그럼 다시 한번 초딩 버전으로 저 번역을 다시 번역하면,

given a list of triangles and a thickness per layer, computes the total number of layers and 
삼각형들로 잘라야 할 무의 맨 좌/우, 상/하 위치를 알기 때문에 무의 크기 (20mm 높이) 를 알 수 있다. 
무를 0.2 mm 두께로 모두 잘라야 한다. (사시미 칼이 필요할 듯 ..)
다 자르면 무 조각은 (20 mm / 0.2 mm = 100 번 잘라서) 총 100개가 된다.

checks which line segments need to be drawn in each layer, returns the list of slices with the list of line segments to draw per slice, as a tuple with a bool for if the slice is a bottom or top.
첫번째 슬라이스와 모든 삼각형이 겹치는 부분이 있는지 찾는다.
두번째 슬라이스와 모든 삼각형이 겹치는 부분이 있는지 찾는다.
....
마지막 슬라이스와 모든 삼각형이 겹치는 부분이 있는지 찾는다.
이렇게 찾은 겹친 부분을 모두 모은다.

"아쒸. 아저씨 이게 무슨 초딩 언어에요!!!" 라고 할만도 합니다 ㅠㅜ..
음.. 최후의 수단입니다.. 그림을 그려 보겠습니다. 흠.. 그릴 수 있을까요...

자! 그렸습니다. 대박. 저 그림에 소질 있는 듯 ㅋㅋ.

그림의 회색 사각형이 첫번째 무 슬라이스 이고, 빨간색 삼각형이 12개의 삼각형 중 3번째 삼각형 입니다.
삼각형은 3개의 선으로 구성되죠? 저 3개의 선이 무 슬라이스와 만나는 부분을 찾아 봅니다.
바로 이 녹색 선이죠?



이런식으로 모든 슬라이스와 모슨 삼각형의 겹치는 부분을 찾아내면 그것이 슬라이스입니다.

좀 극단적인 예제를 하나 들어 볼까요?

이 그림은 첫 무 슬라이서와 2번째 삼각형의 겹치는 부분을 찾아 본 그림입니다.

당연히 아래 그림처럼 삼각형 전체가 겹치죠?

이렇게 모든 6면은 꽉 채워지게 되는 원리 입니다.

여기까지 하면 더이상 초딩들도 시위를 하지 않을 거라 믿어 의심치 않습니다.
자  그럼 두번째 보스 깬거 맞죠? 그럼 마크 한번 해 주고~

1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시럽과 함께 접시에 담는다)

아. 그런데.. 제 스타일과 다르게 너무 많은 분량의 글을 써 버렸네요.ㅠㅜ
이럴때 가수들이 콘서트를 하다가 마이크를 관중석으로 향하게 하는 트릭을 쓰는데 저도 한번 그래 보겠습니다. ㅋㅋㅋ

3번과 4번 보스는 제가 2번째 보스를 깬것과 동일한 방식으로 한번 해 보세요~ ㅎㅎㅎㅎㅎㅎㅎㅎㅎㅎ
(죄송합니다. 정말 급 피곤해서 ㅠㅜ)
살짝 힌트를 드리면 서포트는 오버행 각도를 넘어서면 선을 긋고, infill 은 처음에 받아들이 20% infill 값으로 띄엄띄엄 넣는 방식입니다.
1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시럽과 함께 접시에 담는다)

콜록콜록... 
그럼 마지막 보스만 깨고 정말 이 게임은 끝내겠습니다.

gcode 를 저장하는 것은 쉽습니다.
일단 start gcode 를 수동으로 넣어 줍니다.
f.write(";Start GCode\n") f.write("M109 S210.000000\n")
f.write("G28 X0 Y0 Z0\n")
f.write("G92 E0\n")
f.write("G29\n")

그리고 2번째 보스를 만났을 때 수집한 겹쳐지는 부분을 모두 쏟아 냅니다.
선들이기 때문에 G0 나 G1 을 사용해서
G1 X000 Y000 Z000 F000
식으로 모두 저장 합니다.

다음은 3번과 4번 보스와 싸워 이긴 서포트와 인필 라인을 써 줍니다.
2번과 동일하게 라인이기 때문에
G1 X000 Y000 Z000 F000
로 합니다.

마지막으로 end gcode 를 수동으로 적어 줍니다.
f.write(";End GCode\n") f.write("M104 S0\n")
f.write("M140 S0\n")
f.write("G91\n")
f.write("G1 E-1 F300\n")
f.write("G1 Z+0.5 E-5 X-20 Y-20 F2700\n")
f.write("G28 X0 Y0\n")
f.write("M84\n")
f.write("G90\n")
이렇게 해서 모든 게임이 완료 되었습니다.
1. STL 파일을 읽어서 Triangle (삼각형) 을 만들고 (무, 사과, 배 중에 맘에 드는 것을 골라서,)
2. 슬라이싱을 하고 (일정한 간격으로 썰고, 그것을 다시 썰거나 돌려 깎아서)
3. 서포트를 세우고 (설탕)
4. infill 을 채우고 (시럽)
5. gcode 파일로 저장한다. (길게 늘어놓고 설탕, 시럽과 함께 접시에 담는다)

재미 있으셨나요? 그런데 이렇게 모든 글을 마무리 하면 안되겠죠?

6 편에서 마지막으로 이렇게 슬라이싱 된 gcode 를 직접 출력한 결과에 대한 내용정리와
맨처음 이 글이 시작된 이유인 45도 기울어진 무한 프린팅 gocode 생성 팁에 대한 것을 적어 보겠습니다.

see you soon.....

==========================6편 (완결)=================================

자... 이제 기나긴 여정을 마무리 해 볼까 합니다.

'아드레날린 24' 라는 영화를 봤었는데.. 지금 기분이 딱 그 영화의 주인공 같습니다.
정말 미친듯이 24시간 동안 달린 것 같네요. 한 주제로 6편의 글을 24시간 내에 쓰다니 ㅠㅜ.. 
감동도 있고 뿌듯도 하네요.

글 중간에 카페 회원분들께서 Gura 슬라이서로 이름을 지어 주셔서... ㅋㅋㅋㅋ
일단 GURA 슬라이서로 명명 하겠습니다.

자 그럼 유종의 미를 거두러 떠나 볼까요.

5편까지 분석한 gcode 로 저만의 슬라이서를 만들었습니다.

ㅎㅎ 사실 오픈소스가 너무 잘 되어 있어서, start /end gcode 와 Print speed 정도 튜닝한게 다지만요.
아 참. 전 델타라서 델타에 관련된 코드를 좀 patch 했습니다.
직교식을 사용하시는 분은 해당 오픈소스를 큰 변경없이 그냥 사용하셔도 될 수준입니다.

슬라이싱 한 gcode 를 Cura 에서 읽어 보면 이렇게 나옵니다.


그리고 이걸 미릭보기 하면 이렇게..


괜츈하죠?

그럼 실제 출력하면 결과물이 어떨까요?

출력 시간은 30분 15 초 걸렸습니다.

일단 바닥면 입니다.아주 깔끔 하지는 않지만 아주 나쁘지도 않습니다.
brim 이나 skirt 기능은 구현하지 않았기 때문에 개선의 여지는 있습니다.


옆에서 본 모습입니다. 나쁘지 않습니다.
하지만 Cura 가 오랜시간 출력 품질을 올리기 위해 얼마나 노력을 했는지 알것 같습니다.
외벽/내벽을 구분해서 많은 옵션이 추가된 이유를 알 것 같습니다.


infill 패턴은 line 으로 구현이 되어 있어서 zig-zag 정도 추가해 주면 좋을 것 같습니다.

음. 총평은... 나쁘지 않습니다. 정말.. 이정도면 시간 투자해서 개선하면 자체 슬라이서 개발 가능하겠다는
자신감? 이 충분이 들 수준입니다.

그럼 최종 미션인, 무한 프린팅 슬라이서 결과 입니다. 두둥~~ 코드로 적겠습니다.

@@ -119,11 +119,11 @@ def fileToTriangles(filename):
                     break
                 points.insert(0, Point(float(l[2]), float(l[3]), float(l[4][:-1])))
             elif counter == 2:
-                points.insert(0, Point(float(l[1]), float(l[2]), float(l[3])))
+                points.insert(0, Point(float(l[1]), float(l[2]) + float(l[3])*0.707, float(l[3])))
             elif counter == 3:
-                points.insert(0, Point(float(l[1]), float(l[2]), float(l[3])))
+                points.insert(0, Point(float(l[1]), float(l[2]) + float(l[3])*0.707, float(l[3])))
             elif counter == 4:
-                points.insert(0, Point(float(l[1]), float(l[2]), float(l[3])))
+                points.insert(0, Point(float(l[1]), float(l[2]) + float(l[3])*0.707, float(l[3])))
             counter += 1

ㅎㅎ.. 1편에서 계산한 Z * cos (45) 를 Y 에 더해준 코드 입니다.
결과는? 이렇습니다~~



ㅋ 완벽합니다. 일반 프린터에서 보면 비뚤어진 모델 같지만,
이 gcode 가 45도 기울어진 무한 프린터에 들어가면 정확히 큐브로 출력이 될 것이니까요.

이글을 보시고 본인만의 슬라이서를 만들어 보고 싶으신 분들은 두려워 마시고 용기내어 한번 해 보세요~ 

 뿌듯뿌듯.. 이렇게 GURA 슬라이서 대장정을 마무리 하겠습니다.

>> 체력이 돌아오면 이런 시나리오로 펌웨어 (Garlin??)도 만들어 볼까요? ㅋㅋㅋㅋ

댓글 없음: