Building a DIY CNC router with 3D printed parts

Building a CNC router is something I have wanted to do for a few years, but never really got to. With the DIY CNC kits being a bit too expensive for my taste and, I have to admit, I do not have really need it. However with the current situation in the world, and some extra 3D printer parts that were collecting dust, I got the inspiration to finally build a CNC router. I wanted to do things by myself as much as possible, and to do this I wanted to add a few constraints:

  • Use as many 3D printed parts as possible (of course where it makes sense, and does not compromise the structure too much)
  • Try to be as cheap as possible, these things can be really expensive
  • Don’t use existing plans/designs, lets be creative
  • Imagine the design as we go, aka no planning (this is more my own lazyness)

Of course I don’t expect a really good CNC router with all these constraints, and doing the design myself. I know next to nothing about designing something like this anyways. But it’s a good experience for building things, design, testing, and 3D printing (I bought a 3D printer for a reason, I hope). So here it is, the final result:

Image of the CNC router.
DIY CNC Router, version 1

This is the full build of the CNC router. Using aluminium profiles as a frame and 3D printer parts to connect everything together. So far it works pretty well!

Features / specs

It’s not the strongest thing, lets be honest, but it does the job well enough for me. The NEMA 17 steppers aren’t really strong enough for high feedrates. The frame itself is okay for slow speed, but not quite strong enough for fast movements. A short overview of the specs:

  • Dual Y, X, and Z motors; 1.5A NEMA 17
  • Y/Y resolution: 0.01mm; Z resolution: 0.0025mm
  • 500W Spindle
  • Frame dimensions: 800×1000
  • Milling dimensions: 600x800x60

As a cost saving measure I used unsupported rails, but added 3D printed supports. This seems to work quite well. All the brackets between the aluminium profiles, motors, etc. are all 3D printed custom parts. On the X axis it would be a nice upgrade to better rails, since they flex a bit more in the Y direction.

Electronics / Software

What I thought would be the easy part :p. I’m reusing a Creality mainboard from an Ender-3 3D printer, which seems to limit a bit which firmware I can use. At first I tried klipper which is very easy to configure, but did not support some gcodes I wanted to use. In the end I’m using Marlin with a custom board and configuration.

Unfortunately it wasn’t the easiest part, getting the configuring correct required a lot more testing and debugging than expected. Overall it was working pretty well within a few evenings of work.

Wiring and controller for CNC machine.

As visible in the picture, a raspberry pi is used to control the router. This seemed to me like the easiest solution. I did not want to hookup any extra buttons or a display. The device runs OctoPrint to provide web based access to control the machine. I tried out cncjs, and might still switch to it since it is better suited for CNC use. A strange bug I had with both is that running gcode from the raspberry pi doesn’t work properly and stalls the machine, indicating it might be bug elsewhere (I suspect serial communication in some way). Running of the SD card with the Creality board works fine.


Overall I’m quite happy with the results, and it works better than expected. The performance is good enough for my use cases at the moment. I have some things I want to improve in the future, like geared stepper motors, and a better X carriage. I started this project without knowing what I’m doing, and I did learn a lot of new things.

There isn’t a howto guide or anything, since there probably are designs that will be a lot better in every way on the internet. However the modified marlin code, and OpenSCAD drawings are available on github.

Finally we used this machine for a bench we are making as a present for my grandparents with their names engraved in the wood.

Wood engraved with the CNC router.

3D Printing with the Ender 3 – A journey

Last summer I wanted to finally get into 3D printing, since prices have dropped significantly since I last want to get into it a few years back. On the recommendation of a friend I bought the cheap Ender 3. Over the last couple of months I’ve been trying to improve the print quality, speed, and reliability. Mostly for fun, but it was nice to have a printer to test out gcode we had to generate as part of the “Computational Fabrication” course at UHasselt where we had to write a program to slice STL files.

Calibration, tension, and leveling

Ender 3 components before assembly.

While the first prints were okay, they definitely had some problems. Turns out using this printer is not just following the included assembly instructions, and that’s it. The basic lessons I had to learn to get a good print were: tension the X-axis belt properly, check the tightness of the eccentric nut/wheel on the X carriage, make sure the X-axis is perpendicular with the Z-axis (the eccentric nuts on the side), calibrate the extrusion E-steps, and make sure the bed is leveled properly. That last one was a bit of a problem, since the build plate was a bit warped out of the box, for this I decided to get a glass bed, although a BL-Touch might also be nice.

Another thing that made the printer a fair bit quieter, was to take a piece of the packing foam from the box, and put it under the printer to act as a damper for all the vibrations. At the time I was testing with a 0.2mm nozzle, and this made a visible difference in print quality! Hopefully I can improve this further in the future.

