1//////////////////////////////////////////////////////////////////////////////////////////////
2// LibFile: gears.scad
3// Spur Gears, Bevel Gears, Racks, Worms and Worm Gears.
4// Inspired by code by Leemon Baird, 2011, Leemon@Leemon.com
5// Includes:
6// include <BOSL2/std.scad>
7// include <BOSL2/gears.scad>
8// FileGroup: Parts
9// FileSummary: Gears, racks, worms, and worm gears.
10//////////////////////////////////////////////////////////////////////////////////////////////
11
12
13// Section: Terminology
14// The outline of a gear is a smooth circle (the "pitch circle") which has
15// mountains and valleys added so it is toothed. There is an inner
16// circle (the "root circle") that touches the base of all the teeth, an
17// outer circle that touches the tips of all the teeth, and the invisible
18// pitch circle in between them. There is also a "base circle", which can
19// be smaller than all three of the others, which controls the shape of
20// the teeth. The side of each tooth lies on the path that the end of a
21// string would follow if it were wrapped tightly around the base circle,
22// then slowly unwound. That shape is an "involute", which gives this
23// type of gear its name.
24
25
26// Section: Gears
27
28// Function&Module: spur_gear()
29// Usage: As a Module
30// spur_gear(pitch, teeth, thickness, [shaft_diam], [hide=], [pressure_angle=], [clearance=], [backlash=], [helical=], [slices=], [interior=]) [ATTACHMENTS];
31// spur_gear(mod=, teeth=, thickness=, [shaft_diam=], ...) [ATTACHMENTS];
32// Usage: As a Function
33// vnf = spur_gear(pitch, teeth, thickness, [shaft_diam], ...);
34// vnf = spur_gear(mod=, teeth=, thickness=, [shaft_diam], ...);
35// Topics: Gears
36// See Also: rack()
37// Description:
38// Creates a (potentially helical) involute spur gear. The module `spur_gear()` gives an involute
39// spur gear, with reasonable defaults for all the parameters. Normally, you should just choose the
40// first 4 parameters, and let the rest be default values. The module `spur_gear()` gives a gear in
41// the XY plane, centered on the origin, with one tooth centered on the positive Y axis. The most
42// important is `pitch_radius()`, which tells how far apart to space gears that are meshing, and
43// `outer_radius()`, which gives the size of the region filled by the gear. A gear has a "pitch
44// circle", which is an invisible circle that cuts through the middle of each tooth (though not the
45// exact center). In order for two gears to mesh, their pitch circles should just touch. So the
46// distance between their centers should be `pitch_radius()` for one, plus `pitch_radius()` for the
47// other, which gives the radii of their pitch circles. In order for two gears to mesh, they must
48// have the same `pitch` and `pressure_angle` parameters. `pitch` gives the number of millimeters
49// of arc around the pitch circle covered by one tooth and one space between teeth. The
50// `pressure_angle` controls how flat or bulged the sides of the teeth are. Common values include
51// 14.5 degrees and 20 degrees, and occasionally 25. Though I've seen 28 recommended for plastic
52// gears. Larger numbers bulge out more, giving stronger teeth, so 28 degrees is the default here.
53// The ratio of `teeth` for two meshing gears gives how many times one will make a full revolution
54// when the the other makes one full revolution. If the two numbers are coprime (i.e. are not both
55// divisible by the same number greater than 1), then every tooth on one gear will meet every tooth
56// on the other, for more even wear. So coprime numbers of teeth are good.
57// Arguments:
58// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
59// teeth = Total number of teeth around the entire perimeter
60// thickness = Thickness of gear in mm
61// shaft_diam = Diameter of the hole in the center, in mm. Default: 0 (no shaft hole)
62// ---
63// hide = Number of teeth to delete to make this only a fraction of a circle
64// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
65// clearance = Clearance gap at the bottom of the inter-tooth valleys.
66// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
67// helical = Teeth are slanted around the spur gear at this angle away from the gear axis of rotation.
68// slices = Number of vertical layers to divide gear into. Useful for refining gears with `helical`.
69// scale = Scale of top of gear compared to bottom. Useful for making crown gears.
70// interior = If true, create a mask for difference()ing from something else.
71// mod = The metric module/modulus of the gear.
72// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
73// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
74// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
75// Example: Spur Gear
76// spur_gear(pitch=5, teeth=20, thickness=8, shaft_diam=5);
77// Example: Metric Gear
78// spur_gear(mod=2, teeth=20, thickness=8, shaft_diam=5);
79// Example: Helical Gear
80// spur_gear(
81// pitch=5, teeth=20, thickness=10,
82// shaft_diam=5, helical=-30, slices=12,
83// $fa=1, $fs=1
84// );
85// Example(Anim,Frames=8,VPT=[0,30,0],VPR=[0,0,0],VPD=300): Assembly of Gears
86// n1 = 11; //red gear number of teeth
87// n2 = 20; //green gear
88// n3 = 5; //blue gear
89// n4 = 16; //orange gear
90// n5 = 9; //gray rack
91// pitch = 9; //all meshing gears need the same `pitch` (and the same `pressure_angle`)
92// thickness = 6;
93// hole = 3;
94// rack_base = 12;
95// r1 = pitch_radius(pitch,n1);
96// r2 = pitch_radius(pitch,n2);
97// r3 = pitch_radius(pitch,n3);
98// r4 = pitch_radius(pitch,n4);
99// r5 = pitch_radius(pitch,n5);
100// a1 = $t * 360 / n1;
101// a2 = -$t * 360 / n2 + 180/n2;
102// a3 = -$t * 360 / n3;
103// a4 = -$t * 360 / n4 - 7.5*180/n4;
104// color("#f77") zrot(a1) spur_gear(pitch,n1,thickness,hole);
105// color("#7f7") back(r1+r2) zrot(a2) spur_gear(pitch,n2,thickness,hole);
106// color("#77f") right(r1+r3) zrot(a3) spur_gear(pitch,n3,thickness,hole);
107// color("#fc7") left(r1+r4) zrot(a4) spur_gear(pitch,n4,thickness,hole,hide=n4-3);
108// color("#ccc") fwd(r1) right(pitch*$t)
109// rack(pitch=pitch,teeth=n5,thickness=thickness,height=rack_base,anchor=CENTER,orient=BACK);
110function spur_gear(
111 pitch = 3,
112 teeth = 11,
113 thickness = 6,
114 shaft_diam = 0,
115 hide = 0,
116 pressure_angle = 28,
117 clearance = undef,
118 backlash = 0.0,
119 helical = 0,
120 slices = 2,
121 interior = false,
122 mod,
123 anchor = CENTER,
124 spin = 0,
125 orient = UP
126) =
127 let(
128 pitch = is_undef(mod) ? pitch : pitch_value(mod),
129 p = pitch_radius(pitch, teeth),
130 c = outer_radius(pitch, teeth, clearance, interior),
131 r = _root_radius(pitch, teeth, clearance, interior),
132 twist = atan2(thickness*tan(helical),p),
133 rgn = [
134 spur_gear2d(
135 pitch = pitch,
136 teeth = teeth,
137 pressure_angle = pressure_angle,
138 hide = hide,
139 clearance = clearance,
140 backlash = backlash,
141 interior = interior
142 ),
143 if (shaft_diam > 0) circle(d=shaft_diam, $fn=max(12,segs(shaft_diam/2)))
144 ],
145 vnf = linear_sweep(rgn, height=thickness, center=true)
146 ) reorient(anchor,spin,orient, h=thickness, r=p, p=vnf);
147
148
149module spur_gear(
150 pitch = 3,
151 teeth = 11,
152 thickness = 6,
153 shaft_diam = 0,
154 hide = 0,
155 pressure_angle = 28,
156 clearance = undef,
157 backlash = 0.0,
158 helical = 0,
159 slices = 2,
160 interior = false,
161 mod,
162 anchor = CENTER,
163 spin = 0,
164 orient = UP
165) {
166 pitch = is_undef(mod) ? pitch : pitch_value(mod);
167 p = pitch_radius(pitch, teeth);
168 c = outer_radius(pitch, teeth, clearance, interior);
169 r = _root_radius(pitch, teeth, clearance, interior);
170 twist = atan2(thickness*tan(helical),p);
171 attachable(anchor,spin,orient, r=p, l=thickness) {
172 difference() {
173 linear_extrude(height=thickness, center=true, convexity=teeth/2, twist=twist) {
174 spur_gear2d(
175 pitch = pitch,
176 teeth = teeth,
177 pressure_angle = pressure_angle,
178 hide = hide,
179 clearance = clearance,
180 backlash = backlash,
181 interior = interior
182 );
183 }
184 if (shaft_diam > 0) {
185 cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
186 }
187 }
188 children();
189 }
190}
191
192
193// Function&Module: spur_gear2d()
194// Usage: As Module
195// spur_gear2d(pitch, teeth, [hide=], [pressure_angle=], [clearance=], [backlash=], [interior=]) [ATTACHMENTS];
196// spur_gear2d(mod=, teeth=, [hide=], [pressure_angle=], [clearance=], [backlash=], [interior=]) [ATTACHMENTS];
197// Usage: As Function
198// poly = spur_gear2d(pitch, teeth, [hide=], [pressure_angle=], [clearance=], [backlash=], [interior=]);
199// poly = spur_gear2d(mod=, teeth=, [hide=], [pressure_angle=], [clearance=], [backlash=], [interior=]);
200// Topics: Gears
201// See Also: spur_gear()
202// Description:
203// When called as a module, creates a 2D involute spur gear. When called as a function, returns a
204// 2D path for the perimeter of a 2D involute spur gear. Normally, you should just specify the
205// first 2 parameters `pitch` and `teeth`, and let the rest be default values.
206// Meshing gears must match in `pitch`, `pressure_angle`, and `helical`, and be separated by
207// the sum of their pitch radii, which can be found with `pitch_radius()`.
208// Arguments:
209// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
210// teeth = Total number of teeth around the spur gear.
211// hide = Number of teeth to delete to make this only a fraction of a circle
212// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
213// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
214// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
215// interior = If true, create a mask for difference()ing from something else.
216// mod = The metric module/modulus of the gear.
217// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
218// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
219// Example(2D): Typical Gear Shape
220// spur_gear2d(pitch=5, teeth=20);
221// Example(2D): Metric Gear
222// spur_gear2d(mod=2, teeth=20);
223// Example(2D): Lower Pressure Angle
224// spur_gear2d(pitch=5, teeth=20, pressure_angle=20);
225// Example(2D): Partial Gear
226// spur_gear2d(pitch=5, teeth=20, hide=15, pressure_angle=20);
227// Example(2D): Called as a Function
228// path = spur_gear2d(pitch=8, teeth=16);
229// polygon(path);
230function spur_gear2d(
231 pitch = 3,
232 teeth = 11,
233 hide = 0,
234 pressure_angle = 28,
235 clearance = undef,
236 backlash = 0.0,
237 interior = false,
238 mod,
239 anchor = CENTER,
240 spin = 0
241) = let(
242 pitch = is_undef(mod) ? pitch : pitch_value(mod),
243 pr = pitch_radius(pitch=pitch, teeth=teeth),
244 tooth_profile = _gear_tooth_profile(
245 pitch = pitch,
246 teeth = teeth,
247 pressure_angle = pressure_angle,
248 clearance = clearance,
249 backlash = backlash,
250 interior = interior,
251 valleys = false
252 ),
253 pts = concat(
254 [for (tooth = [0:1:teeth-hide-1])
255 each rot(tooth*360/teeth, p=tooth_profile)
256 ],
257 hide>0? [[0,0]] : []
258 )
259) reorient(anchor,spin, two_d=true, r=pr, p=pts);
260
261
262module spur_gear2d(
263 pitch = 3,
264 teeth = 11,
265 hide = 0,
266 pressure_angle = 28,
267 clearance = undef,
268 backlash = 0.0,
269 interior = false,
270 mod,
271 anchor = CENTER,
272 spin = 0
273) {
274 pitch = is_undef(mod) ? pitch : pitch_value(mod);
275 path = spur_gear2d(
276 pitch = pitch,
277 teeth = teeth,
278 hide = hide,
279 pressure_angle = pressure_angle,
280 clearance = clearance,
281 backlash = backlash,
282 interior = interior
283 );
284 pr = pitch_radius(pitch=pitch, teeth=teeth);
285 attachable(anchor,spin, two_d=true, r=pr) {
286 polygon(path);
287 children();
288 }
289}
290
291
292
293// Function&Module: rack()
294// Usage: As a Module
295// rack(pitch, teeth, thickness, height, [pressure_angle=], [backlash=]) [ATTACHMENTS];
296// rack(mod=, teeth=, thickness=, height=, [pressure_angle=], [backlash]=) [ATTACHMENTS];
297// Usage: As a Function
298// vnf = rack(pitch, teeth, thickness, height, [pressure_angle=], [backlash=]);
299// vnf = rack(mod=, teeth=, thickness=, height=, [pressure_angle=], [backlash=]);
300// Topics: Gears
301// See Also: spur_gear()
302// Description:
303// This is used to create a 3D rack, which is a linear bar with teeth that a gear can roll along.
304// A rack can mesh with any gear that has the same `pitch` and `pressure_angle`.
305// When called as a function, returns a 3D [VNF](vnf.scad) for the rack.
306// When called as a module, creates a 3D rack shape.
307// Arguments:
308// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
309// teeth = Total number of teeth along the rack. Default: 20
310// thickness = Thickness of rack in mm (affects each tooth). Default: 5
311// height = Height of rack in mm, from tooth top to back of rack. Default: 10
312// ---
313// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 28
314// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
315// clearance = Clearance gap at the bottom of the inter-tooth valleys.
316// helical = The angle of the rack teeth away from perpendicular to the rack length. Used to match helical spur gear pinions. Default: 0
317// mod = The metric module/modulus of the gear.
318// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
319// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
320// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
321// Extra Anchors:
322// "adendum" = At the tips of the teeth, at the center of rack.
323// "adendum-left" = At the tips of the teeth, at the left end of the rack.
324// "adendum-right" = At the tips of the teeth, at the right end of the rack.
325// "adendum-back" = At the tips of the teeth, at the back of the rack.
326// "adendum-front" = At the tips of the teeth, at the front of the rack.
327// "dedendum" = At the base of the teeth, at the center of rack.
328// "dedendum-left" = At the base of the teeth, at the left end of the rack.
329// "dedendum-right" = At the base of the teeth, at the right end of the rack.
330// "dedendum-back" = At the base of the teeth, at the back of the rack.
331// "dedendum-front" = At the base of the teeth, at the front of the rack.
332// Example(VPR=[60,0,325],VPD=130):
333// rack(pitch=5, teeth=10, thickness=5, height=5, pressure_angle=20);
334// Example: Rack for Helical Gear
335// rack(pitch=5, teeth=10, thickness=5, height=5, pressure_angle=20, helical=30);
336// Example: Alternate Helical Gear
337// rack(pitch=5, teeth=10, thickness=5, height=5, pressure_angle=20, helical=-30);
338// Example: Metric Rack
339// rack(mod=2, teeth=10, thickness=5, height=5, pressure_angle=20);
340// Example(Anim,VPT=[0,0,12],VPD=100,Frames=6): Rack and Pinion
341// teeth1 = 16; teeth2 = 16;
342// pitch = 5; thick = 5; helical = 30;
343// pr = pitch_radius(pitch=pitch, teeth=teeth2);
344// right(pr*2*PI/teeth2*$t) rack(pitch=pitch, teeth=teeth1, thickness=thick, height=5, helical=helical);
345// up(pr) yrot(186.5-$t*360/teeth2)
346// spur_gear(pitch=pitch, teeth=teeth2, thickness=thick, helical=helical, shaft_diam=5, orient=BACK);
347module rack(
348 pitch = 5,
349 teeth = 20,
350 thickness = 5,
351 height = 10,
352 pressure_angle = 28,
353 backlash = 0.0,
354 clearance,
355 helical=0,
356 mod,
357 anchor = CENTER,
358 spin = 0,
359 orient = UP
360) {
361 pitch = is_undef(mod) ? pitch : pitch_value(mod);
362 a = _adendum(pitch);
363 d = _dedendum(pitch, clearance);
364 l = teeth * pitch;
365 anchors = [
366 named_anchor("adendum", [0,0,a], BACK),
367 named_anchor("adendum-left", [-l/2,0,a], LEFT),
368 named_anchor("adendum-right", [ l/2,0,a], RIGHT),
369 named_anchor("adendum-front", [0,-thickness/2,a], DOWN),
370 named_anchor("adendum-back", [0, thickness/2,a], UP),
371 named_anchor("dedendum", [0,0,-d], BACK),
372 named_anchor("dedendum-left", [-l/2,0,-d], LEFT),
373 named_anchor("dedendum-right", [ l/2,0,-d], RIGHT),
374 named_anchor("dedendum-front", [0,-thickness/2,-d], DOWN),
375 named_anchor("dedendum-back", [0, thickness/2,-d], UP),
376 ];
377 attachable(anchor,spin,orient, size=[l, thickness, 2*abs(a-height)], anchors=anchors) {
378 skew(sxy=tan(helical)) xrot(90) {
379 linear_extrude(height=thickness, center=true, convexity=teeth*2) {
380 rack2d(
381 pitch = pitch,
382 teeth = teeth,
383 height = height,
384 pressure_angle = pressure_angle,
385 backlash = backlash,
386 clearance = clearance
387 );
388 }
389 }
390 children();
391 }
392}
393
394
395function rack(
396 pitch = 5,
397 teeth = 20,
398 thickness = 5,
399 height = 10,
400 pressure_angle = 28,
401 backlash = 0.0,
402 clearance,
403 helical=0,
404 mod,
405 anchor = CENTER,
406 spin = 0,
407 orient = UP
408) =
409 let(
410 pitch = is_undef(mod) ? pitch : pitch_value(mod),
411 a = _adendum(pitch),
412 d = _dedendum(pitch, clearance),
413 l = teeth * pitch,
414 anchors = [
415 named_anchor("adendum", [0,0,a], BACK),
416 named_anchor("adendum-left", [-l/2,0,a], LEFT),
417 named_anchor("adendum-right", [ l/2,0,a], RIGHT),
418 named_anchor("adendum-front", [0,-thickness/2,a], DOWN),
419 named_anchor("adendum-back", [0, thickness/2,a], UP),
420 named_anchor("dedendum", [0,0,-d], BACK),
421 named_anchor("dedendum-left", [-l/2,0,-d], LEFT),
422 named_anchor("dedendum-right", [ l/2,0,-d], RIGHT),
423 named_anchor("dedendum-front", [0,-thickness/2,-d], DOWN),
424 named_anchor("dedendum-back", [0, thickness/2,-d], UP),
425 ],
426 path = rack2d(
427 pitch = pitch,
428 teeth = teeth,
429 height = height,
430 pressure_angle = pressure_angle,
431 backlash = backlash,
432 clearance = clearance
433 ),
434 vnf = linear_sweep(path, height=thickness, anchor="origin", orient=FWD),
435 out = helical==0? vnf : skew(sxy=tan(helical), p=vnf)
436 ) reorient(anchor,spin,orient, size=[l, thickness, 2*abs(a-height)], anchors=anchors, p=out);
437
438
439
440
441// Function&Module: rack2d()
442// Usage: As a Module
443// path = rack2d(pitch, teeth, height, [pressure_angle=], [backlash=]) [ATTACHMENTS];
444// path = rack2d(mod=, teeth=, height=, [pressure_angle=], [backlash=]) [ATTACHMENTS];
445// Usage: As a Function
446// path = rack2d(pitch, teeth, height, [pressure_angle=], [backlash=]);
447// path = rack2d(mod=, teeth=, height=, [pressure_angle=], [backlash=]);
448// Topics: Gears
449// See Also: spur_gear2d()
450// Description:
451// This is used to create a 2D rack, which is a linear bar with teeth that a gear can roll along.
452// A rack can mesh with any gear that has the same `pitch` and `pressure_angle`.
453// When called as a function, returns a 2D path for the outline of the rack.
454// When called as a module, creates a 2D rack shape.
455// Arguments:
456// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
457// teeth = Total number of teeth along the rack
458// height = Height of rack in mm, from tooth top to back of rack.
459// ---
460// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
461// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
462// mod = The metric module/modulus of the gear.
463// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
464// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
465// Extra Anchors:
466// "adendum" = At the tips of the teeth, at the center of rack.
467// "adendum-left" = At the tips of the teeth, at the left end of the rack.
468// "adendum-right" = At the tips of the teeth, at the right end of the rack.
469// "dedendum" = At the height of the teeth, at the center of rack.
470// "dedendum-left" = At the height of the teeth, at the left end of the rack.
471// "dedendum-right" = At the height of the teeth, at the right end of the rack.
472// Example(2D):
473// rack2d(pitch=5, teeth=10, height=10, pressure_angle=20);
474// Example(2D): Called as a Function
475// path = rack2d(pitch=8, teeth=8, height=10, pressure_angle=28);
476// polygon(path);
477function rack2d(
478 pitch = 5,
479 teeth = 20,
480 height = 10,
481 pressure_angle = 28,
482 backlash = 0.0,
483 clearance = undef,
484 mod,
485 anchor = CENTER,
486 spin = 0
487) =
488 let(
489 pitch = is_undef(mod) ? pitch : pitch_value(mod),
490 a = _adendum(pitch),
491 d = _dedendum(pitch, clearance)
492 )
493 assert(a+d < height)
494 let(
495 xa = a * sin(pressure_angle),
496 xd = d * sin(pressure_angle),
497 l = teeth * pitch,
498 anchors = [
499 named_anchor("adendum", [ 0, a,0], BACK),
500 named_anchor("adendum-left", [-l/2, a,0], LEFT),
501 named_anchor("adendum-right", [ l/2, a,0], RIGHT),
502 named_anchor("dedendum", [ 0,-d,0], BACK),
503 named_anchor("dedendum-left", [-l/2,-d,0], LEFT),
504 named_anchor("dedendum-right", [ l/2,-d,0], RIGHT),
505 ],
506 path = [
507 [-(teeth-1)/2 * pitch + -1/2 * pitch, a-height],
508 [-(teeth-1)/2 * pitch + -1/2 * pitch, -d],
509 for (i = [0:1:teeth-1]) let(
510 off = (i-(teeth-1)/2) * pitch
511 ) each [
512 [off + -1/4 * pitch + backlash - xd, -d],
513 [off + -1/4 * pitch + backlash + xa, a],
514 [off + 1/4 * pitch - backlash - xa, a],
515 [off + 1/4 * pitch - backlash + xd, -d],
516 ],
517 [ (teeth-1)/2 * pitch + 1/2 * pitch, -d],
518 [ (teeth-1)/2 * pitch + 1/2 * pitch, a-height],
519 ]
520 ) reorient(anchor,spin, two_d=true, size=[l,2*abs(a-height)], anchors=anchors, p=path);
521
522
523module rack2d(
524 pitch = 5,
525 teeth = 20,
526 height = 10,
527 pressure_angle = 28,
528 backlash = 0.0,
529 clearance = undef,
530 mod,
531 anchor = CENTER,
532 spin = 0
533) {
534 pitch = is_undef(mod) ? pitch : pitch_value(mod);
535 a = _adendum(pitch);
536 d = _dedendum(pitch, clearance);
537 l = teeth * pitch;
538 anchors = [
539 named_anchor("adendum", [ 0, a,0], BACK),
540 named_anchor("adendum-left", [-l/2, a,0], LEFT),
541 named_anchor("adendum-right", [ l/2, a,0], RIGHT),
542 named_anchor("dedendum", [ 0,-d,0], BACK),
543 named_anchor("dedendum-left", [-l/2,-d,0], LEFT),
544 named_anchor("dedendum-right", [ l/2,-d,0], RIGHT),
545 ];
546 path = rack2d(
547 pitch = pitch,
548 teeth = teeth,
549 height = height,
550 pressure_angle = pressure_angle,
551 backlash = backlash,
552 clearance = clearance
553 );
554 attachable(anchor,spin, two_d=true, size=[l, 2*abs(a-height)], anchors=anchors) {
555 polygon(path);
556 children();
557 }
558}
559
560
561
562
563// Function&Module: bevel_gear()
564// Usage: As a Module
565// bevel_gear(pitch|mod, teeth, face_width, pitch_angle, [shaft_diam], [hide], [pressure_angle], [clearance], [backlash], [cutter_radius], [spiral_angle], [slices], [interior]);
566// Usage: As a Function
567// vnf = bevel_gear(pitch|mod, teeth, face_width, pitch_angle, [hide], [pressure_angle], [clearance], [backlash], [cutter_radius], [spiral_angle], [slices], [interior]);
568// Topics: Gears
569// See Also: bevel_pitch_angle()
570// Description:
571// Creates a (potentially spiral) bevel gear. The module `bevel_gear()` gives a bevel gear, with
572// reasonable defaults for all the parameters. Normally, you should just choose the first 4
573// parameters, and let the rest be default values. The module `bevel_gear()` gives a gear in the XY
574// plane, centered on the origin, with one tooth centered on the positive Y axis. The various
575// functions below it take the same parameters, and return various measurements for the gear. The
576// most important is `pitch_radius()`, which tells how far apart to space gears that are meshing,
577// and `outer_radius()`, which gives the size of the region filled by the gear. A gear has a "pitch
578// circle", which is an invisible circle that cuts through the middle of each tooth (though not the
579// exact center). In order for two gears to mesh, their pitch circles should just touch. So the
580// distance between their centers should be `pitch_radius()` for one, plus `pitch_radius()` for the
581// other, which gives the radii of their pitch circles. In order for two gears to mesh, they must
582// have the same `pitch` and `pressure_angle` parameters. `pitch` gives the number of millimeters of arc around
583// the pitch circle covered by one tooth and one space between teeth. The `pressure_angle` controls how flat or
584// bulged the sides of the teeth are. Common values include 14.5 degrees and 20 degrees, and
585// occasionally 25. Though I've seen 28 recommended for plastic gears. Larger numbers bulge out
586// more, giving stronger teeth, so 28 degrees is the default here. The ratio of `teeth` for two
587// meshing gears gives how many times one will make a full revolution when the the other makes one
588// full revolution. If the two numbers are coprime (i.e. are not both divisible by the same number
589// greater than 1), then every tooth on one gear will meet every tooth on the other, for more even
590// wear. So coprime numbers of teeth are good.
591// Arguments:
592// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
593// teeth = Total number of teeth around the entire perimeter. Default: 20
594// face_width = Width of the toothed surface in mm, from inside to outside. Default: 10
595// pitch_angle = Angle of beveled gear face. Default: 45
596// mate_teeth = The number of teeth in the gear that this gear will mate with. Overrides `pitch_angle` if given.
597// shaft_diam = Diameter of the hole in the center, in mm. Module use only. Default: 0 (no shaft hole)
598// hide = Number of teeth to delete to make this only a fraction of a circle. Default: 0
599// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 28
600// clearance = Clearance gap at the bottom of the inter-tooth valleys.
601// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
602// cutter_radius = Radius of spiral arc for teeth. If 0, then gear will not be spiral. Default: 0
603// spiral_angle = The base angle for spiral teeth. Default: 0
604// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
605// slices = Number of vertical layers to divide gear into. Useful for refining gears with `spiral`. Default: 1
606// interior = If true, create a mask for difference()ing from something else.
607// mod = The metric module/modulus of the gear.
608// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
609// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
610// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
611// Extra Anchors:
612// "apex" = At the pitch cone apex for the bevel gear.
613// "pitchbase" = At the natural height of the pitch radius of the beveled gear.
614// "flattop" = At the top of the flat top of the bevel gear.
615// Example: Beveled Gear
616// bevel_gear(
617// pitch=5, teeth=36, face_width=10, shaft_diam=5,
618// pitch_angle=45, spiral_angle=0
619// );
620// Example: Spiral Beveled Gear and Pinion
621// t1 = 16; t2 = 28;
622// bevel_gear(
623// pitch=5, teeth=t1, mate_teeth=t2,
624// slices=12, anchor="apex", orient=FWD
625// );
626// bevel_gear(
627// pitch=5, teeth=t2, mate_teeth=t1, left_handed=true,
628// slices=12, anchor="apex", spin=180/t2
629// );
630// Example(Anim,Frames=4,VPD=175): Manual Spacing of Pinion and Gear
631// t1 = 14; t2 = 28; pitch=5;
632// back(pitch_radius(pitch=pitch, teeth=t2)) {
633// yrot($t*360/t1)
634// bevel_gear(
635// pitch=pitch, teeth=t1, mate_teeth=t2, shaft_diam=5,
636// slices=12, orient=FWD
637// );
638// }
639// down(pitch_radius(pitch=pitch, teeth=t1)) {
640// zrot($t*360/t2)
641// bevel_gear(
642// pitch=pitch, teeth=t2, mate_teeth=t1, left_handed=true,
643// shaft_diam=5, slices=12, spin=180/t2
644// );
645// }
646function bevel_gear(
647 pitch = 5,
648 teeth = 20,
649 face_width = 10,
650 pitch_angle = 45,
651 mate_teeth,
652 hide = 0,
653 pressure_angle = 20,
654 clearance = undef,
655 backlash = 0.0,
656 cutter_radius = 30,
657 spiral_angle = 35,
658 left_handed = false,
659 slices = 5,
660 interior = false,
661 mod,
662 anchor = "pitchbase",
663 spin = 0,
664 orient = UP
665) =
666 let(
667 pitch = is_undef(mod) ? pitch : pitch_value(mod),
668 slices = cutter_radius==0? 1 : slices,
669 pitch_angle = is_undef(mate_teeth)? pitch_angle : atan(teeth/mate_teeth),
670 pr = pitch_radius(pitch, teeth),
671 rr = _root_radius(pitch, teeth, clearance, interior),
672 pitchoff = (pr-rr) * sin(pitch_angle),
673 ocone_rad = opp_ang_to_hyp(pr, pitch_angle),
674 icone_rad = ocone_rad - face_width,
675 cutter_radius = cutter_radius==0? 1000 : cutter_radius,
676 midpr = (icone_rad + ocone_rad) / 2,
677 radcp = [0, midpr] + polar_to_xy(cutter_radius, 180+spiral_angle),
678 angC1 = law_of_cosines(a=cutter_radius, b=norm(radcp), c=ocone_rad),
679 angC2 = law_of_cosines(a=cutter_radius, b=norm(radcp), c=icone_rad),
680 radcpang = v_theta(radcp),
681 sang = radcpang - (180-angC1),
682 eang = radcpang - (180-angC2),
683 profile = _gear_tooth_profile(
684 pitch = pitch,
685 teeth = teeth,
686 pressure_angle = pressure_angle,
687 clearance = clearance,
688 backlash = backlash,
689 interior = interior,
690 valleys = false,
691 center = true
692 ),
693 verts1 = [
694 for (v = lerpn(0,1,slices+1)) let(
695 p = radcp + polar_to_xy(cutter_radius, lerp(sang,eang,v)),
696 ang = v_theta(p)-90,
697 dist = norm(p)
698 ) [
699 let(
700 u = dist / ocone_rad,
701 m = up((1-u) * pr / tan(pitch_angle)) *
702 up(pitchoff) *
703 zrot(ang/sin(pitch_angle)) *
704 back(u * pr) *
705 xrot(pitch_angle) *
706 scale(u)
707 )
708 for (tooth=[0:1:teeth-1])
709 each apply(xflip() * zrot(360*tooth/teeth) * m, path3d(profile))
710 ]
711 ],
712 botz = verts1[0][0].z,
713 topz = last(verts1)[0].z,
714 thickness = abs(topz - botz),
715 cpz = (topz + botz) / 2,
716 vertices = [for (x=verts1) reverse(x)],
717 sides_vnf = vnf_vertex_array(vertices, caps=false, col_wrap=true, reverse=true),
718 top_verts = last(vertices),
719 bot_verts = vertices[0],
720 gear_pts = len(top_verts),
721 face_pts = gear_pts / teeth,
722 top_faces =[
723 for (i=[0:1:teeth-1], j=[0:1:(face_pts/2)-1]) each [
724 [i*face_pts+j, (i+1)*face_pts-j-1, (i+1)*face_pts-j-2],
725 [i*face_pts+j, (i+1)*face_pts-j-2, i*face_pts+j+1]
726 ],
727 for (i=[0:1:teeth-1]) each [
728 [gear_pts, (i+1)*face_pts-1, i*face_pts],
729 [gear_pts, ((i+1)%teeth)*face_pts, (i+1)*face_pts-1]
730 ]
731 ],
732 vnf1 = vnf_join([
733 [
734 [each top_verts, [0,0,top_verts[0].z]],
735 top_faces
736 ],
737 [
738 [each bot_verts, [0,0,bot_verts[0].z]],
739 [for (x=top_faces) reverse(x)]
740 ],
741 sides_vnf
742 ]),
743 lvnf = left_handed? vnf1 : xflip(p=vnf1),
744 vnf = down(cpz, p=lvnf),
745 anchors = [
746 named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
747 named_anchor("flattop", [0,0,thickness/2]),
748 named_anchor("apex", [0,0,hyp_ang_to_opp(ocone_rad,90-pitch_angle)+pitchoff-thickness/2])
749 ]
750 ) reorient(anchor,spin,orient, vnf=vnf, extent=true, anchors=anchors, p=vnf);
751
752
753module bevel_gear(
754 pitch = 5,
755 teeth = 20,
756 face_width = 10,
757 pitch_angle = 45,
758 mate_teeth,
759 shaft_diam = 0,
760 hide = 0,
761 pressure_angle = 20,
762 clearance = undef,
763 backlash = 0.0,
764 cutter_radius = 30,
765 spiral_angle = 35,
766 left_handed = false,
767 slices = 5,
768 interior = false,
769 mod,
770 anchor = "pitchbase",
771 spin = 0,
772 orient = UP
773) {
774 pitch = is_undef(mod) ? pitch : pitch_value(mod);
775 slices = cutter_radius==0? 1 : slices;
776 pitch_angle = is_undef(mate_teeth)? pitch_angle : atan(teeth/mate_teeth);
777 pr = pitch_radius(pitch, teeth);
778 ipr = pr - face_width*sin(pitch_angle);
779 rr = _root_radius(pitch, teeth, clearance, interior);
780 pitchoff = (pr-rr) * sin(pitch_angle);
781 vnf = bevel_gear(
782 pitch = pitch,
783 teeth = teeth,
784 face_width = face_width,
785 pitch_angle = pitch_angle,
786 hide = hide,
787 pressure_angle = pressure_angle,
788 clearance = clearance,
789 backlash = backlash,
790 cutter_radius = cutter_radius,
791 spiral_angle = spiral_angle,
792 left_handed = left_handed,
793 slices = slices,
794 interior = interior,
795 anchor=CENTER
796 );
797 axis_zs = [for (p=vnf[0]) if(norm(point2d(p)) < EPSILON) p.z];
798 thickness = max(axis_zs) - min(axis_zs);
799 anchors = [
800 named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
801 named_anchor("flattop", [0,0,thickness/2]),
802 named_anchor("apex", [0,0,adj_ang_to_opp(pr,90-pitch_angle)+pitchoff-thickness/2])
803 ];
804 attachable(anchor,spin,orient, r1=pr, r2=ipr, h=thickness, anchors=anchors) {
805 difference() {
806 vnf_polyhedron(vnf, convexity=teeth/2);
807 if (shaft_diam > 0) {
808 cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
809 }
810 }
811 children();
812 }
813}
814
815
816
817
818
819// Function&Module: worm()
820// Usage: As a Module
821// worm(pitch|mod, d, l, [starts], [left_handed], [pressure_angle], [backlash], [clearance]);
822// Usage: As a Function
823// vnf = worm(pitch|mod, d, l, [starts], [left_handed], [pressure_angle], [backlash], [clearance]);
824// Topics: Gears
825// See Also: worm_gear()
826// Description:
827// Creates a worm shape that can be matched to a worm gear.
828// Arguments:
829// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
830// d = The diameter of the worm. Default: 30
831// l = The length of the worm. Default: 100
832// starts = The number of lead starts. Default: 1
833// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
834// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
835// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
836// clearance = Clearance gap at the bottom of the inter-tooth valleys.
837// mod = The metric module/modulus of the gear.
838// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
839// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
840// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
841// Example:
842// worm(pitch=8, d=30, l=50, $fn=72);
843// Example: Multiple Starts.
844// worm(pitch=8, d=30, l=50, starts=3, $fn=72);
845// Example: Left Handed
846// worm(pitch=8, d=30, l=50, starts=3, left_handed=true, $fn=72);
847// Example: Called as Function
848// vnf = worm(pitch=8, d=35, l=50, starts=2, left_handed=true, pressure_angle=20, $fn=72);
849// vnf_polyhedron(vnf);
850function worm(
851 pitch=5,
852 d=30, l=100,
853 starts=1,
854 left_handed=false,
855 pressure_angle=20,
856 backlash=0,
857 clearance,
858 mod,
859 anchor=CENTER,
860 spin=0,
861 orient=UP
862) =
863 let(
864 pitch = is_undef(mod) ? pitch : pitch_value(mod),
865 rack_profile = select(rack2d(
866 pitch = pitch,
867 teeth = starts,
868 height = d,
869 pressure_angle = pressure_angle,
870 backlash = backlash,
871 clearance = clearance
872 ), 1, -2),
873 polars = [
874 for (i=idx(rack_profile)) let(
875 p = rack_profile[i],
876 a = 360 * p.x / pitch / starts
877 ) [a, p.y + d/2]
878 ],
879 maxang = 360 / segs(d/2),
880 refined_polars = [
881 for (i=idx(polars,e=-2)) let(
882 delta = polars[i+1].x - polars[i].x,
883 steps = ceil(delta/maxang),
884 step = delta/steps
885 ) for (j = [0:1:steps-1])
886 [polars[i].x + j*step, lerp(polars[i].y,polars[i+1].y, j/steps)]
887 ],
888 cross_sect = [ for (p = refined_polars) polar_to_xy(p.y, p.x) ],
889 revs = l/pitch/starts,
890 zsteps = ceil(revs*360/maxang),
891 zstep = l/zsteps,
892 astep = revs*360/zsteps,
893 profiles = [
894 for (i=[0:1:zsteps]) let(
895 z = i*zstep - l/2,
896 a = i*astep - 360*revs/2
897 )
898 apply(zrot(a)*up(z), path3d(cross_sect))
899 ],
900 rprofiles = [ for (prof=profiles) reverse(prof) ],
901 vnf1 = vnf_vertex_array(rprofiles, caps=true, col_wrap=true, style="min_edge"),
902 vnf = left_handed? xflip(p=vnf1) : vnf1
903 ) reorient(anchor,spin,orient, d=d, l=l, p=vnf);
904
905
906module worm(
907 pitch=5,
908 d=15, l=100,
909 starts=1,
910 left_handed=false,
911 pressure_angle=20,
912 backlash=0,
913 clearance,
914 mod,
915 anchor=CENTER,
916 spin=0,
917 orient=UP
918) {
919 vnf = worm(
920 pitch=pitch,
921 starts=starts,
922 d=d, l=l,
923 left_handed=left_handed,
924 pressure_angle=pressure_angle,
925 backlash=backlash,
926 clearance=clearance,
927 mod=mod
928 );
929 attachable(anchor,spin,orient, d=d, l=l) {
930 vnf_polyhedron(vnf, convexity=ceil(l/pitch)*2);
931 children();
932 }
933}
934
935
936// Function&Module: worm_gear()
937// Usage: As a Module
938// worm_gear(pitch|mod, teeth, worm_diam, [worm_starts], [crowning], [left_handed], [pressure_angle], [backlash], [slices], [clearance], [shaft_diam]);
939// Usage: As a Function
940// vnf = worm_gear(pitch|mod, teeth, worm_diam, [worm_starts], [crowning], [left_handed], [pressure_angle], [backlash], [slices], [clearance]);
941// Topics: Gears
942// See Also: worm()
943// Description:
944// Creates a worm gear to match with a worm.
945// Arguments:
946// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
947// teeth = Total number of teeth along the rack. Default: 30
948// worm_diam = The pitch diameter of the worm gear to match to. Default: 30
949// worm_starts = The number of lead starts on the worm gear to match to. Default: 1
950// worm_arc = The arc of the worm to mate with, in degrees. Default: 60 degrees
951// crowning = The amount to oversize the virtual hobbing cutter used to make the teeth, to add a slight crowning to the teeth to make them fir the work easier. Default: 1
952// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
953// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
954// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
955// clearance = Clearance gap at the bottom of the inter-tooth valleys.
956// slices = The number of vertical slices to refine the curve of the worm throat. Default: 10
957// mod = The metric module/modulus of the gear.
958// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
959// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
960// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
961// Example: Right-Handed
962// worm_gear(pitch=5, teeth=36, worm_diam=30, worm_starts=1);
963// Example: Left-Handed
964// worm_gear(pitch=5, teeth=36, worm_diam=30, worm_starts=1, left_handed=true);
965// Example: Multiple Starts
966// worm_gear(pitch=5, teeth=36, worm_diam=30, worm_starts=4);
967// Example: Metric Worm Gear
968// worm_gear(mod=2, teeth=32, worm_diam=30, worm_starts=1);
969// Example(Anim,Frames=4,FrameMS=125,VPD=220,VPT=[-15,0,0]): Meshing Worm and Gear
970// $fn=36;
971// pitch = 5; starts = 4;
972// worm_diam = 30; worm_length = 50;
973// gear_teeth=36;
974// right(worm_diam/2)
975// yrot($t*360/starts)
976// worm(d=worm_diam, l=worm_length, pitch=pitch, starts=starts, orient=BACK);
977// left(pitch_radius(pitch=pitch, teeth=gear_teeth))
978// zrot(-$t*360/gear_teeth)
979// worm_gear(pitch=pitch, teeth=gear_teeth, worm_diam=worm_diam, worm_starts=starts);
980// Example: Meshing Worm and Gear Metricly
981// $fn = 72;
982// modulus = 2; starts = 3;
983// worm_diam = 30; worm_length = 50;
984// gear_teeth=36;
985// right(worm_diam/2)
986// worm(d=worm_diam, l=worm_length, mod=modulus, starts=starts, orient=BACK);
987// left(pitch_radius(mod=modulus, teeth=gear_teeth))
988// worm_gear(mod=modulus, teeth=gear_teeth, worm_diam=worm_diam, worm_starts=starts);
989// Example: Called as Function
990// vnf = worm_gear(pitch=8, teeth=30, worm_diam=30, worm_starts=1);
991// vnf_polyhedron(vnf);
992function worm_gear(
993 pitch = 5,
994 teeth = 36,
995 worm_diam = 30,
996 worm_starts = 1,
997 worm_arc = 60,
998 crowning = 1,
999 left_handed = false,
1000 pressure_angle = 20,
1001 backlash = 0,
1002 clearance,
1003 mod,
1004 slices = 10,
1005 anchor = CENTER,
1006 spin = 0,
1007 orient = UP
1008) =
1009 assert(worm_arc >= 10 && worm_arc <= 60)
1010 let(
1011 pitch = is_undef(mod) ? pitch : pitch_value(mod),
1012 p = pitch_radius(pitch, teeth),
1013 circ = 2 * PI * p,
1014 r1 = p + worm_diam/2 + crowning,
1015 r2 = worm_diam/2 + crowning,
1016 thickness = worm_gear_thickness(pitch=pitch, teeth=teeth, worm_diam=worm_diam, worm_arc=worm_arc, crowning=crowning, clearance=clearance),
1017 helical = pitch * worm_starts * worm_arc / 360 * 360 / circ,
1018 tooth_profile = reverse(_gear_tooth_profile(
1019 pitch = pitch,
1020 teeth = teeth,
1021 pressure_angle = pressure_angle,
1022 clearance = clearance,
1023 backlash = backlash,
1024 valleys = false,
1025 center = true
1026 )),
1027 profiles = [
1028 for (slice = [0:1:slices]) let(
1029 u = slice/slices - 0.5,
1030 zang = u * worm_arc,
1031 tp = [0,r1,0] - spherical_to_xyz(r2, 90, 90+zang),
1032 zang2 = u * helical
1033 ) [
1034 for (i = [0:1:teeth-1]) each
1035 apply(
1036 zrot(-i*360/teeth+zang2) *
1037 move(tp) *
1038 xrot(-zang) *
1039 scale(cos(zang)),
1040 path3d(tooth_profile)
1041 )
1042 ]
1043 ],
1044 top_verts = last(profiles),
1045 bot_verts = profiles[0],
1046 face_pts = len(tooth_profile),
1047 gear_pts = face_pts * teeth,
1048 top_faces =[
1049 for (i=[0:1:teeth-1], j=[0:1:(face_pts/2)-2]) each [
1050 [i*face_pts+j, (i+1)*face_pts-j-1, (i+1)*face_pts-j-2],
1051 [i*face_pts+j, (i+1)*face_pts-j-2, i*face_pts+j+1]
1052 ],
1053 for (i=[0:1:teeth-1]) each [
1054 [gear_pts, (i+1)*face_pts-1, i*face_pts],
1055 [gear_pts, ((i+1)%teeth)*face_pts, (i+1)*face_pts-1]
1056 ]
1057 ],
1058 sides_vnf = vnf_vertex_array(profiles, caps=false, col_wrap=true, style="min_edge"),
1059 vnf1 = vnf_join([
1060 [
1061 [each top_verts, [0,0,top_verts[0].z]],
1062 [for (x=top_faces) reverse(x)]
1063 ],
1064 [
1065 [each bot_verts, [0,0,bot_verts[0].z]],
1066 top_faces
1067 ],
1068 sides_vnf
1069 ]),
1070 vnf = left_handed? xflip(p=vnf1) : vnf1
1071 ) reorient(anchor,spin,orient, r=p, l=thickness, p=vnf);
1072
1073
1074module worm_gear(
1075 pitch = 5,
1076 teeth = 36,
1077 worm_diam = 30,
1078 worm_starts = 1,
1079 worm_arc = 60,
1080 crowning = 1,
1081 left_handed = false,
1082 pressure_angle = 20,
1083 backlash = 0,
1084 slices = 10,
1085 clearance,
1086 mod,
1087 shaft_diam = 0,
1088 anchor = CENTER,
1089 spin = 0,
1090 orient = UP
1091) {
1092 pitch = is_undef(mod) ? pitch : pitch_value(mod);
1093 p = pitch_radius(pitch, teeth);
1094 vnf = worm_gear(
1095 pitch = pitch,
1096 teeth = teeth,
1097 worm_diam = worm_diam,
1098 worm_starts = worm_starts,
1099 worm_arc = worm_arc,
1100 crowning = crowning,
1101 left_handed = left_handed,
1102 pressure_angle = pressure_angle,
1103 backlash = backlash,
1104 slices = slices,
1105 clearance = clearance
1106 );
1107 thickness = pointlist_bounds(vnf[0])[1].z;
1108 attachable(anchor,spin,orient, r=p, l=thickness) {
1109 difference() {
1110 vnf_polyhedron(vnf, convexity=teeth/2);
1111 if (shaft_diam > 0) {
1112 cylinder(d=shaft_diam, l=worm_diam, center=true);
1113 }
1114 }
1115 children();
1116 }
1117}
1118
1119
1120
1121
1122/// Function&Module: _gear_tooth_profile()
1123/// Usage: As Module
1124/// _gear_tooth_profile(pitch|mod, teeth, [pressure_angle], [clearance], [backlash], [interior], [valleys]);
1125/// Usage: As Function
1126/// path = _gear_tooth_profile(pitch|mod, teeth, [pressure_angle], [clearance], [backlash], [interior], [valleys]);
1127/// Topics: Gears
1128/// See Also: spur_gear2d()
1129/// Description:
1130/// When called as a function, returns the 2D profile path for an individual gear tooth.
1131/// When called as a module, creates the 2D profile shape for an individual gear tooth.
1132/// Arguments:
1133/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1134/// teeth = Total number of teeth on the spur gear that this is a tooth for.
1135/// pressure_angle = Pressure Angle. Controls how straight or bulged the tooth sides are. In degrees.
1136/// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
1137/// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
1138/// interior = If true, create a mask for difference()ing from something else.
1139/// valleys = If true, add the valley bottoms on either side of the tooth. Default: true
1140/// center = If true, centers the pitch circle of the tooth profile at the origin. Default: false.
1141/// mod = The metric module/modulus of the gear.
1142/// Example(2D):
1143/// _gear_tooth_profile(pitch=5, teeth=20, pressure_angle=20);
1144/// Example(2D): Metric Gear Tooth
1145/// _gear_tooth_profile(mod=2, teeth=20, pressure_angle=20);
1146/// Example(2D):
1147/// _gear_tooth_profile(
1148/// pitch=5, teeth=20, pressure_angle=20, valleys=false
1149/// );
1150/// Example(2D): As a function
1151/// path = _gear_tooth_profile(
1152/// pitch=5, teeth=20, pressure_angle=20, valleys=false
1153/// );
1154/// stroke(path, width=0.1);
1155function _gear_tooth_profile(
1156 pitch = 3,
1157 teeth = 11,
1158 pressure_angle = 28,
1159 clearance = undef,
1160 backlash = 0.0,
1161 interior = false,
1162 valleys = true,
1163 center = false,
1164 mod
1165) = let(
1166 pitch = is_undef(mod) ? pitch : pitch_value(mod),
1167 p = pitch_radius(pitch, teeth),
1168 c = outer_radius(pitch, teeth, clearance, interior),
1169 r = _root_radius(pitch, teeth, clearance, interior),
1170 b = _base_radius(pitch, teeth, pressure_angle),
1171 t = pitch/2-backlash/2, //tooth thickness at pitch circle
1172 k = -_gear_iang(b, p) - t/2/p/PI*180, //angle to where involute meets base circle on each side of tooth
1173 kk = r<b? k : -180/teeth,
1174 isteps = 5,
1175 pts = [
1176 if (valleys) each [
1177 _gear_polar(r-1, 180.1/teeth),
1178 _gear_polar(r, 180.1/teeth),
1179 ],
1180 _gear_polar(r, -kk),
1181 for (i=[0: 1:isteps]) _gear_q7(i/isteps,r,b,c,k,-1),
1182 for (i=[isteps:-1:0]) _gear_q7(i/isteps,r,b,c,k, 1),
1183 _gear_polar(r, kk),
1184 if (valleys) each [
1185 _gear_polar(r, -180.1/teeth),
1186 _gear_polar(r-1, -180.1/teeth),
1187 ]
1188 ],
1189 pts2 = center? fwd(p, p=pts) : pts
1190) pts2;
1191
1192
1193module _gear_tooth_profile(
1194 pitch = 3,
1195 teeth = 11,
1196 pressure_angle = 28,
1197 backlash = 0.0,
1198 clearance = undef,
1199 interior = false,
1200 valleys = true,
1201 center = false,
1202 mod
1203) {
1204 no_children($children);
1205 pitch = is_undef(mod) ? pitch : pitch_value(mod);
1206 r = _root_radius(pitch, teeth, clearance, interior);
1207 fwd(r)
1208 polygon(
1209 points=_gear_tooth_profile(
1210 pitch = pitch,
1211 teeth = teeth,
1212 pressure_angle = pressure_angle,
1213 backlash = backlash,
1214 clearance = clearance,
1215 interior = interior,
1216 valleys = valleys,
1217 center = center
1218 )
1219 );
1220}
1221
1222
1223// Section: Computing Gear Dimensions
1224// These functions let the user find the derived dimensions of the gear.
1225// A gear fits within a circle of radius outer_radius, and two gears should have
1226// their centers separated by the sum of their pitch_radius.
1227
1228
1229// Function: circular_pitch()
1230// Usage:
1231// circp = circular_pitch(pitch|mod);
1232// Topics: Gears
1233// Description:
1234// Get tooth density expressed as "circular pitch".
1235// Arguments:
1236// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1237// mod = The metric module/modulus of the gear.
1238// Example:
1239// circp = circular_pitch(pitch=5);
1240// circp = circular_pitch(mod=2);
1241function circular_pitch(pitch=5, mod) =
1242 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1243 pitch;
1244
1245
1246// Function: diametral_pitch()
1247// Usage:
1248// dp = diametral_pitch(pitch|mod);
1249// Topics: Gears
1250// Description:
1251// Get tooth density expressed as "diametral pitch".
1252// Arguments:
1253// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1254// mod = The metric module/modulus of the gear.
1255// Example:
1256// dp = diametral_pitch(pitch=5);
1257// dp = diametral_pitch(mod=2);
1258function diametral_pitch(pitch=5, mod) =
1259 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1260 PI / pitch;
1261
1262
1263// Function: pitch_value()
1264// Usage:
1265// pitch = pitch_value(mod);
1266// Topics: Gears
1267// Description:
1268// Get circular pitch in mm from module/modulus. The circular pitch of a gear is the number of
1269// millimeters per tooth around the pitch radius circle.
1270// Arguments:
1271// mod = The module/modulus of the gear.
1272function pitch_value(mod) = mod * PI;
1273
1274
1275// Function: module_value()
1276// Usage:
1277// mod = module_value(pitch);
1278// Topics: Gears
1279// Description:
1280// Get tooth density expressed as "module" or "modulus" in millimeters. The module is the pitch
1281// diameter of the gear divided by the number of teeth on it. For example, a gear with a pitch
1282// diameter of 40mm, with 20 teeth on it will have a modulus of 2.
1283// Arguments:
1284// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1285function module_value(pitch=5) = pitch / PI;
1286
1287
1288/// Function: _adendum()
1289/// Usage:
1290/// ad = _adendum(pitch|mod);
1291/// Topics: Gears
1292/// Description:
1293/// The height of the top of a gear tooth above the pitch radius circle.
1294/// Arguments:
1295/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1296/// mod = The metric module/modulus of the gear.
1297/// Example:
1298/// ad = _adendum(pitch=5);
1299/// ad = _adendum(mod=2);
1300/// Example(2D):
1301/// pitch = 5; teeth = 17;
1302/// pr = pitch_radius(pitch=pitch, teeth=teeth);
1303/// adn = _adendum(pitch=5);
1304/// #spur_gear2d(pitch=pitch, teeth=teeth);
1305/// color("black") {
1306/// stroke(circle(r=pr),width=0.1,closed=true);
1307/// stroke(circle(r=pr+adn),width=0.1,closed=true);
1308/// }
1309function _adendum(pitch=5, mod) =
1310 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1311 module_value(pitch) * 1.0;
1312
1313
1314/// Function: _dedendum()
1315/// Usage:
1316/// ddn = _dedendum(pitch|mod, [clearance]);
1317/// Topics: Gears
1318/// Description:
1319/// The depth of the gear tooth valley, below the pitch radius.
1320/// Arguments:
1321/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1322/// clearance = If given, sets the clearance between meshing teeth.
1323/// mod = The metric module/modulus of the gear.
1324/// Example:
1325/// ddn = _dedendum(pitch=5);
1326/// ddn = _dedendum(mod=2);
1327/// Example(2D):
1328/// pitch = 5; teeth = 17;
1329/// pr = pitch_radius(pitch=pitch, teeth=teeth);
1330/// ddn = _dedendum(pitch=5);
1331/// #spur_gear2d(pitch=pitch, teeth=teeth);
1332/// color("black") {
1333/// stroke(circle(r=pr),width=0.1,closed=true);
1334/// stroke(circle(r=pr-ddn),width=0.1,closed=true);
1335/// }
1336function _dedendum(pitch=5, clearance, mod) =
1337 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1338 is_undef(clearance)? (1.25 * module_value(pitch)) :
1339 (module_value(pitch) + clearance);
1340
1341
1342// Function: pitch_radius()
1343// Usage:
1344// pr = pitch_radius(pitch|mod, teeth);
1345// Topics: Gears
1346// Description:
1347// Calculates the pitch radius for the gear. Two mated gears will have their centers spaced apart
1348// by the sum of the two gear's pitch radii.
1349// Arguments:
1350// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1351// teeth = The number of teeth on the gear.
1352// mod = The metric module/modulus of the gear.
1353// Example:
1354// pr = pitch_radius(pitch=5, teeth=11);
1355// pr = pitch_radius(mod=2, teeth=20);
1356// Example(2D):
1357// pr = pitch_radius(pitch=5, teeth=11);
1358// #spur_gear2d(pitch=5, teeth=11);
1359// color("black")
1360// stroke(circle(r=pr),width=0.1,closed=true);
1361function pitch_radius(pitch=5, teeth=11, mod) =
1362 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1363 pitch * teeth / PI / 2;
1364
1365
1366// Function: outer_radius()
1367// Usage:
1368// or = outer_radius(pitch|mod, teeth, [clearance], [interior]);
1369// Topics: Gears
1370// Description:
1371// Calculates the outer radius for the gear. The gear fits entirely within a cylinder of this radius.
1372// Arguments:
1373// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1374// teeth = The number of teeth on the gear.
1375// clearance = If given, sets the clearance between meshing teeth.
1376// interior = If true, calculate for an interior gear.
1377// mod = The metric module/modulus of the gear.
1378// Example:
1379// or = outer_radius(pitch=5, teeth=20);
1380// or = outer_radius(mod=2, teeth=16);
1381// Example(2D):
1382// pr = outer_radius(pitch=5, teeth=11);
1383// #spur_gear2d(pitch=5, teeth=11);
1384// color("black")
1385// stroke(circle(r=pr),width=0.1,closed=true);
1386function outer_radius(pitch=5, teeth=11, clearance, interior=false, mod) =
1387 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1388 pitch_radius(pitch, teeth) +
1389 (interior? _dedendum(pitch, clearance) : _adendum(pitch));
1390
1391
1392/// Function: _root_radius()
1393/// Usage:
1394/// rr = _root_radius(pitch|mod, teeth, [clearance], [interior]);
1395/// Topics: Gears
1396/// Description:
1397/// Calculates the root radius for the gear, at the base of the dedendum.
1398/// Arguments:
1399/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1400/// teeth = The number of teeth on the gear.
1401/// clearance = If given, sets the clearance between meshing teeth.
1402/// interior = If true, calculate for an interior gear.
1403/// mod = The metric module/modulus of the gear.
1404/// Example:
1405/// rr = _root_radius(pitch=5, teeth=11);
1406/// rr = _root_radius(mod=2, teeth=16);
1407/// Example(2D):
1408/// pr = _root_radius(pitch=5, teeth=11);
1409/// #spur_gear2d(pitch=5, teeth=11);
1410/// color("black")
1411/// stroke(circle(r=pr),width=0.1,closed=true);
1412function _root_radius(pitch=5, teeth=11, clearance, interior=false, mod) =
1413 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1414 pitch_radius(pitch, teeth) -
1415 (interior? _adendum(pitch) : _dedendum(pitch, clearance));
1416
1417
1418/// Function: _base_radius()
1419/// Usage:
1420/// br = _base_radius(pitch|mod, teeth, [pressure_angle]);
1421/// Topics: Gears
1422/// Description:
1423/// Get the base circle for involute teeth, at the base of the teeth.
1424/// Arguments:
1425/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1426/// teeth = The number of teeth on the gear.
1427/// pressure_angle = Pressure angle in degrees. Controls how straight or bulged the tooth sides are.
1428/// mod = The metric module/modulus of the gear.
1429/// Example:
1430/// br = _base_radius(pitch=5, teeth=20, pressure_angle=20);
1431/// br = _base_radius(mod=2, teeth=18, pressure_angle=20);
1432/// Example(2D):
1433/// pr = _base_radius(pitch=5, teeth=11);
1434/// #spur_gear2d(pitch=5, teeth=11);
1435/// color("black")
1436/// stroke(circle(r=pr),width=0.1,closed=true);
1437function _base_radius(pitch=5, teeth=11, pressure_angle=28, mod) =
1438 let( pitch = is_undef(mod) ? pitch : pitch_value(mod) )
1439 pitch_radius(pitch, teeth) * cos(pressure_angle);
1440
1441
1442// Function: bevel_pitch_angle()
1443// Usage:
1444// ang = bevel_pitch_angle(teeth, mate_teeth, [drive_angle]);
1445// Topics: Gears
1446// See Also: bevel_gear()
1447// Description:
1448// Returns the correct pitch angle for a bevel gear with a given number of tooth, that is
1449// matched to another bevel gear with a (possibly different) number of teeth.
1450// Arguments:
1451// teeth = Number of teeth that this gear has.
1452// mate_teeth = Number of teeth that the matching gear has.
1453// drive_angle = Angle between the drive shafts of each gear. Default: 90ยบ.
1454// Example:
1455// ang = bevel_pitch_angle(teeth=18, mate_teeth=30);
1456// Example(2D):
1457// t1 = 13; t2 = 19; pitch=5;
1458// pang = bevel_pitch_angle(teeth=t1, mate_teeth=t2, drive_angle=90);
1459// color("black") {
1460// zrot_copies([0,pang])
1461// stroke([[0,0,0], [0,-20,0]],width=0.2);
1462// stroke(arc(r=3, angle=[270,270+pang]),width=0.2);
1463// }
1464// #bevel_gear(
1465// pitch=5, teeth=t1, mate_teeth=t2,
1466// spiral_angle=0, cutter_radius=1000,
1467// slices=12, anchor="apex", orient=BACK
1468// );
1469function bevel_pitch_angle(teeth, mate_teeth, drive_angle=90) =
1470 atan(sin(drive_angle)/((mate_teeth/teeth)+cos(drive_angle)));
1471
1472
1473// Function: worm_gear_thickness()
1474// Usage:
1475// thick = worm_gear_thickness(pitch|mod, teeth, worm_diam, [worm_arc], [crowning], [clearance]);
1476// Topics: Gears
1477// See Also: worm(), worm_gear()
1478// Description:
1479// Calculate the thickness of the worm gear.
1480// Arguments:
1481// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
1482// teeth = Total number of teeth along the rack. Default: 30
1483// worm_diam = The pitch diameter of the worm gear to match to. Default: 30
1484// worm_arc = The arc of the worm to mate with, in degrees. Default: 60 degrees
1485// crowning = The amount to oversize the virtual hobbing cutter used to make the teeth, to add a slight crowning to the teeth to make them fir the work easier. Default: 1
1486// clearance = Clearance gap at the bottom of the inter-tooth valleys.
1487// mod = The metric module/modulus of the gear.
1488// Example:
1489// thick = worm_gear_thickness(pitch=5, teeth=36, worm_diam=30);
1490// thick = worm_gear_thickness(mod=2, teeth=28, worm_diam=25);
1491// Example(2D):
1492// pitch = 5; teeth=17;
1493// worm_diam = 30; starts=2;
1494// y = worm_gear_thickness(pitch=pitch, teeth=teeth, worm_diam=worm_diam);
1495// #worm_gear(
1496// pitch=pitch, teeth=teeth,
1497// worm_diam=worm_diam,
1498// worm_starts=starts,
1499// orient=BACK
1500// );
1501// color("black") {
1502// ycopies(y) stroke([[-25,0],[25,0]], width=0.5);
1503// stroke([[-20,-y/2],[-20,y/2]],width=0.5,endcaps="arrow");
1504// }
1505function worm_gear_thickness(pitch=5, teeth=30, worm_diam=30, worm_arc=60, crowning=1, clearance, mod) =
1506 let(
1507 pitch = is_undef(mod) ? pitch : pitch_value(mod),
1508 r = worm_diam/2 + crowning,
1509 pitch_thick = r * sin(worm_arc/2) * 2,
1510 pr = pitch_radius(pitch, teeth),
1511 rr = _root_radius(pitch, teeth, clearance, false),
1512 pitchoff = (pr-rr) * sin(worm_arc/2),
1513 thickness = pitch_thick + 2*pitchoff
1514 ) thickness;
1515
1516
1517function _gear_polar(r,t) = r*[sin(t),cos(t)];
1518function _gear_iang(r1,r2) = sqrt((r2/r1)*(r2/r1) - 1)/PI*180 - acos(r1/r2); //unwind a string this many degrees to go from radius r1 to radius r2
1519function _gear_q6(b,s,t,d) = _gear_polar(d,s*(_gear_iang(b,d)+t)); //point at radius d on the involute curve
1520function _gear_q7(f,r,b,r2,t,s) = _gear_q6(b,s,t,(1-f)*max(b,r)+f*r2); //radius a fraction f up the curved side of the tooth
1521
1522
1523
1524
1525// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap