1//////////////////////////////////////////////////////////////////////
2// LibFile: screw_drive.scad
3// Masks for Phillips, Torx and square (Robertson) driver holes.
4// Includes:
5// include <BOSL2/std.scad>
6// include <BOSL2/screw_drive.scad>
7// FileGroup: Threaded Parts
8// FileSummary: Masks for Phillips, Torx and square (Robertson) driver holes.
9//////////////////////////////////////////////////////////////////////
10
11
12include <structs.scad>
13
14// Section: Phillips Drive
15
16// Module: phillips_mask()
17// Synopsis: Creates a mask for a Philips screw drive.
18// SynTags: Geom
19// Topics: Screws, Masks
20// See Also: hex_drive_mask(), phillips_depth(), phillips_diam(), torx_mask(), robertson_mask()
21// Usage:
22// phillips_mask(size) [ATTACHMENTS];
23// Description:
24// Creates a mask for creating a Phillips drive recess given the Phillips size. Each mask can
25// be lowered to different depths to create different sizes of recess.
26// Arguments:
27// size = The size of the bit as an integer or string. "#0", "#1", "#2", "#3", or "#4"
28// ---
29// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
30// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
31// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
32// Example:
33// xdistribute(10) {
34// phillips_mask(size="#1");
35// phillips_mask(size="#2");
36// phillips_mask(size=3);
37// phillips_mask(size=4);
38// }
39
40// Specs for phillips recess here:
41// https://www.fasteners.eu/tech-info/ISO/4757/
42
43function _phillips_shaft(x) = [3,4.5,6,8,10][x];
44function _ph_bot_angle() = 28.0;
45function _ph_side_angle() = 26.5;
46
47module phillips_mask(size="#2", $fn=36, anchor=BOTTOM, spin=0, orient=UP) {
48 dummy = assert(in_list(size,["#0","#1","#2","#3","#4",0,1,2,3,4]));
49 num = is_num(size) ? size : ord(size[1]) - ord("0");
50 shaft = _phillips_shaft(num);
51 b = [0.61, 0.97, 1.47, 2.41, 3.48][num];
52 e = [0.31, 0.435, 0.815, 2.005, 2.415][num];
53 g = [0.81, 1.27, 2.29, 3.81, 5.08][num];
54 alpha = [ 136, 138, 140, 146, 153][num];
55 beta = [7.00, 7.00, 5.75, 5.75, 7.00][num];
56 gamma = 92.0;
57 h1 = adj_ang_to_opp(g/2, _ph_bot_angle()); // height of the small conical tip
58 h2 = adj_ang_to_opp((shaft-g)/2, 90-_ph_side_angle()); // height of larger cone
59 l = h1+h2;
60 h3 = adj_ang_to_opp(b/2, _ph_bot_angle()); // height where cutout starts
61 p0 = [0,0];
62 p1 = [adj_ang_to_opp(e/2, 90-alpha/2), -e/2];
63 p2 = p1 + [adj_ang_to_opp((shaft-e)/2, 90-gamma/2),-(shaft-e)/2];
64 attachable(anchor,spin,orient, d=shaft, l=l) {
65 down(l/2) {
66 difference() {
67 rotate_extrude()
68 polygon([[0,0],[g/2,h1],[shaft/2,l],[0,l]]);
69 zrot(45)
70 zrot_copies(n=4, r=b/2) {
71 up(h3) {
72 yrot(beta) {
73 down(1)
74 linear_extrude(height=l+2, convexity=4, center=false) {
75 path = [p0, p1, p2, [p2.x,-p2.y], [p1.x,-p1.y]];
76 polygon(path);
77 }
78 }
79 }
80 }
81 }
82 }
83 children();
84 }
85}
86
87
88
89// Function: phillips_depth()
90// Synopsis: Returns the depth a phillips recess needs to be for a given diameter.
91// Topics: Screws, Masks
92// See Also: phillips_mask(), hex_drive_mask(), phillips_depth(), phillips_diam(), torx_mask()
93// Usage:
94// depth = phillips_depth(size, d);
95// Description:
96// Returns the depth of the Phillips recess required to produce the specified diameter, or
97// undef if not possible.
98// Arguments:
99// size = size as a number or text string like "#2"
100// d = desired diameter
101function phillips_depth(size, d) =
102 assert(in_list(size,["#0","#1","#2","#3","#4",0,1,2,3,4]))
103 let(
104 num = is_num(size) ? size : ord(size[1]) - ord("0"),
105 shaft = [3,4.5,6,8,10][num],
106 g = [0.81, 1.27, 2.29, 3.81, 5.08][num],
107 h1 = adj_ang_to_opp(g/2, _ph_bot_angle()), // height of the small conical tip
108 h2 = adj_ang_to_opp((shaft-g)/2, 90-_ph_side_angle()) // height of larger cone
109 )
110 d>=shaft || d<g ? undef :
111 (d-g) / 2 / tan(_ph_side_angle()) + h1;
112
113
114// Function: phillips_diam()
115// Synopsis: Returns the diameter of a phillips recess of a given depth.
116// Topics: Screws, Masks
117// See Also: phillips_mask(), hex_drive_mask(), phillips_depth(), phillips_diam(), torx_mask()
118// Usage:
119// diam = phillips_diam(size, depth);
120// Description:
121// Returns the diameter at the top of the Phillips recess when constructed at the specified depth,
122// or undef if that depth is not valid.
123// Arguments:
124// size = size as number or text string like "#2"
125// depth = depth of recess to find the diameter of
126function phillips_diam(size, depth) =
127 assert(in_list(size,["#0","#1","#2","#3","#4",0,1,2,3,4]))
128 let(
129 num = is_num(size) ? size : ord(size[1]) - ord("0"),
130 shaft = _phillips_shaft(num),
131 g = [0.81, 1.27, 2.29, 3.81, 5.08][num],
132 h1 = adj_ang_to_opp(g/2, _ph_bot_angle()), // height of the small conical tip
133 h2 = adj_ang_to_opp((shaft-g)/2, 90-_ph_side_angle()) // height of larger cone
134 )
135 depth<h1 || depth>= h1+h2 ? undef :
136 2 * tan(_ph_side_angle())*(depth-h1) + g;
137
138
139// Section: Hex drive
140
141// Module: hex_drive_mask()
142// Synopsis: Creates a mask for a hex drive recess.
143// SynTags: Geom
144// Topics: Screws, Masks
145// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), robertson_mask()
146// Usage:
147// hex_drive_mask(size, length, [anchor], [spin], [orient], [$slop]) [ATTACHMENTS];
148// Description:
149// Creates a mask for hex drive. Note that the hex recess specs requires
150// a slightly oversized recess. You can use $slop to increase the size by
151// `2 * $slop` if necessary.
152//
153module hex_drive_mask(size,length,l,h,height,anchor,spin,orient)
154{
155 length = one_defined([length,height,l,h],"length,height,l,h");
156 realsize = 1.0072*size + 0.0341 + 2 * get_slop(); // Formula emperically determined from ISO standard
157 linear_sweep(height=length,hexagon(id=realsize),anchor=anchor,spin=spin,orient=orient) children();
158}
159function hex_drive_mask(size,length,l,h,height,anchor,spin,orient) = no_function("hex_drive_mask");
160
161
162// Section: Torx Drive
163
164// Module: torx_mask()
165// Synopsis: Creates a mask for a torx drive recess.
166// SynTags: Geom
167// Topics: Screws, Masks
168// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), robertson_mask()
169// Usage:
170// torx_mask(size, l, [center]) [ATTACHMENTS];
171// Description: Creates a torx bit tip. The anchors are located on the circumscribing cylinder. See {{torx_info()}} for allowed sizes.
172// Arguments:
173// size = Torx size.
174// l = Length of bit.
175// center = If true, centers mask vertically.
176// ---
177// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
178// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
179// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
180// Examples:
181// torx_mask(size=30, l=10, $fa=1, $fs=1);
182module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) {
183 od = torx_diam(size);
184 anchor = get_anchor(anchor, center, BOT, BOT);
185 attachable(anchor,spin,orient, d=od, l=l) {
186 linear_extrude(height=l, convexity=4, center=true) {
187 torx_mask2d(size);
188 }
189 children();
190 }
191}
192
193
194// Module: torx_mask2d()
195// Synopsis: Creates the 2D cross section for a torx drive recess.
196// SynTags: Geom
197// Topics: Screws, Masks
198// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info(), robertson_mask()
199// Usage:
200// torx_mask2d(size);
201// Description: Creates a torx bit 2D profile. The anchors are located on the circumscribing circle. See {{torx_info()}} for allowed sizes.
202// Arguments:
203// size = Torx size.
204// Example(2D):
205// torx_mask2d(size=30, $fa=1, $fs=1);
206module torx_mask2d(size,anchor=CENTER,spin) {
207 info = torx_info(size);
208 od = info[0];
209 id = info[1];
210 tip = info[3];
211 rounding = info[4];
212 base = od - 2*tip;
213 $fn = quantup(segs(od/2),12);
214 attachable(anchor,spin,two_d=true,d=od){
215 difference() {
216 union() {
217 circle(d=base);
218 zrot_copies(n=2) {
219 hull() {
220 zrot_copies(n=3) {
221 translate([base/2,0,0]) {
222 circle(r=tip, $fn=$fn/2);
223 }
224 }
225 }
226 }
227 }
228 zrot_copies(n=6) {
229 zrot(180/6) {
230 translate([id/2+rounding,0,0]) {
231 circle(r=rounding);
232 }
233 }
234 }
235 }
236 children();
237 }
238}
239
240
241// Function: torx_info()
242// Synopsis: Returns the dimensions of a torx drive.
243// Topics: Screws, Masks
244// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info()
245// Usage:
246// info = torx_info(size);
247// Description:
248// Get the typical dimensional info for a given Torx size.
249// Returns a list containing, in order:
250// - Outer Diameter
251// - Inner Diameter
252// - Drive Hole Depth
253// - External Tip Rounding Radius
254// - Inner Rounding Radius
255// .
256// The allowed torx sizes are:
257// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 27, 30, 40, 45, 50, 55,
258// 60, 70, 80, 90, 100.
259// Arguments:
260// size = Torx size.
261function torx_info(size) =
262 let(
263 info_arr = [ // Depth is from metric socket head screws, ISO 14583
264 //T# OD ID H Re Ri
265 [ 1, [ 0.90, 0.65, 0.40, 0.059, 0.201]], // depth interpolated
266 [ 2, [ 1.00, 0.73, 0.44, 0.069, 0.224]], // depth interpolated
267 [ 3, [ 1.20, 0.87, 0.53, 0.081, 0.266]], // depth interpolated
268 [ 4, [ 1.35, 0.98, 0.59, 0.090, 0.308]], // depth interpolated
269 [ 5, [ 1.48, 1.08, 0.65, 0.109, 0.330]], // depth interpolated
270 [ 6, [ 1.75, 1.27, 0.775, 0.132, 0.383]],
271 [ 7, [ 2.08, 1.50, 0.886, 0.161, 0.446]], // depth interpolated
272 [ 8, [ 2.40, 1.75, 1.0, 0.190, 0.510]],
273 [ 9, [ 2.58, 1.87, 1.078, 0.207, 0.554]], // depth interpolated
274 [ 10, [ 2.80, 2.05, 1.142, 0.229, 0.598]],
275 [ 15, [ 3.35, 2.40, 1.2, 0.267, 0.716]], // depth interpolated
276 [ 20, [ 3.95, 2.85, 1.4, 0.305, 0.859]], // depth interpolated
277 [ 25, [ 4.50, 3.25, 1.61, 0.375, 0.920]],
278 [ 27, [ 5.07, 3.65, 1.84, 0.390, 1.108]],
279 [ 30, [ 5.60, 4.05, 2.22, 0.451, 1.194]],
280 [ 40, [ 6.75, 4.85, 2.63, 0.546, 1.428]],
281 [ 45, [ 7.93, 5.64, 3.115, 0.574, 1.796]],
282 [ 50, [ 8.95, 6.45, 3.82, 0.775, 1.816]],
283 [ 55, [ 11.35, 8.05, 5.015, 0.867, 2.667]],
284 [ 60, [ 13.45, 9.60, 5.805, 1.067, 2.883]],
285 [ 70, [ 15.70, 11.20, 6.815, 1.194, 3.477]],
286 [ 80, [ 17.75, 12.80, 7.75, 1.526, 3.627]],
287 [ 90, [ 20.20, 14.40, 8.945, 1.530, 4.468]],
288 [100, [ 22.40, 16.00, 10.79, 1.720, 4.925]],
289 ],
290 found = struct_val(info_arr,size)
291 )
292 assert(found, str("Unsupported Torx size, ",size))
293 found;
294
295
296// Function: torx_diam()
297// Synopsis: Returns the diameter of a torx drive.
298// Topics: Screws, Masks
299// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info()
300// Usage:
301// diam = torx_diam(size);
302// Description: Get the typical outer diameter of Torx profile.
303// Arguments:
304// size = Torx size.
305function torx_diam(size) = torx_info(size)[0];
306
307
308// Function: torx_depth()
309// Synopsis: Returns the typical depth of a torx drive recess.
310// Topics: Screws, Masks
311// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info()
312// Usage:
313// depth = torx_depth(size);
314// Description: Gets typical drive hole depth.
315// Arguments:
316// size = Torx size.
317function torx_depth(size) = torx_info(size)[2];
318
319
320
321// Section: Robertson/Square Drives
322
323// Module: robertson_mask()
324// Synopsis: Creates a mask for a Robertson/Square drive recess.
325// SynTags: Geom
326// Topics: Screws, Masks
327// See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info(), robertson_mask()
328// Usage:
329// robertson_mask(size, [extra], [ang], [$slop=]);
330// Description:
331// Creates a mask for creating a Robertson/Square drive recess given the drive size as an integer.
332// The width of the recess will be oversized by `2 * $slop`. Note that this model is based
333// on an incomplete spec. https://www.aspenfasteners.com/content/pdf/square_drive_specification.pdf
334// We determined the angle by doing print tests on a Prusa MK3S with $slop set to 0.05.
335// Arguments:
336// size = The size of the square drive, as an integer from 0 to 4.
337// extra = Extra length of drive mask to create.
338// ang = taper angle of each face. Default: 2.5
339// ---
340// $slop = enlarge recess by this twice amount. Default: 0
341// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: TOP
342// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
343// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
344// Side Effects:
345// Sets tag to "remove" if no tag is set.
346// Example:
347// robertson_mask(size=2);
348// Example:
349// difference() {
350// cyl(d1=2, d2=8, h=4, anchor=TOP);
351// robertson_mask(size=2);
352// }
353module robertson_mask(size, extra=1, ang=2.5,anchor=TOP,spin,orient) {
354 dummy=assert(is_int(size) && size>=0 && size<=4);
355 Mmin = [0.0696, 0.0900, 0.1110, 0.1315, 0.1895][size];
356 Mmax = [0.0710, 0.0910, 0.1126, 0.1330, 0.1910][size];
357 M = (Mmin + Mmax) / 2 * INCH;
358 Tmin = [0.063, 0.105, 0.119, 0.155, 0.191][size];
359 Tmax = [0.073, 0.113, 0.140, 0.165, 0.201][size];
360 T = (Tmin + Tmax) / 2 * INCH;
361 Fmin = [0.032, 0.057, 0.065, 0.085, 0.090][size];
362 Fmax = [0.038, 0.065, 0.075, 0.095, 0.100][size];
363 F = (Fmin + Fmax) / 2 * INCH;
364 h = T + extra;
365 Mslop=M+2*get_slop();
366 Mtop = Mslop + 2*adj_ang_to_opp(F+extra,ang);
367 Mbot = Mslop - 2*adj_ang_to_opp(T-F,ang);
368 anchors = [named_anchor("standard",[0,0,T-h/2], UP, 0)];
369 default_tag("remove")
370 attachable(anchor,spin,orient,size=[Mbot,Mbot,T],size2=[Mtop,Mtop],anchors=anchors){
371 down(T/2)
372 intersection(){
373 prismoid([Mbot,Mbot],[Mtop,Mtop],h=h,anchor=BOT);
374 cyl(d1=0, d2=Mslop/(T-F)*sqrt(2)*h, h=h, anchor=BOT);
375 }
376 children();
377 }
378}
379
380
381
382// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap