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: http://www.3dbenchy.com/)

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 (https://www.thingiverse.com/thing:3182917) 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 (https://www.thingiverse.com/thing:3441643 and https://www.thingiverse.com/thing:3437190). 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 https://www.thingiverse.com/thing:2802474 so I don’t accidentally put my fingers between the fan blades.

A Raspberry Pi 4 case (https://www.thingiverse.com/thing:3714695) 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 (https://octoprint.org/) 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.

Conclusion

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.