Heat Insert Press

19 minute read

Thumbnail

TL;DR

  • Heat-Insert Press to ensure proper placement of brass threads in 3D-printed Parts
  • Old 3D-Printer hotend gets a new life, so you don’t ruin your nice soldering tips
  • Custom PCB functions as a controller and mechanical part at the same time
  • Counterweight so the gantry doesn’t fall on your fingers
  • USB-C Power Delivery is cool

Download project ZIP file

This file includes:

  • STL files
  • Fusion 360 source file
  • STEP files
  • PCB DXF file
  • Images
  • Schematic
  • Code
Click here to download

License

My project is licensed under the Attribution-NonCommercial 3.0 Unported (CC BY-NC 3.0) license. Please respect the following points:

  • Improve! Make improvements to my design so it fits your needs, and share your work
  • Always give appropriate credit
  • Don’t use it commercially

Discord

Come join the Discord channel for this project (Thanks Paul!): Discord Channel Invitation

Introduction

Heat inserts are small brass cylinders with a thread in it. Typically used for injection moulding, they quickly became a popular way to connect 3D-printed parts. You use them by melting the inserts into a slightly smaller hole, thus making a strong connection.

Usually, one would use a soldering iron to heat them up, and that can work very well. However, if you have large prints or use expensive filaments like PA12, you would have to be very brave to risk it without a rig - soldering irons are simply not perfect for this job.

A popular trick to make the inserts straight is to buy a special tip for the soldering iron. That would increase the reliability. And even though I don’t have such tips at hand, I think they are a great product. Not only do they prevent plastic from flowing into the thread, but you also don’t mess up your good tips for soldering.

Before making a final judgement about heat-inserts, I wanted to build a rig to be able to properly install them. Inspired by previous projects from Adafruit and maker.moekoe, I decided to take it a step further and make a custom PCB. I wanted to use a cheap hotend I had lying around, which was totally unusable for 3D-Printing, because of the poor machining quality. Being able to reuse it for the press gives it a good use.

The whole project is targeted as an inexpensive and nice way to build a press with parts I already had from previous 3D-Printing projects or that are available easily. I highly encourage you to use whatever parts you have on hand, and tried my best to model the parts parametric, so it should be little effort to adapt the printed parts.

Material

This part list should cover all of the parts needed to build your own heat-insert press.

Tip

I made a cool little calculator if you need custom sizes for your press. I only verified the 140mm version, but I don’t see why it shouldn’t be able to make it a bit bigger. Remember to use longer belts too!

How tall are the parts you want to insert threads in?
My parts are at most mm tall.

Please use the following measurements:

  • Aluminum profile: 200mm
  • 12mm rods: 200mm
  • 10mm rod: 225mm
Compared to my 140mm build, it makes approximately the following price difference: 0

Screws and Hardware Parts

Make sure to follow the DIN standard, as some parts have tight tolerances that require the given hardware!

Part Notes Quantity Source
M3x8 DIN 916 12 Wuhushiyu
M3x12 DIN 7984 24 Dold
M3x20 DIN 912 2 Dold
M3x30 DIN 7991 4 Dold
M3 nut DIN 934 12 Dold
M3 square nut DIN 557 16 Wuhushiyu
M3 washer DIN 125 8 Dold
M4x14 DIN 912 1 Dold
M5x10 DIN 7380 2 Dold
T-Nut M5 Slot 6 2 Dold
M6x12 DIN 7380 4 Dold

Linear Motion and Frame

You can also substitute for parts you already have, you don’t need high-precision in this application, so most vendors should be fine. Some parts can be out of stock, but you can order them custom-cut for a minimal fee. Example links are given, I used more affordable bearings. Unfortunately, mine are a bit wobbly which makes the whole assembly slightly inaccurate.

Part Notes Quantity Source
Aluminium Profile 20cm 2040L Type B Slot 6 1 Dold
Rod 10mm 225mm - 1 Dold
Rod 12mm 200mm - 2 Dold
LM10LUU - 1 Dold
LM12UU - 2 Dold
Wooden plate 20mm 200mmx250mm 1 Buy from local store

