Introduction: 3D Printing Relief

This project is to understand how gcode works by generating code with customized script. I set a goal to make logo relief by 3D printing.

The main gcode I used is below:

G0 F[speed] X[posX] Y[posY] ; move without extrusion

G1 F[speed] X[posX] Y[posY] E[amt] ; move to a location with extrusion

G1 F1200 E-6.0 ; Retraction

G1 F1200 E6.0 ; Extraction

G1 F300 Z[layerH * layterIdx] ; go up to certain layer height

Step 1: Scan a Image With Diagonal Lines

Inspired by how 3D print "cap" a volume, which use diagonal scan lines to cover the opening, I started experimenting with the scan line algorithms. I managed to create diagonal scan lines of a rectangle area. I run the scan lines on a image. The scanning head can detect the pixel values on its location. Here I tried to pick out the "Leica" script, so the condition is if the pixel brightness(0-255 range) is larger than 240, then I break the scan line. Continuing scanning, if found a pixel dimmer than 240, then start recording the scan line again. This give the hollow area for the script.

Of course, I can have the opposite image; start recording the scan line when pixel is brighter than 240 and ends the recording when it is dimmer. Then I get only the scrip image.

By making the hollow version in one diagonal direction and the script version in the other direction, I can combine them together.

Step 2: Exporting to Gcode

The results are stored as a list of line objects, each of which contains a starting position and an ending position. By looping through each pair of positions, I can guide the 3D printer to draw each line with g1 command. Additionally, I found that after finish one line, I should use g0 command to move from the end of the previous line to the beginning of the next line.

Below is the Processing code.

1. Calculating the extrusion amount for the movement according to the layer height and movement distance

float len = PVector.dist(start, stop);
float numerator = 0.4 * len * 0.16;
float denominator = (1.75 / 2) * (1.75 / 2) * PI;
float e = numerator / denominator<br>

2. Move to the beginning of the new line with G0, and draw the line to its end with G1

output.println("G1 F1200 E-6.0 ; Retraction");<br>output.println("G0 F9000 X"+ nf(start.x, 0, 2) +" Y"+nf(start.y, 0, 2));
output.println("G1 F1200 E6.0 ; Extraction");
output.println("G1 F500 X"+ nf(stop.x, 0, 2) +" Y"+nf(stop.y, 0, 2) + " E" + nf(e, 0, 8));<br>

After realizing one layer is not feasible, I copy-pasted the code twice to have multiple identical layers. The results are flexible

Step 3: Create Layers

I realized the one layer structure is not possible to make good results, so I added more layers. I created a array of line lists.

ArrayList<Line>[] layers;<br>
class Line {
  PVector start;
  PVector stop;
  Line(PVector _start, PVector _stop) {
    start = _start;
    stop = _stop;
  }
}<br>

I also enclosed the scanning algorithms into functions which will generate lines on different layers.

void build_outside(ArrayList<Line> lines) {

	...
}
void build_inside(ArrayList<Line> lines) {
	...
}

Moreover, I want to add solid base before the logo start to appear. So I removed the conditional part and get a solid scanned surface. The scan lines will be attached to the line list of given layer. There are two solid filling function, one is going-up direction, and the other is going-down direction. I also created 4-lined boundary generation function.

void build_layer_slope(ArrayList lines) { ... }
void build_layer_steep(ArrayList lines) { ... }
void build_boundry(ArrayList lines) { ... }<br>

Then to plan multiple layers of work for a printer can be done like below:

layers = new ArrayList[10];
for (int i = 0; i < 10; i ++) {
  layers[i] = new ArrayList<Line>();
}


build_boundry(layers[0]);
build_layer_steep(layers[0]);
build_boundry(layers[1]);
build_layer_slope(layers[1]);
build_boundry(layers[2]);
build_layer_steep(layers[2]);
build_boundry(layers[3]);
build_layer_slope(layers[3]);
for (int i = 4; i < 10; i++) {
  build_boundry(layers[i]);
  build_outside(layers[i]);
}

Step 4: Optimization

The line used to only move from the left to right. I made the direction alternating so increased the printing speed.

It is done by swap the starting and ending position.

    PVector start, stop;
    int step;
    if (n%2 == 0) {
      start = p1;
      stop = p2;
      step = 1;
    } else {
      start = p2;
      stop = p1;
      step = -1;
    }

I also experiment with different layer height. I tried with 0.28 layer height and it is not good quality.

I also tried with variable extrusion, higher on the base layer and gradually lower on the relief layer by the command below, here i is layer index. It is not obvious.

float numerator = 0.4 * len * map(i, 0, 9, 0.18, 0.12);<br>

I also tried with printing both the outside and the inside of the logo with different direction filling.

I also rewrite the code so the coordinates matched better with the 3D printer. Each pixel is mapped to a 0.4mm-diametered square.