Machinekit and Cura

Slicing and Cura

The process of creating program code (GCode), which are used as input for 3D printers, from 3D object files (STL) is called slicing, because the object is basically sliced into many very thin layers.

Cura is an open source slicing software supported by Ultimaker for their 3d printers. Besides the official version from Ultimaker, many other 3d printer manufacturers support Cura as slicing software. The lasted version of Cura is based on Python and Qt5/QML, which makes it a perfect match for integration with Machinekit and QtQuickVcp. Throughout this article, I use Cura version 2.3.1.

[Update on Jan 22nd 2017]: Updated the blog post for Cura 2.3.1

What I used before

Until recently I have used Slic3r as my main CAM/slicing software for 3d printing. This required a few modifications to the Slic3r source code, since Machinekit uses RS274-NGC flavor GCode compared to RepRap/Marling flavor GCode used by most 3d printers. This is especially important since I use Machinekit with velocity extrusion support. However, since the modifications to Slic3r are not going to be merged upstream, I started to look for a suitable alternative.

Adding a new GCode flavor to Cura

It turned out that it is not very hard to add support for new GCode flavors to Cura using plugins, written in Python. To add a new plugin it is best to start off by forking an existing Cura plugin, in my case the X3GWriter plugin. The resulting NGCWriter plugin can be found on Github.

Let’s take a look at the file of the plugin:

from . import NGCWriter

from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")