Electronics

You can reuse any old 3D-Printer mainboard like the stock Ender 3 board, but if you also want a fancy custom PCB to control your heat-insert press, here are the components I used. If you seriously want to replicate my project but don’t have a PCB yet, please drop me an email and we might be able to figure something out together!

Part Notes Quantity Source
Buck Converter LM2596 1 Samiore Robot
OLED 0,96" I2C 1 Samiore Robot
USB-C Trigger board IP2721 1 Samiore Robot
Mosfet AOD4184 1 WXFJYLYI
Piksey Atto Microcontroller 1 BnBe
JST-XH jack + plug 2P 2 LCSC
Flyback Diode - 1 LCSC
LED SMD 1206 1 LCSC
Resistor 330Ω SMD 1206 1 LCSC
Resistor 3,3kΩ SMD 1206 1 LCSC
Resistor 10kΩ SMD 1206 3 LCSC
Capacitor 220µF SMD 1 LCSC
Button SMD 4 LCSC
Screw Terminal 5mm Pitch 2 Liyadu
Male Header pin 2,54mm Pitch - -
Female Header pin 2,54mm Pitch - -
PCB - 1 Aisler

Others

There are mounting slots for a V6 style hotend, but I haven’t designed a clamp yet. It should fit though. You could also use another thermistor, but you will have to change the firmware then. For the power supply, just make sure it can supply enough power and voltage for this application. Otherwise any USB-C PD supply with protection features should be fine. I used a small piece of Aluminium extrusion for the handle, but unfortunately I cannot find a source for that. Get creative or print something!

Part Notes Quantity Source
Hotend MK8/Ender 3 - Style 1 -
Heater 24V 40W maximal! 1 Dold
Thermistor Semitec 104GT 1 Dold
Fan 30x30x10 24V 1 3dJake
GT2 Idlers 3mm bore 2 Dold
GT2 belt around 300mm 1 Dold
Handle, M4 thread Rod or extrusion 1 -
USB-C PD Power Plug 20V 2,5A min 1 -
Concrete or sand - - -

Tools

Besides standard tools, you will need a small file and a thread cutter for M3 and M6. To make the wooden base, you will need to drill holes. The other parts are - obviously - 3D-printed. Any material should do.

I custom-machined a nozzle on a lathe together with my uncle, however I also tried it with a file and it worked surprisingly well.

I highly recommend you to use a crimping tool to properly terminate the fan and thermistor wires. Personally, I use the Engineer PA-09 and I am very happy with it.

Have some grease and threadlocker ready.

Build

Design features

Gantry

The gantry is the most important part, because it connects the bearings with the arms. First, I simply made an extrusion so the bearings could slide in, but I later learned about a trick from @the_constructioneer to make bearing seats. Not only do they make it look better, but also the bearings are held more securely and printer tolerances are a not so important.

At the bottom of the part, there are three holes that allow you to remove the bearing safely, in case you need to back it out. Instead of hammering on the seal, you can simply poke through the holes to allow them to slide out.

Furthermore, my part includes a belt clip, that mounts the belt onto the gantry. The slot for the belt is all the way to the bottom, so you could make the belt into a loop. The screw heads for the belt clip sit exactly in the aluminum profile slots, so there should be no interference.

Square nuts were used to mount the PCB onto the gantry, and hex nuts for the belt clip.

Gantry

Rod holder bottom

This part connects the linear rods as well as the profile to the wooden plate. At first I made a hole for the bearings with a small offset and used three screws to fix it. However, it was very difficult to cut the threads because it was at an unfortunate angle.

Therefore, I made the holes oval so there was some wiggle room in the direction facing outwards, but not to the inside. This allowed me to use only two set screws that fix the rod against the mount.

The aluminum profile is mounted with M6 screws that screw into the profile. I made the holes in the rod holder a big larger to account for inaccuracies while preparing the wooden plate, and that worked well. Using 6 M3 screws + washers, you can mount it securely.

