Tuesday, 11 March 2014

Buried nuts and hanging holes

I needed to make some M4 nuts that could be finger tightened but I didn't have room for a standard wing-nut, so I decided to embed nuts in a printed plastic knob. I knocked up a simple design in OpenScad :-


M4 nuts are nominally 3.2mm thick. I made the base and lid 2.4mm and sliced it with 0.4mm layers. That meant the top of the nut would be flush with a layer boundary at 5.6mm and I confirmed that the first covering layer was at 6.0mm in Skeinlayer. So I needed to pause the build before the start of the layer at Z=6.0 and insert the nuts.

I run my USB machines using Raspberry PIs and OctoPrint (so that all my machines are connected via Ethernet) and noticed a post by the author, Gina Häußge, that said OctoPrint interprets an M0 in the gcode as a pause command. The host stops sending gcode until you press the pause button to un-pause it again. I believe other hosts use @PAUSE to do the same thing.

So M0 is exactly what I needed. The only problem is that up until then I mistakenly thought M0 meant end of program and placed it at the end of the PLA profiles that I distribute. Fortunately the version of Marlin I use ignores it but if you want to use the latest version, or OctoPrint, then you need to remove it from end.gcode, otherwise either the host or the firmware will pause at the end of the print and wait for a button press. Harmless but a bit confusing.

So, armed with a new appreciation of what M0 is, I searched my gcode for the first instance of Z6.0 which looks like this:

F12000.0
G1 X-9.082 Y3.907 Z6.0 F12000.0
G1 X-5.457 Y-3.937 Z6.0 F12000.0
G1 X-7.05 Y-3.803 Z6.0 F12000.0
G1 X-11.486 Y-4.991 Z6.0 F12000.0
G1 X-13.721 Y-10.229 Z6.0 F12000.0
G1 F1800.0
G1 E1.0
G1 F12000.0
M101
G1 X-12.65 Y-10.848 Z6.0 F1837.1615 E0.036

What we have is a sequence of non-extruding moves followed by an un-retract and the first extrusion. The moves are the result of the comb module and not really relevant if we are restarting after a pause, so I removed all but the last move and inserted my pause code:

M104 S100
G1 Z6.0
G1 X-100 Y-100 F9000
M0
G1 X10.0 Y98.0 F9000
G1 Z0.05
M109 S250
G92 E0
G1 E3 F50
G1 E-1 F1200
G1 X40.0 F4000
G1 Z6.0 F9000

G1 X-13.721 Y-10.229 Z6.0 F12000.0
G1 F1800.0
G1 E1.0
G1 F12000.0
M101
G1 X-12.65 Y-10.848 Z6.0 F1837.1615 E0.036

I set the extruder temperature to 100°C to minimise ooze and stop it discolouring while waiting for me to insert the nuts. The bed is left on so the half printed objects don't detach. It then moves up to Z = 6.0 to clear the objects before going to X = -100, Y =-100. That moves the bed to the front and the extruder to the far right on a Mendel90, giving the best access to the partially printed objects. M0 then pauses the program.

I threaded the nuts onto a screw to insert them easily without touching the hot plastic. 



After pressing the pause button to make OctoPrint resume, the print head moves to the front of the bed to do another ooze free warmup. The only difference from the start of the print is it parks the nozzle 10mm further left to avoid the blob it has already made and it moves to Z = 6.0 before resuming the print.

This all worked very well except for a slight snag. ABS does not stick to steel, so when it extruded the circular holes on top of the nuts it made a bit of a mess.



Normally I would use a one layer support diaphragm when printing suspended holes and drill it out afterwards. In this case it can't be drilled because the nut is in the way, so I developed a method of printing holes in mid air. 

The last layer of the nut trap looks like this: 



You can't print a smaller hole on the next layer as the outline would be printed in mid air. The infill is also only attached at one end. After a few layers it does sort itself out but leaves a mess. However, what you can do is print two bridges over the large hole with a gap between them equal to the diameter of the small hole:



This is done by cutting out a one layer rectangle clipped to the hexagon. It is rotated to match the layer's infill direction because Skeinforge fails to detect it as a bridge, probably because the bridged area is tiny.

On the next layer we can bridge in the opposite direction and close down the hole to a square:



Two sides are supported by the edges of the rectangle below and the other two span the gap. 

On the next layer we can approximate the hole with an octagon. Four edges are coincident with the square and the other four span small gaps:



It is now a good enough approximation to a circle for such a small hole so it continues up to the top as an octagon. The resulting print is much neater:



The cavity for the nut is made by subtracting a shape like this: 


Here is the OpenScad code. It needs various functions from the Mendel90 source tree.

//
// Smaller alternative to a wingnut
//
include <conf config.scad>

module hanging_hole(or, ir, ofn = 0) {
    union() {
        intersection() {
            if(ofn)
                cylinder(r = or, h = 3 * layer_height, center = true, $fn = ofn);
            else
                poly_cylinder(r = or, h = 3 * layer_height, center = true);
            rotate([0, 0, 90])
                cube([2 * or + 1, 2 * ir, 2 * layer_height], center = true);
        }
        rotate([0, 0, 90])
            cube([ir * 2, ir * 2, 4 * layer_height + 4 * eta], center = true);

        rotate([0, 0, 22.5])
            translate([0, 0, 2 * layer_height])
                cylinder(r = corrected_radius(ir, 8), h = 100, $fn = 8);
    }
}

base_thickness = 2.4;
lid_thickness = 2.4;

