W4: G-Code

Introduction: W4: G-Code

About: Ph.D. Student in Media Arts & Technology @ UCSB

Last week, we started generating G-Code in Grasshopper that controls the 3d-printer directly. Ender 3 Pro is using Marlin flavored G-Code. Marlin index contains various codes for controlling motion and temperatures on the device, but I found G0/G1 commands particularly interesting. These commands control the movement of nozzle head in 3 dimensions, its speed and extrusion amount. According to the docs, the G0 command is encouraged in situations where no extrusion is happening.

G1 [E<pos::mm>] [F<rate::mm/min>] [X<pos::mm>] [Y<pos::mm>] [Z<pos::mm>]

Step 1: G-Code & Custom Slicer

The previous process of saving G-code commands into a file in the TF card proved too slow to rapidly experiment. I looked online for live control of the printer through my computer. Pronterface is open-source software that can communicate with Ender 3 Pro in real-time. It has GUI (see Figure) components to move nozzle head, a console for G-code execution, and a window to visualize tool paths for a loaded g-code file. I used this program to execute files generated in Grasshopper.

I started experimenting with the sample slicer code provided by Jennifer Jacobs. This sample code takes geometry as input and slices it parallel to the XY-plane. Resulting points are then processed in the Python component and each line segment is converted into motion of nozzle head.

def makeGcodeSpeed(fr, to, speed):
    l = (to - fr).Length
    numerator = (_NozzleWidth * l * _LayerHeight)
    denominator = (1.75 / 2) * (1.75 / 2) * math.pi

    e = numerator / denominator

    return "G1 F" + str(speed) + " X" + "{:.{}f}".format(to.X,2) + " Y" + "{:.{}f}".format(to.Y,2) + " E" + "{:.{}f}".format(e,8) + "\n"

The above function takes two points and speed as input and returns the g-code line required for printing the line. The extrusion amount is calculated by the volume of material that needs to be extruded from the nozzle. The Rhino screenshot and photo are the resulting forms from this process with a truncated cone.

Step 2: Silkworm 2

I also experimented with Grasshopper plug-in Silkworm. I downloaded Silkworm 2beta as it is the most recent version. Unfortunately, I couldn't find detailed information about how to use this version as all the examples are for v1. Yet it comes with five intuitive components:


This component takes the nozzle width, layer height, and filament diameter as input and calculates the required flow ratio for the Extrusion component.


It accepts the flow ratio and speed as inputs and generates nozzle movements from a set of lines and delimiters. It accepts a set of lines or points, iterates them sequentially. Without providing any delimiters, this component will produce continuous extrusion paths.


The line segments defined in Delimiter would retract the filament. It has 7 input connections but I had a hard time understanding the relationships between the retraction and these parameters. I will come back to it later.


This is the main component that generates a g-code string and a model. The g-code string does not contain any preparatory lines, so I had to write a custom file saver for the output by starting with initial heat settings followed by the actual g-code. The model parameter is passed to the Silkworm Viewer for path visualization.

Silkworm Viewer:

This component takes the Silkworm model. Display Logistics shows the non-extrusion paths, and Display Values shows the extruded paths.

After experimenting with basic lines in Grasshopper, I tried printing this example. I am having a problem with converting curves to line segments to feed into Silkworm. To get the line output, I used the Explode component on the curve geometry, which gives me a set of points. Then I used the End Points component to create Lines with the start and endpoints. However the resulting g-code starts from Z=0, then immediately jumps to Z=45 and starts printing from the top. I suspect the problem is in my method of line creation. Any thoughts?

Be the First to Share


    • Leather Challenge

      Leather Challenge
    • Build a Tool Contest

      Build a Tool Contest
    • Tinkercad to Fusion 360 Challenge

      Tinkercad to Fusion 360 Challenge



    Question 2 years ago

    Hey Mert, thanks for sharing about your experience using pronterface.

    Did you just connect to the Ender 3 via usb? Are you aware of any way to send messages through pronterface-- with OSC for example? I'm interested in the potential for real-time control.


    Answer 2 years ago

    Yes, Ender 3 was connected via USB. You can send one line at a time in real-time using the Pronterface console view, and it also displays the response from the printer itself (e.g. "cold extrusion prevented"). I will try to find a better pipeline for this communication tho, I will let you know if I find other ways.


    Reply 7 months ago

    Hi Mert, thank you for uploading this research. I was wondering whether you have been able to implement control of the printer from within grasshopper itself? To create a seamless workflow between creating GCode and sending it to the Ender 3? I have an E3Pro running OctoPrint on a RPi4B, and am currently attempting to use this network connection to send commands from within GH.


    Reply 7 months ago

    Hi! Thanks for reaching out.

    Using Grasshopper to control Ender 3 is a great idea! I haven't implemented a real-time connection for GH+Ender3 but you can find a real-time drawing interface for Processing+Ender3 here. It consists of a Processing front end acting as a drawing and a simplified CAD interface, and a Python backend for the two-way communication with the printer. Both the front and backend are available in my GitHub (listed in the instructable). I imagine the Python backend will work in Grasshopper without too much hassle, and once you can send Gcode using Python in Grasshopper, you will need to assign a toolpath not from Processing but from within the Grasshopper. The backend should handle Gcode scheduling correctly for good-quality prints, but if there is anything wrong or problematic, please do ping me on the issues page in Github.

    I hope this helps. Please do share your experiments with me. Looking forward to seeing what you make with the system!