The hex shapes are for optical reasons only, but I think they do make a nice touch.

Rod Holder Bottom

Arms

Two arms connect the hotend with the gantry, and at the same time act as a surface for the PCB to rest on. They are slightly curved to make a cleaner look, and have a cable tie mount as well as a 4mm hole to add a handle.

On the front, there are two holes to mount the hotend, one of them is a slot so you can also use a V6-style hotend. There is also a place to mount a 3030 fan, using M3 screws. Due to space limitations, this thread needs to be cut directly into the plastic.

You will find four slot for square nuts for mounting it to the gantry as well as the PCB. There are also small slots for making the belt clip screws fit. Not only does the PCB act as a circuit board, but also to stabilize the arms and to retain the LM12UU bearings.

Arms

Rod holder top

Because I first didn’t think of making a counterweight, I planned on making a very similar part to the bottom rod holder. However, the counterweight can improve user experience, so I added it. The LM10LUU bearings are longer, to use the full Z-height, I had to make the top rod holder angled. After a few experiments in Fusion 360, that worked out quite well and you can see the result here.

It is important that you insert the square nuts for the idlers first, because only after that you can insert the M6 screws for the profile.

Rod Holder Top

Counterweight

The counterweight runs on its own 10mm rod and has two small guides that slot into the 2040 profile. You could use concrete or sand to fill it. The sand could escape and make a mess, so I decided to use concrete.

I’m very happy how the part turned out, all the nut holes are on the outside, so no concrete/sand can flow there. However, you need to keep in mind that the belt clip for the counterweight needs some space while pouring the concrete. Also, remove the bearing and all hardware parts before filling it up.

Yet again I used the bearing tricks described earlier. I wanted it to pull the whole gantry up, so there is no chance of it falling onto your hands while working, but unfortunately it’s too light; It stays in the position. You could try using some metal bolts to increase the weight if that bothers you.

Counterweight

Endstopper

To precisely insert the threads at the same height, I made this small part that you can adjust to make an endstop. Initially, I didn’t use those small guides on the side, however it was too wobbly. It is not perfect, but works good enough.

The small knob has a square insert, I simple filed down a screw until it fit and that made a good connection.

Endstopper

Slicing/Printing

I printed all parts on my Hevo printer using PrusaSlicer. I recommend a 0,25mm nozzle and 0,3mm extrusion width, because the walls were modeled with a multiple of that number. However, I printed it with a 0,4mm nozzle and that worked well too. Layer height doesn’t matter too much, and overall they are simple prints. Almost no supports are needed! For horizontal holes, I added a small gradation which should make it easier to print.

Nevertheless, I recommend checking the holes and - if necessary - cleaning the parts with sand paper. Especially where plastic comes in contact with plastic, it’s a good idea to make it flat.

The C_gantry.stl file requires a very well-leveled bed, because warping could occur. The lid for the counterweight F1_[a]_lid.stl probably requires support structures because it has a very big angle. Also, this file should be printed with a rather small layer-height.

I chose to use PLA for my project, but most material should be fine. All the black parts are marked with [a] in the filename for reference. Most parts also have part numbers on them.

Info

Here you can see a preview for all part including printing orientation, however I recommend you to download it in the project ZIP.

File name: /stl/release_stl_preview.stl
Click here to download
This STL viewer was made with JavaScript/three.js, learn more about it here. It might take a second or two to load.

Nozzle

My first experiments were conducted with a normal MK8 nozzle, and while that worked well, it sometimes was tricky to insert them perfectly straight. That’s why I machined a custom nozzle on a lathe together with my uncle. I choose Aluminium, because it is affordable and is good thermal conductor. I won’t go into much detail here, but Basically one side is a M6 thread and the other has a turned down shaft with the appropriate diameter.

Nozzle