function nut_knob_height(nut) = base_thickness + nut_thickness(nut) + lid_thickness;

module nut_knob_stl(screw = M4_hex_screw, d = 14) {
    nut = screw_nut(screw);
    h = nut_knob_height(nut);
    flutes = 3;

    stl("nut_knob");
    rotate([0, 0, -45])
        difference() {
            cylinder(r = d / 2, h = h);                                                 // basic shape

            for(i = [0 : flutes - 1])                                                   // flutes for finger grip
                rotate([0, 0, i * 360 / flutes + 30])
                    translate([d * cos(90 / flutes), 0, base_thickness])
                        cylinder(r = d / 2, h = 100);

            union() {                                                                   // nut cavity
                difference() {
                    translate([0, 0, base_thickness + nut_thickness(nut)])
                        nut_trap(screw_clearance_radius(screw), nut_radius(nut), nut_thickness(nut));

                    translate([0, 0, base_thickness + nut_thickness(nut)])              // remove top of nut trap
                        cylinder(r = 20, h = 110);
                }

                translate([0, 0, base_thickness + nut_thickness(nut)])
                    hanging_hole(nut_radius(nut), screw_clearance_radius(screw), 6);    // replace with hanging hole
            }

        }
}

So this seems to be a general solution to printing holes in mid air without any support material. The only downside is that it is a bit weaker than using a membrane and drilling it out. In this case no strength above the nut was required. In general you can just make it two layers thicker.

16 comments:

  1. Great work Chris! have you tried it to see if it works on Slic3r as well?

    ReplyDelete
    Replies
    1. Thanks, Tony,

      No I don't use anything other than Skeinforge. I have tried the other Slicers but if they don't produce objects the right size out of the box I don't persist with them.

      Delete
  2. I came up with the same idea for the divider between two bearings in the crowned idler pulleys for Reprap Wallace, but I found that it worked better to reduce the hole to a square with radius equal to the apothem of the larger (octagonal) hole. The sides of the square bridge because the corners are anchored, and any solid infill lines over the empty space (for holes this size, the perimeters may be the only thing extending over the gap) adhere to them and bridge to the edge. A hexagonal hole could be reduced to a triangle in the same manner for an even greater reduction. In my case, the bearings were to be inserted after printing and it bridged just fine, but it should work better with the metal under the overhang to prevent drooping and compress the extruded plastic (the way another layer of plastic under it would) to ensure that it spreads out enough for the infill to contact and adhere to the perimeter.

    This makes a more even overhanging surface, but won't work in one layer if the radius of the square/triangle is less than the apothem of the larger hole below. On the other hand, two iterations of this method may result in a more desirable shape for the underside than the method shown above.

    ReplyDelete
  3. Do you plan on working some of these into the Mendel90 design in the future?

    ReplyDelete
    Replies
    1. Well they can be used to replace the wing nuts that hold the extruder to leave room for something else...

      Delete
  4. Did you try applying some slurry to the nut before resuming? That might allow the printing to adhere to the nut instead of altering your model.

    ReplyDelete
    Replies
    1. No I didn't think of doing that but I prefer to design parts which require as little manual work as possible.

      Delete
  5. I've been thinking of the same issue. Just in a different way.

    After looking at the Crossfire2 on thingiverse I noticed they bond the nuts into the frame of the quadcopter (see pic below). So it got me thinking it might be a good solution for attaching the extruder. The nuts are glued in to the bottom of the X carriage and you only need to screw in the bolts to hold the extruder.

    http://thingiverse-production.s3.amazonaws.com/renders/5a/51/4d/95/f4/IMG_1616_preview_featured.jpg

    ReplyDelete
    Replies
    1. The problem is you can't get to the bolt under the motor.

      Delete
    2. D'oh. You're right. Completely forgot about the motor layout.

      I recently switched to using an EZstruder and 1.75 filament. So my motor is rotated 90degrees and no longer blocks the bolts. http://www.thingiverse.com/thing:151551

      Delete
  6. Chris, I noted this comment "Raspberry PIs and OctoPrint". Out of interest, are you connecting the Rasberry Pi's and printers via USB, and are you still using SD cards to print from? I know you have previously identified issues printing over USB.

    ReplyDelete
    Replies
    1. Yes I can run reliably over USB from an RPI because it gets its ground from the Melzi, so there is no ground loop or ground bounce. I have Mendel90 parts that I print time and time again on SD but when I print a one off I just load it onto the RPI and print over USB. I haven't tried any hi res models like Yoda. That might need SD for speed as it does on Windows. Normal geometric parts work fine though.

      Delete
  7. I have made similar nuts in the past, but rather than insert the nut mid print, the hexagonal hole has slightly tapered walls. Fitting the nut afterwards and pulling them in place by screwing in a machine screw results in a permanent press fit.

    ReplyDelete
  8. Hi, I got a similar idea to create captive nuts, instead I positioned the nut vertically. This way, I did not had to worry about hanging holes. However the nut is held by 4 sides instead of 6 but it was firm enough for my application. http://solidutopia.com/3d-print-around-captive-parts/
    Captives parts is a powerfull concept applied to 3D printing and it is good to have multiple ways to use it. Thanks

    ReplyDelete
  9. It struck me that if you were to brush a thin coat of ABS solution (ABS dissolved in acetone) or solvent cement (used for joining plastic pipes) over the part after inserting the nut, the ABS would stick to it so you don't have to mess about with your rectangular bridging layers. I've used both to coat my glass bed for ABS printing with good effect.

    ReplyDelete