def getMetaData():
    return {
        "plugin": {
            "name": catalog.i18nc("@label", "NGC Writer"),
            "author": "Machine Koder",
            "version": "1.0",
            "description": catalog.i18nc("NGC Writer Plugin Description", "Writes RS-274 GCode to a file"),
            "api": 3

        "mesh_writer": {
            "output": [{
                "extension": "ngc",
                "description": catalog.i18nc("@item:inlistbox", "RS-274 GCode File"),
                "mime_type": "text/x-ngc",
                "mode": NGCWriter.NGCWriter.OutputMode.TextMode

def register(app):
    return {"mesh_writer": NGCWriter.NGCWriter()}

We see that the plugin registers as "mesh_writer" which allows us to post-process the GCode generated by Cura. The MIME type text/x-ngc tells Cura to use this output plugin whenever a .ngc file needs to be generated.

In the module a class inheriting from MeshWriter is used:

class NGCWriter(MeshWriter):
    version = 3

    def __init__(self):

    def write(self, stream, node, mode=MeshWriter.OutputMode.TextMode):
        if mode != MeshWriter.OutputMode.TextMode:
            Logger.log("e", "NGC Writer does not support non-text mode.")
            return False

        #Get the g-code.
        scene = Application.getInstance().getController().getScene()
        gcode_list = getattr(scene, "gcode_list")
        if gcode_list:
            gcodeConverter = GCode2Ngc()
            veConverter = Ngc2Ve()

            for gcode in gcode_list:

            return True

        return False

The RepRap flavor GCode can be accessed layer by layer (not line by line) as a list. This list is then passed to our to post processors. GCode2Ngc converts the RepRap flavor GCode to Machinekit compatible RS274-NGC GCode. The second post-processor Ngc2Ve applies modifications for velocity extrusion support. I will not go into details about the post processors in this post. However, feel free to check out the source code on Github

To install the plugin, we just need to copy the complete folder (which is a Python module) to /lib/cura/plugins/. The plugin loads automatically at the next start of Cura.

Adding a new 3D printer to Cura

To use the newly created output plugin, we have to add a new 3D printer configuration to Cura. Again it is easiest to start off with an existing configuration which can be found in /share/cura/resources/definitions/.

Here is the configuration I created for the UNI-PRINT-3D machine:

    "id": "uni_print_3d",
    "name": "UNI-PRINT-3D",
    "version": 2,
    "inherits": "fdmprinter",
        "visible": true,
        "author": "Alexander Rössler",
        "category": "TheCoolTool",
        "manufacturer": "TheCoolTool",
        "file_formats": "text/x-ngc;text/x-gcode",
        "platform": "uni_print_3d_platform.stl",
        "platform_offset": [0, 0, 0]

    "overrides": {
        "machine_name": { "default_value": "UNI-PRINT-3D" },
        "machine_heated_bed": { "default_value": true },
        "machine_width": { "default_value": 186 },
        "machine_height": { "default_value": 230 },
        "machine_depth": { "default_value": 220 },
        "machine_center_is_zero": { "default_value": true },
        "machine_nozzle_size": { "default_value": 0.4 },
        "material_diameter": { "default_value": 1.75 },
        "machine_nozzle_heat_up_speed": { "default_value": 2.0 },
        "machine_nozzle_cool_down_speed": { "default_value": 2.0 },
        "machine_head_shape_min_x": { "default_value": 75 },
        "machine_head_shape_min_y": { "default_value": 18 },
        "machine_head_shape_max_x": { "default_value": 18 },
        "machine_head_shape_max_y": { "default_value": 35 },
        "machine_nozzle_gantry_distance": { "default_value": 55 },
        "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },

        "machine_start_gcode": {
            "default_value": "M53; enable feed-hold\nG0 Z2.0; always start from the same height to compensate backlash\nG28; move extruder to 0\nM420 R0.0 E0.0 D0.0 P0.1 ; turn the lights on\nM107; turn off fan\nG64 P0.05 Q0.05; path blending settings\nG23; unretract"
        "machine_end_gcode": {
            "default_value": "M104 P0 ; turn off hotend\nG0 X-80 Y100; move the extruder out of the way\nM420 R0.0 E0.1 D0.0 P0.6 ; signalize end of print\nM140 P0 ; turn off heatbed\nM65 P16 ; turn off external fan\nM65 P15 ; turn off power"

Most of the values in the JSON file should be straightforward if you are familiar with 3D printing. The most important line to mention is "file_formats": "text/x-ngc;text/x-gcode", which enables the use of the NGCWriter plugin.

To add a new 3d printer platform to Cura (see "platform": "uni_print_3d_platform.stl",) we have to add a new mesh aka. STL file to /share/cura/resources/meshes/. To model a new platform my 3d printer I used the CAD software OpenSCAD. Basically I created a simple cube with the size of my build platform:

w = 190;
d = 280;
th = 5;

translate([-w/2,-d/2,-th]) cube([w,d,th]);

After rendering the cube (F6) we can export the STL file from the menu of the OpenSCAD GUI. The newly generated STL file needs to be placed in /share/cura/resources/meshes/ and we are all set.


Wrapping up

The complete code of the Cura plugin and 3d printer configuration can be found on Github: machinekoder/uni-print-3d-cura. I have already used Cura for several successful prints. So far, I am very satisfied with the slicing quality. Compared to Slic3r I noticed that the Cura generated GCode is more consistent when it comes to the diameter of the extruded material, which in theory, should result in better printing quality.


I hope the provided information is useful. More posts about 3D printing will follow soon, so please stay tuned and subscribe. Any feedback is welcome.

13 thoughts on “Machinekit and Cura

  1. Thank you for the well written insight into machinekit and hal. I am slowly moving from linuxcnc to machinekit on my cnc-machines an my Unimat-cnc set. Looking forward to the next.

  2. I would be interested in your general views on machinekit for 3D printing. What are the benefits and drawbacks compared to the 32 bit Coretex M3/M4 class solutions.

    1. The biggest drawbacks of Machinekit compared to Cortex M3/4 I see in the smaller user base. Furthermore, the Cortex 3D printing solutions are usually ports of the RepRap/Arduino solutions optimized for 3D printing. Markin, Sprinter, … all contain a huge number of FDM-related optimizations, which sometimes even violate acceleration constraints. Furthermore, RepRap flavor GCode is supported by all slicers out-of-the-box.

      The biggest advantage of Machinekit is its adaptability. Since it runs on a Linux computer, you can integrate whatever you want into your Machinekit configurations, as demonstrated in my blog post about controlling smart-plugs from HAL. Furthermore, Machinekit bases on decades of experience and optimizations from the CNC industry, which solves a similar problem as 3d printing. Machinekit as a solution for 3D printing is especially interesting for you if you like to try out new things or adapt your 3D printer configuration. Moreover, there is also some additional educational value to using Machinekit compared to uC based boards, since one can analyze and work with control systems at run-time.

      My opinion is that with better availability of cheap real-time capable Linux platforms, Linux will become a viable solution for control systems. This development will probably also increase the demand for Linux-based software, such as Machinekit and in the long term, we will see more 3D printers running Machinekit.

  3. An other thing is a big CON when using Machinekit is that it can’t handle files bigger than 58 Mb. For one or another reason if you use UK Axis it’s even wore, not even 20 Mb can be handled.
    I handle this problem by splitting up the Gcode file.

  4. For reference, the paths you have here for the 2.1.3 version were not those used by the package I installed.
    Plugins ended up in: /opt/cura/lib/plugins/
    Machines and meshes ended up in: /opt/cura/share/cura/resources/
    To avoid blobs on layer change I would suggest making your M700 commands not break path blending though (in the back end).
    Other than that, worked like a charm. Thank you for the write-up.

    Cura 2.3 is out of beta. Looking forward to an update on it. 🙂

      1. You were correct. Your code is fine. 🙂
        My issue was related to my using “S” as the parameter for extruder index for color blending in my M163 subroutine. Apparently I shouldn’t use that as it’s also used for spindle speed.
        I changed it to use “I” and the pauses stopped. Thank you.

  5. Hi Alexander,
    I’ve just finished my first print with your entire toolchain. I’m very pleased with the result and especially with the usability. Previously I had this post processing script which worked fine, but was usable for me alone. Now I can have other family members slice models and use the printer. I’m using Cura 2.1.3 with your plugins and Machineface. The only thing I had to do w.r.t. Cora was to change the filament diameter in your post processing script since I use a 2.85 mm filament.
    Thank you for taking VE to the next level!

Leave a Reply

Your email address will not be published. Required fields are marked *