Hints for assembly

  • Make sure to remove the PTFE tube from the hotend before using it
  • Cut the threads slowly and carefully
  • Add some grease to the bearings
  • Make sure the bearings are “press-fit”, you might have to change the extrusion multiplier
  • Add threadlocker to the nuts holding the hotend
  • Before pouring the concrete, remove all hardware from the counterweight
  • Set the voltage of the step-down converter before soldering it onto the PCB

PCB

Warning

Given the position of this project, I don’t declare my circuit and code as a safe and perfect solution. Thermal runaway could lead to dangerous errors and cause incidents. Don’t use my code/circuit unattended!

Wire_Managment

If you decide not to use an old 3D-Printer mainboard, you can replicate my circuit to make your own controller and use my code. I used an Piksey Atto Microcontroller because I have a few of them, but unfortunately they are not for sale anymore. It is however very similar to the Arduino Leonardo, so it should be easy to change it to something else.

PCB

It was tricky to chose an appropriate resistor for the voltage divider of the thermistor, but I went with 3,3kΩ.

Initially, I wanted solder all parts directly onto the PCB, due to time and simplicity reasons, I decided to solder the modules directly. Turns out that needs a lot more space, and it was tricky to fit everything onto the PCB. Besides a wrong footprint orientation, I am happy with the result.

For now, I used a regular soldering iron to solder all the parts, I chose 1206 SMD components which are easy to solder. The extraordinary shape was an experiment to see how well you can use a PCB as a mechanical part. As I hoped, it worked really well to hold everything together.

While debugging, I found that my components made very weird coil noises and randomly froze. After trying everything to reduce memory usage, I ended up reducing the logic voltage to 3,5V, which solved all issues. I can’t explain why, especially since my parts are rated for 5V instead of 3,3V, but it seems to work well. Also, there is a very weird bug that causes the fuse of the power supply and also my PC triggered. I think it has to do with the step-down converter somehow backfeeding the voltage. But since you aren’t meant to connect a cable to the microcontroller anyway, I didn’t bother with it.

Knowing these bugs, I urge you not to replicate this circuit. Nevertheless, I will provide it here for referencing.

This browser does not support PDFs. Please download the PDF to view it: Download PDF.

For the best experience, please use a Desktop browser and open this viewer in a new tab!

Code

I wrote all the firmware in the Arduino IDE because it is very simple to use. Here were my goals for it:

  • PID control
  • Various protection features (Min-/Maxtemp, Thermal Runaway, Runtime)
  • Nice interface
  • Different profiles

I tried the PID control, following a tutorial from Electronoobs but it simply didn’t work as well as I wanted. For now, I left that out unfortunately. Same goes with Thermal Runway Protection, that should detect if the power applied to the heater doesn’t get reflected on a temperature change (for example a loose heater). I was not able to code that by myself, and after checking out the code of the open-source 3D-Printer firmware Marlin, I also didn’t fully understand it. If you have a tip on how to do that, do let me know!

However, in my opinion the interface turned out really great, it has custom temperature presets and shows the temperature. I first tried to use a simplified version of the Steinhart–Hart equation but it gave me inaccurate results at the lower end. You might be able to correct that using a different R2 in the voltage divider, or a other nomial temperature. I found a cool library by @YuriiSalimov which is also based on the said equation, but worked a lot better. I later confirmed the temperatures by using an old 3D-Printer mainboard with the appropriate Marlin configuration. To my surprise, it was mostly the same temperature. Thanks a lot for your great library! You will need to download it either according to his instructions or simply with the Arduino library manager.

Furthermore, I used the Adafruit GFX library along with the SSD1306 library for using the display. It worked really well and I am grateful for their good documentation. Pick up a genuine display in their store now (you will likely need to adjust the PCB and code)! I followed a this tutorial but I had to edit the I2C address. You can find information about the libraries here along with the license.

Tip

Download the code in the project ZIP!

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Heat-Insert Press controller firmware
// Written by Matteo (matti04.net)
// More information: https://matti04.net/projects/heat-insert-press/
// Code is for reference only - do not leave the press running unattented! 

