adrianschlatter / threadlib

thread library for OpenSCAD

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

specifying bolt by length

nohkumado opened this issue · comments

hello, modified a bit the bolt module to be able to specify the bolt by length:
module bolt(designator, turns = 5, higbee_arc=20, fn=120, table=THREAD_TABLE, h = -1)
{
name = str(sanitize(designator), "-ext");
union() {
specs = thread_specs(name, table=table);
P = specs[0]; Dsupport = specs[2];
H = (h >0)? h: (turns + 1) * P;
thread(name, turns=(h >0)?H/P-1:turns, higbee_arc=higbee_arc, fn=fn, table=table);
translate([0, 0, -P / 2])
cylinder(h=H, d=Dsupport, $fn=fn);
};
};

its in my tree... don't know if its any use to make pull requests?

made the same modification to nut in the meantime...

Please do not add new features / issues to an existing pull request. This is more confusing than helpful.

I understand that specifying length instead of turns is a desired feature. So far, I didn't see an elegant solution: Defining bolt2(designator, length, ...) has maintenance issues (see #32). Your approach does not have that problem but it's also not very elegant. Writing bolt("M8", turns=5, length=0.3) is perfectly correct syntax but will not work correctly.

I'm considering a solution like this:

bolt("M4", turns=0.3, unit="length")

Another (code-incompatible) solution would be:

bolt("M4", length=5, unit="turns")
bolt("M4", length=0.3, unit="length")

well the last one would be my preferred one :D even indeed i breaks existing code....

I've been thinking a little more about that feature. I still believe that specifying bolt and nut lengths would make sense. The question remains: What about the thread() module?

The Length Problem

A logical approach would be to calculate turns = length / P. That would not be useful, however. Usually, a thread will be attached to some support. Usually, the length of that support is known and the length of the thread is derived from it (not the other way around). A thread using the length of the support would not fit onto a support of the same length. The length of the thread should be a little less than the length of the support. "A little less" means approximately one pitch. And looking up the pitch is exactly what we want to avoid. User code would not get simpler or shorter.

A more useful but a little counterintuitive approach is to calculate turns = length / P - 1. That way, the thread will fit onto the support. It could happen that the thread just touches (on one side or both sides) the end of the support. But usually - for thread-types with crest centered in pitch-length - one "valley" remains free on both sides. The user that wants to add a little more space either adds it as a length (mm, inches, whatever) or as a number of turns. In the latter case, she will again have to look up the pitch. But I guess the former will be good enough in many cases and will avoid this lookup => simpler and shorter user code.

What makes this approach a little more counterintuitive is the name of the argument (which I can't change without breaking backwards compatibility): thread("M4", turns=3.2, units="length").

User code would then look like this:

// make my own bolt:
L = 0.3;
   
specs = thread_specs("M4-ext");
P = specs[0];
Dsupport = specs[2];
translate([0, 0, +P / 2])
    thread("M4-ext"), turns=L, units="length");
cylinder(h=L, d=Dsupport);

Whoops: We still have to look up thread specs! We need to know the diameter of the support and we still need to know the pitch so that we can translate by half a pitch (otherwise, it would overlap the end).

The Half-Pitch Problem

The solution is ugly: thread("M4-ext"), turns=L, units="length", shiftByHalfPitch=true)

Alternative: break backwards compatibility and shift by P/2 by default.

The Support-Diameter Problem

A thread needs a support. To get the proper diameter, I need to look it up ...

An elegant solution could be something like this (would solve the P/2 problem as well):

P, Rrot, Dsupport, profile = thread("M4-ext"), turns=L, units="length");
translate([0, 0, -P / 2])
    cylinder(h=L, d=Dsupport);

This would require a new language feature in OpenSCAD that allows modules to not only create an object but to return values as well.

Conclusions

Providing length support for thread() module is utterly useless.

If we go for a length feature, it will be used in bolt() and nut() exclusively, or it will be added to thread() as well but then simply to remain consistent, not because it is useful.

I just realized that I have never used bolt() or nut() in my own parts. They were always special enough to warrant the use of thread(). To make sure we do not miss something: Can someone provide real examples where bolt() or nut() was used to build a part?

Thanks for your example code. As far as I can see, you would really get rid of the call to thread_specs() if nut() is extended to support a length argument.

However, you have hard-coded the "aussenradius" which is actually pretty much what thread_specs() returns as Dsupport. In that sense, you did indirectly need that call to thread_specs(). You would have the choice of removing the argument "aussenradius" of module "mutter" (and look it up via thread_specs() instead) or removing the call to thread_specs() (keeping the argument that has to be looked up manually to match the thread).

I have the impression that efficient use of a length argument is significantly hampered by limitations of OpenSCAD (see Support Diameter Problem in my previous post).

Since you asked for examples of using bolt() to produce parts....

When converting from the 'threads.scad' that Prusa used in their printer designs (and I subsequently used...) all of my parts assume 'bolt' type interactions. Also, I've used that module extensively for literally printing bolts. I think the recommendation to place length-based code into the bolt() functions is exactly what needs to happen, and should be doable in a backwards compatible manner, without making the user code of the bolt() module yicky.

Can you provide these examples? Can you comment on my summary of the situation I have provided above?

Since you asked for examples of using bolt() to produce parts....

When converting from the 'threads.scad' that Prusa used in their printer designs (and I subsequently used...) all of my parts assume 'bolt' type interactions. Also, I've used that module extensively for literally printing bolts. I think the recommendation to place length-based code into the bolt() functions is exactly what needs to happen, and should be doable in a backwards compatible manner, without making the user code of the bolt() module yicky.

I just realized today they're using openscad-threads! (which is at least twice as slow at creating comparable high-res thread profiles)

I have many parts that render 'taps' -- or a positive representing the internal threads, then removing the material with difference. I commonly do this if I don't have an actual tap for that thread type or size.

Here's a few (horrible) examples:
https://github.com/bvarner/bricabrac/blob/master/plumbing/Threaded_Barbed_Tee.scad
https://github.com/bvarner/bricabrac/blob/master/plumbing/latex_hose_connector.scad

A few better ones:
https://github.com/bvarner/bricabrac/blob/master/hydroponic_rig/PVC_Inlet_Cleanout.stl
https://github.com/bvarner/bricabrac/blob/master/hydroponic_rig/PVC_Drain_Cleanout.scad