In the previous tutorial we have seen what G-code is, how it works and how you can write it by yourself on any text editor. In this tutorial we will start to automate the process using Processing. We will write some simple functions that will allow us to easily output G-code files. Notice that this can be obtained in many (and more sophisticated) ways, however here we will try to keep things as simple as possible, in order to give everyone the possibility to understand the concepts and start to make their own experiments. Let’s get started.
Processing is a programming language based on Java. It has been created with the goal of making programming accessible to anyone and to rapidly prototype sketches and ideas. If you have no experience with coding, this might be a good chance to start learning this great tool.
Setting up the G-code functions
Let’s open a new Processing sketch. In this first example we will only need the setup()
function.
As we said last time, the G-code is a simple text file, so we will store the commands in an ArrayList
of strings as a global variable:
ArrayList<String> gcode;
Let’s write a function that feeds this ArrayList
with our G-code commands:
void gCommand(String command) { gcode.add(command); }
Then we need a function to export our G-code:
void gExport() { //Create a unique name for the exported file String name_save = "gcode_"+day()+""+hour()+""+minute()+"_"+second()+".g"; //Convert from ArrayList to array (required by saveString function) String[] arr_gcode = gcode.toArray(new String[gcode.size()]); // Export GCODE saveStrings(name_save, arr_t_gcode); }
Let’s test in setup()
what we have written so far:
void setup() { gcode = new ArrayList<String>(); gCommand("G1 X3 Y20"); gCommand("G1 X20 Y2 Z1"); gExport(gcode); }
Run your sketch by pressing CTRL+R, then press CTRL+K to open the sketch folder. You will find the G-code file that you have just generated with inside the two commands that we wrote.
Not bad, right? Let’s write two functions that will manage for us the beginning and the end of the print, as seen in the previous tutorial:
void startPrint(){ gCommand("G91"); //Relative mode gCommand("G1 Z1"); //Up one millimeter gCommand("G28 X0 Y0"); //Home X and Y axes gCommand("G90"); //Absolute mode gCommand("G1 X117.5 Y125 F8000"); //Go to the center (modify according to your printer) gCommand("G28 Z0"); //Home Z axis gCommand("G1 Z0"); //Go to height 0 gCommand("T0"); //Select extruder 1 gCommand("G92 E0"); //Reset extruder position to 0 } void endPrint(){ gCommand("G91"); //Relative mode gCommand("G1 E-4 F3000"); //Retract filament to avoid filament drop on last layer gCommand("G1 X0 Y100 Z20"); //Facilitate object removal gCommand("G1 E4"); //Restore filament position gCommand("M 107"); //Turn fans off }
Now we need a function able to calculate for us the amount of extrusion between two points.
Let’s first write some global variables:
float path_width = 0.4; float layer_height = 0.2; float filament_diameter = 1.75;
Let’s pre-compute some values, also as global variables:
float extruded_path_section = path_width * layer_height; float filament_section = PI * sq(1.75/2.0f);
And now the extrusion function:
float extrude(PVector p1, PVector p2) { float points_distance = dist(p1.x, p1.y, p2.x, p2.y); float volume_extruded_path = extruded_path_section * points_distance; float length_extruded_path = volume_extruded_path / filament_section; return length_extruded_path; }
And finally, some simple functions for setting the printing speed and enabling and disabling the fans:
void setSpeed(float speed) { gCommand("G1 F" + speed); } void enableFan() { gCommand("M 106"); } void disableFan() { gCommand("M 107"); }
Now we have all what we need: a function for writing G-code, one for exporting it, two functions for setting up and finishing the print and one for calculating the amount of extrusion, plus commands for fans and speed.
A first example
Let’s use what we have written so far to print the cube from the first tutorial. This time we will use Absolute mode. Let’s add another two global variables for the center of our printing table (we will also update the startPrint()
function accordingly:
float width_table = 235; //mm float height_table = 250; //mm float height_printer = 165; //mm float x_center_table = width_table / 2.0f; float y_center_table = height_table / 2.0f; void startPrint() { //... gCommand("G1 " + x_center_talbe + " " + y_center_table + " F8000"); //Go to the center //... }
And now, using a two for
loops (one for the layers and one for the sides of the squares), we write inside of setup()
what we need for our cube. You will now find the complete code for our sketch:
ArrayList<String> gcode; float width_table = 235; //mm float height_table = 250; //mm float height_printer = 165; //mm float x_center_table = width_table / 2.0f; float y_center_table = height_table / 2.0f; float path_width = 0.4; float layer_height = 0.2; float filament_diameter = 1.75; float extruded_path_section = path_width * layer_height; float filament_section = PI * sq(1.75/2.0f); void setup() { gcode = new ArrayList<String>(); startPrint(); float length_side_cube = 10; float tot_layers = length_side_cube / layer_height; float current_z = 0; float extrusion = 0; float extrusion_multiplier = 1; float angle_increment = TWO_PI / 4.0f; PVector previous_point = new PVector(); for (int layer = 0; layer<tot_layers; layer++) { current_z += layer_height; gCommand("G1 Z" + current_z); if (layer == 0) { // Slow speed and thick extrusion at the beginning of the print setSpeed(400); extrusion_multiplier = 2; } else if (layer == 2) { extrusion_multiplier = 1; } else if (layer == 3) { // Increase the speed setSpeed(1200); enableFan(); } for (float angle = 0; angle<=TWO_PI; angle+=angle_increment) { float x = x_center_table + cos(angle) * length_side_cube; float y = y_center_table + sin(angle) * length_side_cube; PVector next_point = new PVector(x, y); if (layer == 0 && angle==0) { // Go to starting position gCommand("G1 X" + x + " Y" + y); } else { extrusion += (extrude(previous_point, next_point) * extrusion_multiplier); gCommand("G1 X" + x + " Y" + y + " E" + extrusion); } previous_point = next_point; } } endPrint(); gExport(); exit(); } float extrude(PVector p1, PVector p2) { float points_distance = dist(p1.x, p1.y, p2.x, p2.y); float volume_extruded_path = extruded_path_section * points_distance; float length_extruded_path = volume_extruded_path / filament_section; return length_extruded_path; } void setSpeed(float speed) { gCommand("G1 F" + speed); } void enableFan() { gCommand("M 106"); } void disableFan() { gCommand("M 107"); } void startPrint() { gCommand("G91"); //Relative mode gCommand("G1 Z1"); //Up one millimeter gCommand("G28 X0 Y0"); //Home X and Y axes gCommand("G90"); //Absolute mode gCommand("G1 X" + x_center_table + " Y" + y_center_table + " F8000"); //Go to the center gCommand("G28 Z0"); //Home Z axis gCommand("G1 Z0"); //Go to height 0 gCommand("T0"); //Select extruder 1 gCommand("G92 E0"); //Reset extruder position to 0 } void endPrint() { gCommand("G91"); //Relative mode gCommand("G1 E-4 F3000"); //Retract filament to avoid filament drop on last layer gCommand("G1 X0 Y100 Z20"); //Facilitate object removal gCommand("G1 E4"); //Restore filament position gCommand("M 107"); //Turn fans off } void gCommand(String command) { gcode.add(command); } void gExport() { //Create a unique name for the exported file String name_save = "gcode_"+day()+""+hour()+""+minute()+"_"+second()+".g"; //Convert from ArrayList to array (required by saveString function) String[] arr_gcode = gcode.toArray(new String[gcode.size()]); // Export GCODE saveStrings(name_save, arr_gcode); }
This example was simple and quite straightforward. Thanks to it you can already start to make some interesting experiments. However, if we decide to expand it, the code could get messy pretty soon. Furthermore, the structure is not very flexible and it would force us to rewrite a lot of code in case that we want to develop different projects.
That’s why, in the following tutorial, we will use the power of Object Oriented Programming (OOP) to create a more solid framework that you will be able to use and reuse in multiple occasions.
In the meantime, how about having a look at the Processing’s page? It’s full of useful tutorials and examples for you to learn.
See you next time!