#define SENSOR_PIN             A0         // Thermistor pin
#define mosfet                 5          // Mosfet pin
#define btn_UP                 14         // Button UP pin
#define btn_OK                 16         // Button OK pin
#define btn_DOWN               15         // Button DOWN pin
#define REFERENCE_RESISTANCE   3300       // R2 in the voltage divider for thermistor
#define NOMINAL_RESISTANCE     100000     // Resistance of the thermistor at the nomial temperature
#define NOMINAL_TEMPERATURE    25         // Nominal Temperature for the nominal resistance of the thermistor
#define B_VALUE                4725       // B-Value of thermistor (see datasheet)
#define READINGS_NUMBER        15         // How many thermistor readings for average?
#define DELAY_TIME             25         // Delay between thermistor readings

char *profiles[] = {"custom", "PLA", "PETG", "ABS", "PA", "PA-CF"}; // Names of Filament profiles
int temperatures[] = {30, 205, 230, 220, 250};                      // Temperatures of Filament profiles

// WARNING: Safety-critical features - do not change
#define maxtemp                280        // Maximal temperature the thermistor can handle before Max-Temp triggers
#define mintemp                0          // Minimal temperature before Min-Temp triggers
#define runtimeLimit           10         // Maximal runtime in minutes


#include <Wire.h>                 // Library for I2C
#include <Adafruit_GFX.h>         // Library for graphics
#include <Adafruit_SSD1306.h>     // Library for OLED
#include <Thermistor.h>           // Library for thermistor
#include <NTC_Thermistor.h>       // Additional library for thermistor
#include <AverageThermistor.h>    // Additional library for thermistor

Adafruit_SSD1306 display(128, 64, &Wire, -1); // Create instance for display
Thermistor* thermistor = NULL;                // Create instance for thermistor

int currentProfile = 1;  // For storing the currently selected profile
float celsius = 1;       // For storing the current temperature

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Display communication
  delay(2000);
  display.clearDisplay();

  Thermistor* originThermistor = new NTC_Thermistor(  // Thermistor configuration
    SENSOR_PIN,
    REFERENCE_RESISTANCE,
    NOMINAL_RESISTANCE,
    NOMINAL_TEMPERATURE,
    B_VALUE
  );
  thermistor = new AverageThermistor(   // For thermistor averaging
    originThermistor,
    READINGS_NUMBER,
    DELAY_TIME
  );
  pinMode(btn_UP, INPUT);     // Pin definition for button UP
  pinMode(btn_OK, INPUT);     // Pin definition for button OK
  pinMode(btn_DOWN, INPUT);   // Pin definition for button DOWN

  pinMode(mosfet, OUTPUT);    // Pin definition for mosfet

  display.setTextSize(1); //Bootscreen
  display.setTextColor(WHITE);
  display.drawRect(0, 18, 100, 46, WHITE);
  display.setCursor(2, 20);
  display.println(F("Press OK to"));
  display.setCursor(2, 30);
  display.println(F("start the heater"));
  display.drawLine(0, 39, 99, 39, WHITE);
  display.setCursor(2, 48);
  display.println(F("DEVELOPMENT ONLY"));
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.println(F("HIP-HEATER"));
  display.setCursor(115, 19);
  display.setTextSize(1);
  display.println(F("UP"));
  display.drawRect(113, 17, 15, 11, WHITE);
  display.setCursor(115, 37);
  display.println(F("OK"));
  display.drawRect(113, 35, 15, 11, WHITE);
  display.setCursor(103, 55);
  display.println(F("DOWN"));
  display.drawRect(101, 53, 27, 11, WHITE);
  display.display();
  while (digitalRead(btn_OK) == 1) {  // Wait for user to confirm heating
  }
  delay(750); // Delay so OK is not pressed too early

}