0.2mm nozzle experiment (3D benchy:

Mods & Upgrades

This is where the fun begins, so many things to try! Along the way I decided I wanted to make this printer more quiet, since this would also reduce vibrations, and hopefully improve print quality. The additional silence allowed me to move the printer from another room into my workspace, I had put the printer in another room because the noise it created was too much for me. Some of the changes are 3D printed, and some are extra hardware.

Printed upgrades

Hero Me fan duct ( to help with part cooling (bridging in specific). I did replace the 40mm fan with a noctua fan for silence, this also reduced vibrations on the carriage significantly.

Since I had some 80mm fans laying around, I added a cover for both the mainboard and PSU using these fans ( and Especially swapping the small fan over the mainboard made this machine a lot quieter, the PSU fan not so much but that depends more on the specific fan I used. I also added some fan covers from so I don’t accidentally put my fingers between the fan blades.

A Raspberry Pi 4 case ( to hold and attach a Raspberry Pi running Octoprint.

Hardware upgrades

The first hardware upgrades I did were a glass bed, and the gold bed springs. Bed leveling has become a lot easier, and I need to do it less often. I could have gone for auto bed leveling, but I don’t really lose a lot of time re-leveling.

The next upgrade was not really print quality, but it’s nice to have a webcam stream to monitor print progress. Luckily I had a Raspberry Pi laying around, so I installed Octoprint ( and setup a webcam. Overall it’s pretty nice, but I did have some stability issues with the serial connection to the printer. Another nice thing about Octoprint, is the plugin support, especially since I had a humidity and temperature sensor I could use to monitor the environment using the Raspberry Pi GPIO pins.

The next upgrade was the Ender 3 silent mainboard, it’s crazy how much quieter these motors are with different drivers. This board is a drop-in replacement for the existing board, and uses the TMC2208 stepper drivers. I had to change the vref voltage, since they were way too low and caused issues. Besides that, I also installed a newer marlin firmware on the board. I managed to pick this one up on a black Friday sale, but for full price I think a SKR board or something similar would have been a better choice.

I did replace the extruder with an aluminium one, but I have a dual gear extrusion on its way, so I’m curious as to how that one will perform. I’ve had some underextrusion printing with smaller nozzles, like 0.2mm, so I hope this will help with the smaller nozzles or with higher printing speeds.

Overall thoughts

The Ender 3 has been pretty good, getting into 3D printing, but it does require time and attention to get properly set up. There are a lot of mods to try out, and improve the printer, so it’s great if you’re into that like I am :). And it looks pretty cool in the dark!

Adventures in C – Executing instructions in data

So this was a fun experiment. The idea was something along the lines of “Can we use a pointer to some data as a function?”. Turns out, yes that is perfectly possible! Although this is probably a very bad idea to actually use in any actual code. The only reason I wanted to try this, was to see if it could be used for a CTF style challenge.

So let’s get started! I started with two very simple functions.

int getnum1(int x) {
    x += 1;
    return x * x;

int getnum2(int x) {
    x += 2;
    return x * x;

Lets compile them, from the resulting binary we can extract the getnum2() function (eg. using objdump). So we get the following HEX in an array.

uint8_t magic[20] = {0x55, 0x48, 0x89, 0xe5, 0x89, 0x7d, 0xfc,
                     0x83, 0x45, 0xfc, 0x02, 0x8b, 0x45, 0xfc,
                     0x0f, 0xaf, 0x45, 0xfc, 0x5d, 0xc3};

Next we need to see how to make our program execute this block. Normally data blocks are protected from execution, however using the mprotect() call we can allow execution on a block of memory. For detailed usage see the mprotect man page.

static char *magicbuffer;

// Get the page size
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize == -1) {
    printf("Sysconf error\n");

// Get aligned page of memory
magicbuffer = memalign(pagesize, 1 * pagesize);

// Set execute on memory
if (mprotect(magicbuffer, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
    printf("Setting memory protections failed\n");

// Copy instructions to memory
memcpy(magicbuffer, magic, 20);

Now, lets try to execute those instructions.

int (*func)(int) = &getnum1;
printf("Num 1: %d\n", func(1));
func = (int (*)(int))magicbuffer;
printf("Num 2: %d\n", func(1));

This prints the output of getnum1() and getnum2(), without getnum2() needing to be defined.


This as just a fun experiment, I had no idea this was possible. It’s always good to know what’s possible, but I don’t really know any practical uses for this. I rarely write any articles, so any feedback is appreciated.