void loop() {
  // Intro cleanup
  display.fillRect(0, 18, 100, 46, BLACK);
  display.drawRect(0, 18, 100, 46, WHITE);
  display.drawLine(0, 39, 99, 39, WHITE);
  display.display();
  delay(50);

  // Profile Selection
  display.setTextSize(2);
  display.setCursor(10, 44);
  display.println(profiles[currentProfile]);
  display.setTextSize(1);
  display.setCursor(2, 48);
  display.println(currentProfile);
  display.setCursor(2, 20);
  display.println(F("Select the"));
  display.setCursor(2, 30);
  display.println(F("material here:"));
  display.display();
  while (digitalRead(btn_OK) == 1) {  // Cycle through profile selector until OK is pressed
    if (digitalRead(btn_UP) == 0 && currentProfile < 5) {   // One profile higher
      currentProfile++;
      display.fillRect(0, 39, 100, 25, BLACK);
      display.drawRect(0, 39, 100, 25, WHITE);
      display.setTextSize(1);
      display.setCursor(2, 48);
      display.println(currentProfile);
      display.setTextSize(2);
      display.setCursor(10, 44);
      display.println(profiles[currentProfile]);
      display.display();
      delay(100);
    }
    if (digitalRead(btn_DOWN) == 0 && currentProfile > 0) {   // One profile lower
      currentProfile--;
      display.fillRect(0, 39, 100, 25, BLACK);
      display.drawRect(0, 39, 100, 25, WHITE);
      display.setTextSize(1);
      display.setCursor(2, 48);
      display.println(currentProfile);
      display.setTextSize(2);
      display.setCursor(10, 44);
      display.println(profiles[currentProfile]);
      display.display();
      delay(100);
    }
    delay(100);
  }

  // Heater Interface
  display.fillRect(0, 18, 100, 46, BLACK);
  display.drawRect(0, 18, 100, 46, WHITE);
  display.drawLine(0, 39, 99, 39, WHITE);
  display.setTextSize(1);
  display.setCursor(2, 20);
  display.println(F("Heating..."));
  display.setCursor(2, 30);
  display.println(profiles[currentProfile]);
  display.setCursor(2, 48);
  display.println(F("C"));
  display.display();

  while (1) {   // Cycle through heating
    celsius = thermistor->readCelsius();
    display.fillRect(0, 39, 100, 25, BLACK);
    display.drawRect(0, 39, 100, 25, WHITE);
    display.setCursor(10, 44);
    display.setTextSize(2);
    display.println(celsius);
    display.setTextSize(1);
    display.setCursor(2, 48);
    display.println(F("C"));
    display.display();

    // Heater Protection
    if (celsius < mintemp || celsius > maxtemp) {   // Check if temperature is in allowed range
      digitalWrite(mosfet, LOW);
      display.clearDisplay();
      display.setTextSize(4);
      display.setCursor(0, 16);
      display.println(F("ERROR"));
      display.setTextSize(1);
      display.setCursor(0, 50);
      display.println(F("Min-/Max-Temp"));
      display.display();
      delay (100);
      digitalWrite(mosfet, LOW);
      while (1) {
        delay(100);
      }
    }
    if (millis() > 60000*runtimeLimit) {    // Check if the press was turned on for too long
      digitalWrite(mosfet, LOW);
      display.clearDisplay();
      display.setTextSize(4);
      display.setCursor(0, 16);
      display.println(F("ERROR"));
      display.setTextSize(1);
      display.setCursor(0, 50);
      display.println(F("Runtime"));
      display.display();
      delay (100);
      digitalWrite(mosfet, LOW);
      while (1) {
        delay(100);
      }
    }

    // Simple Heater
    if (celsius < temperatures[currentProfile]) {
      digitalWrite(mosfet, HIGH);
    }
    else {
      digitalWrite(mosfet, LOW);
    }
  }
  digitalWrite(mosfet, LOW);
}

Result

And now to the result! Here you can see a picture of it: Press

All the motion goes smooth and the gantry stays in place as needed:

First experiments went great and all the inserts are straight. Once I do further testing, I might add some notes here. Thanks for reading! Nozzle