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_GEAR_PITCH = 5;
14_GEAR_HELICAL = 0;
15_GEAR_THICKNESS = 10;
16_GEAR_PA = 20;
17
18
19$parent_gear_type = undef;
20$parent_gear_pitch = undef;
21$parent_gear_teeth = undef;
22$parent_gear_pa = undef;
23$parent_gear_helical = undef;
24$parent_gear_thickness = undef;
25$parent_gear_dir = undef;
26$parent_gear_travel = 0;
27
28
29function _inherit_gear_param(name, val, pval, dflt, invert=false) =
30 is_undef(val)
31 ? is_undef(pval)
32 ? dflt
33 : (invert?-1:1)*pval
34 : is_undef(pval)
35 ? assert(is_finite(val), str("Invalid ",name," value: ",val))
36 val
37 : (invert?-1:1)*val;
38
39
40function _inherit_gear_pitch(fname,pitch,circ_pitch,diam_pitch,mod,warn=true) =
41 pitch != undef?
42 assert(is_finite(pitch) && pitch>0)
43 warn? echo(str(
44 "WARNING: The use of the argument pitch= in ", fname,
45 " is deprecated. Please use circ_pitch= instead."
46 )) pitch : pitch :
47 circ_pitch != undef?
48 assert(is_finite(circ_pitch) && circ_pitch>0)
49 circ_pitch :
50 diam_pitch != undef?
51 assert(is_finite(diam_pitch) && diam_pitch>0)
52 circular_pitch(diam_pitch=diam_pitch) :
53 mod != undef?
54 assert(is_finite(mod) && mod>0)
55 circular_pitch(mod=mod) :
56 $parent_gear_pitch != undef? $parent_gear_pitch :
57 5;
58
59function _inherit_gear_pa(pressure_angle) =
60 _inherit_gear_param("pressure_angle", pressure_angle, $parent_gear_pa, dflt=20);
61
62function _inherit_gear_helical(helical,invert=false) =
63 _inherit_gear_param("helical", helical, $parent_gear_helical, dflt=0, invert=invert);
64
65function _inherit_gear_thickness(thickness) =
66 _inherit_gear_param("thickness", thickness, $parent_gear_thickness, dflt=10);
67
68
69// Section: Quick Introduction to Gears
70// This section gives a quick overview of gears with a focus on the information you need
71// to know to understand the gear parameters and create some gears. The topic of gears is very complex and highly technical and
72// this section provides the minimal information needed for gear making. If you want more information about the
73// details of gears, consult the references below, which are the ones that we consulted when writing the library code.
74// - Tec Science
75// * [Involute Gears](https://www.tec-science.com/mechanical-power-transmission/involute-gear/geometry-of-involute-gears/)
76// * [Gear engagement](https://www.tec-science.com/mechanical-power-transmission/involute-gear/meshing-line-action-contact-pitch-circle-law/)
77// * [Gears meshing with racks](https://www.tec-science.com/mechanical-power-transmission/involute-gear/rack-meshing/)
78// * [Gear undercutting](https://www.tec-science.com/mechanical-power-transmission/involute-gear/undercut/)
79// * [Profile shifting](https://www.tec-science.com/mechanical-power-transmission/involute-gear/profile-shift/)
80// * [Detailed gear calculations](https://www.tec-science.com/mechanical-power-transmission/involute-gear/calculation-of-involute-gears/)
81// * [Worm drive](https://www.tec-science.com/mechanical-power-transmission/gear-types/worms-and-worm-gears/)
82// - SDPSI (A long document covering a variety of gear types and gear calculations)
83// * [Elements of Gear Technology](https://www.sdp-si.com/resources/elements-of-metric-gear-technology/index.php)
84// - Crown Face Gears
85// * [Crown Gearboxes](https://mag.ebmpapst.com/en/industries/drives/crown-gearboxes-efficiency-energy-savings-decentralized-drive-technology_14834/)
86// * [Crown gear pressure angle](https://mag.ebmpapst.com/en/industries/drives/the-formula-for-the-pressure-angle_14624/)
87// * [Face Gears: Geometry and Strength](https://www.geartechnology.com/ext/resources/issues/0107x/kissling.pdf)
88
89// Subsection: Involute Spur Gears
90// The simplest gear form is the involute spur gear, which is an extrusion of a two dimensional form.
91// Figure(3D,Med,NoAxes,VPT=[4.62654,-1.10349,0.281802],VPR=[55,0,25],VPD=236.957): Involute Spur Gear
92// spur_gear(mod=5,teeth=18,pressure_angle=20,thickness=25,shaft_diam=15);
93// Continues:
94// The term "involute" refers to the shape of the teeth: the curves of the teeth are involutes of circles,
95// which are curves that optimize gear performance.
96// Figure(2D,Med,NoAxes,VPT=[8,74,0],VPR=[0,0,0],VPD=150): The three marked circles are key references on gear teeth. The pitch circle, which is roughly in the middle of the teeth, is the reference used to define the pitch of teeth on the gear. The pressure angle is the angle the tooth makes with the pitch circle. In this example, the pressure angle is 20 degrees as shown by the red lines.
97// $fn=128;
98// intersection(){
99// spur_gear2d(mod=5,teeth=30,pressure_angle=20);
100// back(82)rect([45, 20],anchor=BACK);
101// }
102// color("black"){
103// stroke(arc(r=_root_radius(mod=5,teeth=30),angle=[70,110]),width=.25);
104// stroke(arc(r=pitch_radius(mod=5,teeth=30),angle=[70,110]),width=.25);
105// stroke(arc(r=outer_radius(mod=5,teeth=30),angle=[70,110]),width=.25);
106// back(63.5)right(24.2)text("root circle",size=2.5);
107// back(69.5)right(26.5)text("pitch circle",size=2.5);
108// back(74)right(28)text("outer circle",size=2.5);
109// }
110// base = _base_radius(mod=5, teeth=30);
111// pitchpt = pitch_radius(mod=5, teeth=30);
112// color("red"){
113// zrot(87-360/30) zrot(20,cp=[pitchpt,0]) stroke([[base-5,0],[base+15,0]], width=0.25);
114// zrot(87-360/30) stroke([[pitchpt,0],[pitchpt+11,0]], width=0.25);
115// right(8.3) back(74) zrot(87-360/30) zrot(10,cp=[pitchpt,0]) stroke(arc(angle=[0,20],r=10.5),endcaps="arrow2",width=.25);
116// back(84) right(13) text("pressure angle",size=2.5);
117// }
118// Continues:
119// The size of the teeth can be specified as the circular pitch, the distance along the pitch circle
120// from the start of one tooth to the start of the text tooth. The circular pitch can be computed as
121// `PI*d/teeth` where `d` is the diameter of the pitch circle and `teeth` is the number of teeth on the gear.
122// This simply divides up the pitch circle into the specified number of teeth. However, the customary
123// way to specify metric gears is using the module, ratio of the diameter of the gear to the number of teeth: `m=d/teeth`.
124// The module is hence the circular pitch divided by a factor of π. A third way to specify gear sizes is the diametral pitch,
125// which is the number of teeth that fit on a gear with a diameter of one inch, or π times the number of teeth per inch.
126// Note that for the module or circular pitch, larger values make larger teeth,
127// but for the diametral pitch, the opposite is true. Throughout this library, module and circular pitch
128// are specified basic OpenSCAD units, so if you work in millimeters and want to give circular pitch in inches, be
129// sure to multiply by `INCH`. The diametral pitch is given based on inches under the assumption that OpenSCAD units are millimeters.
130// .
131// Basic gears as shown above will mesh when their pitch circles are tangent.
132// The critical requirements for two gears to mesh are that
133// - The teeth are the same size
134// - The pressure angles are identical
135// .
136// Increasing pressure angle makes the tooth stronger, increases power transmission, and can reduce tooth interference for
137// gears with a small number of teeth, but it also increases gear wear and meshing noise. Higher pressure angles also
138// increase the force that tries to push the gears apart, and hence the load on the gear axles. The current standard pressure
139// angle is 20 degrees. It replaces an old 14.5 degree standard.
140// Figure(2D,Med,NoAxes): Teeth of the same size with different pressure angles. Note that 20 deg is the industry standard.
141// pang = [30,20,14.5];
142// ycopies(n=3, spacing=25){
143// intersection(){
144// spur_gear2d(mod=5, teeth=30, pressure_angle=pang[$idx]);
145// back(82) rect([45,20], anchor=BACK);
146// }
147// back(68) right(26) text(str(pang[$idx]), size=6.5);
148// }
149// Continues:
150// In order for the gear teeth to fit together, and to allow space for lubricant, the valleys of the teeth
151// are made deeper by the `clearance` distance. This defaults to `module/4`.
152// Figure(2D,Med,NoAxes,VPT=[5.62512,-1.33268,-0.0144912],VPR=[0,0,0],VPD=126): The clearance is extra space at the tooth valley that separates the tooth tip (in green) from the tooth valley below it.
153// intersection(){
154// rack2d(mod=5, teeth=10, bottom=15, pressure_angle=14.5);
155// rect([35,20]);
156// }
157// color("lightgreen")render()
158// intersection(){
159// back(gear_dist(mod=5, teeth1=146, teeth2=0 ,profile_shift1=0))
160// spur_gear2d(mod=5, teeth=146, profile_shift=0, pressure_angle=14.5);
161// rect([45,20]);
162// }
163// color("black") {
164// stroke([[-10,-5],[20,-5]], width=.25);
165// stroke([[-10,-6.2],[20,-6.2]], width=.25);
166// fwd(6.4) right(22) text("clearance", size=2.5);
167// }
168// Continues:
169// Another clearance requirement can present a serious problem when the number of teeth is low. As the gear rotates, the
170// teeth may interfere with each other. This may require undercutting the gear teeth to create space, which weakens the teeth.
171// Is is best to avoid gears with very small numbers of teeth when possible.
172// Figure(2D,Med,NoAxes,VPT=[0.042845,6.5338,-0.0144912],VPR=[0,0,0],VPD=126): The green gear with only five teeth has a severe undercut, which weakens its teeth. This undercut is necessary to avoid interference with the teeth from the other gear during rotation. Note that the yellow rack tooth is deep into the undercut space.
173// ang=16;
174// rack2d(mod=5, teeth=3, bottom=15, pressure_angle=14.5, rounding=0);
175// left(2*PI*pitch_radius(mod=5, teeth=5)*ang/360)
176// color("lightgreen")
177// back(gear_dist(mod=5, teeth1=5, profile_shift1=0, teeth2=0))
178// zrot(ang)
179// spur_gear2d(mod=5, teeth=5, clearance=.00001, profile_shift=0, pressure_angle=14.5, shaft_diam=5);
180
181// Subsection: Corrected Gears and Profile Shifting
182// A solution to the problem of undercutting is to use profile shifting. Profile shifting uses a different portion of the
183// involute curve to form the gear teeth, and this adjustment to the tooth form can eliminate undercutting, while
184// still allowing the gear to mesh with unmodified gears. Profile shifting
185// changes the diameter at which the gear meshes so it no longer meshes at the pitch circle.
186// A profile shift of `x`
187// will increase the mesh distance by approximately `x*m` where `m` is the gear module. The exact adjustment,
188// which you compute with {{gear_dist()}}, is a complex calculation that depends on the profile shifts of both meshing gears. This means that profile shifting
189// can also be used to fine tune the spacing between gears. When the gear has many teeth a negative profile shift may
190// be able to bring the gears slightly closer together, while still avoiding undercutting.
191// Profile shifting also changes the effective pressure angle of the gear engagement.
192// .
193// The minimum number of teeth to avoid undercutting is 17 for a pressure angle of 20, but it is 32 for a pressure
194// angle of 14.5 degrees. It can be computed as `2/(sin(alpha))^2` where `alpha` is the pressure angle.
195// By default, the gear modules produce corrected gears. You can override this by specifying the profile shift
196// yourself. A small undercut may be acceptable, for example: a rule of thumb indicates that gears as small as 14
197// teeth are OK with a 20 degree pressure angle, because the undercut is too small to weaken the teeth significantly.
198// Figure(2D,Med,NoAxes,VPT=[1.33179,10.6532,-0.0144912],VPR=[0,0,0],VPD=155.556): Basic five tooth gear form on the left. Corrected gear with profile shifting on the right. The profile shifted teeth lack the weak undercut section. The axis of the corrected gear is shifted away from the mating rack.
199// $fn=32;
200// ang1=-20;
201// ang2=20;
202// color("blue")
203// left(2*PI*pitch_radius(mod=5, teeth=5)*ang1/360)
204// left(3*5*PI/2)
205// back(gear_dist(mod=5,teeth1=5,profile_shift1=0,teeth2=0,pressure_angle=14.5))
206// zrot(ang1)
207// spur_gear2d(mod=5, teeth=5, profile_shift=0, pressure_angle=14.5, shaft_diam=2);
208// color("green")
209// left(2*PI*pitch_radius(mod=5, teeth=5)*ang2/360)
210// right(3*5*PI/2)
211// back(gear_dist(mod=5, teeth1=5, teeth2=0,pressure_angle=14.5))
212// zrot(ang2)
213// spur_gear2d(mod=5, teeth=5, pressure_angle=14.5, shaft_diam=2);
214// rack2d(teeth=4, bottom=15, mod=5, pressure_angle=14.5);
215// Continues:
216// Profile shifting brings with it another complication: in order to maintain the specified clearance, the tips of the
217// gear teeth need to be shortened. The shortening factor depends on characteristics of both gears, so it cannot
218// be automatically incorporated. (Consider the situation where one gear mates with multiple other gears.) With modest
219// profile shifts, you can probably ignore this adjustment, but with more extreme profile shifts, it may be important.
220// You can compute the shortening parameter using {{gear_shorten()}}. Note that the actual shortening distance is obtained
221// by scaling the shortening factor by the gear's module.
222// Figure(2D,Big,NoAxes,VPT=[55.8861,-4.31463,8.09832],VPR=[0,0,0],VPD=325.228): With large profile shifts the teeth need to be shortened or they don't have clearance in the valleys of the teeth in the meshing gear.
223// teeth1=25;
224// teeth2=19;
225// mod=4;
226// ps1 = 0.75;
227// ps2 = 0.75;
228// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
229// color("lightblue")
230// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,gear_spin=-90);
231// right(d)
232// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,gear_spin=-90);
233// right(9)stroke([[1.3*d/2,0],[d/2+4,0]], endcap2="arrow2",color="black");
234// fwd(2)right(d/2+25)color("black"){back(4)text("No clearance",size=6);
235// fwd(4)text("at tooth tip",size=6);}
236// Figure(2D,Big,NoAxes,VPT=[55.8861,-4.31463,8.09832],VPR=[0,0,0],VPD=325.228): Applying the correct shortening factor restores the clearance to its set value.
237// teeth1=25;
238// teeth2=19;
239// mod=4;
240// ps1 = 0.75;
241// ps2 = 0.75;
242// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
243// shorten=gear_shorten(teeth1,teeth2,0,ps1,ps2);
244// color("lightblue")
245// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,shorten=shorten,gear_spin=-90);
246// right(d)
247// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,shorten=shorten,gear_spin=-90);
248// right(9)stroke([[1.3*d/2,0],[d/2+4,0]], endcap2="arrow2",color="black");
249// fwd(2)right(d/2+25)color("black"){back(4)text("Normal",size=6);
250// fwd(4)text("Clearance",size=6);}
251// Subsection: Helical Gears
252// Helicals gears are a modification of spur gears. They can replace spur gears in any application. The teeth are cut
253// following a slanted, helical path. The angled teeth engage more gradually than spur gear teeth, so they run more smoothly
254// and quietly. A disadvantage of helical gears is that they have thrust along the axis of the gear that must be
255// accomodated. Helical gears also have more sliding friction between the meshing teeth compared to spur gears.
256// Figure(3D,Med,NoAxes,VPT=[3.5641,-7.03148,4.86523],VPR=[62.7,0,29.2],VPD=263.285): A Helical Gear
257// spur_gear(mod=5,teeth=18,pressure_angle=20,thickness=35,helical=-29,shaft_diam=15,slices=15);
258// Continues:
259// Helical gears have the same compatibility requirements as spur gears, with the additional requirement that
260// the helical angles must be opposite each other, so a gear with a helical angle of 35 must mesh with one
261// that has an angle of −35. The industry convention refers to these as left-handed and right handed. In
262// this library, positive helical angles produce a left handed gear and negative angles produce a right handed gear.
263// Figure(3D,Med,NoAxes,VPT=[73.6023,-29.9518,-12.535],VPR=[76,0,1.2],VPD=610): Left and right handed helical gears at 35 degrees.
264// spur_gear(mod=5, teeth=20, helical=35, thickness=70,slices=15);
265// right(150)
266// spur_gear(mod=5, teeth=20, helical=-35, thickness=70,slices=15);
267// down(22)
268// left(60)
269// fwd(220)
270// rot($vpr)
271// color("black")text3d("left handed right handed",size=18);
272// down(52)
273// left(55)
274// fwd(220)
275// rot($vpr)
276// color("black")text3d("helical=35 helical=−35",size=18);
277// Continues:
278// The pitch circle of a helical gear is larger compared to a spur gear
279// by the cosine of the helical angle, so you cannot simply drop helical gears in to replace spur gears without
280// making other adjustments. This dependence does allow you to make
281// make much bigger spacing adjustments than are possible with profile shifting—without changing the tooth count.
282// The {{gear_dist()}} function will also compute the appropriate gear spacing for helical gears.
283// The effective pressure angle of helical gears is larger than the nominal pressure angle. This can make it possible
284// to avoid undercutting without having to use profile shifting, so smaller tooth count gears can be more effective
285// using the helical form.
286// Figure(Anim,Med,Frames=10,NoAxes,VPT=[43.8006,15.9214,3.52727],VPR=[62.3,0,20.3],VPD=446.129): Meshing compatible helical gears
287// zrot($t*360/18)
288// spur_gear(mod=5, teeth=18, pressure_angle=20, thickness=25, helical=-29, shaft_diam=15);
289// right(gear_dist(mod=5, teeth1=18, teeth2=18, helical=29))
290// zrot(360/18/2)
291// zrot(-$t*360/18)
292// spur_gear(mod=5, teeth=18, pressure_angle=20, thickness=25, helical=29, shaft_diam=15);
293// Continues:
294// Helical gears can mesh in a second manner that is different from spur gears: they can turn on skew, or crossed axes. These are also
295// sometimes called "screw gears". The general requirement for two non-profile-shifted helical gears to mesh is that the angle
296// between the gears' axes must equal the sum of the helical angles of the two gears, thus for parallel axes, the helical
297// angles must sum to zero. If helical gears are profile shifted, then in addition to adjusting the distance between the
298// gears, a small adjustment in the angle is needed, so profile shifted gears won't mesh exactly at the sum of their angles.
299// The calculation for gear spacing is different for skew axis gears than for parallel gears, so you do this using {{gear_dist_skew()}},
300// and if you use profile shifting, then you can compute the angle using {{gear_skew_angle()}}.
301// Figure(Anim,Med,NoAxes,Frames=10,VPT=[44.765,6.09492,-3.01199],VPR=[55.7,0,33.2],VPD=401.289): Two helical gears meshing with axes at a 45 degree angle
302// dist = gear_dist_skew(mod=5, teeth1=18, teeth2=18, helical1=22.5,helical2=22.5);
303// axiscolor="darkgray";
304// down(10)color(axiscolor) cyl(d=15, l=145);
305// zrot($t*360/18)
306// color("lightblue")spur_gear(mod=5,teeth=18,pressure_angle=20,thickness=25,helical=22.5,shaft_diam=15);
307// right(dist)
308// xrot(45) {color(axiscolor)cyl(d=15,l=85);
309// zrot(360/18/2)
310// zrot(-$t*360/18)
311// spur_gear(mod=5,teeth=18,pressure_angle=20,thickness=25,helical=22.5,shaft_diam=15);}
312// Subsection: Herringbone Gears
313// The herringbone gear is made from two stacked helical gears with opposite angles. This design addresses the problem
314// of axial forces that afflict helical gears by having one section that slopes to the
315// right and another that slopes to the left. Herringbone gears also have the advantage of being self-aligning.
316// Figure(3D,Med,NoAxes,VPT=[3.5641,-7.03148,4.86523],VPR=[62.7,0,29.2],VPD=263.285): A herringbone gear
317// spur_gear(mod=5, teeth=16, pressure_angle=20, thickness=35, helical=-20, herringbone=true, shaft_diam=15);
318// Subsection: Ring Gears (Internal Gears)
319// A ring gear (or internal gear) is a gear where the teeth are on the inside of a circle. Such gears must be mated
320// to a regular (external) gear, which rotates around the inside.
321// Figure(2D,Med,NoAxes,VPT=[0.491171,1.07815,0.495977],VPR=[0,0,0],VPD=292.705): A interior or ring gear (yellow) with a mating spur gear (blue)
322// teeth1=18;
323// teeth2=30;
324// ps1=undef;
325// ps2=auto_profile_shift(teeth=teeth1);
326// mod=3;
327// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2,profile_shift1=ps1, profile_shift2=ps2,helical=0, internal2=true);
328// ang = 0;
329// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2,helical=0,backing=4);
330// zrot(ang*360/teeth2)
331// color("lightblue")
332// fwd(d)
333// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=0);
334// Continues:
335// Ring gears are subject to all the usual mesh requirements: the teeth must be the same size, the pressure angles must
336// match and they must have opposite helical angles. The {{gear_dist()}} function can give the center separation of
337// a ring gear and its mating spur gear. Ring gears have additional complications that tend to arise when the number of
338// teeth is small or the teeth counts of the ring gear and spur gear are too close together. The mating spur gear must
339// have few enough teeth so that the teeth don't interfere on the other side of the ring. Very small spur gears can interfere
340// on the tips of the ring gear's teeth.
341// Figure(2D,Med,NoAxes,VPT=[-1.16111,0.0525612,0.495977],VPR=[0,0,0],VPD=213.382): The red regions show interference between the two gears: the 18 tooth spur gear does not fit inside the 20 tooth ring gear.
342// teeth1=18;
343// teeth2=20;
344// ps1=undef;
345// ps2=auto_profile_shift(teeth=teeth1);
346// mod=3;
347// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2,profile_shift1=ps1, profile_shift2=ps2,helical=0, internal2=true);
348// ang = 0;
349// color_overlaps(){
350// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2,helical=0,backing=4);
351// zrot(ang*360/teeth2)
352// fwd(d)
353// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=0);
354// }
355// Figure(2D,Big,NoAxes,VPT=[10.8821,-26.1226,-0.0685569],VPD=43.9335,VPR=[0,0,16.8]): Interference at teeth tips, shown in red, with a 5 tooth and 19 tooth gear.
356// $fn=128;
357// teeth1=5;
358// teeth2=19;
359// ps1=0;
360// ps2=0;
361// mod=3;
362// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2,profile_shift1=ps1, profile_shift2=ps2,helical=0, internal2=true);
363// ang = 1;
364// color_overlaps(){
365// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2,helical=0,backing=4);
366// zrot(ang*360/teeth2)
367// fwd(d)
368// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=0);
369// }
370// Continues:
371// The tooth tip interference can often be controlled using profile shifting of the ring gear, but another requirement is
372// that the profile shift of the ring gear must be at least as big as the profile shift of the mated spur gear. In order
373// to ensure that this condition holds, you may need to use {{auto_profile_shift()}} to find the profile shift that is
374// automatically applied to the spur gear you want to use.
375// Figure(2D,Med,VPT=[4.02885,-46.6334,1.23363],VPR=[0,0,6.3],VPD=75.2671,NoAxes): Ring gear without profile shifting doesn't have room for the fat profile shifted teeth of the 5-tooth spur gear, with overlaps shown in red.
376// $fn=128;
377// teeth1=5;
378// teeth2=35;
379// ps1=undef;
380// ps2=0;
381// mod=3;
382// d=45-.7;
383// ang = .5;
384// color_overlaps(){
385// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2,helical=0,backing=4);
386// zrot(ang*360/teeth2)
387// fwd(d)
388// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=0);
389// }
390// Figure(2D,Med,VPT=[9.87969,-45.6706,0.60448],VPD=82.6686,VPR=[0,0,11],NoAxes): When the ring gear is profile shifted to match the spur gear, then the gears mesh without interference.
391// $fn=128;
392// teeth1=5;
393// teeth2=35;
394// ps1=undef;
395// ps2=auto_profile_shift(teeth=teeth1);
396// mod=3;
397// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2,profile_shift1=ps1, profile_shift2=ps2,helical=0, internal2=true);
398// ang = .5;
399// color_overlaps(){
400// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2,helical=0,backing=4);
401// zrot(ang*360/teeth2)
402// fwd(d)
403// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=0);
404// }
405// Figure(3D,Med,NoAxes,VPT=[2.48983,2.10149,0.658081],VPR=[70.4,0,123],VPD=237.091): A helical ring gear (yellow) mating with the compatible spur gear (blue)
406// $fn=128;
407// teeth1=18;
408// teeth2=30;
409// ps1=undef;
410// ps2=auto_profile_shift(teeth=teeth1);
411// mod=3;
412// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2,profile_shift1=ps1, profile_shift2=ps2,helical=30, internal2=true);
413// ang = 0;
414// ring_gear(mod=mod, teeth=teeth2,profile_shift=ps2,backing=4,helical=30,thickness=15);
415// zrot(ang*360/teeth2)
416// color("lightblue")
417// fwd(d)
418// spur_gear(mod=mod, teeth=teeth1, profile_shift=ps1,gear_spin=-ang*360/teeth1,helical=-30,thickness=15);
419// Subsection: Worm Drive
420// A worm drive is a gear system for connecting skew shafts at 90 degrees. They offer higher load capacity compared to
421// crossed helical gears. The assembly is driven by the "worm", which is a gear that resembles a screw.
422// Like a screw, it can have one, or several starts. These starts correspond to teeth on a helical gear;
423// in fact, the worm can be regarded as a type of helical gear at a very extreme angle, where the teeth wrap
424// around the gear. The worm mates with the "worm gear" which is also called the "worm wheel". The worm gear
425// resembles a helical gear at a very slight angle.
426// Figure(3D,Med,NoAxes,VPT=[38.1941,-7.67869,7.95996],VPR=[56.4,0,25],VPD=361.364): Worm drive assembly, with worm on the left and worm gear (worm wheel) on the right. When the worm turns its screwing action drives the worm gear.
427// starts=2;
428// ps=0;
429// dist_ba=0;
430// gear_ba=0;
431// worm(
432// d=44, // mate_teeth=30,
433// circ_pitch=3*PI,
434// starts=starts,orient=BACK);
435// right(worm_dist(d=44,mod=3,teeth=30, starts=starts,profile_shift=ps,backlash=dist_ba))
436// zrot(360/30*.5)
437// worm_gear(
438// circ_pitch=3*PI,
439// teeth=30,
440// worm_diam=44,profile_shift=ps,
441// worm_starts=starts,backlash=gear_ba);
442// Continues:
443// A close look at the worm gear reveals that it differs significantly from a helical or spur gear.
444// This gear is an "enveloping" gear, which is designed to follow the curved profile of the worm,
445// resulting in much better contact between the teeth of the worm and the teeth of the worm gear.
446// The worm shown above is a cylindrical worm, which is the most common type.
447// It is possible to design the worm to follow the curved shape of its mated gear, resulting
448// in an enveloping (also called "globoid") worm. This type of worm makes better contact with
449// the worm gear, but is less often used due to manufacturing complexity and consequent expense.
450// Figure(3D,Big,NoAxes,VPT=[0,0,0],VPR=[192,0,180],VPD=172.84): A cylindrical worm appears on the left in green. Note it's straight sides. The enveloping (globoid) worm gears appears on the right in green. Note that its sides curve so several teeth can mate with the worm gear, and it requires a complex tooth form
451// tilt=20;
452// starts=1;
453// ps=0;
454// pa=27;
455// dist_ba=0;
456// gear_ba=0;
457// xdistribute(spacing=25){
458// xflip()yrot(-tilt)
459// union(){
460// color("lightgreen")
461// xrot(90)
462// zrot(-90)
463// enveloping_worm( mate_teeth=60,$fn=128,
464// d=14, pressure_angle=pa, mod=3/2,
465// starts=starts);
466// right(worm_dist(d=14,mod=3/2,teeth=60, starts=starts,profile_shift=ps,backlash=dist_ba,pressure_angle=pa))
467// zrot(360/30*.25)
468// worm_gear(
469// mod=3/2,pressure_angle=pa,
470// teeth=60,crowning=0,
471// worm_diam=14,profile_shift=ps,
472// worm_starts=starts,backlash=gear_ba);
473// }
474// yrot(-tilt)
475// union(){
476// color("lightgreen")
477// xrot(90)
478// zrot(-90)
479// worm(l=43, $fn=128,
480// d=14, pressure_angle=pa, left_handed=true,
481// mod=3/2,//circ_pitch=3*PI/2,
482// starts=starts);
483// right(worm_dist(d=14,mod=3/2,teeth=60, starts=starts,profile_shift=ps,backlash=dist_ba,pressure_angle=pa))
484// zrot(360/30*.25)
485// worm_gear(
486// mod=3/2,pressure_angle=pa,
487// teeth=60,crowning=0,left_handed=true,
488// worm_diam=14,profile_shift=ps,
489// worm_starts=starts,backlash=gear_ba);
490// }
491// }
492// Continues:
493// As usual, a proper mesh requires that the pressure angles match and the teeth of the worm and worm gear
494// are the same size. Additionally the worm gear must be constructed to match the diameter of the worm
495// and the number of starts on the worm. Note that the number of starts changes the angle at of the
496// teeth on the worm, and hence requires a change to the angle of teeth on the worm gear.
497// Of course an enveloping worm needs to know the diameter of the worm gear; you provide this
498// information indirectly by giving the number of teeth on the worm gear.
499// The {{worm_dist()}} function will give the correct center spacing for the worm from its mating worm gear.
500// .
501// Worm drives are often "self-locking", which means that torque transmission can occur only from the worm to the worm gear,
502// so they must be driven by the worm. Self-locking results from the small lead angle of the worm threads, which produces
503// high frictional forces at contact. A multi-start worm has a higher lead angle and as a result is less likely
504// to be self-locking, so a multi-start worm can be chosen to avoid self-locking.
505// Since self-locking is associated with friction, self-locking drives have lower efficiency,
506// usually less than 50%. Worm drive efficiency can exceed 90% if self-locking is not required. One consideration
507// with self-locking systems is that if the worm gear moves a large mass and the drive is suddenly shut off, the
508// worm wheel is still trying to move due to inertia, which can create large loads that fracture the worm.
509// In such cases, the worm cannot be stopped abruptly but must rotate a little further (called "over travel")
510// after switching off the drive
511// Subsection: Bevel Gears
512// Bevel gearing is another way of dealing with intersecting gear shafts. For bevel gears, the teeth centers lie on
513// the surface of an imaginary cone, which is the pitch cone of the bevel gear. Two bevel gears mesh when their pitch cones
514// touch along their length. The teeth of bevel gears narrow as they get closer to the center of the gear.
515// Tooth dimensions and pitch diameter are referenced to the outer end of the teeth.
516// Bevel gears can be made with straight teeth, analogous to spur gears, and with the
517// same disadvantage of sudden full contact that is noisy. Spiral teeth are analogous to helical
518// teeth on cylindrical gears: the teeth engage gradually and smoothly, transmitting motion more smoothly
519// and quietly. Also like helical gears, they have the disadvantage of introducing axial forces, and
520// usually they can only operate in one rotation direction.
521// A third type of tooth is the zerol tooth, which has curved teeth like the spiral teeth,
522// but with a zero angle. These share advantages of straight teeth and spiral teeth: they are quiet like
523// straight teeth but they lack the axial thrust of spiral gears, and they can operate in both directions.
524// They are also reportedly stronger than either spiral or bevel gears.
525// Figure(3D,Med,VPT=[-5.10228,-3.09311,3.06426],VPR=[67.6,0,131.9],VPD=237.091,NoAxes): Straight tooth bevel gear with 45 degree angled teeth. To get a gear like this you must specify a spiral angle of zero and a cutter radius of zero.
526// bevel_gear(mod=3,teeth=35,face_width=20,spiral_angle=0,cutter_radius=0);
527// Figure(3D,Med,VPT=[-5.10228,-3.09311,3.06426],VPR=[67.6,0,131.9],VPD=237.091,NoAxes): Straight tooth bevel gear with 45 degree angled teeth. A gear like this has a positive spiral angle, which determines how sloped the teeth are and a positive cutter radius, which determines how curved the teeth are.
528// bevel_gear(mod=3,teeth=35,face_width=20);
529// Figure(3D,Med,VPT=[-5.10228,-3.09311,3.06426],VPR=[67.6,0,131.9],VPD=237.091,NoAxes): Zerol tooth bevel gear with 45 degree angled teeth. A gear like this has a spiral angle of zero, but a positive cutter radius, which determines how curved the teeth are.
530// bevel_gear(mod=3,teeth=35,face_width=20,spiral_angle=0);
531// Continues:
532// Bevel gears have demanding requirements for successful mating of two gears. Of course the tooth size
533// and pressure angle must match. But beyond that, their pitch cones have to meet at their points.
534// This means that if you specify the tooth counts
535// of two gears and the desired shaft angle, then that information completely determines the pitch cones, and hence
536// the geometry of the gear. You cannot simply mate two arbitary gears that have the same tooth size
537// and pressure angle like you can with helical gears: the gears must be designed in pairs to work together.
538// .
539// It is most common to design bevel gears so operate with their shafts at 90 degree angles, but
540// this is not required, and you can design pairs of bevel gears for any desired shaft angle.
541// Note, however, that given a pair of teeth counts, a bevel gear pair is not possible at all angles.
542// Figure(3D,Med,NoAxes,VPT=[-1.42254,-1.98925,13.5702],VPR=[76,0,145],VPD=263.435): Two zerol bevel gears mated with shafts at 90 degrees.
543// bevel_gear(mod=3,teeth=35,face_width=10,spiral_angle=0,mate_teeth=15);
544// cyl(h=40,d=3,$fn=16,anchor=BOT);
545// color("lightblue")left(pitch_radius(mod=3,teeth=35))up(pitch_radius(mod=3,teeth=15))
546// yrot(90){zrot(360/15/2)bevel_gear(mod=3,teeth=15,face_width=10,spiral_angle=0,cutter_radius=-30,mate_teeth=35);
547// cyl(h=60,d=3,$fn=16,anchor=BOT);}
548// Figure(3D,Med,NoAxes,VPT=[1.55215,1.94725,16.4524],VPR=[76,0,181.4],VPD=263.435): Two zerol bevel gears mated with shafts at a 35 deg angle. Note that if the blue gear is tipped slightly more its shaft will intersect the shaft of the yellow gear underneath that gear; that indicates an impossible angle for this pair of teeth counts.
549// function bevel_angles(z1,z2,shaft) =
550// [atan(sin(shaft)/((z2/z1)+cos(shaft))),
551// atan(sin(shaft)/((z1/z2)+cos(shaft)))];
552// angles = bevel_angles(35,15,115);
553// bevel_gear(mod=3,teeth=35,face_width=10,spiral_angle=0,pitch_angle=angles[0],cutter_radius=30);
554// cyl(h=40,d=3,$fn=16,anchor=BOT);
555// color("lightblue")
556// left(pitch_radius(mod=3,teeth=35))yrot(20)up(pitch_radius(mod=3,teeth=15))
557// yrot(90)zrot(360/15/2){
558// bevel_gear(mod=3,teeth=15,face_width=10,spiral_angle=0,cutter_radius=-30,pitch_angle=(angles[1]));
559// cyl(h=60,d=3,$fn=16,anchor=BOT);
560// }
561// Continues:
562// In the above figure you can see a gear that is very flat. A bevel gear that is perfectly flat is called a planar bevel gear or
563// sometimes also a crown gear. The latter term may be confusing because it also refers to a similar looking
564// but very different type of gear that is described below. A planar bevel gear can only mate with another
565// compatible bevel gear. It has a degenerate cone with its apex on the gear itself, so the mating pinion gear cannot
566// mate at a 90 degree angle because if it did, it's cone could not meet the center of the planar bevel gear.
567// Subsection: Crown Gears (Face Gears)
568// Crown gears, sometimes called Face Crown Gears or just Face Gears, are gears with teeth pointing straight up so
569// the gear resembles a crown. This type of gear is not the same as a bevel gear with vertical teeth, which would mate
570// to another bevel gear. A crown gear mates to a spur gear at a ninety degree angle. A feature of the crown gear assembly
571// is that the spur gear can shift along its axis without affecting the mesh.
572// Figure(2D,Med,NoAxes,VPT=[-2.19006,-1.67419,-4.49379],VPR=[67.6,0,131.9],VPD=113.4): A Crown or Face gear with its mating spur gear in blue.
573// crown_gear(mod=1, teeth=32, backing=3, face_width=7);
574// color("lightblue")
575// back(pitch_radius(mod=1,teeth=32)+7/2)
576// up(gear_dist(mod=1,teeth1=0,teeth2=9))spur_gear(mod=1, teeth=9,orient=BACK,thickness=7,gear_spin=360/9/2);
577// Continues:
578// When constructing a crown gear you need to make it with the same given pressure and and tooth size as
579// the spur gear you wish to mate to it. However, the teeth of a crown gear have pressure angle that varies
580// along the width of the tooth. The vertical separation of the spur gear from the crown gear is given
581// by {{gear_dist()}} where you treat the crown gear as a rack. The inner radius of the teeth on the
582// crown gear is the pitch radius determined by the gear's tooth size and number of teeth. The face width
583// of a crown gear is limited by geometry, so if you make it too large you will get an error.
584// .
585// Note that the geometry of these crown gears is tricky and not well documented by sources we have found.
586// If you know something about crown gears that could improve the implementation, please open an issue
587// on github.
588// Section: Backlash (Fitting Real Gears Together)
589// You may have noticed that the example gears shown fit together perfectly, making contact on both sides of
590// the teeth. Real gears need space between the teeth to prevent the gears from jamming, to provide space
591// for lubricant, and to provide allowance for fabrication error. This space is called backlash. Excessive backlash
592// is undesirable, especially if the drive reverses frequently.
593// .
594// Backlash can be introduced in two ways. One is to make the teeth narrower, so the gaps between the teeth are
595// larger than the teeth. Alternatively, you can move the gears farther apart than their ideal spacing.
596// Backlash can be measured in several different ways. The gear modules in this library accept a backlash
597// parameter which specifies backlash as a circular distance at the pitch circle. The modules narrow
598// the teeth by the amount specified, which means the spaces between the teeth grow larger. Of course, if you apply
599// backlash to both gears then the total backlash in the system is the combined amount from both gears.
600// Usually it is best to apply backlash symmetrically to both gears, but if one gear is very small it may
601// be better to place the backlash entirely on the larger gear to avoid weakening the teeth of the small gear.
602// Figure(2D,Big,VPT=[4.5244,64.112,0.0383045],VPR=[0,0,0],VPD=48.517,NoAxes): Backlash narrows the teeth by the specified length along the pitch circle. Below the ideal gear appears in the lighter color and the darker color shows the same gear with a very large backlash, which appears with half of the backlash on either side of the tooth.
603// teeth1=20;
604// mod=5;
605// r1 = pitch_radius(mod=mod,teeth=teeth1,helical=40);
606// bang=4/(2*PI*r1) * 360 ;
607// zrot(-180/teeth1*.5){
608// color("white")
609// dashed_stroke(arc(r=r1, n=30, angle=[80,110]), width=.05);
610// spur_gear2d(mod=mod, teeth=teeth1,backlash=0+.5*0,profile_shift="auto",gear_spin=180/teeth1*.5,helical=40);
611// %spur_gear2d(mod=mod, teeth=teeth1,backlash=4+.5*0,profile_shift="auto",gear_spin=180/teeth1*.5,helical=40);
612// color("black")stroke(arc(n=32,r=r1,angle=[90+bang/2,90]),width=.1,endcaps="arrow2");
613// }
614// color("black")back(r1+.25)right(5.5)text("backlash/2",size=1);
615// Figure(2D,Med,VPT=[0.532987,50.0891,0.0383045],VPR=[0,0,0],VPD=53.9078): Here two gears appear together with a more reasonable backlash applied to both gears. Again the lighter color shows the ideal gears and the darker shade shows the gear with backlash. Note that in this example, backlash is present on both of the meshing gears, so the total backlash of the system is the combined backlash from both gears.
616// teeth1=20;teeth2=33;
617// mod=5;
618// ha=0;
619// r1 = pitch_radius(mod=mod,teeth=teeth1,helical=ha);
620// r2=pitch_radius(mod=mod,teeth=teeth2,helical=ha);
621// bang=4/(2*PI*r1) * 360 ;
622//
623// back(r1+pitch_radius(mod=mod,teeth=teeth2,helical=ha)){
624// spur_gear2d(mod=mod, teeth=teeth2,backlash=.5*0,helical=ha,gear_spin=-180/teeth2/2);
625// %spur_gear2d(mod=mod, teeth=teeth2,backlash=1,helical=ha,gear_spin=-180/teeth2/2);
626// }
627// {
628// spur_gear2d(mod=mod, teeth=teeth1,backlash=0+.5*0,profile_shift=0,gear_spin=180/teeth1*.5,helical=ha);
629// %spur_gear2d(mod=mod, teeth=teeth1,backlash=1+.5*0,profile_shift=0,gear_spin=180/teeth1*.5,helical=ha);
630// *color("white"){
631// dashed_stroke(arc(r=r1, n=30, angle=[80,110]), width=.05);
632// back(r1+r2)
633// dashed_stroke(arc(r=r2, n=30, angle=[-80,-110]), width=.05);
634// }
635// //color("black")stroke(arc(n=32,r=r1,angle=[90+bang/2,90]),width=.1,endcaps="arrow2");
636// }
637// Figure(2D,Med,VPT=[0.532987,50.0891,0.0383045],VPR=[0,0,0],VPD=53.9078): Here the same gears as in the previous figure appear with backlash applied using the `backlash` parameter to {{gear_dist()}} to shift them apart. The original ideal gears are in the lighter shade and the darker colored gears have been separated to create the backlash.
638// teeth1=20;teeth2=33;
639// mod=5;
640// ha=0;
641// r1 = pitch_radius(mod=mod,teeth=teeth1,helical=ha);
642// r2 = pitch_radius(mod=mod,teeth=teeth2,helical=ha);
643// bang=4/(2*PI*r1) * 360 ;
644// shift = 1 * cos(ha)/2/tan(20);
645// back(r1+pitch_radius(mod=mod,teeth=teeth2,helical=ha)){
646// zrot(-180/teeth2/2){
647// %back(shift)spur_gear2d(mod=mod, teeth=teeth2,backlash=0,helical=ha);
648// spur_gear2d(mod=mod, teeth=teeth2,backlash=0,helical=ha);
649// }
650// }
651// zrot(180/teeth1*.5){
652// %fwd(shift)spur_gear2d(mod=mod, teeth=teeth1,backlash=0+.5*0,profile_shift=0,helical=ha);
653// spur_gear2d(mod=mod, teeth=teeth1,backlash=0,profile_shift=0,helical=ha);
654// }
655
656// Section: Gears
657
658// Function&Module: spur_gear()
659// Synopsis: Creates a spur gear, helical gear, or internal ring gear.
660// SynTags: Geom, VNF
661// Topics: Gears, Parts
662// See Also: rack(), spur_gear(), spur_gear2d(), bevel_gear()
663// Usage: As a Module
664// spur_gear(circ_pitch, teeth, [thickness], [helical=], [pressure_angle=], [profile_shift=], [backlash=], [shaft_diam=], [hide=], [clearance=], [slices=], [internal=], [herringbone=]) [ATTACHMENTS];
665// spur_gear(mod=|diam_pitch=, teeth=, [thickness=], ...) [ATTACHMENTS];
666// Usage: As a Function
667// vnf = spur_gear(circ_pitch, teeth, [thickness], ...);
668// vnf = spur_gear(mod=|diam_pitch=, teeth=, [thickness=], ...);
669// Description:
670// Creates a involute spur gear, helical gear, herringbone gear, or a mask for an internal ring gear.
671// For more information about gears, see [A Quick Introduction to Gears](gears.scad#section-a-quick-introduction-to-gears).
672// You must specify the teeth size using either `mod=`, `circ_pitch=` or `diam_pitch=`, and you
673// must give the number of teeth of the gear. Spur gears have straight teeth and
674// mesh together on parallel shafts without creating any axial thrust. The teeth engage suddenly across their
675// entire width, creating stress and noise. Helical gears have angled teeth and engage more gradually, so they
676// run more smoothly and quietly, however they do produce thrust along the gear axis. This can be
677// circumvented using herringbone or double helical gears, which have no axial thrust and also self-align.
678// Helical gears can mesh along shafts that are not parallel, where the angle between the shafts is
679// the sum of the helical angles of the two gears.
680// .
681// The module creates the gear in the XY plane, centered on the origin, with one tooth centered on the positive Y axis.
682// In order for two gears to mesh they must have the same tooth size and `pressure_angle`, and
683// generally the helical angles should be of opposite sign.
684// The usual pressure angle (and default) is 20 degrees. Another common value is 14.5 degrees.
685// Ideally the teeth count of two meshing gears will be relatively prime because this ensures that
686// every tooth on one gear will meet every tooth on the other, creating even wear.
687// .
688// The "pitch circle" of the gear is a reference circle where the circular pitch is defined that
689// is used to construct the gear. It runs approximately through the centers of the teeth.
690// Two basic gears will mesh when their pitch circles are tangent. Anchoring for these gears is
691// done on the pitch circle by default, so basic gears can be meshed using anchoring.
692// However, when a gear has a small number of teeth, the basic gear form will result in undercutting,
693// which weakens the teeth. To avoid this, profile shifting is automatically applied and in this
694// case, the distance between the gears is a complicated calculation and must be determined using {{gear_dist()}}.
695// If you wish to override this correction, you can use `profile_shift=0`, or set it to a specific
696// value like 0.5. Another complication with profile shifted gears is that the tips may be too long,
697// which can eat into the clearance space. To address this problem you can use the `shorten` parameter,
698// which you can compute using {{gear_shorten()}}.
699// .
700// Helical gears can mesh with skew or crossed axes, a configuration sometimes called "screw gears".
701// Without profile shifting, that angle is the sum of the helical angles.
702// With profile shifting it is slightly different and is given by {{gear_skew_angle()}}.
703// These gears still mesh on the pitch circle when they are not profile shifted, but the correction to
704// gear separation for a proper mesh of profile shifted gears is different for skew gears and is
705// computed using {{gear_dist_skew()}}.
706// .
707// To create space for gears to mesh in practice you will need to set a positive value for backlash, or
708// use the `backlash` argument to {{gear_dist()}}.
709// Arguments:
710// circ_pitch = The circular pitch, or distance between teeth around the pitch circle.
711// teeth = Total number of teeth around the entire perimeter
712// thickness = Thickness of gear. Default: 10
713// ---
714// mod = The module of the gear (pitch diameter / teeth)
715// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
716// helical = Teeth spiral around the gear at this angle, positive for left handed, negative for right handed. Default: 0
717// herringbone = If true, and helical is set, creates a herringbone gear. Default: False
718// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
719// profile_shift = Profile shift factor x. Default: "auto"
720// shorten = Shorten gear tips by the module times this value. Needed for large profile shifted gears. Default: 0
721// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
722// shaft_diam = Diameter of the hole in the center. Default: 0 (no shaft hole)
723// hide = Number of teeth to delete to make this only a fraction of a circle. Default: 0
724// gear_spin = Rotate gear and children around the gear center, regardless of how gear is anchored. Default: 0
725// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: mod/4
726// slices = Number of vertical layers to divide gear into. Useful for refining gears with `helical`.
727// internal = If true, create a mask for difference()ing from something else.
728// atype = Set to "root", "tip" or "pitch" to determine anchoring circle. Default: "pitch"
729// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
730// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
731// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
732// Side Effects:
733// If internal is true then the default tag is "remove"
734// Anchor Types:
735// root = anchor on the root circle
736// pitch = anchor on the pitch circle (default)
737// tip = anchor on the tip circle
738// Example: Spur Gear
739// spur_gear(circ_pitch=5, teeth=20, thickness=8, shaft_diam=5);
740// Example: Metric Gear
741// spur_gear(mod=2, teeth=20, thickness=8, shaft_diam=5);
742// Example: Helical Gear
743// spur_gear(
744// circ_pitch=5, teeth=20, thickness=10,
745// shaft_diam=5, helical=-30, slices=12,
746// $fa=1, $fs=1
747// );
748// Example: Herringbone Gear
749// spur_gear(
750// circ_pitch=5, teeth=20, thickness=10, shaft_diam=5,
751// helical=30, herringbone=true, slices=5
752// );
753// Example(Med,VPT=[-0.0213774,2.42972,-0.2709],VPR=[36.1,0,20.1],VPD=74.3596): Effects of Profile Shifting.
754// circ_pitch=5; teeth=7; thick=10; shaft=5; strokewidth=0.2;
755// pr = pitch_radius(circ_pitch, teeth);
756// left(10) {
757// profile_shift = 0;
758// d = gear_dist(circ_pitch=circ_pitch,teeth,0,profile_shift1=profile_shift);
759// back(d) spur_gear(circ_pitch, teeth, thick, shaft, profile_shift=profile_shift);
760// rack(circ_pitch, teeth=3, thickness=thick, orient=BACK);
761// color("black") up(thick/2) linear_extrude(height=0.1) {
762// back(d) dashed_stroke(circle(r=pr), width=strokewidth, closed=true);
763// dashed_stroke([[-7.5,0],[7.5,0]], width=strokewidth);
764// }
765// }
766// right(10) {
767// profile_shift = 0.59;
768// d = gear_dist(circ_pitch=circ_pitch,teeth,0,profile_shift1=profile_shift);
769// back(d) spur_gear(circ_pitch, teeth, thick, shaft, profile_shift=profile_shift);
770// rack(circ_pitch, teeth=3, thickness=thick, orient=BACK);
771// color("black") up(thick/2) linear_extrude(height=0.1) {
772// back(d)
773// dashed_stroke(circle(r=pr), width=strokewidth, closed=true);
774// dashed_stroke([[-7.5,0],[7.5,0]], width=strokewidth);
775// }
776// }
777// Example(Anim,Med,Frames=8,VPT=[0,30,0],VPR=[0,0,0],VPD=300): Assembly of Gears
778// $fn=12;
779// n1 = 11; //red gear number of teeth
780// n2 = 20; //green gear
781// n3 = 6; //blue gear
782// n4 = 16; //orange gear
783// n5 = 9; //gray rack
784// circ_pitch = 9; //all meshing gears need the same `circ_pitch` (and the same `pressure_angle`)
785// thickness = 6;
786// hole = 3;
787// rack_base = 12;
788// d12 = gear_dist(circ_pitch=circ_pitch,teeth1=n1,teeth2=n2);
789// d13 = gear_dist(circ_pitch=circ_pitch,teeth1=n1,teeth2=n3);
790// d14 = gear_dist(circ_pitch=circ_pitch,teeth1=n1,teeth2=n4);
791// d1r = gear_dist(circ_pitch=circ_pitch,teeth1=n1,teeth2=0);
792// a1 = $t * 360 / n1;
793// a2 = -$t * 360 / n2 + 180/n2;
794// a3 = -$t * 360 / n3 - 3*90/n3;
795// a4 = -$t * 360 / n4 - 3.5*180/n4;
796// color("#f77") zrot(a1) spur_gear(circ_pitch,n1,thickness,hole);
797// color("#7f7") back(d12) zrot(a2) spur_gear(circ_pitch,n2,thickness,hole);
798// color("#77f") right(d13) zrot(a3) spur_gear(circ_pitch,n3,thickness,hole);
799// color("#fc7") left(d14) zrot(a4) spur_gear(circ_pitch,n4,thickness,hole,hide=n4-3);
800// color("#ccc") fwd(d1r) right(circ_pitch*$t)
801// rack(pitch=circ_pitch,teeth=n5,thickness=thickness,width=rack_base,anchor=CENTER,orient=BACK);
802// Example(NoAxes,VPT=[1.13489,-4.48517,1.04995],VPR=[55,0,25],VPD=139.921): Helical gears meshing with non-parallel shafts
803// ang1 = 30;
804// ang2 = 10;
805// circ_pitch = 5;
806// n = 20;
807// dist = gear_dist_skew(
808// circ_pitch=circ_pitch,
809// teeth1=n, teeth2=n,
810// helical1=ang1, helical2=ang2);
811// left(dist/2) spur_gear(
812// circ_pitch, teeth=n, thickness=10,
813// shaft_diam=5, helical=ang1, slices=12,
814// gear_spin=-90
815// );
816// right(dist/2)
817// xrot(ang1+ang2)
818// spur_gear(
819// circ_pitch=circ_pitch, teeth=n, thickness=10,
820// shaft_diam=5, helical=ang2, slices=12,
821// gear_spin=90-180/n
822// );
823// Example(Anim,Big,NoAxes,Frames=36,VPT=[0,0,0],VPR=[55,0,25],VPD=220): Planetary Gear Assembly
824// $fn=128;
825// rteeth=56; pteeth=16; cteeth=24;
826// circ_pitch=5; thick=10; pa=20;
827// gd = gear_dist(circ_pitch=circ_pitch, cteeth, pteeth);
828// ring_gear(
829// circ_pitch=circ_pitch,
830// teeth=rteeth,
831// thickness=thick,
832// pressure_angle=pa);
833// for (a=[0:3]) {
834// zrot($t*90+a*90) back(gd) {
835// color("green")
836// spur_gear(
837// circ_pitch=circ_pitch,
838// teeth=pteeth,
839// thickness=thick,
840// shaft_diam=5,
841// pressure_angle=pa,
842// spin=-$t*90*rteeth/pteeth);
843// }
844// }
845// color("orange")
846// zrot($t*90*rteeth/cteeth+$t*90+180/cteeth)
847// spur_gear(
848// circ_pitch=circ_pitch,
849// teeth=cteeth,
850// thickness=thick,
851// shaft_diam=5,
852// pressure_angle=pa);
853
854function spur_gear(
855 circ_pitch,
856 teeth,
857 thickness,
858 shaft_diam = 0,
859 hide = 0,
860 pressure_angle,
861 clearance,
862 backlash = 0.0,
863 helical,
864 interior,
865 internal,
866 profile_shift="auto",
867 slices,
868 herringbone=false,
869 shorten=0,
870 diam_pitch,
871 mod,
872 pitch,
873 gear_spin = 0,
874 atype = "pitch",
875 anchor = CENTER,
876 spin = 0,
877 orient = UP
878) =
879 let(
880 dummy = !is_undef(interior) ? echo("In spur_gear(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0,
881 internal = first_defined([internal,interior,false]),
882 circ_pitch = _inherit_gear_pitch("spur_gear()", pitch, circ_pitch, diam_pitch, mod),
883 PA = _inherit_gear_pa(pressure_angle),
884 helical = _inherit_gear_helical(helical, invert=!internal),
885 thickness = _inherit_gear_thickness(thickness),
886 profile_shift = auto_profile_shift(teeth,PA,helical,profile_shift=profile_shift)
887 )
888 assert(is_integer(teeth) && teeth>3)
889 assert(is_finite(thickness) && thickness>0)
890 assert(is_finite(shaft_diam) && shaft_diam>=0)
891 assert(is_integer(hide) && hide>=0 && hide<teeth)
892 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
893 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
894 assert(is_finite(backlash) && backlash>=0)
895 assert(is_finite(helical) && abs(helical)<90)
896 assert(is_bool(herringbone))
897 assert(slices==undef || (is_integer(slices) && slices>0))
898 assert(is_finite(gear_spin))
899 let(
900 pr = pitch_radius(circ_pitch, teeth, helical),
901 or = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal,shorten=shorten),
902 rr = _root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=internal),
903 anchor_rad = atype=="pitch" ? pr
904 : atype=="tip" ? or
905 : atype=="root" ? rr
906 : assert(false,"atype must be one of \"root\", \"tip\" or \"pitch\""),
907 circum = 2 * PI * pr,
908 twist = 360*thickness*tan(helical)/circum,
909 slices = default(slices, ceil(twist/360*segs(pr)+1)),
910 rgn = spur_gear2d(
911 circ_pitch = circ_pitch,
912 teeth = teeth,
913 pressure_angle = PA,
914 hide = hide,
915 helical = helical,
916 clearance = clearance,
917 backlash = backlash,
918 internal = internal,
919 shorten = shorten,
920 profile_shift = profile_shift,
921 shaft_diam = shaft_diam
922 ),
923 rvnf = herringbone
924 ? zrot(twist/2, p=linear_sweep(rgn, height=thickness, twist=twist, slices=slices, center=true))
925 : let(
926 wall_vnf = linear_sweep(rgn, height=thickness/2, twist=twist/2, slices=ceil(slices/2), center=false, caps=false),
927 cap_vnf = vnf_from_region(rgn, transform=up(thickness/2)*zrot(twist/2))
928 )
929 vnf_join([
930 wall_vnf, zflip(p=wall_vnf),
931 cap_vnf, zflip(p=cap_vnf),
932 ]),
933 vnf = zrot(gear_spin, p=rvnf)
934 ) reorient(anchor,spin,orient, h=thickness, r=anchor_rad, p=vnf);
935
936
937module spur_gear(
938 circ_pitch,
939 teeth,
940 thickness,
941 shaft_diam = 0,
942 hide = 0,
943 pressure_angle,
944 clearance,
945 backlash = 0.0,
946 helical,
947 internal,
948 interior,
949 profile_shift="auto",
950 slices,
951 herringbone=false,
952 shorten=0,
953 pitch,
954 diam_pitch,
955 mod,
956 gear_spin = 0,
957 atype="pitch",
958 anchor = CENTER,
959 spin = 0,
960 orient = UP
961) {
962 dummy = !is_undef(interior) ? echo("In spur_gear(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0;
963 internal = first_defined([internal,interior,false]);
964 circ_pitch = _inherit_gear_pitch("spur_gear()", pitch, circ_pitch, diam_pitch, mod);
965 PA = _inherit_gear_pa(pressure_angle);
966 helical = _inherit_gear_helical(helical, invert=!internal);
967 thickness = _inherit_gear_thickness(thickness);
968 profile_shift = auto_profile_shift(teeth,PA,helical,profile_shift=profile_shift);
969 checks =
970 assert(is_integer(teeth) && teeth>3)
971 assert(is_finite(thickness) && thickness>0)
972 assert(is_finite(shaft_diam) && shaft_diam>=0)
973 assert(is_integer(hide) && hide>=0 && hide<teeth)
974 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
975 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
976 assert(is_finite(backlash) && backlash>=0)
977 assert(is_finite(helical) && abs(helical)<90)
978 assert(is_bool(herringbone))
979 assert(slices==undef || (is_integer(slices) && slices>0))
980 assert(is_finite(gear_spin));
981 pr = pitch_radius(circ_pitch, teeth, helical);
982 or = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal,shorten=shorten);
983 rr = _root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=internal);
984 anchor_rad = atype=="pitch" ? pr
985 : atype=="tip" ? or
986 : atype=="root" ? rr
987 : assert(false,"atype must be one of \"root\", \"tip\" or \"pitch\"");
988 circum = 2 * PI * pr;
989 twist = 360*thickness*tan(helical)/circum;
990 slices = default(slices, ceil(twist/360*segs(pr)+1));
991 default_tag("remove", internal) {
992 attachable(anchor,spin,orient, r=anchor_rad, l=thickness) {
993 zrot(gear_spin)
994 if (herringbone) {
995 zflip_copy() down(0.01)
996 linear_extrude(
997 height=thickness/2+0.01, center=false,
998 twist=twist/2, slices=ceil(slices/2),
999 convexity=teeth/2
1000 ) {
1001 spur_gear2d(
1002 circ_pitch = circ_pitch,
1003 teeth = teeth,
1004 pressure_angle = PA,
1005 hide = hide,
1006 helical = helical,
1007 clearance = clearance,
1008 backlash = backlash,
1009 internal = internal,
1010 shorten = shorten,
1011 profile_shift = profile_shift,
1012 shaft_diam = shaft_diam
1013 );
1014 }
1015 } else {
1016 zrot(twist/2)
1017 linear_extrude(
1018 height=thickness, center=true,
1019 twist=twist, slices=slices,
1020 convexity=teeth/2
1021 ) {
1022 spur_gear2d(
1023 circ_pitch = circ_pitch,
1024 teeth = teeth,
1025 pressure_angle = PA,
1026 hide = hide,
1027 helical = helical,
1028 clearance = clearance,
1029 backlash = backlash,
1030 internal = internal,
1031 profile_shift = profile_shift,
1032 shaft_diam = shaft_diam
1033 );
1034 }
1035 }
1036 union() {
1037 $parent_gear_type = "spur";
1038 $parent_gear_pitch = circ_pitch;
1039 $parent_gear_teeth = teeth;
1040 $parent_gear_pa = PA;
1041 $parent_gear_helical = helical;
1042 $parent_gear_thickness = thickness;
1043 union() children();
1044 }
1045 }
1046 }
1047}
1048
1049
1050// Function&Module: spur_gear2d()
1051// Synopsis: Creates a 2D spur gear or internal ring gear.
1052// SynTags: Geom, Region
1053// Topics: Gears, Parts
1054// See Also: rack(), spur_gear(), spur_gear2d(), bevel_gear()
1055// Usage: As Module
1056// spur_gear2d(circ_pitch, teeth, [pressure_angle=], [profile_shift=], [shorten=], [hide=], [shaft_diam=], [clearance=], [backlash=], [internal=]) [ATTACHMENTS];
1057// spur_gear2d(mod=|diam_pitch=, teeth=, [pressure_angle=], [profile_shift=], [shorten=], [hide=], [shaft_diam=], [clearance=], [backlash=], [internal=]) [ATTACHMENTS];
1058// Usage: As Function
1059// rgn = spur_gear2d(circ_pitch, teeth, [pressure_angle=], [profile_shift=], [shorten=], [hide=], [shaft_diam=], [clearance=], [backlash=], [internal=]);
1060// rgn = spur_gear2d(mod=, teeth=, [pressure_angle=], [profile_shift=], [shorten=], [hide=], [shaft_diam=], [clearance=], [backlash=], [internal=]);
1061// Description:
1062// Creates a 2D involute spur gear, or a mask for an internal ring gear.
1063// For more information about gears, see [A Quick Introduction to Gears](gears.scad#section-a-quick-introduction-to-gears).
1064// You must specify the teeth size using either `mod=`, `circ_pitch=` or `diam_pitch=`, and you
1065// must give the number of teeth.
1066// .
1067// The module creates the gear in centered on the origin, with one tooth centered on the positive Y axis.
1068// In order for two gears to mesh they must have the same tooth size and `pressure_angle`
1069// The usual pressure angle (and default) is 20 degrees. Another common value is 14.5 degrees.
1070// Ideally the teeth count of two meshing gears will be relatively prime because this ensures that
1071// every tooth on one gear will meet every tooth on the other, creating even wear.
1072// .
1073// The "pitch circle" of the gear is a reference circle where the circular pitch is defined that
1074// is used to construct the gear. It runs approximately through the centers of the teeth.
1075// Two basic gears will mesh when their pitch circles are tangent. Anchoring for these gears is
1076// done on the pitch circle by default, so basic gears can be meshed using anchoring.
1077// However, when a gear has a small number of teeth, the basic gear form will result in undercutting,
1078// which weakens the teeth. To avoid this, profile shifting is automatically applied and in this
1079// case, the distance between the gears is a complicated calculation and must be determined using {{gear_dist()}}.
1080// If you wish to override this correction, you can use `profile_shift=0`, or set it to a specific
1081// value like 0.5. Another complication with profile shifted gears is that the tips may be too long,
1082// which can eat into the clearance space. To address this problem you can use the `shorten` parameter,
1083// which you can compute using {{gear_shorten()}}.
1084// .
1085// To create space for gears to mesh in practice you will need to set a positive value for backlash, or
1086// use the `backlash` argument to {{gear_dist()}}.
1087// Arguments:
1088// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1089// teeth = Total number of teeth around the spur gear.
1090// ---
1091// mod = The module of the gear (pitch diameter / teeth)
1092// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
1093// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
1094// profile_shift = Profile shift factor x. Default: "auto"
1095// shorten = Shorten gear tips by the module times this value. Needed for large profile shifted gears. Default: 0
1096// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
1097// helical = Adjust teeth form (stretch out the teeth) to give the cross section of a gear with this helical angle. Default: 0
1098// hide = Number of teeth to delete to make this only a fraction of a circle
1099// gear_spin = Rotate gear and children around the gear center, regardless of how gear is anchored. Default: 0
1100// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear. Default: mod/4
1101// internal = If true, create a mask for difference()ing from something else.
1102// shaft_diam = If given, the diameter of the central shaft hole.
1103// atype = Set to "root", "tip" or "pitch" to determine anchoring circle. Default: "pitch"
1104// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
1105// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
1106// Side Effects:
1107// If internal is true then the default tag is "remove"
1108// Anchor Types:
1109// root = anchor on the root circle
1110// pitch = anchor on the pitch circle (default)
1111// tip = anchor on the tip circle
1112// Example(2D): Typical Gear Shape
1113// spur_gear2d(circ_pitch=5, teeth=20, shaft_diam=5);
1114// Example(2D): By Metric Module
1115// spur_gear2d(mod=2, teeth=20, shaft_diam=5);
1116// Example(2D): By Imperial Gear Pitch
1117// spur_gear2d(diam_pitch=10, teeth=20, shaft_diam=5);
1118// Example(2D): Lower Pressure Angle
1119// spur_gear2d(circ_pitch=5, teeth=20, pressure_angle=14);
1120// Example(2D): Partial Gear
1121// spur_gear2d(circ_pitch=5, teeth=20, hide=15, pressure_angle=20);
1122// Example(2D,Med,VPT=[0.151988,3.93719,1.04995],VPR=[0,0,0],VPD=74.3596): Effects of Profile Shifting.
1123// circ_pitch=5; teeth=7; shaft=5; strokewidth=0.2;
1124// module the_gear(profile_shift=0) {
1125// $fn=72;
1126// pr = pitch_radius(circ_pitch,teeth);
1127// mr = gear_dist(circ_pitch=circ_pitch,teeth,profile_shift1=profile_shift,teeth2=0);
1128// back(mr) {
1129// spur_gear2d(circ_pitch, teeth, shaft_diam=shaft, profile_shift=profile_shift);
1130// up(0.1) color("black")
1131// dashed_stroke(circle(r=pr), width=strokewidth, closed=true);
1132// }
1133// }
1134// module the_rack() {
1135// $fn=72;
1136// rack2d(circ_pitch, teeth=3);
1137// up(0.1) color("black")
1138// dashed_stroke([[-7.5,0],[7.5,0]], width=strokewidth);
1139// }
1140// left(10) { the_gear(0); the_rack(); }
1141// right(10) { the_gear(0.59); the_rack(); }
1142// Example(2D): Planetary Gear Assembly
1143// rteeth=56; pteeth=16; cteeth=24;
1144// circ_pitch=5; pa=20;
1145// gd = gear_dist(circ_pitch=circ_pitch, cteeth,pteeth);
1146// ring_gear2d(
1147// circ_pitch=circ_pitch,
1148// teeth=rteeth,
1149// pressure_angle=pa);
1150// for (a=[0:3]) {
1151// zrot(a*90) back(gd) {
1152// color("green")
1153// spur_gear2d(
1154// circ_pitch=circ_pitch,
1155// teeth=pteeth,
1156// pressure_angle=pa);
1157// }
1158// }
1159// color("orange")
1160// zrot(180/cteeth)
1161// spur_gear2d(
1162// circ_pitch=circ_pitch,
1163// teeth=cteeth,
1164// pressure_angle=pa);
1165// Example(2D): Called as a Function
1166// rgn = spur_gear2d(circ_pitch=8, teeth=16, shaft_diam=5);
1167// region(rgn);
1168
1169function spur_gear2d(
1170 circ_pitch,
1171 teeth,
1172 hide = 0,
1173 pressure_angle,
1174 clearance,
1175 backlash = 0.0,
1176 internal,
1177 interior,
1178 profile_shift="auto",
1179 helical,
1180 shaft_diam = 0,
1181 shorten = 0,
1182 pitch,
1183 diam_pitch,
1184 mod,
1185 gear_spin = 0,
1186 atype="pitch",
1187 anchor = CENTER,
1188 spin = 0
1189) = let(
1190 dummy = !is_undef(interior) ? echo("In spur_gear2d(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0,
1191 internal = first_defined([internal,interior,false]),
1192 circ_pitch = _inherit_gear_pitch("spur_gear2d()", pitch, circ_pitch, diam_pitch, mod),
1193 PA = _inherit_gear_pa(pressure_angle),
1194 helical = _inherit_gear_helical(helical, invert=!internal),
1195 profile_shift = auto_profile_shift(teeth,PA,helical,profile_shift=profile_shift)
1196 )
1197 assert(is_integer(teeth) && teeth>3)
1198 assert(is_finite(shaft_diam) && shaft_diam>=0)
1199 assert(is_integer(hide) && hide>=0 && hide<teeth)
1200 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1201 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1202 assert(is_finite(backlash) && backlash>=0)
1203 assert(is_finite(helical) && abs(helical)<90)
1204 assert(is_finite(gear_spin))
1205 let(
1206 pr = pitch_radius(circ_pitch, teeth, helical=helical),
1207 or = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal,shorten=shorten),
1208 rr = _root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=internal),
1209 anchor_rad = atype=="pitch" ? pr
1210 : atype=="tip" ? or
1211 : atype=="root" ? rr
1212 : assert(false,"atype must be one of \"root\", \"tip\" or \"pitch\""),
1213 tooth = _gear_tooth_profile(
1214 circ_pitch=circ_pitch,
1215 teeth=teeth,
1216 pressure_angle=PA,
1217 clearance=clearance,
1218 backlash=backlash,
1219 profile_shift=profile_shift,
1220 helical=helical,
1221 shorten=shorten,
1222 internal=internal
1223 ),
1224 perim = [
1225 for (i = [0:1:teeth-1-hide])
1226 each zrot(-i*360/teeth+gear_spin, p=tooth),
1227 if (hide>0) [0,0],
1228 ],
1229 rgn = [
1230 list_unwrap(deduplicate(perim)),
1231 if (shaft_diam>0 && !hide)
1232 reverse(circle(d=shaft_diam, $fn=max(16,segs(shaft_diam/2)))),
1233 ]
1234 ) reorient(anchor,spin, two_d=true, r=anchor_rad, p=rgn);
1235
1236
1237module spur_gear2d(
1238 circ_pitch,
1239 teeth,
1240 hide = 0,
1241 pressure_angle,
1242 clearance,
1243 backlash = 0.0,
1244 internal,
1245 interior,
1246 profile_shift="auto",
1247 helical,
1248 shorten = 0,
1249 shaft_diam = 0,
1250 pitch,
1251 diam_pitch,
1252 mod,
1253 gear_spin = 0,
1254 atype="pitch",
1255 anchor = CENTER,
1256 spin = 0
1257) {
1258 dummy = !is_undef(interior) ? echo("In spur_gear2d(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0;
1259 internal = first_defined([internal,interior,false]);
1260 circ_pitch = _inherit_gear_pitch("spur_gear2d()", pitch, circ_pitch, diam_pitch, mod);
1261 PA = _inherit_gear_pa(pressure_angle);
1262 helical = _inherit_gear_helical(helical, invert=!internal);
1263 profile_shift = auto_profile_shift(teeth,PA,helical,profile_shift=profile_shift);
1264 checks =
1265 assert(is_integer(teeth) && teeth>3)
1266 assert(is_finite(shaft_diam) && shaft_diam>=0)
1267 assert(is_integer(hide) && hide>=0 && hide<teeth)
1268 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1269 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1270 assert(is_finite(backlash) && backlash>=0)
1271 assert(is_finite(helical) && abs(helical)<90)
1272 assert(is_finite(gear_spin));
1273 rgn = spur_gear2d(
1274 circ_pitch = circ_pitch,
1275 teeth = teeth,
1276 hide = hide,
1277 pressure_angle = PA,
1278 clearance = clearance,
1279 helical = helical,
1280 backlash = backlash,
1281 profile_shift = profile_shift,
1282 internal = internal,
1283 shorten = shorten,
1284 shaft_diam = shaft_diam
1285 );
1286 pr = pitch_radius(circ_pitch, teeth, helical=helical);
1287 or = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal,shorten=shorten);
1288 rr = _root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=internal);
1289 anchor_rad = atype=="pitch" ? pr
1290 : atype=="tip" ? or
1291 : atype=="root" ? rr
1292 : assert(false,"atype must be one of \"root\", \"tip\" or \"pitch\"");
1293 attachable(anchor,spin, two_d=true, r=anchor_rad) {
1294 zrot(gear_spin) region(rgn);
1295 union() {
1296 $parent_gear_type = "spur2D";
1297 $parent_gear_pitch = circ_pitch;
1298 $parent_gear_teeth = teeth;
1299 $parent_gear_pa = PA;
1300 $parent_gear_helical = helical;
1301 $parent_gear_thickness = 0;
1302 union() children();
1303 }
1304 }
1305}
1306
1307
1308// Module: ring_gear()
1309// Synopsis: Creates a 3D ring gear.
1310// SynTags: Geom
1311// Topics: Gears, Parts
1312// See Also: rack(), ring_gear2d(), spur_gear(), spur_gear2d(), bevel_gear()
1313// Usage:
1314// ring_gear(circ_pitch, teeth, thickness, [backing|od=|or=|width=], [pressure_angle=], [helical=], [herringbone=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1315// ring_gear(mod=, teeth=, thickness=, [backing=|od=|or=|width=], [pressure_angle=], [helical=], [herringbone=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1316// ring_gear(diam_pitch=, teeth=, thickness=, [backing=|od=|or=|width=], [pressure_angle=], [helical=], [herringbone=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1317// Description:
1318// Creates a 3D involute ring gear.
1319// Meshing gears must have the same tooth size, pressure angle and helical angle as usual.
1320// Additionally, you must have more teeth on an internal gear than its mating external gear, and
1321// the profile shift on the ring gear must be at least as big as the profile shift on the mating gear.
1322// You may need to use {{auto_profile_shift()}} to find this value if your mating gear has a small number of teeth.
1323// The gear spacing is given by {{gear_dist()}}.
1324// Arguments:
1325// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1326// teeth = Total number of teeth around the spur gear.
1327// thickness = Thickness of ring gear in mm
1328// backing = The width of the ring gear backing. Default: height of teeth
1329// ---
1330// od = outer diameter of the ring
1331// or = outer radius of the ring
1332// width = width of the ring, measuring from tips of teeth to outside of ring.
1333// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
1334// helical = The angle of the rack teeth away from perpendicular to the gear axis of rotation. Stretches out the tooth shapes. Used to match helical spur gear pinions. Default: 0
1335// herringbone = If true, and helical is set, creates a herringbone gear.
1336// profile_shift = Profile shift factor x for tooth profile. Default: 0
1337// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
1338// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
1339// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
1340// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
1341// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
1342// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
1343// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
1344// Example:
1345// ring_gear(circ_pitch=5, teeth=48, thickness=10);
1346// Example: Adjusting Backing
1347// ring_gear(circ_pitch=5, teeth=48, thickness=10, backing=30);
1348// Example(Med): Adjusting Pressure Angle
1349// ring_gear(circ_pitch=5, teeth=48, thickness=10, pressure_angle=28);
1350// Example(Med): Tooth Profile Shifting
1351// ring_gear(circ_pitch=5, teeth=48, thickness=10, profile_shift=0.5);
1352// Example(Med): Helical Ring Gear
1353// ring_gear(circ_pitch=5, teeth=48, thickness=15, helical=30);
1354// Example(Med): Herringbone Ring Gear
1355// ring_gear(circ_pitch=5, teeth=48, thickness=30, helical=30, herringbone=true);
1356
1357module ring_gear(
1358 circ_pitch,
1359 teeth,
1360 thickness = 10,
1361 backing,
1362 pressure_angle,
1363 helical,
1364 herringbone = false,
1365 profile_shift=0,
1366 clearance,
1367 backlash = 0.0,
1368 or,od,width,
1369 pitch,
1370 diam_pitch,
1371 mod,
1372 slices,
1373 gear_spin = 0,
1374 anchor = CENTER,
1375 spin = 0,
1376 orient = UP
1377) {
1378 circ_pitch = _inherit_gear_pitch("ring_gear()",pitch, circ_pitch, diam_pitch, mod);
1379 PA = _inherit_gear_pa(pressure_angle);
1380 helical = _inherit_gear_helical(helical); //Maybe broken???
1381 thickness = _inherit_gear_thickness(thickness);
1382 checks =
1383 assert(is_finite(profile_shift), "Profile shift for ring gears must be numerical")
1384 assert(is_integer(teeth) && teeth>3)
1385 assert(is_finite(thickness) && thickness>0)
1386 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1387 assert(is_finite(helical) && abs(helical)<90)
1388 assert(is_bool(herringbone))
1389 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1390 assert(is_finite(backlash) && backlash>=0)
1391 assert(slices==undef || (is_integer(slices) && slices>0))
1392 assert(num_defined([backing,or,od,width])<=1, "Cannot define more than one of backing, or, od and width")
1393 assert(is_finite(gear_spin));
1394 pr = pitch_radius(circ_pitch, teeth, helical=helical);
1395 ar = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=true);
1396 rr=_root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=true);
1397 or = is_def(or) ?
1398 assert(is_finite(or) && or>ar, "or is invalid or too small for teeth")
1399 or
1400 : is_def(od) ?
1401 assert(is_finite(od) && od>2*ar, "od is invalid or too small for teeth")
1402 od/2
1403 : is_def(width) ?
1404 assert(is_finite(width) && width>ar-rr, "width is invalid or too small for teeth")
1405 rr+width
1406 : is_def(backing) ?
1407 assert(all_positive([backing]), "backing must be a positive value")
1408 ar+backing
1409 : 2*ar - rr; // default case
1410 circum = 2 * PI * pr;
1411 twist = 360*thickness*tan(-helical)/circum;
1412 slices = default(slices, ceil(twist/360*segs(pr)+1));
1413 attachable(anchor,spin,orient, h=thickness, r=pr) {
1414 zrot(gear_spin)
1415 if (herringbone) {
1416 zflip_copy() down(0.01)
1417 linear_extrude(height=thickness/2, center=false, twist=twist/2, slices=ceil(slices/2), convexity=teeth/4) {
1418 difference() {
1419 circle(r=or);
1420 spur_gear2d(
1421 circ_pitch = circ_pitch,
1422 teeth = teeth,
1423 pressure_angle = PA,
1424 helical = helical,
1425 clearance = clearance,
1426 backlash = backlash,
1427 profile_shift = profile_shift,
1428 internal = true
1429 );
1430 }
1431 }
1432 } else {
1433 zrot(twist/2)
1434 linear_extrude(height=thickness,center=true, twist=twist, convexity=teeth/4) {
1435 difference() {
1436 circle(r=or);
1437 spur_gear2d(
1438 circ_pitch = circ_pitch,
1439 teeth = teeth,
1440 pressure_angle = PA,
1441 helical = helical,
1442 clearance = clearance,
1443 backlash = backlash,
1444 profile_shift = profile_shift,
1445 internal = true
1446 );
1447 }
1448 }
1449 }
1450 children();
1451 }
1452}
1453
1454
1455// Module: ring_gear2d()
1456// Synopsis: Creates a 2D ring gear.
1457// SynTags: Geom
1458// Topics: Gears, Parts
1459// See Also: rack(), spur_gear(), spur_gear2d(), bevel_gear()
1460// Usage:
1461// ring_gear2d(circ_pitch, teeth, [backing|od=|or=|width=], [pressure_angle=], [helical=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1462// ring_gear2d(mod=, teeth=, [backing=|od=|or=|width=], [pressure_angle=], [helical=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1463// ring_gear2d(diam_pitch=, teeth=, [backing=|od=|or=|width=], [pressure_angle=], [helical=], [profile_shift=], [clearance=], [backlash=]) [ATTACHMENTS];
1464// Description:
1465// Creates a 2D involute ring gear.
1466// Meshing gears must have the same tooth size, pressure angle and helical angle as usual.
1467// Additionally, you must have more teeth on an internal gear than its mating external gear, and
1468// the profile shift on the ring gear must be at least as big as the profile shift on the mating gear.
1469// You may need to use {{auto_profile_shift()}} to find this value if your mating gear has a small number of teeth.
1470// The gear spacing is given by {{gear_dist()}}.
1471// Arguments:
1472// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
1473// teeth = Total number of teeth around the spur gear.
1474// backing = The width of the ring gear backing. Default: height of teeth
1475// ---
1476// od = outer diameter of the ring
1477// or = outer radius of the ring
1478// width = width of the ring, measuring from tips of teeth to outside of ring.
1479// helical = The angle of the rack teeth away from perpendicular to the gear axis of rotation. Stretches out the tooth shapes. Used to match helical spur gear pinions. Default: 0
1480// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
1481// profile_shift = Profile shift factor x for tooth profile. Default: 0
1482// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
1483// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
1484// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
1485// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
1486// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
1487// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
1488// Example(2D,Big): Meshing a ring gear with a spur gear
1489// circ_pitch=5; teeth1=50; teeth2=18;
1490// dist = gear_dist(circ_pitch=circ_pitch, teeth1, teeth2, internal1=true);
1491// ring_gear2d(circ_pitch=circ_pitch, teeth=teeth1);
1492// color("lightblue")back(dist)
1493// spur_gear2d(circ_pitch=circ_pitch, teeth=teeth2);
1494// Example(2D,Med,VPT=[-0.117844,-0.439102,-0.372203],VPR=[0,0,0],VPD=192.044): Meshing a ring gear with an auto-profile-shifted spur gear:
1495// teeth1=7; teeth2=15;
1496// ps1=undef; // Allow auto profile shifting for first gear
1497// ps2=auto_profile_shift(teeth=teeth1);
1498// mod=3;
1499// d = gear_dist(mod=mod, teeth1=teeth1, teeth2=teeth2, profile_shift1=ps1, profile_shift2=ps2, internal2=true);
1500// ring_gear2d(mod=mod, teeth=teeth2,profile_shift=ps2);
1501// color("lightblue") fwd(d)
1502// spur_gear2d(mod=mod, teeth=teeth1, profile_shift=ps1);
1503
1504module ring_gear2d(
1505 circ_pitch,
1506 teeth,
1507 backing,
1508 pressure_angle,
1509 helical,
1510 profile_shift=0,
1511 clearance,
1512 backlash = 0.0,
1513 or,od,width,
1514 pitch,
1515 diam_pitch,
1516 mod,
1517 gear_spin = 0,shorten=0,
1518 anchor = CENTER,
1519 spin = 0
1520) {
1521 circ_pitch = _inherit_gear_pitch("ring_gear2d()",pitch, circ_pitch, diam_pitch, mod);
1522 PA = _inherit_gear_pa(pressure_angle);
1523 helical = _inherit_gear_helical(helical);
1524 checks =
1525 assert(is_finite(profile_shift), "Profile shift for ring gears must be numerical")
1526 assert(is_integer(teeth) && teeth>3)
1527 assert(num_defined([backing,or,od,width])<=1, "Cannot define more than one of backing, or, od and width")
1528 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1529 assert(is_finite(helical) && abs(helical)<90)
1530 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1531 assert(is_finite(backlash) && backlash>=0)
1532 assert(is_finite(gear_spin));
1533 pr = pitch_radius(circ_pitch, teeth, helical=helical);
1534 ar = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=true);
1535 rr=_root_radius(circ_pitch, teeth, clearance, profile_shift=profile_shift, internal=true);
1536 or = is_def(or) ?
1537 assert(is_finite(or) && or>ar, "or is invalid or too small for teeth")
1538 or
1539 : is_def(od) ?
1540 assert(is_finite(od) && od>2*ar, "od is invalid or too small for teeth")
1541 od/2
1542 : is_def(width) ?
1543 assert(is_finite(width) && width>ar-rr, "width is invalid or too small for teeth")
1544 rr+width
1545 : is_def(backing) ?
1546 assert(all_positive([backing]), "backing must be a positive value")
1547 ar+backing
1548 : 2*ar - rr; // default case
1549 attachable(anchor,spin, two_d=true, r=pr) {
1550 zrot(gear_spin)
1551 difference() {
1552 circle(r=or);
1553 spur_gear2d(
1554 circ_pitch = circ_pitch,
1555 teeth = teeth,
1556 pressure_angle = PA,
1557 helical = helical,
1558 clearance = clearance,
1559 backlash = backlash,shorten=shorten,
1560 profile_shift = profile_shift,
1561 internal = true
1562 );
1563 }
1564 children();
1565 }
1566}
1567
1568
1569
1570
1571// Function&Module: rack()
1572// Synopsis: Creates a straight or helical gear rack.
1573// SynTags: Geom, VNF
1574// Topics: Gears, Parts
1575// See Also: rack2d(), spur_gear(), spur_gear2d(), bevel_gear()
1576// Usage: As a Module
1577// rack(pitch, teeth, thickness, [base|bottom=|width=], [helical=], [pressure_angle=], [backlash=], [clearance=]) [ATTACHMENTS];
1578// rack(mod=, teeth=, thickness=, [base=|bottom=|width=], [helical=], [pressure_angle=], [backlash]=, [clearance=]) [ATTACHMENTS];
1579// Usage: As a Function
1580// vnf = rack(pitch, teeth, thickness, [base|bottom=|width=], [helical=], [pressure_angle=], [backlash=], [clearance=]);
1581// vnf = rack(mod=, teeth=, thickness=, [base=|bottom=|width=], [helical=], [pressure_angle=], [backlash=], [clearance=]);
1582// Description:
1583// This is used to create a 3D rack, which is a linear bar with teeth that a gear can roll along.
1584// A rack can mesh with any gear that has the same `pitch` and `pressure_angle`. A helical rack meshes with a gear with the opposite
1585// helical angle.
1586// When called as a function, returns a 3D [VNF](vnf.scad) for the rack.
1587// When called as a module, creates a 3D rack shape.
1588// .
1589// By default the rack has a backing whose height is equal to the height of the teeth. You can specify a different backing size
1590// or you can specify the total width of the rack (from the bottom of the rack to tooth tips) or the
1591// bottom point of the rack, which is the distance from the pitch line to the bottom of the rack.
1592// .
1593// The rack appears oriented with
1594// its teeth pointed UP, so to mesh with gears in the XY plane, use `orient=BACK` or `orient=FWD` and apply any desired rotation.
1595// The pitch line of the rack is aligned with the x axis, the TOP anchors are at the tips of the teeth and the BOTTOM anchors at
1596// the bottom of the backing. Note that for helical racks the corner anchors still point at 45 degr angles.
1597// Arguments:
1598// pitch = The pitch, or distance in mm between teeth along the rack. Matches up with circular pitch on a spur gear. Default: 5
1599// teeth = Total number of teeth along the rack. Default: 20
1600// thickness = Thickness of rack in mm (affects each tooth). Default: 5
1601// backing = Distance from bottom of rack to the roots of the rack's teeth. (Alternative to bottom or width.) Default: height of rack teeth
1602// ---
1603// bottom = Distance from rack's pitch line (the x-axis) to the bottom of the rack. (Alternative to backing or width)
1604// width = Distance from base of rack to tips of teeth (alternative to bottom and backing).
1605// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
1606// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
1607// helical = The angle of the rack teeth away from perpendicular to the rack length. Used to match helical spur gear pinions. Default: 0
1608// herringbone = If true, and helical is set, creates a herringbone rack.
1609// profile_shift = Profile shift factor x. Default: 0
1610// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
1611// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
1612// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
1613// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
1614// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
1615// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
1616// Extra Anchors:
1617// "root" = At the base of the teeth, at the center of rack.
1618// "root-left" = At the base of the teeth, at the left end of the rack.
1619// "root-right" = At the base of the teeth, at the right end of the rack.
1620// "root-back" = At the base of the teeth, at the back of the rack.
1621// "root-front" = At the base of the teeth, at the front of the rack.
1622// Example(NoScales,VPR=[60,0,325],VPD=130):
1623// rack(pitch=5, teeth=10, thickness=5);
1624// Example(NoScales,VPT=[0.317577,3.42688,7.83665],VPR=[27.7,0,359.8],VPD=139.921): Rack for Helical Gear
1625// rack(pitch=5, teeth=10, thickness=5, backing=5, helical=30);
1626// Example(NoScales): Metric Rack, oriented BACK to align with a gear in default orientation. With profile shifting set to zero the gears mesh at their pitch circles.
1627// rack(mod=2, teeth=10, thickness=5, bottom=5, pressure_angle=14.5,orient=BACK);
1628// color("red") spur_gear(mod=2, teeth=18, thickness=5, pressure_angle=14.5,anchor=FRONT,profile_shift=0);
1629// Example(NoScales): Orienting the rack to the right using {zrot()}. In this case the gear has automatic profile shifting so we must use {{gear_dist()}} to correctly position the gear.
1630// zrot(-90)rack(mod=2, teeth=6, thickness=5, bottom=5, pressure_angle=14.5,orient=BACK);
1631// color("red")
1632// right(gear_dist(mod=2,0,12,pressure_angle=14.5))
1633// spur_gear(mod=2, teeth=12, thickness=5, pressure_angle=14.5);
1634// Example(NoScales,Anim,VPT=[0,0,12],VPD=100,Frames=18): Rack and Pinion with helical teeth
1635// teeth1 = 16; teeth2 = 16;
1636// pitch = 5; thick = 5; helical = 30;
1637// pr = pitch_radius(pitch, teeth2, helical=helical);
1638// pos = 3*(1-2*abs($t-1/2))-1.5;
1639// right(pr*2*PI/teeth2*pos)
1640// rack(pitch, teeth1, thickness=thick, helical=helical);
1641// up(pr)
1642// spur_gear(
1643// pitch, teeth2,
1644// thickness = thick,
1645// helical = -helical,
1646// shaft_diam = 5,
1647// orient = BACK,
1648// gear_spin = 180-pos*360/teeth2);
1649// Example(NoAxes,VPT=[-7.10396,-9.70691,3.50121],VPR=[60.2,0,325],VPD=213.262): Skew axis helical gear and rack engagement.
1650// mod=5; teeth=8; helical1=17.5; helical2=22.5;
1651// d = gear_dist_skew(mod=mod, teeth, 0, helical1,helical2);
1652// rack(mod=mod, teeth=5, thickness=30, helical=helical2, orient=FWD);
1653// color("lightblue")
1654// yrot(-helical1-helical2) fwd(d)
1655// spur_gear(mod=mod, teeth=teeth, helical=helical1, gear_spin=180/teeth, thickness=30);
1656
1657module rack(
1658 pitch,
1659 teeth,
1660 thickness,
1661 backing,
1662 width, bottom,
1663 pressure_angle,
1664 backlash = 0.0,
1665 clearance,
1666 helical,
1667 herringbone = false,
1668 profile_shift = 0,
1669 gear_travel = 0,
1670 circ_pitch,
1671 diam_pitch,
1672 mod,
1673 anchor = CENTER,
1674 spin = 0,
1675 orient = UP
1676) {
1677 pitch = _inherit_gear_pitch("rack()",pitch, circ_pitch, diam_pitch, mod, warn=false);
1678 PA = _inherit_gear_pa(pressure_angle);
1679 helical = _inherit_gear_helical(helical);
1680 thickness = _inherit_gear_thickness(thickness);
1681 checks=
1682 assert(is_integer(teeth) && teeth>0)
1683 assert(is_finite(thickness) && thickness>0)
1684 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1685 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1686 assert(is_finite(backlash) && backlash>=0)
1687 assert(is_finite(helical) && abs(helical)<90)
1688 assert(is_bool(herringbone))
1689 assert(is_finite(profile_shift))
1690 assert(is_finite(gear_travel));
1691 trans_pitch = pitch / cos(helical);
1692 a = _adendum(pitch, profile_shift);
1693 d = _dedendum(pitch, clearance, profile_shift);
1694 bottom = is_def(bottom) ?
1695 assert(is_finite(bottom) && bottom>d, "bottom is invalid or too small for teeth")
1696 bottom
1697 : is_def(width) ?
1698 assert(is_finite(width) && width>a+d, "Width is invalid or too small for teeth")
1699 width - a
1700 : is_def(backing) ?
1701 assert(all_positive([backing]), "Backing must be a positive value")
1702 backing+d
1703 : 2*d+a; // default case
1704 l = teeth * trans_pitch;
1705 anchors = [
1706 named_anchor("root", [0,0,-d], BACK),
1707 named_anchor("root-left", [-l/2,0,-d], LEFT),
1708 named_anchor("root-right", [ l/2,0,-d], RIGHT),
1709 named_anchor("root-front", [0,-thickness/2,-d], FWD),
1710 named_anchor("root-back", [0, thickness/2,-d], BACK),
1711 ];
1712 endfix = sin(helical)*thickness/2;
1713 override = function(anchor)
1714 anchor.z==1 ? [ [anchor.x*l/2-endfix*anchor.y,anchor.y*thickness/2,a], undef, undef]
1715 : anchor.x!=0 ? [ [anchor.x*l/2-endfix*anchor.y,anchor.y*thickness/2,anchor.z*bottom], undef,undef]
1716 : undef;
1717 size = [l, thickness, 2*bottom];
1718 attachable(anchor,spin,orient, size=size, anchors=anchors, override=override) {
1719 right(gear_travel)
1720 xrot(90) {
1721 if (herringbone) {
1722 zflip_copy()
1723 skew(axz=-helical)
1724 linear_extrude(height=thickness/2, center=false, convexity=teeth*2) {
1725 rack2d(
1726 pitch = pitch,
1727 teeth = teeth,
1728 bottom = bottom,
1729 pressure_angle = PA,
1730 backlash = backlash,
1731 clearance = clearance,
1732 helical = helical,
1733 profile_shift = profile_shift
1734 );
1735 }
1736 } else {
1737 skew(axz=helical)
1738 linear_extrude(height=thickness, center=true, convexity=teeth*2) {
1739 rack2d(
1740 pitch = pitch,
1741 teeth = teeth,
1742 bottom = bottom,
1743 pressure_angle = PA,
1744 backlash = backlash,
1745 clearance = clearance,
1746 helical = helical,
1747 profile_shift = profile_shift
1748 );
1749 }
1750 }
1751 }
1752 children();
1753 }
1754}
1755
1756
1757function rack(
1758 pitch,
1759 teeth,
1760 thickness,
1761 backing, bottom, width,
1762 pressure_angle,
1763 backlash = 0.0,
1764 clearance,
1765 helical,
1766 herringbone = false,
1767 profile_shift = 0,
1768 circ_pitch,
1769 diam_pitch,
1770 mod,
1771 gear_travel = 0,
1772 anchor = CENTER,
1773 spin = 0,
1774 orient = UP
1775) =
1776 let(
1777 pitch = _inherit_gear_pitch("rack()",pitch, circ_pitch, diam_pitch, mod, warn=false),
1778 PA = _inherit_gear_pa(pressure_angle),
1779 helical = _inherit_gear_helical(helical),
1780 thickness = _inherit_gear_thickness(thickness)
1781 )
1782 assert(is_integer(teeth) && teeth>0)
1783 assert(is_finite(thickness) && thickness>0)
1784 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1785 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1786 assert(is_finite(backlash) && backlash>=0)
1787 assert(is_finite(helical) && abs(helical)<90)
1788 assert(is_bool(herringbone))
1789 assert(is_finite(profile_shift))
1790 assert(is_finite(gear_travel))
1791 let(
1792 trans_pitch = pitch / cos(helical),
1793 a = _adendum(pitch, profile_shift),
1794 d = _dedendum(pitch, clearance, profile_shift),
1795 bottom = is_def(bottom) ?
1796 assert(is_finite(bottom) && bottom>d, "bottom is invalid or too small for teeth")
1797 bottom
1798 : is_def(width) ?
1799 assert(is_finite(width) && width>a+d, "Width is invalid or too small for teeth")
1800 width - a
1801 : is_def(backing) ?
1802 assert(all_positive([backing]), "Backing must be a positive value")
1803 backing+d
1804 : 2*d+a, // default case
1805 l = teeth * trans_pitch,
1806 path = rack2d(
1807 pitch = pitch,
1808 teeth = teeth,
1809 bottom = bottom,
1810 pressure_angle = PA,
1811 backlash = backlash,
1812 clearance = clearance,
1813 helical = helical,
1814 profile_shift = profile_shift
1815 ),
1816 vnf = herringbone
1817 ? sweep(path, [
1818 left(adj_ang_to_opp(thickness/2,helical)) *
1819 back(thickness/2) * xrot(90),
1820 xrot(90),
1821 left(adj_ang_to_opp(thickness/2,helical)) *
1822 fwd(thickness/2) * xrot(90),
1823 ], style="alt", orient=FWD)
1824 : skew(axy=-helical, p=linear_sweep(path, height=thickness, anchor="origin", orient=FWD)),
1825 out = right(gear_travel, p=vnf),
1826 size = [l, thickness, 2*bottom],
1827 anchors = [
1828 named_anchor("tip", [0,0,a], BACK),
1829 named_anchor("tip-left", [-l/2,0,a], LEFT),
1830 named_anchor("tip-right", [ l/2,0,a], RIGHT),
1831 named_anchor("tip-front", [0,-thickness/2,a], DOWN),
1832 named_anchor("tip-back", [0, thickness/2,a], UP),
1833 named_anchor("root", [0,0,-d], BACK),
1834 named_anchor("root-left", [-l/2,0,-d], LEFT),
1835 named_anchor("root-right", [ l/2,0,-d], RIGHT),
1836 named_anchor("root-front", [0,-thickness/2,-d], DOWN),
1837 named_anchor("root-back", [0, thickness/2,-d], UP),
1838 ]
1839 ) reorient(anchor,spin,orient, size=size, anchors=anchors, p=out);
1840
1841
1842
1843
1844// Function&Module: rack2d()
1845// Synopsis: Creates a 2D gear rack.
1846// SynTags: Geom, Path
1847// Topics: Gears, Parts
1848// See Also: rack(), spur_gear(), spur_gear2d(), bevel_gear()
1849// Usage: As a Module
1850// rack2d(pitch, teeth, [base|bottom=|width=], [pressure_angle=], [backlash=], [clearance=]) [ATTACHMENTS];
1851// rack2d(mod=, teeth=, [base=|bottom=|width=], [pressure_angle=], [backlash=], [clearance=]) [ATTACHMENTS];
1852// Usage: As a Function
1853// path = rack2d(pitch, teeth, [base|bottom=|width=], [pressure_angle=], [backlash=], [clearance=]);
1854// path = rack2d(mod=, teeth=, [base=|bottom=|width=], [pressure_angle=], [backlash=], [clearance=]);
1855// Description:
1856// Create a 2D rack, a linear bar with teeth that a gear can roll along.
1857// A rack can mesh with any spur gear or helical gear that has the same `pitch` and `pressure_angle`.
1858// When called as a function, returns a 2D path for the outline of the rack.
1859// When called as a module, creates a 2D rack shape.
1860// .
1861// By default the rack has a backing whose height is equal to the height of the teeth. You can specify a different backing size
1862// or you can specify the total width of the rack (from the bottom of the rack to tooth tips) or the
1863// bottom point of the rack, which is the distance from the pitch line to the bottom of the rack.
1864// .
1865// The rack appears with its pitch line on top of the x axis. The BACK anchor refers to the tips of the teeth and the FRONT
1866// anchor refers to the front of the backing. You can use named anchors to access the roots of the teeth.
1867// Arguments:
1868// pitch = The pitch, or distance in mm between teeth along the rack. Matches up with circular pitch on a spur gear. Default: 5
1869// teeth = Total number of teeth along the rack
1870// backing = Distance from bottom of rack to the roots of the rack's teeth. (Alternative to bottom or width.) Default: height of rack teeth
1871// ---
1872// bottom = Distance from rack's pitch line (the x-axis) to the bottom of the rack. (Alternative to backing or width)
1873// width = Distance from base of rack to tips of teeth (alternative to bottom and backing).
1874// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
1875// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
1876// helical = The angle of the rack teeth away from perpendicular to the rack length. Stretches out the tooth shapes. Used to match helical spur gear pinions. Default: 0
1877// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees.
1878// profile_shift = Profile shift factor x for tooth shape. Default: 0
1879// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
1880// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
1881// gear_travel = The distance the rack should be moved by linearly. Default: 0
1882// rounding = If true, rack tips and valleys are slightly rounded. Default: true
1883// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
1884// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
1885// Extra Anchors:
1886// "root" = At the height of the teeth, at the center of rack.
1887// "root-left" = At the height of the teeth, at the left end of the rack.
1888// "root-right" = At the height of the teeth, at the right end of the rack.
1889// Example(2D):
1890// rack2d(pitch=5, teeth=10);
1891// Example(2D): Called as a Function
1892// path = rack2d(pitch=8, teeth=8, pressure_angle=25);
1893// polygon(path);
1894
1895function rack2d(
1896 pitch,
1897 teeth,
1898 backing,
1899 pressure_angle,
1900 backlash = 0,
1901 clearance,
1902 helical,
1903 profile_shift = 0,
1904 circ_pitch,
1905 diam_pitch,
1906 mod,
1907 width, bottom,
1908 gear_travel = 0,
1909 rounding = true,
1910 anchor = CENTER,
1911 spin = 0
1912) = let(
1913 pitch = _inherit_gear_pitch("rack2d()",pitch, circ_pitch, diam_pitch, mod, warn=false),
1914 PA = _inherit_gear_pa(pressure_angle),
1915 helical = _inherit_gear_helical(helical),
1916 mod = module_value(circ_pitch=pitch)
1917 )
1918 assert(is_integer(teeth) && teeth>0)
1919 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
1920 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
1921 assert(is_finite(backlash) && backlash>=0)
1922 assert(is_finite(helical) && abs(helical)<90)
1923 assert(is_finite(gear_travel))
1924 assert(num_defined([width,backing,bottom])<=1, "Can define only one of width, backing and bottom")
1925 let(
1926 adendum = _adendum(pitch, profile_shift),
1927 dedendum = _dedendum(pitch, clearance, profile_shift),
1928 clear = default(clearance, 0.25 * mod),
1929 bottom = is_def(bottom) ?
1930 assert(is_finite(bottom) && bottom>dedendum, "bottom is invalid or too small for teeth")
1931 bottom
1932 : is_def(width) ?
1933 assert(is_finite(width) && width>adendum+dedendum, "Width is invalid or too small for teeth")
1934 width - adendum
1935 : is_def(backing) ?
1936 assert(all_positive([backing]), "Backing must be a positive value")
1937 backing+dedendum
1938 : 2*dedendum+adendum // default case
1939 )
1940 let(
1941 trans_pitch = pitch / cos(helical),
1942 trans_pa = atan(tan(PA)/cos(helical)),
1943 tthick = trans_pitch/PI * (PI/2 + 2*profile_shift * tan(PA)) - backlash,
1944 l = teeth * trans_pitch,
1945 ax = ang_adj_to_opp(trans_pa, adendum),
1946 dx = dedendum*tan(trans_pa),
1947 poff = tthick/2,
1948 tooth = [
1949 [-trans_pitch/2, -dedendum],
1950 if (rounding) each arc(n=4, r=clear, corner=[
1951 [-trans_pitch/2, -dedendum],
1952 [-poff-dx, -dedendum],
1953 [-poff+ax, +adendum],
1954 ]) else [-poff-dx, -dedendum],
1955 if (rounding) each arc(n=4, r=trans_pitch/16, corner=[
1956 [-poff-dx, -dedendum],
1957 [-poff+ax, +adendum],
1958 [+poff-ax, +adendum],
1959 ]) else [-poff+ax, +adendum],
1960 if (rounding) each arc(n=4, r=trans_pitch/16, corner=[
1961 [-poff+ax, +adendum],
1962 [+poff-ax, +adendum],
1963 [+poff+dx, -dedendum],
1964 ]) else [+poff-ax, +adendum],
1965 if (rounding) each arc(n=4, r=clear, corner=[
1966 [+poff-ax, +adendum],
1967 [+poff+dx, -dedendum],
1968 [+trans_pitch/2, -dedendum],
1969 ]) else [+poff+dx, -dedendum],
1970 [+trans_pitch/2, -dedendum],
1971 ],
1972 path2 = [
1973 for(m = xcopies(trans_pitch,n=teeth))
1974 each apply(m,tooth)
1975 ],
1976 path = right(gear_travel, p=[
1977 [path2[0].x, -bottom],
1978 each path2,
1979 [last(path2).x, -bottom],
1980 ]),
1981 size=[l,2*bottom],
1982 anchors = [
1983 named_anchor("root", [ 0,-dedendum,0], BACK),
1984 named_anchor("root-left", [-l/2,-dedendum,0], LEFT),
1985 named_anchor("root-right", [ l/2,-dedendum,0], RIGHT),
1986 ],
1987 override = [
1988 [[0,1] , [[0,adendum]]],
1989 [[1,1] , [[l/2,adendum]]],
1990 [[-1,1] , [[-l/2,adendum]]],
1991 ]
1992 ) reorient(anchor,spin, two_d=true, size=size, anchors=anchors, override=override, p=path);
1993
1994
1995
1996module rack2d(
1997 pitch,
1998 teeth,
1999 backing,
2000 width, bottom,
2001 pressure_angle,
2002 backlash = 0,
2003 clearance,
2004 helical,
2005 profile_shift = 0,
2006 gear_travel = 0,
2007 circ_pitch,
2008 diam_pitch,
2009 mod,
2010 rounding = true,
2011 anchor = CENTER,
2012 spin = 0
2013) {
2014 pitch = _inherit_gear_pitch("rack2d()",pitch, circ_pitch, diam_pitch, mod, warn=false);
2015 PA = _inherit_gear_pa(pressure_angle);
2016 helical = _inherit_gear_helical(helical);
2017 checks =
2018 assert(is_integer(teeth) && teeth>0)
2019 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
2020 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2021 assert(is_finite(backlash) && backlash>=0)
2022 assert(is_finite(helical) && abs(helical)<90)
2023 assert(is_finite(gear_travel))
2024 assert(num_defined([width,backing,bottom])<=1, "Can define only one of width, backing and bottom");
2025 trans_pitch = pitch / cos(helical);
2026 a = _adendum(pitch, profile_shift);
2027 d = _dedendum(pitch, clearance, profile_shift);
2028 bottom = is_def(bottom) ?
2029 assert(is_finite(bottom) && bottom>d, "bottom is invalid or too small for teeth")
2030 bottom
2031 : is_def(width) ?
2032 assert(is_finite(width) && width>a+d, "Width is invalid or too small for teeth")
2033 width - a
2034 : is_def(backing) ?
2035 assert(all_positive([backing]), "Backing must be a positive value")
2036 backing+d
2037 : 2*d+a; // default case
2038 l = teeth * trans_pitch;
2039 path = rack2d(
2040 pitch = pitch,
2041 teeth = teeth,
2042 bottom=bottom,
2043 pressure_angle = PA,
2044 backlash = backlash,
2045 clearance = clearance,
2046 helical = helical,
2047 rounding=rounding,
2048 profile_shift= profile_shift
2049 );
2050 size = [l, 2*bottom];
2051 anchors = [
2052 named_anchor("root", [ 0,-d,0], BACK),
2053 named_anchor("root-left", [-l/2,-d,0], LEFT),
2054 named_anchor("root-right", [ l/2,-d,0], RIGHT),
2055 ];
2056 override = [
2057 [[0,1] , [[0,a]]],
2058 [[1,1] , [[l/2,a]]],
2059 [[-1,1] , [[-l/2,a]]],
2060 ];
2061 attachable(anchor,spin, two_d=true, size=size, anchors=anchors, override=override) {
2062 right(gear_travel) polygon(path);
2063 children();
2064 }
2065}
2066
2067
2068
2069// Function&Module: crown_gear()
2070// Synopsis: Creates a crown gear that can mesh with a spur gear.
2071// SynTags: Geom, VNF
2072// Topics: Gears, Parts
2073// See Also: rack(), rack2d(), spur_gear(), spur_gear2d(), bevel_pitch_angle(), bevel_gear()
2074// Usage: As a Module
2075// crown_gear(circ_pitch, teeth, backing, face_width, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2076// crown_gear(diam_pitch=, teeth=, backing=, face_width=, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2077// crown_gear(mod=, teeth=, backing=, face_width=, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2078// Usage: As a Function
2079// vnf = crown_gear(circ_pitch, teeth, backing, face_width, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2080// vnf = crown_gear(diam_pitch=, teeth=, backing=, face_width=, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2081// vnf = crown_gear(mod=, teeth=, backing=, face_width=, [pressure_angle=], [clearance=], [backlash=], [profile_shift=], [slices=]);
2082// Description:
2083// Creates a crown gear. The module `crown_gear()` gives a crown gear, with reasonable defaults
2084// for all the parameters. Normally, you should just choose the first 4 parameters, and let the
2085// rest be default values.
2086// .
2087// The module `crown_gear()` gives a crown gear in the XY plane, centered on the origin, with one tooth
2088// centered on the positive Y axis. The crown gear will have the pitch circle of the teeth at Z=0 by default.
2089// The inner radius of the crown teeth can be calculated with the `pitch_radius()` function, and the outer
2090// radius of the teeth is `face_width=` more than that.
2091// Arguments:
2092// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
2093// teeth = Total number of teeth around the entire perimeter. Default: 20
2094// backing = Distance from base of crown gear to roots of teeth (alternative to bottom and backing).
2095// face_width = Width of the toothed surface in mm, from inside radius to outside. Default: 5
2096// ---
2097// bottom = Distance from crown's pitch plane (Z=0) to the bottom of the crown gear. (Alternative to backing or thickness)
2098// thickness = Distance from base of crown gear to tips of teeth (alternative to bottom and backing).
2099// pitch_angle = Angle of beveled gear face. Default: 45
2100// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
2101// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
2102// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
2103// slices = Number of vertical layers to divide gear into. Useful for refining gears with `spiral`. Default: 1
2104// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
2105// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
2106// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
2107// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
2108// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
2109// Example:
2110// crown_gear(mod=1, teeth=40, backing=3, face_width=5, pressure_angle=20);
2111// Example:
2112// mod=1; cteeth=40; pteeth=17; backing=3; PA=20; face=5;
2113// cpr = pitch_radius(mod=mod, teeth=cteeth);
2114// ppr = pitch_radius(mod=mod, teeth=pteeth);
2115// crown_gear(mod=mod, teeth=cteeth, backing=backing,
2116// face_width=face, pressure_angle=PA);
2117// back(cpr+face/2)
2118// up(ppr)
2119// spur_gear(mod=mod, teeth=pteeth,
2120// pressure_angle=PA, thickness=face,
2121// orient=BACK, gear_spin=180/pteeth,
2122// profile_shift=0);
2123
2124function crown_gear(
2125 circ_pitch,
2126 teeth,
2127 backing,
2128 face_width=5,
2129 pressure_angle=20,
2130 clearance,
2131 backlash=0,
2132 profile_shift=0,
2133 slices=10,
2134 bottom,
2135 thickness,
2136 diam_pitch,
2137 pitch,
2138 mod,
2139 gear_spin=0,
2140 anchor=CTR,
2141 spin=0,
2142 orient=UP
2143) = let(
2144 pitch = _inherit_gear_pitch("crown_gear()", pitch, circ_pitch, diam_pitch, mod, warn=false),
2145 PA = _inherit_gear_pa(pressure_angle)
2146 )
2147 assert(is_integer(teeth) && teeth>0)
2148 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
2149 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2150 assert(is_finite(backlash) && backlash>=0)
2151 assert(is_finite(gear_spin))
2152 assert(num_defined([thickness,backing,bottom])<=1, "Can define only one of thickness, backing and bottom")
2153 let(
2154 a = _adendum(pitch, profile_shift),
2155 d = _dedendum(pitch, clearance, profile_shift),
2156 bottom = is_def(bottom) ?
2157 assert(is_finite(bottom) && bottom>d, "bottom is invalid or too small for teeth")
2158 bottom
2159 : is_def(thickness) ?
2160 assert(is_finite(thickness) && thickness>a+d, "Width is invalid or too small for teeth")
2161 thickness - a
2162 : is_def(backing) ?
2163 assert(all_positive([backing]), "Backing must be a positive value")
2164 backing+d
2165 : 2*d+a, // default case
2166 mod = module_value(circ_pitch=pitch),
2167 ir = mod * teeth / 2,
2168 or = ir + face_width,
2169 profiles = [
2170 for (slice = [0:1:slices-1])
2171 let(
2172 u = slice / (slices-1),
2173 r = or - u*face_width,
2174 wpa = acos(ir * cos(PA) / r),
2175 profile = select(
2176 rack2d(
2177 mod=mod, teeth=1,
2178 pressure_angle=wpa,
2179 clearance=clearance,
2180 backlash=backlash,
2181 profile_shift=profile_shift,
2182 rounding=false
2183 ), 2, -3
2184 ),
2185 delta = profile[1] - profile[0],
2186 slope = delta.y / delta.x,
2187 C = profile[0].y - slope * profile[0].x,
2188 profile2 = profile[1].x > 0
2189 ? [profile[0], [0,C], [0,C], profile[3]]
2190 : profile,
2191 m = back(r) * xrot(90),
2192 tooth = apply(m, path3d(profile2)),
2193 rpitch = pitch * r / ir
2194 )
2195 assert(profile[3].x <= rpitch/2, "face_width is too wide for the given gear geometry. Either decrease face_width, or increase the module or tooth count.")
2196 [
2197 for (i = [0:1:teeth-1])
2198 let(a = gear_spin - i * 360 / teeth)
2199 each zrot(a, p=tooth)
2200 ]
2201 ],
2202 rows = [
2203 [for (p=profiles[0]) [p.x,p.y,-bottom]],
2204 each profiles,
2205 [for (p=last(profiles)) [p.x,p.y,last(profiles)[0].z]],
2206 ],
2207 vnf = vnf_vertex_array(rows, col_wrap=true, caps=true)
2208 ) reorient(anchor,spin,orient, r=or, h=2*bottom, p=vnf);
2209
2210
2211module crown_gear(
2212 circ_pitch,
2213 teeth,
2214 backing,
2215 face_width=10,
2216 pressure_angle=20,
2217 clearance,
2218 backlash=0,
2219 profile_shift=0,
2220 slices=10,
2221 bottom,
2222 thickness,
2223 diam_pitch,
2224 pitch,
2225 mod,
2226 gear_spin=0,
2227 anchor=CTR,
2228 spin=0,
2229 orient=UP
2230) {
2231 pitch = _inherit_gear_pitch("crown_gear()", pitch, circ_pitch, diam_pitch, mod, warn=false);
2232 PA = _inherit_gear_pa(pressure_angle);
2233 checks =
2234 assert(is_integer(teeth) && teeth>0)
2235 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
2236 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2237 assert(is_finite(backlash) && backlash>=0)
2238 assert(is_finite(gear_spin))
2239 assert(num_defined([thickness,backing,bottom])<=1, "Can define only one of width, backing and bottom")
2240 ;
2241 pr = pitch_radius(circ_pitch=pitch, teeth=teeth);
2242 a = _adendum(pitch, profile_shift);
2243 d = _dedendum(pitch, clearance, profile_shift);
2244 bottom = is_def(bottom) ?
2245 assert(is_finite(bottom) && bottom>d, "bottom is invalid or too small for teeth")
2246 bottom
2247 : is_def(thickness) ?
2248 assert(is_finite(thickness) && thickness>a+d, "Width is invalid or too small for teeth")
2249 thickness - a
2250 : is_def(backing) ?
2251 assert(all_positive([backing]), "Backing must be a positive value")
2252 backing+d
2253 : 2*d+a; // default case
2254 vnf = crown_gear(
2255 circ_pitch=pitch,
2256 teeth=teeth,
2257 bottom=bottom,
2258 face_width=face_width,
2259 pressure_angle=PA,
2260 clearance=clearance,
2261 backlash=backlash,
2262 profile_shift=profile_shift,
2263 slices=slices,
2264 gear_spin=gear_spin
2265 );
2266 attachable(anchor,spin,orient, r=pr+face_width, h=2*bottom) {
2267 vnf_polyhedron(vnf, convexity=teeth/2);
2268 children();
2269 }
2270}
2271
2272
2273// Function&Module: bevel_gear()
2274// Synopsis: Creates a straight or spiral bevel gear.
2275// SynTags: Geom, VNF
2276// Topics: Gears, Parts
2277// See Also: rack(), rack2d(), spur_gear(), spur_gear2d(), bevel_pitch_angle(), bevel_gear()
2278// Usage: As a Module
2279// bevel_gear(circ_pitch, teeth, face_width, [pitch_angle=]|[mate_teeth=], [shaft_diam=], [hide=], [pressure_angle=], [clearance=], [backlash=], [cutter_radius=], [spiral_angle=], [left_handed=], [slices=], [internal=]);
2280// bevel_gear(mod=, teeth=, face_width=, [pitch_angle=]|[mate_teeth=], [shaft_diam=], [hide=], [pressure_angle=], [clearance=], [backlash=], [cutter_radius=], [spiral_angle=], [left_handed=], [slices=], [internal=]);
2281// Usage: As a Function
2282// vnf = bevel_gear(circ_pitch, teeth, face_width, [pitch_angle=]|[mate_teeth=], [hide=], [pressure_angle=], [clearance=], [backlash=], [cutter_radius=], [spiral_angle=], [left_handed=], [slices=], [internal=]);
2283// vnf = bevel_gear(mod=, teeth=, face_width=, [pitch_angle=]|[mate_teeth=], [hide=], [pressure_angle=], [clearance=], [backlash=], [cutter_radius=], [spiral_angle=], [left_handed=], [slices=], [internal=]);
2284// Description:
2285// Creates a (potentially spiral) bevel gear. The module `bevel_gear()` gives a bevel gear, with
2286// reasonable defaults for all the parameters. Normally, you should just choose the first 4
2287// parameters, and let the rest be default values. In straight bevel gear sets, when each tooth
2288// engages it inpacts the corresponding tooth. The abrupt tooth engagement causes impact stress
2289// which makes them more prone to breakage. Spiral bevel gears have teeth formed along spirals so
2290// they engage more gradually, resulting in a less abrupt transfer of force, so they are quieter
2291// in operation and less likely to break.
2292// .
2293// The module `bevel_gear()` gives a gear in the XY plane, centered on the origin, with one tooth
2294// centered on the positive Y axis. The various functions below it take the same parameters, and
2295// return various measurements for the gear. The most important function is `mesh_radius()`, which tells
2296// how far apart to space gears that are meshing, and `outer_radius()`, which gives the size of the
2297// region filled by the gear. A gear has a "pitch circle", which is an invisible circle that cuts
2298// through the middle of each tooth (though not the exact center). In order for two gears to mesh,
2299// their pitch circles should just touch, if no profile shifting is done). So the distance between
2300// their centers should be `mesh_radius()` for one, plus `mesh_radius()` for the other, which gives
2301// the radii of their pitch circles and profile shifts. In order for two gears to mesh, they must
2302// have the same `circ_pitch` and `pressure_angle` parameters. `circ_pitch` gives the number of millimeters
2303// of arc around the pitch circle covered by one tooth and one space between teeth. The `pressure_angle`
2304// controls how flat or bulged the sides of the teeth are. Common values include 14.5 degrees and 20
2305// degrees, and occasionally 25. The default here is 20 degrees. Larger numbers bulge out more,
2306// giving stronger teeth. The ratio of `teeth` for two meshing gears gives how many times one will make a full
2307// revolution when the the other makes one full revolution. If the two numbers are coprime (i.e.
2308// are not both divisible by the same number greater than 1), then every tooth on one gear will meet
2309// every tooth on the other, for more even wear. So coprime numbers of teeth are good.
2310// Arguments:
2311// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
2312// teeth = Total number of teeth around the entire perimeter. Default: 20
2313// face_width = Width of the toothed surface in mm, from inside to outside. Default: 10
2314// ---
2315// pitch_angle = Angle of beveled gear face. Default: 45
2316// mate_teeth = The number of teeth in the gear that this gear will mate with. Overrides `pitch_angle` if given.
2317// shaft_diam = Diameter of the hole in the center, in mm. Module use only. Default: 0 (no shaft hole)
2318// hide = Number of teeth to delete to make this only a fraction of a circle. Default: 0
2319// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
2320// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
2321// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
2322// cutter_radius = Radius of spiral arc for teeth. If 0, then gear will have straight teeth. Default: 30
2323// spiral_angle = The base angle for spiral teeth. If zero the teeth will be zerol or straight. Default: 30
2324// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
2325// slices = Number of vertical layers to divide gear into. Useful for refining gears with `spiral`. Default: 1
2326// internal = If true, create a mask for difference()ing from something else.
2327// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
2328// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
2329// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
2330// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
2331// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
2332// Extra Anchors:
2333// "apex" = At the pitch cone apex for the bevel gear.
2334// "pitchbase" = At the natural height of the pitch radius of the beveled gear.
2335// "flattop" = At the top of the flat top of the bevel gear.
2336// Side Effects:
2337// If internal is true then the default tag is "remove"
2338// Example: Beveled Gear
2339// bevel_gear(
2340// circ_pitch=5, teeth=36, face_width=10, shaft_diam=5,
2341// pitch_angle=45, spiral_angle=0
2342// );
2343// Example: Spiral Beveled Gear and Pinion
2344// t1 = 16; t2 = 28;
2345// bevel_gear(
2346// circ_pitch=5, teeth=t1, mate_teeth=t2,
2347// slices=12, anchor="apex", orient=FWD
2348// );
2349// bevel_gear(
2350// circ_pitch=5, teeth=t2, mate_teeth=t1, left_handed=true,
2351// slices=12, anchor="apex", spin=180/t2
2352// );
2353// Example(Anim,Frames=4,VPD=175): Manual Spacing of Pinion and Gear
2354// t1 = 14; t2 = 28; circ_pitch=5;
2355// back(pitch_radius(circ_pitch, t2)) {
2356// yrot($t*360/t1)
2357// bevel_gear(
2358// circ_pitch=circ_pitch, teeth=t1, mate_teeth=t2, shaft_diam=5,
2359// slices=12, orient=FWD
2360// );
2361// }
2362// down(pitch_radius(circ_pitch, t1)) {
2363// zrot($t*360/t2)
2364// bevel_gear(
2365// circ_pitch=circ_pitch, teeth=t2, mate_teeth=t1, left_handed=true,
2366// shaft_diam=5, slices=12, spin=180/t2
2367// );
2368// }
2369
2370function bevel_gear(
2371 circ_pitch,
2372 teeth,
2373 face_width = 10,
2374 pitch_angle = 45,
2375 mate_teeth,
2376 hide = 0,
2377 pressure_angle = 20,
2378 clearance,
2379 backlash = 0.0,
2380 cutter_radius = 30,
2381 spiral_angle = 35,
2382 left_handed = false,
2383 slices = 5,
2384 internal,
2385 interior,
2386 pitch,
2387 diam_pitch,
2388 mod,
2389 anchor = "pitchbase",
2390 spin = 0,
2391 orient = UP
2392) = let(
2393 dummy = !is_undef(interior) ? echo("In bevel_gear(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0,
2394 internal = first_defined([internal,interior,false]),
2395 circ_pitch = _inherit_gear_pitch("bevel_gear()",pitch, circ_pitch, diam_pitch, mod),
2396 PA = _inherit_gear_pa(pressure_angle),
2397 spiral_angle = _inherit_gear_helical(spiral_angle, invert=!internal),
2398 face_width = _inherit_gear_thickness(face_width),
2399 slices = cutter_radius==0? 1 : slices,
2400 pitch_angle = is_undef(mate_teeth)? pitch_angle : atan(teeth/mate_teeth),
2401 pr = pitch_radius(circ_pitch, teeth),
2402 rr = _root_radius(circ_pitch, teeth, clearance, internal),
2403 pitchoff = (pr-rr) * sin(pitch_angle),
2404 ocone_rad = opp_ang_to_hyp(pr, pitch_angle),
2405 icone_rad = ocone_rad - face_width,
2406 cutter_radius = cutter_radius==0? 1000 : cutter_radius,
2407 midpr = (icone_rad + ocone_rad) / 2,
2408 radcp = [0, midpr] + polar_to_xy(cutter_radius, 180+spiral_angle),
2409 angC1 = law_of_cosines(a=cutter_radius, b=norm(radcp), c=ocone_rad),
2410 angC2 = law_of_cosines(a=cutter_radius, b=norm(radcp), c=icone_rad),
2411 radcpang = v_theta(radcp),
2412 sang = radcpang - (180-angC1),
2413 eang = radcpang - (180-angC2),
2414 profile = reverse(_gear_tooth_profile(
2415 circ_pitch = circ_pitch,
2416 teeth = teeth,
2417 pressure_angle = PA,
2418 clearance = clearance,
2419 backlash = backlash,
2420 internal = internal,
2421 center = true
2422 )),
2423 verts1 = [
2424 for (v = lerpn(0,1,slices+1)) let(
2425 p = radcp + polar_to_xy(cutter_radius, lerp(sang,eang,v)),
2426 ang = v_theta(p)-90,
2427 dist = norm(p)
2428 ) [
2429 let(
2430 u = dist / ocone_rad,
2431 m = up((1-u) * pr / tan(pitch_angle)) *
2432 up(pitchoff) *
2433 zrot(ang/sin(pitch_angle)) *
2434 back(u * pr) *
2435 xrot(pitch_angle) *
2436 scale(u)
2437 )
2438 for (tooth=[0:1:teeth-1])
2439 each apply(xflip() * zrot(360*tooth/teeth) * m, path3d(profile))
2440 ]
2441 ],
2442 botz = verts1[0][0].z,
2443 topz = last(verts1)[0].z,
2444 thickness = abs(topz - botz),
2445 cpz = (topz + botz) / 2,
2446 vertices = [for (x=verts1) reverse(x)],
2447 sides_vnf = vnf_vertex_array(vertices, caps=false, col_wrap=true, reverse=true),
2448 top_verts = last(vertices),
2449 bot_verts = vertices[0],
2450 gear_pts = len(top_verts),
2451 face_pts = gear_pts / teeth,
2452 top_faces =[
2453 for (i=[0:1:teeth-1], j=[0:1:(face_pts/2)-1]) each [
2454 [i*face_pts+j, (i+1)*face_pts-j-1, (i+1)*face_pts-j-2],
2455 [i*face_pts+j, (i+1)*face_pts-j-2, i*face_pts+j+1]
2456 ],
2457 for (i=[0:1:teeth-1]) each [
2458 [gear_pts, (i+1)*face_pts-1, i*face_pts],
2459 [gear_pts, ((i+1)%teeth)*face_pts, (i+1)*face_pts-1]
2460 ]
2461 ],
2462 vnf1 = vnf_join([
2463 [
2464 [each top_verts, [0,0,top_verts[0].z]],
2465 top_faces
2466 ],
2467 [
2468 [each bot_verts, [0,0,bot_verts[0].z]],
2469 [for (x=top_faces) reverse(x)]
2470 ],
2471 sides_vnf
2472 ]),
2473 lvnf = left_handed? vnf1 : xflip(p=vnf1),
2474 vnf = down(cpz, p=lvnf),
2475 anchors = [
2476 named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
2477 named_anchor("flattop", [0,0,thickness/2]),
2478 named_anchor("apex", [0,0,hyp_ang_to_opp(ocone_rad,90-pitch_angle)+pitchoff-thickness/2])
2479 ]
2480 ) reorient(anchor,spin,orient, vnf=vnf, extent=true, anchors=anchors, p=vnf);
2481
2482
2483module bevel_gear(
2484 circ_pitch,
2485 teeth,
2486 face_width = 10,
2487 pitch_angle = 45,
2488 mate_teeth,
2489 shaft_diam = 0,
2490 pressure_angle = 20,
2491 clearance = undef,
2492 backlash = 0.0,
2493 cutter_radius = 30,
2494 spiral_angle = 35,
2495 left_handed = false,
2496 slices = 5,
2497 internal,
2498 interior,
2499 pitch,
2500 diam_pitch,
2501 mod,
2502 anchor = "pitchbase",
2503 spin = 0,
2504 orient = UP
2505) {
2506 dummy = !is_undef(interior) ? echo("In bevel_gear(), the argument 'interior=' has been deprecated, and may be removed in the future. Please use 'internal=' instead."):0;
2507 internal = first_defined([internal,interior,false]);
2508 circ_pitch = _inherit_gear_pitch("bevel_gear()",pitch, circ_pitch, diam_pitch, mod);
2509 PA = _inherit_gear_pa(pressure_angle);
2510 spiral_angle = _inherit_gear_helical(spiral_angle, invert=!internal);
2511 face_width = _inherit_gear_thickness(face_width);
2512 slices = cutter_radius==0? 1 : slices;
2513 pitch_angle = is_undef(mate_teeth)? pitch_angle : atan(teeth/mate_teeth);
2514 pr = pitch_radius(circ_pitch, teeth);
2515 ipr = pr - face_width*sin(pitch_angle);
2516 rr = _root_radius(circ_pitch, teeth, clearance, internal);
2517 pitchoff = (pr-rr) * sin(pitch_angle);
2518 vnf = bevel_gear(
2519 circ_pitch = circ_pitch,
2520 teeth = teeth,
2521 face_width = face_width,
2522 pitch_angle = pitch_angle,
2523 pressure_angle = PA,
2524 clearance = clearance,
2525 backlash = backlash,
2526 cutter_radius = cutter_radius,
2527 spiral_angle = spiral_angle,
2528 left_handed = left_handed,
2529 slices = slices,
2530 internal = internal,
2531 anchor=CENTER
2532 );
2533 axis_zs = [for (p=vnf[0]) if(norm(point2d(p)) < EPSILON) p.z];
2534 thickness = max(axis_zs) - min(axis_zs);
2535 anchors = [
2536 named_anchor("pitchbase", [0,0,pitchoff-thickness/2]),
2537 named_anchor("flattop", [0,0,thickness/2]),
2538 named_anchor("apex", [0,0,adj_ang_to_opp(pr,90-pitch_angle)+pitchoff-thickness/2])
2539 ];
2540 default_tag("remove",internal) {
2541 attachable(anchor,spin,orient, r1=pr, r2=ipr, h=thickness, anchors=anchors) {
2542 difference() {
2543 vnf_polyhedron(vnf, convexity=teeth/2);
2544 if (shaft_diam > 0) {
2545 cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
2546 }
2547 }
2548 children();
2549 }
2550 }
2551}
2552
2553
2554// Function&Module: worm()
2555// Synopsis: Creates a worm that will mate with a worm gear.
2556// SynTags: Geom, VNF
2557// Topics: Gears, Parts
2558// See Also: worm(), worm_gear(), rack(), rack2d(), spur_gear(), spur_gear2d(), bevel_pitch_angle(), bevel_gear()
2559// Usage: As a Module
2560// worm(circ_pitch, d, l, [starts=], [left_handed=], [pressure_angle=], [backlash=], [clearance=]);
2561// worm(mod=, d=, l=, [starts=], [left_handed=], [pressure_angle=], [backlash=], [clearance=]);
2562// Usage: As a Function
2563// vnf = worm(circ_pitch, d, l, [starts=], [left_handed=], [pressure_angle=], [backlash=], [clearance=]);
2564// vnf = worm(mod=, d=, l=, [starts=], [left_handed=], [pressure_angle=], [backlash=], [clearance=]);
2565// Description:
2566// Creates a worm shape that can be matched to a worm gear.
2567// Arguments:
2568// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
2569// d = The diameter of the worm. Default: 30
2570// l = The length of the worm. Default: 100
2571// starts = The number of lead starts. Default: 1
2572// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
2573// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
2574// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
2575// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
2576// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
2577// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
2578// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
2579// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
2580// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
2581// Example:
2582// worm(circ_pitch=8, d=30, l=50, $fn=72);
2583// Example: Multiple Starts.
2584// worm(circ_pitch=8, d=30, l=50, starts=3, $fn=72);
2585// Example: Left Handed
2586// worm(circ_pitch=8, d=30, l=50, starts=3, left_handed=true, $fn=72);
2587// Example: Called as Function
2588// vnf = worm(circ_pitch=8, d=35, l=50, starts=2, left_handed=true, pressure_angle=20, $fn=72);
2589// vnf_polyhedron(vnf);
2590
2591function worm(
2592 circ_pitch,
2593 d=30, l=100,
2594 starts=1,
2595 left_handed=false,
2596 pressure_angle,
2597 backlash=0,
2598 clearance,
2599 diam_pitch,
2600 mod,
2601 pitch,
2602 gear_spin=0,
2603 anchor=CENTER,
2604 spin=0,
2605 orient=UP
2606) =
2607 let(
2608 circ_pitch = _inherit_gear_pitch("worm()", pitch, circ_pitch, diam_pitch, mod),
2609 PA = _inherit_gear_pa(pressure_angle)
2610 )
2611 assert(is_integer(starts) && starts>0)
2612 assert(is_finite(l) && l>0)
2613 //assert(is_finite(shaft_diam) && shaft_diam>=0)
2614 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
2615 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2616 assert(is_finite(backlash) && backlash>=0)
2617 assert(is_bool(left_handed))
2618 assert(is_finite(gear_spin))
2619 let(
2620 helical = asin(starts * circ_pitch / PI / d),
2621 trans_pitch = circ_pitch / cos(helical),
2622 tooth = xflip(
2623 p=select(rack2d(
2624 pitch=circ_pitch,
2625 teeth=1,
2626 pressure_angle=PA,
2627 clearance=clearance,
2628 backlash=backlash,
2629 helical=helical,
2630 profile_shift=0
2631 ), 1, -2)
2632 ),
2633 rack_profile = [
2634 for (t = xcopies(trans_pitch, n=2*ceil(l/trans_pitch)+1))
2635 each apply(t, tooth)
2636 ],
2637 steps = max(36, segs(d/2)),
2638 step = 360 / steps,
2639 zsteps = ceil(l / trans_pitch / starts * steps),
2640 zstep = l / zsteps,
2641 profiles = [
2642 for (j = [0:1:zsteps]) [
2643 for (i = [0:1:steps-1]) let(
2644 u = i / steps - 0.5,
2645 ang = 360 * (1 - u) + 90,
2646 z = j*zstep - l/2,
2647 zoff = trans_pitch * starts * u,
2648 h = lookup(z+zoff, rack_profile)
2649 )
2650 cylindrical_to_xyz(d/2+h, ang, z)
2651 ]
2652 ],
2653 vnf1 = vnf_vertex_array(profiles, caps=true, col_wrap=true, style="alt"),
2654 m = product([
2655 zrot(gear_spin),
2656 if (left_handed) xflip(),
2657 ]),
2658 vnf = apply(m, vnf1)
2659 ) reorient(anchor,spin,orient, d=d, l=l, p=vnf);
2660
2661
2662module worm(
2663 circ_pitch,
2664 d=15, l=100,
2665 starts=1,
2666 left_handed=false,
2667 pressure_angle,
2668 backlash=0,
2669 clearance,
2670 pitch,
2671 diam_pitch,
2672 mod,
2673 gear_spin=0,
2674 anchor=CENTER,
2675 spin=0,
2676 orient=UP
2677) {
2678 circ_pitch = _inherit_gear_pitch("worm()", pitch, circ_pitch, diam_pitch, mod);
2679 PA = _inherit_gear_pa(pressure_angle);
2680 checks =
2681 assert(is_integer(starts) && starts>0)
2682 assert(is_finite(l) && l>0)
2683 //assert(is_finite(shaft_diam) && shaft_diam>=0)
2684 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
2685 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2686 assert(is_finite(backlash) && backlash>=0)
2687 assert(is_bool(left_handed))
2688 assert(is_finite(gear_spin));
2689 helical = asin(starts * circ_pitch / PI / d);
2690 trans_pitch = circ_pitch / cos(helical);
2691 vnf = worm(
2692 circ_pitch=circ_pitch,
2693 starts=starts,
2694 d=d, l=l,
2695 left_handed=left_handed,
2696 pressure_angle=PA,
2697 backlash=backlash,
2698 clearance=clearance,
2699 mod=mod
2700 );
2701 attachable(anchor,spin,orient, d=d, l=l) {
2702 zrot(gear_spin) vnf_polyhedron(vnf, convexity=ceil(l/trans_pitch)*2);
2703 children();
2704 }
2705}
2706
2707
2708// Function&Module: enveloping_worm()
2709// Synopsis: Creates a double-enveloping worm that will mate with a worm gear.
2710// SynTags: Geom, VNF
2711// Topics: Gears, Parts
2712// See Also: worm(), worm_gear(), rack(), rack2d(), spur_gear(), spur_gear2d(), bevel_pitch_angle(), bevel_gear()
2713// Usage: As a Module
2714// enveloping_worm(circ_pitch, mate_teeth, d, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2715// enveloping_worm(mod=, mate_teeth=, d=, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2716// enveloping_worm(diam_pitch=, mate_teeth=, d=, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2717// Usage: As a Function
2718// vnf = enveloping_worm(circ_pitch, mate_teeth, d, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2719// vnf = enveloping_worm(mod=, mate_teeth=, d=, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2720// vnf = enveloping_worm(diam_pitch=, mate_teeth=, d=, [left_handed=], [starts=], [arc=], [pressure_angle=]);
2721// Description:
2722// Creates a double-enveloping worm shape that can be matched to a worm gear.
2723// Arguments:
2724// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
2725// mate_teeth = The number of teeth in the mated worm gear.
2726// d = The pitch diameter of the worm at its middle.
2727// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
2728// ---
2729// starts = The number of lead starts. Default: 1
2730// arc = Arc angle of the mated worm gear to envelop. Default: `2 * pressure_angle`
2731// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
2732// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
2733// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
2734// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
2735// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
2736// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
2737// Example:
2738// enveloping_worm(circ_pitch=8, mate_teeth=45, d=30, $fn=72);
2739// Example: Multiple Starts.
2740// enveloping_worm(circ_pitch=8, mate_teeth=33, d=30, starts=3, $fn=72);
2741// Example: Left Handed
2742// enveloping_worm(circ_pitch=8, mate_teeth=33, d=30, starts=3, left_handed=true, $fn=72);
2743// Example: Called as Function
2744// vnf = enveloping_worm(circ_pitch=8, mate_teeth=37, d=35, starts=2, left_handed=true, pressure_angle=20, $fn=72);
2745// vnf_polyhedron(vnf);
2746
2747function enveloping_worm(
2748 circ_pitch,
2749 mate_teeth,
2750 d,
2751 left_handed=false,
2752 starts=1,
2753 arc,
2754 pressure_angle,
2755 gear_spin=0,
2756 rounding=true,
2757 taper=true,
2758 diam_pitch,
2759 mod,
2760 pitch,
2761 anchor=CTR,
2762 spin=0,
2763 orient=UP
2764) =
2765 let(
2766 circ_pitch = _inherit_gear_pitch("worm_gear()", pitch, circ_pitch, diam_pitch, mod),
2767 pressure_angle = _inherit_gear_pa(pressure_angle),
2768 arc = default(arc, 2*pressure_angle)
2769 )
2770 assert(is_integer(mate_teeth) && mate_teeth>10)
2771 assert(is_finite(d) && d>0)
2772 assert(is_bool(left_handed))
2773 assert(is_integer(starts) && starts>0)
2774 assert(is_finite(arc) && arc>10 && arc<=2*pressure_angle)
2775 assert(is_finite(gear_spin))
2776 let(
2777 hsteps = segs(d/2),
2778 vsteps = hsteps,
2779 helical = asin(starts * circ_pitch / PI / d),
2780 pr = pitch_radius(circ_pitch, mate_teeth, helical=helical),
2781 taper_table = taper
2782 ? [
2783 [-180, 0],
2784 [-arc/2, 0],
2785 [-arc/2*0.85, 0.75],
2786 [-arc/2*0.8, 0.93],
2787 [-arc/2*0.75, 1],
2788 [+arc/2*0.75, 1],
2789 [+arc/2*0.8, 0.93],
2790 [+arc/2*0.85, 0.75],
2791 [+arc/2, 0],
2792 [+180, 0],
2793 ]
2794 : [
2795 [-180, 0],
2796 [-arc/2-0.00001, 0],
2797 [-arc/2, 1],
2798 [+arc/2, 1],
2799 [+arc/2+0.00001, 0],
2800 [+180, 0],
2801 ],
2802 tarc = 360 / mate_teeth,
2803 rteeth = quantup(ceil(mate_teeth*arc/360),2)+1+2*starts,
2804 rack_path = select(
2805 rack2d(
2806 circ_pitch, rteeth,
2807 pressure_angle=pressure_angle,
2808 rounding=rounding, spin=90
2809 ),
2810 1,-2
2811 ),
2812 adendum = _adendum(circ_pitch, profile_shift=0),
2813 m1 = yscale(360/(circ_pitch*mate_teeth)) * left(adendum),
2814 rows = [
2815 for (i = [0:1:hsteps-1]) let(
2816 u = i / hsteps,
2817 theta = (1-u) * 360,
2818 m2 = back(circ_pitch*starts*u),
2819 polars = [
2820 for (p=apply(m1*m2, rack_path))
2821 if(p.y>=-arc-tarc && p.y<=arc+tarc)
2822 [pr+p.x*lookup(p.y,taper_table)+adendum, p.y]
2823 ],
2824 rpolars = mirror([-1,1],p=polars)
2825 ) [
2826 for (j = [0:1:vsteps-1]) let(
2827 v = j / (vsteps-1),
2828 phi = (v-0.5) * arc,
2829 minor_r = lookup(phi, rpolars),
2830 xy = [d/2+pr,0] + polar_to_xy(minor_r,180-phi),
2831 xyz = xrot(90,p=point3d(xy))
2832 ) zrot(theta, p=xyz)
2833 ]
2834 ],
2835 ys = column(flatten(rows),1),
2836 miny = min(ys),
2837 maxy = max(ys),
2838 vnf1 = vnf_vertex_array(transpose(rows), col_wrap=true, caps=true),
2839 m = product([
2840 zrot(gear_spin),
2841 if (!left_handed) xflip(),
2842 zrot(90),
2843 ]),
2844 vnf = apply(m, vnf1)
2845 ) reorient(anchor,spin,orient, d=d, l=maxy-miny, p=vnf);
2846
2847
2848module enveloping_worm(
2849 circ_pitch,
2850 mate_teeth,
2851 d,
2852 left_handed=false,
2853 starts=1,
2854 arc,
2855 pressure_angle=20,
2856 gear_spin=0,
2857 rounding=true,
2858 taper=true,
2859 diam_pitch,
2860 mod,
2861 pitch,
2862 anchor=CTR,
2863 spin=0,
2864 orient=UP
2865) {
2866 vnf = enveloping_worm(
2867 mate_teeth=mate_teeth,
2868 d=d,
2869 left_handed=left_handed,
2870 starts=starts,
2871 arc=arc,
2872 pressure_angle=pressure_angle,
2873 gear_spin=gear_spin,
2874 rounding=rounding,
2875 taper=taper,
2876 circ_pitch=circ_pitch,
2877 diam_pitch=diam_pitch,
2878 mod=mod,
2879 pitch=pitch
2880 );
2881 bounds = pointlist_bounds(vnf[0]);
2882 delta = bounds[1] - bounds[0];
2883 attachable(anchor,spin,orient, d=max(delta.x,delta.y), l=delta.z) {
2884 vnf_polyhedron(vnf, convexity=mate_teeth);
2885 children();
2886 }
2887}
2888
2889// Function&Module: worm_gear()
2890// Synopsis: Creates a worm gear that will mate with a worm.
2891// SynTags: Geom, VNF
2892// Topics: Gears, Parts
2893// See Also: worm(), worm_gear(), rack(), rack2d(), spur_gear(), spur_gear2d(), bevel_pitch_angle(), bevel_gear()
2894// Usage: As a Module
2895// worm_gear(circ_pitch, teeth, worm_diam, [worm_starts=], [worm_arc=], [crowning=], [left_handed=], [pressure_angle=], [backlash=], [clearance=], [slices=], [shaft_diam=]) [ATTACHMENTS];
2896// worm_gear(mod=, teeth=, worm_diam=, [worm_starts=], [worm_arc=], [crowning=], [left_handed=], [pressure_angle=], [backlash=], [clearance=], [slices=], [shaft_diam=]) [ATTACHMENTS];
2897// Usage: As a Function
2898// vnf = worm_gear(circ_pitch, teeth, worm_diam, [worm_starts=], [worm_arc=], [crowning=], [left_handed=], [pressure_angle=], [backlash=], [clearance=], [slices=]);
2899// vnf = worm_gear(mod=, teeth=, worm_diam=, [worm_starts=], [worm_arc=], [crowning=], [left_handed=], [pressure_angle=], [backlash=], [clearance=], [slices=]);
2900// Description:
2901// Creates a worm gear to match with a worm.
2902// Arguments:
2903// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
2904// teeth = Total number of teeth along the rack. Default: 30
2905// worm_diam = The pitch diameter of the worm gear to match to. Default: 30
2906// worm_starts = The number of lead starts on the worm gear to match to. Default: 1
2907// worm_arc = The arc of the worm to mate with, in degrees. Default: 45 degrees
2908// 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 fit the work easier. Default: 1
2909// left_handed = If true, the gear returned will have a left-handed spiral. Default: false
2910// pressure_angle = Controls how straight or bulged the tooth sides are. In degrees. Default: 20
2911// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle. Default: 0
2912// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
2913// profile_shift = Profile shift factor x. Default: "auto"
2914// slices = The number of vertical slices to refine the curve of the worm throat. Default: 10
2915// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
2916// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
2917// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
2918// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
2919// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
2920// Example: Right-Handed
2921// worm_gear(circ_pitch=5, teeth=36, worm_diam=30, worm_starts=1);
2922// Example: Left-Handed
2923// worm_gear(circ_pitch=5, teeth=36, worm_diam=30, worm_starts=1, left_handed=true);
2924// Example: Multiple Starts
2925// worm_gear(circ_pitch=5, teeth=36, worm_diam=30, worm_starts=4);
2926// Example: Metric Worm Gear
2927// worm_gear(mod=2, teeth=32, worm_diam=30, worm_starts=1);
2928// Example(Anim,Frames=4,FrameMS=125,VPD=220,VPT=[-15,0,0]): Meshing Worm and Gear
2929// $fn=36;
2930// circ_pitch = 5; starts = 4;
2931// worm_diam = 30; worm_length = 50;
2932// gear_teeth=36;
2933// right(worm_diam/2)
2934// yrot($t*360/starts)
2935// worm(
2936// d=worm_diam,
2937// l=worm_length,
2938// circ_pitch=circ_pitch,
2939// starts=starts,
2940// orient=BACK);
2941// left(pitch_radius(circ_pitch, gear_teeth))
2942// zrot(-$t*360/gear_teeth)
2943// worm_gear(
2944// circ_pitch=circ_pitch,
2945// teeth=gear_teeth,
2946// worm_diam=worm_diam,
2947// worm_starts=starts);
2948// Example: Meshing Worm and Gear Metricly
2949// $fn = 72;
2950// modulus = 2; starts = 3;
2951// worm_diam = 30; worm_length = 50;
2952// gear_teeth=36;
2953// right(worm_diam/2)
2954// worm(d=worm_diam, l=worm_length, mod=modulus, starts=starts, orient=BACK);
2955// left(pitch_radius(mod=modulus, teeth=gear_teeth))
2956// worm_gear(mod=modulus, teeth=gear_teeth, worm_diam=worm_diam, worm_starts=starts);
2957// Example: Called as Function
2958// vnf = worm_gear(circ_pitch=8, teeth=30, worm_diam=30, worm_starts=1);
2959// vnf_polyhedron(vnf);
2960
2961function worm_gear(
2962 circ_pitch,
2963 teeth,
2964 worm_diam,
2965 worm_starts=1,
2966 worm_arc=45,
2967 crowning=0.1,
2968 left_handed=false,
2969 pressure_angle,
2970 backlash=0,
2971 clearance,
2972 profile_shift="auto",
2973 slices=10,
2974 gear_spin=0,
2975 pitch,
2976 diam_pitch,
2977 mod,
2978 get_thickness=false,
2979 anchor=CTR,
2980 spin=0,
2981 orient=UP
2982) =
2983 let(
2984 circ_pitch = _inherit_gear_pitch("worm_gear()", pitch, circ_pitch, diam_pitch, mod),
2985 PA = _inherit_gear_pa(pressure_angle),
2986 profile_shift = auto_profile_shift(teeth,PA,profile_shift=profile_shift)
2987 )
2988 assert(is_finite(worm_diam) && worm_diam>0)
2989 assert(is_integer(teeth) && teeth>7)
2990 assert(is_finite(worm_arc) && worm_arc>0 && worm_arc <= 60)
2991 assert(is_integer(worm_starts) && worm_starts>0)
2992 assert(is_bool(left_handed))
2993 assert(is_finite(backlash))
2994 assert(is_finite(crowning) && crowning>=0)
2995 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
2996 assert(is_finite(profile_shift))
2997 let(
2998 gear_arc = 2 * PA,
2999 helical = asin(worm_starts * circ_pitch / PI / worm_diam),
3000 full_tooth = apply(
3001 zrot(90) * scale(0.99),
3002 _gear_tooth_profile(
3003 circ_pitch, teeth=teeth,
3004 pressure_angle=PA,
3005 profile_shift=-profile_shift,
3006 clearance=clearance,
3007 helical=helical,
3008 center=true
3009 )
3010 ),
3011 ftl = len(full_tooth),
3012 tooth_half1 = (select(full_tooth, 0, ftl/2-1)),
3013 tooth_half2 = (select(full_tooth, ftl/2, -1)),
3014 tang = 360 / teeth,
3015 rteeth = quantdn(teeth * gear_arc / 360, 2) / 2 + 0.5,
3016 pr = pitch_radius(circ_pitch, teeth, helical=helical),
3017 oslices = slices * 4,
3018 rows = [
3019 for (data = [[tooth_half1,1], [tooth_half2,-1]])
3020 let (
3021 tooth_half = data[0],
3022 dir = data[1]
3023 )
3024 for (pt = tooth_half) [
3025 for (i = [0:1:oslices])
3026 let (
3027 u = i / oslices,
3028 w_ang = worm_arc * (u - 0.5),
3029 g_ang_delta = w_ang/360 * tang * worm_starts * (left_handed?1:-1),
3030 m = zrot(dir*rteeth*tang+g_ang_delta, cp=[worm_diam/2+pr,0,0]) *
3031 left(crowning) *
3032 yrot(w_ang) *
3033 right(worm_diam/2+crowning) *
3034 zrot(-dir*rteeth*tang+g_ang_delta, cp=[pr,0,0]) *
3035 xrot(180)
3036 ) apply(m, point3d(pt))
3037 ]
3038 ],
3039 midrow = len(rows)/2,
3040 goodcols = [
3041 for (i = idx(rows[0]))
3042 let(
3043 p1 = rows[midrow-1][i],
3044 p2 = rows[midrow][i]
3045 )
3046 if (p1.y > p2.y) i
3047 ],
3048 dowarn = goodcols[0]==0? 0 : echo("Worm gear tooth arc reduced to fit."),
3049 truncrows = [for (row = rows) [ for (i=goodcols) row[i] ] ],
3050 zs = column(flatten(truncrows),2),
3051 minz = min(zs),
3052 maxz = max(zs),
3053 zmax = max(abs(minz), abs(maxz))+0.05,
3054 twang1 = v_theta(truncrows[0][0]),
3055 twang2 = v_theta(last(truncrows[0])),
3056 twang = modang(twang1 - twang2) / (maxz-minz),
3057 resampled_rows = [for (row = truncrows) resample_path(row, n=slices, keep_corners=30, closed=false)],
3058 tooth_rows = [
3059 for (row = resampled_rows) [
3060 zrot(twang*(zmax-row[0].z), p=[row[0].x, row[0].y, zmax]),
3061 each row,
3062 zrot(twang*(-zmax-last(row).z), p=[last(row).x, last(row).y, -zmax]),
3063 ],
3064 ]
3065 )
3066 get_thickness? zmax*2 :
3067 let(
3068 gear_rows = [
3069 for (i = [0:1:teeth-1])
3070 let(
3071 m = zrot(i*tang) *
3072 back(pr) *
3073 zrot(-90) *
3074 left(worm_diam/2)
3075 )
3076 for (row = tooth_rows)
3077 apply(m, row)
3078 ],
3079 vnf1 = vnf_vertex_array(transpose(gear_rows), col_wrap=true, caps=true),
3080 vnf = apply(zrot(gear_spin), vnf1)
3081 ) reorient(anchor,spin,orient, r=pr, h=2*zmax, p=vnf);
3082
3083
3084module worm_gear(
3085 circ_pitch,
3086 teeth,
3087 worm_diam,
3088 worm_starts = 1,
3089 worm_arc = 45,
3090 crowning = 0.1,
3091 left_handed = false,
3092 pressure_angle,
3093 backlash = 0,
3094 clearance,
3095 profile_shift="auto",
3096 slices = 10,
3097 shaft_diam = 0,
3098 gear_spin=0,
3099 pitch,
3100 diam_pitch,
3101 mod,
3102 anchor = CENTER,
3103 spin = 0,
3104 orient = UP
3105) {
3106 circ_pitch = _inherit_gear_pitch("worm_gear()", pitch, circ_pitch, diam_pitch, mod);
3107 PA = _inherit_gear_pa(pressure_angle);
3108 profile_shift = auto_profile_shift(teeth,PA,profile_shift=profile_shift);
3109 checks =
3110 assert(is_integer(teeth) && teeth>10)
3111 assert(is_finite(worm_diam) && worm_diam>0)
3112 assert(is_integer(worm_starts) && worm_starts>0)
3113 assert(is_finite(worm_arc) && worm_arc>0 && worm_arc<90)
3114 assert(is_finite(crowning) && crowning>=0)
3115 assert(is_bool(left_handed))
3116 assert(is_finite(PA) && PA>=0 && PA<90, "Bad pressure_angle value.")
3117 assert(clearance==undef || (is_finite(clearance) && clearance>=0))
3118 assert(is_finite(backlash) && backlash>=0)
3119 assert(is_finite(shaft_diam) && shaft_diam>=0)
3120 assert(slices==undef || (is_integer(slices) && slices>0))
3121 assert(is_finite(profile_shift) && abs(profile_shift)<1)
3122 assert(is_finite(gear_spin));
3123 helical = asin(worm_starts * circ_pitch / PI / worm_diam);
3124 pr = pitch_radius(circ_pitch, teeth, helical);
3125 vnf = worm_gear(
3126 circ_pitch = circ_pitch,
3127 teeth = teeth,
3128 worm_diam = worm_diam,
3129 worm_starts = worm_starts,
3130 worm_arc = worm_arc,
3131 crowning = crowning,
3132 left_handed = left_handed,
3133 pressure_angle = PA,
3134 backlash = backlash,
3135 clearance = clearance,
3136 profile_shift = profile_shift,
3137 slices = slices
3138 );
3139 thickness = pointlist_bounds(vnf[0])[1].z;
3140 attachable(anchor,spin,orient, r=pr, l=thickness) {
3141 zrot(gear_spin)
3142 difference() {
3143 vnf_polyhedron(vnf, convexity=teeth/2);
3144 if (shaft_diam > 0) {
3145 cylinder(h=2*thickness+1, r=shaft_diam/2, center=true, $fn=max(12,segs(shaft_diam/2)));
3146 }
3147 }
3148 children();
3149 }
3150}
3151
3152
3153
3154
3155/// Function: _gear_tooth_profile()
3156/// Usage: As Function
3157/// path = _gear_tooth_profile(pitch, teeth, [pressure_angle], [clearance], [backlash], [internal]);
3158/// Topics: Gears
3159/// See Also: spur_gear2d()
3160/// Description:
3161/// When called as a function, returns the 2D profile path for an individual gear tooth.
3162/// When called as a module, creates the 2D profile shape for an individual gear tooth.
3163/// Arguments:
3164/// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3165/// teeth = Total number of teeth on the spur gear that this is a tooth for.
3166/// pressure_angle = Pressure Angle. Controls how straight or bulged the tooth sides are. In degrees.
3167/// clearance = Gap between top of a tooth on one gear and bottom of valley on a meshing gear (in millimeters)
3168/// backlash = Gap between two meshing teeth, in the direction along the circumference of the pitch circle
3169/// internal = If true, create a mask for difference()ing from something else.
3170/// center = If true, centers the pitch circle of the tooth profile at the origin. Default: false.
3171/// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3172/// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3173/// Example(2D):
3174/// _gear_tooth_profile(circ_pitch=5, teeth=20, pressure_angle=20);
3175/// Example(2D): Metric Gear Tooth
3176/// _gear_tooth_profile(mod=2, teeth=20, pressure_angle=20);
3177/// Example(2D):
3178/// _gear_tooth_profile(
3179/// circ_pitch=5, teeth=20, pressure_angle=20
3180/// );
3181/// Example(2D): As a function
3182/// path = _gear_tooth_profile(
3183/// circ_pitch=5, teeth=20, pressure_angle=20
3184/// );
3185/// stroke(path, width=0.1);
3186
3187function _gear_tooth_profile(
3188 circ_pitch,
3189 teeth,
3190 pressure_angle = 20,
3191 clearance,
3192 backlash = 0.0,
3193 helical = 0,
3194 internal = false,
3195 profile_shift = 0.0,
3196 shorten = 0,
3197 mod,
3198 diam_pitch,
3199 pitch,
3200 center = false
3201) = let(
3202 // Calculate a point on the involute curve, by angle.
3203 _involute = function(base_r,a)
3204 let(b=a*PI/180) base_r * [cos(a)+b*sin(a), sin(a)-b*cos(a)],
3205
3206 steps = 16,
3207 circ_pitch = circular_pitch(pitch=pitch, circ_pitch=circ_pitch, diam_pitch=diam_pitch, mod=mod),
3208 mod = module_value(circ_pitch=circ_pitch),
3209 clear = default(clearance, 0.25 * mod),
3210
3211 // Calculate the important circle radii
3212 arad = outer_radius(circ_pitch, teeth, helical=helical, profile_shift=profile_shift, internal=internal, shorten=shorten),
3213 prad = pitch_radius(circ_pitch, teeth, helical=helical),
3214 brad = _base_radius(circ_pitch, teeth, pressure_angle, helical=helical),
3215 rrad = _root_radius(circ_pitch, teeth, clearance, helical=helical, profile_shift=profile_shift, internal=internal),
3216 srad = max(rrad,brad),
3217 tthick = circ_pitch/PI / cos(helical) * (PI/2 + 2*profile_shift * tan(pressure_angle)) + (internal?backlash:-backlash),
3218 tang = tthick / prad / 2 * 180 / PI,
3219
3220 // Generate a lookup table for the involute curve angles, by radius
3221 involute_lup = [
3222 for (i=[0:5:arad/PI/brad*360])
3223 let(
3224 xy = _involute(brad,i),
3225 pol = xy_to_polar(xy)
3226 )
3227 if (pol.x <= arad * 1.1)
3228 [pol.x, 90-pol.y]
3229 ],
3230
3231 // Generate reverse lookup table for involute radii, by angle
3232 involute_rlup = mirror([-1,1],p=involute_lup), // swaps X and Y columns.
3233
3234 a_ang = lookup(arad, involute_lup),
3235 p_ang = lookup(prad, involute_lup),
3236 b_ang = lookup(brad, involute_lup),
3237 r_ang = lookup(rrad, involute_lup),
3238 s_ang = lookup(srad, involute_lup),
3239 soff = tang + (b_ang - p_ang),
3240 ma_rad = min(arad, lookup(90-soff+0.05*360/teeth/2, involute_rlup)),
3241 ma_ang = lookup(ma_rad, involute_lup),
3242 cap_steps = ceil((ma_ang + soff - 90) / 5),
3243 cap_step = (ma_ang + soff - 90) / cap_steps,
3244 ax = circ_pitch/4 - ang_adj_to_opp(pressure_angle, circ_pitch/PI),
3245
3246 // Calculate the undercut a meshing rack might carve out of this tooth.
3247 undercut = [
3248 for (a=[atan2(ax,rrad):-1:-90])
3249 let(
3250 bx = -a/360 * 2*PI*prad,
3251 x = bx + ax,
3252 y = prad - circ_pitch/PI + profile_shift*circ_pitch/PI,
3253 pol = xy_to_polar(x,y)
3254 )
3255 if (pol.x < arad*1.05)
3256 [pol.x, pol.y-a+180/teeth]
3257 ],
3258 uc_min = min_index(column(undercut,0)),
3259
3260 // Generate a fast lookup table for the undercut.
3261 undercut_lup = [for (i=idx(undercut)) if (i>=uc_min) undercut[i]],
3262
3263 // The u values to use when generating the tooth.
3264 us = [for (i=[0:1:steps*2]) i/steps/2],
3265
3266 // Find top of undercut.
3267 undercut_max = max([
3268 0,
3269 for (u = us) let(
3270 r = lerp(rrad, ma_rad, u),
3271 a1 = lookup(r, involute_lup) + soff,
3272 a2 = lookup(r, undercut_lup),
3273 a = internal || r < undercut_lup[0].x? a1 : min(a1,a2),
3274 b = internal || r < undercut_lup[0].x? false : a1>a2
3275 ) if(a<90+180/teeth && b) r
3276 ]),
3277
3278 // Generate the left half of the tooth.
3279 tooth_half_raw = deduplicate([
3280 for (u = us)
3281 let(
3282 r = lerp(rrad, ma_rad, u),
3283 a1 = lookup(r, involute_lup) + soff,
3284 a2 = lookup(r, undercut_lup),
3285 a = internal || r < undercut_lup[0].x? a1 : min(a1,a2)
3286 )
3287 if ( internal || r > (rrad+clear) )
3288 if (!internal || r < (ma_rad-clear) )
3289 if (a < 90+180/teeth)
3290 polar_to_xy(r, a),
3291 if (!internal)
3292 for (i=[0:1:cap_steps-1]) let(
3293 a = ma_ang + soff - i * (cap_step-1)
3294 ) polar_to_xy(ma_rad, a),
3295 ]),
3296
3297 // Round out the clearance valley
3298 rcircum = 2 * PI * (internal? ma_rad : rrad),
3299 rpart = (180/teeth-tang)/360,
3300 round_r = min(clear, rcircum*rpart),
3301 line1 = internal
3302 ? select(tooth_half_raw,-2,-1)
3303 : select(tooth_half_raw,0,1),
3304 line2 = internal
3305 ? [[0,ma_rad],[-1,ma_rad]]
3306 : zrot(180/teeth, p=[[0,rrad],[1,rrad]]),
3307 isect_pt = line_intersection(line1,line2),
3308 rcorner = internal
3309 ? [last(line1), isect_pt, line2[0]]
3310 : [line2[0], isect_pt, line1[0]],
3311 rounded_tooth_half = deduplicate([
3312 if (!internal && round_r>0) each arc(n=8, r=round_r, corner=rcorner),
3313 if (!internal && round_r<=0) isect_pt,
3314 each tooth_half_raw,
3315 if (internal && round_r>0) each arc(n=8, r=round_r, corner=rcorner),
3316 if (internal && round_r<=0) isect,
3317 ]),
3318
3319 // Strip "jaggies" if found.
3320 strip_left = function(path,i)
3321 i > len(path)? [] :
3322 norm(path[i]) >= undercut_max? [for (j=idx(path)) if(j>=i) path[j]] :
3323 let(
3324 angs = [
3325 for (j=[i+1:1:len(path)-1]) let(
3326 p = path[i],
3327 np = path[j],
3328 r = norm(np),
3329 a = v_theta(np-p)
3330 ) if(r<undercut_max) a
3331 ],
3332 mti = !angs? 0 : min_index(angs),
3333 out = concat([path[i]], strip_left(path, i + mti + 1))
3334 ) out,
3335 tooth_half = !undercut_max? rounded_tooth_half :
3336 strip_left(rounded_tooth_half, 0),
3337
3338 // Mirror the tooth to complete it.
3339 full_tooth = deduplicate([
3340 each tooth_half,
3341 each reverse(xflip(tooth_half)),
3342 ]),
3343
3344 // Reduce number of vertices.
3345 tooth = path_merge_collinear(
3346 resample_path(full_tooth, n=ceil(2*steps), keep_corners=30, closed=false)
3347 ),
3348
3349 out = center? fwd(prad, p=tooth) : tooth
3350) out;
3351
3352
3353
3354// Section: Computing Gear Dimensions
3355// These functions let the user find the derived dimensions of the gear.
3356// A gear fits within a circle of radius outer_radius, and two gears should have
3357// their centers separated by the sum of their pitch_radius.
3358
3359
3360// Function: circular_pitch()
3361// Synopsis: Returns tooth density expressed as "circular pitch".
3362// Topics: Gears, Parts
3363// See Also: spur_gear(), diametral_pitch(), circular_pitch(), module_value()
3364// Usage:
3365// circ_pitch = circular_pitch(circ_pitch);
3366// circ_pitch = circular_pitch(mod=);
3367// circ_pitch = circular_pitch(diam_pitch=);
3368// Description:
3369// Get tooth density expressed as "circular pitch", or the distance in mm between teeth around the pitch circle.
3370// For example, if you have a gear with 11 teeth, and the pitch diameter is 35mm, then the circumfrence
3371// of the pitch diameter is really close to 110mm, making the circular pitch of that gear about 10mm/tooth.
3372// Arguments:
3373// circ_pitch = The circular pitch, or distance in mm between teeth around the pitch circle.
3374// ---
3375// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3376// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3377// Example(2D,Med,VPT=[0,31,0],VPR=[0,0,0],VPD=40):
3378// $fn=144;
3379// teeth=20;
3380// circ_pitch = circular_pitch(diam_pitch=8);
3381// pr = pitch_radius(circ_pitch, teeth);
3382// stroke(spur_gear2d(circ_pitch, teeth), width=0.1);
3383// color("cyan")
3384// dashed_stroke(circle(r=pr), width=0.1);
3385// color("black") {
3386// stroke(
3387// arc(r=pr, start=90+90/teeth, angle=-360/teeth),
3388// width=0.2, endcaps="arrow");
3389// back(pr+1) right(3)
3390// zrot(30) text("Circular Pitch", size=1);
3391// }
3392// Example:
3393// circ_pitch1 = circular_pitch(circ_pitch=5);
3394// circ_pitch2 = circular_pitch(diam_pitch=12);
3395// circ_pitch3 = circular_pitch(mod=2);
3396
3397function circular_pitch(circ_pitch, mod, pitch, diam_pitch) =
3398 assert(one_defined([pitch, mod, circ_pitch, diam_pitch], "pitch,mod,circ_pitch,diam_pitch"))
3399 pitch != undef? assert(is_finite(pitch) && pitch>0) pitch :
3400 circ_pitch != undef? assert(is_finite(circ_pitch) && circ_pitch>0) circ_pitch :
3401 diam_pitch != undef? assert(is_finite(diam_pitch) && diam_pitch>0) PI / diam_pitch * INCH :
3402 assert(is_finite(mod) && mod>0) mod * PI;
3403
3404
3405// Function: diametral_pitch()
3406// Synopsis: Returns tooth density expressed as "diametral pitch".
3407// Topics: Gears, Parts
3408// See Also: spur_gear(), diametral_pitch(), circular_pitch(), module_value()
3409// Usage:
3410// dp = diametral_pitch(circ_pitch);
3411// dp = diametral_pitch(mod=);
3412// dp = diametral_pitch(diam_pitch=);
3413// Description:
3414// Returns tooth density expressed as "diametral pitch", the number of teeth per inch of pitch diameter.
3415// For example, if you have a gear with 30 teeth, with a 1.5 inch pitch diameter, then you have a
3416// diametral pitch of 20 teeth/inch.
3417// Arguments:
3418// circ_pitch = The circular pitch, or distance in mm between teeth around the pitch circle.
3419// ---
3420// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3421// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3422// Example:
3423// diam_pitch1 = diametral_pitch(mod=2);
3424// diam_pitch2 = diametral_pitch(circ_pitch=8);
3425// diam_pitch3 = diametral_pitch(diam_pitch=16);
3426
3427function diametral_pitch(circ_pitch, mod, pitch, diam_pitch) =
3428 let( circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch) )
3429 PI / circ_pitch / INCH;
3430
3431
3432// Function: module_value()
3433// Synopsis: Returns tooth density expressed as "module" or "modulus" in millimeters.
3434// Topics: Gears, Parts
3435// See Also: spur_gear(), diametral_pitch(), circular_pitch(), module_value()
3436// Usage:
3437// mod = module_value(circ_pitch);
3438// mod = module_value(mod=);
3439// mod = module_value(diam_pitch=);
3440// Description:
3441// Get tooth density expressed as "module" or "modulus" in millimeters. The module is the pitch
3442// diameter of the gear divided by the number of teeth on it. For example, a gear with a pitch
3443// diameter of 40mm, with 20 teeth on it will have a modulus of 2.
3444// Arguments:
3445// circ_pitch = The circular pitch, or distance in mm between teeth around the pitch circle.
3446// ---
3447// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3448// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3449// Example:
3450// mod1 = module_value(circ_pitch=8);
3451// mod2 = module_value(mod=2);
3452// mod3 = module_value(diam_pitch=16);
3453
3454function module_value(circ_pitch, mod, pitch, diam_pitch) =
3455 let( circ_pitch = circular_pitch(circ_pitch, mod, pitch, diam_pitch) )
3456 circ_pitch / PI;
3457
3458
3459/// Function: _adendum()
3460/// Usage:
3461/// ad = _adendum(circ_pitch, [profile_shift]);
3462/// ad = _adendum(diam_pitch=, [profile_shift=]);
3463/// ad = _adendum(mod=, [profile_shift=]);
3464/// Topics: Gears
3465/// Description:
3466/// The height of the top of a gear tooth above the pitch radius circle.
3467/// Arguments:
3468/// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3469/// profile_shift = Profile shift factor x. Default: 0
3470/// ---
3471/// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3472/// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3473/// Example:
3474/// ad = _adendum(circ_pitch=5);
3475/// ad = _adendum(mod=2);
3476/// Example(2D):
3477/// circ_pitch = 5; teeth = 17;
3478/// pr = pitch_radius(circ_pitch, teeth);
3479/// adn = _adendum(circ_pitch=5);
3480/// #spur_gear2d(circ_pitch=circ_pitch, teeth=teeth);
3481/// color("black") {
3482/// stroke(circle(r=pr),width=0.1,closed=true);
3483/// stroke(circle(r=pr+adn),width=0.1,closed=true);
3484/// }
3485
3486function _adendum(
3487 circ_pitch,
3488 profile_shift=0,
3489 shorten=0,
3490 diam_pitch,
3491 mod,
3492 pitch
3493) =
3494 let( mod = module_value(circ_pitch, mod, pitch, diam_pitch) )
3495 mod * (1 + profile_shift - shorten);
3496
3497
3498
3499/// Function: _dedendum()
3500/// Usage:
3501/// ddn = _dedendum(circ_pitch=, [clearance], [profile_shift]);
3502/// ddn = _dedendum(diam_pitch=, [clearance=], [profile_shift=]);
3503/// ddn = _dedendum(mod=, [clearance=], [profile_shift=]);
3504/// Topics: Gears
3505/// Description:
3506/// The depth of the gear tooth valley, below the pitch radius.
3507/// Arguments:
3508/// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3509/// clearance = If given, sets the clearance between meshing teeth. Default: module/4
3510/// profile_shift = Profile shift factor x. Default: 0
3511/// ---
3512/// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3513/// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3514/// shorten = amount to shorten tip
3515/// Example:
3516/// ddn = _dedendum(circ_pitch=5);
3517/// ddn = _dedendum(mod=2);
3518/// Example(2D):
3519/// circ_pitch = 5; teeth = 17;
3520/// pr = pitch_radius(circ_pitch, teeth);
3521/// ddn = _dedendum(circ_pitch=5);
3522/// #spur_gear2d(circ_pitch=circ_pitch, teeth=teeth);
3523/// color("black") {
3524/// stroke(circle(r=pr),width=0.1,closed=true);
3525/// stroke(circle(r=pr-ddn),width=0.1,closed=true);
3526/// }
3527
3528function _dedendum(
3529 circ_pitch,
3530 clearance,
3531 profile_shift=0,
3532 diam_pitch,
3533 mod,
3534 pitch
3535) = let(
3536 mod = module_value(circ_pitch, mod, pitch, diam_pitch),
3537 clearance = default(clearance, 0.25 * mod)
3538 )
3539 mod * (1 - profile_shift) + clearance;
3540
3541
3542// Function: pitch_radius()
3543// Synopsis: Returns the pitch radius for a gear.
3544// Topics: Gears, Parts
3545// See Also: spur_gear(), diametral_pitch(), circular_pitch(), module_value(), outer_radius()
3546// Usage:
3547// pr = pitch_radius(pitch, teeth, [helical]);
3548// pr = pitch_radius(mod=, teeth=, [helical=]);
3549// Description:
3550// Calculates the pitch radius for the gear. Two mated gears will have their centers spaced apart
3551// by the sum of the two gear's pitch radii.
3552// Arguments:
3553// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3554// teeth = The number of teeth on the gear.
3555// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
3556// ---
3557// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3558// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3559// Example:
3560// pr = pitch_radius(circ_pitch=5, teeth=11);
3561// pr = pitch_radius(circ_pitch=5, teeth=11, helical=30);
3562// pr = pitch_radius(diam_pitch=10, teeth=11);
3563// pr = pitch_radius(mod=2, teeth=20);
3564// pr = pitch_radius(mod=2, teeth=20, helical=30);
3565// Example(2D,Med,NoScales,VPT=[-0.20531,0.133721,0.658081],VPR=[0,0,0],VPD=82.6686):
3566// $fn=144;
3567// teeth=17; circ_pitch = 5;
3568// pr = pitch_radius(circ_pitch, teeth);
3569// stroke(spur_gear2d(circ_pitch, teeth), width=0.2);
3570// color("blue") dashed_stroke(circle(r=pr), width=0.2);
3571// color("black") {
3572// stroke([[0,0],polar_to_xy(pr,45)],
3573// endcaps="arrow", width=0.3);
3574// fwd(1)
3575// text("Pitch Radius", size=1.5,
3576// halign="center", valign="top");
3577// }
3578
3579function pitch_radius(
3580 circ_pitch,
3581 teeth,
3582 helical=0,
3583 mod,
3584 diam_pitch,
3585 pitch
3586) =
3587 let( circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch) )
3588 assert(is_finite(helical))
3589 assert(is_finite(circ_pitch))
3590 circ_pitch * teeth / PI / 2 / cos(helical);
3591
3592
3593// Function: outer_radius()
3594// Synopsis: Returns the outer radius for a gear.
3595// Topics: Gears, Parts
3596// See Also: spur_gear(), diametral_pitch(), circular_pitch(), module_value(), pitch_radius(), outer_radius()
3597// Usage:
3598// or = outer_radius(circ_pitch, teeth, [helical=], [clearance=], [internal=], [profile_shift=], [shorten=]);
3599// or = outer_radius(mod=, teeth=, [helical=], [clearance=], [internal=], [profile_shift=], [shorten=]);
3600// or = outer_radius(diam_pitch=, teeth=, [helical=], [clearance=], [internal=], [profile_shift=], [shorten=]);
3601// Description:
3602// Calculates the outer radius for the gear. The gear fits entirely within a cylinder of this radius, unless
3603// it has been strongly profile shifted, in which case it will be undersized due to tip clipping.
3604// Arguments:
3605// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3606// teeth = The number of teeth on the gear.
3607// ---
3608// clearance = If given, sets the clearance between meshing teeth. Default: module/4
3609// profile_shift = Profile shift factor x. Default: "auto"
3610// pressure_angle = Pressure angle. Default: 20
3611// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
3612// shorten = Shortening factor, needed to maintain clearance with profile shifting. Default: 0
3613// internal = If true, calculate for an internal gear.
3614// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3615// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3616// Example:
3617// or = outer_radius(circ_pitch=5, teeth=20);
3618// or = outer_radius(circ_pitch=5, teeth=20, helical=30);
3619// or = outer_radius(diam_pitch=10, teeth=17);
3620// or = outer_radius(mod=2, teeth=16);
3621// Example(2D,Med,NoScales,VPT=[-0.20531,0.133721,0.658081],VPR=[0,0,0],VPD=82.6686):
3622// $fn=144;
3623// teeth=17; circ_pitch = 5;
3624// or = outer_radius(circ_pitch, teeth);
3625// stroke(spur_gear2d(circ_pitch, teeth), width=0.2);
3626// color("blue") dashed_stroke(circle(r=or), width=0.2);
3627// color("black") {
3628// stroke([[0,0],polar_to_xy(or,45)],
3629// endcaps="arrow", width=0.3);
3630// fwd(1)
3631// text("Outer Radius", size=1.5,
3632// halign="center", valign="top");
3633// }
3634
3635function outer_radius(circ_pitch, teeth, clearance, internal=false, helical=0, profile_shift="auto", pressure_angle=20, shorten=0, mod, pitch, diam_pitch) =
3636 let(
3637 circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch),
3638 profile_shift = auto_profile_shift(teeth, pressure_angle, helical, profile_shift=profile_shift)
3639 )
3640 pitch_radius(circ_pitch, teeth, helical) + (
3641 internal
3642 ? _dedendum(circ_pitch, clearance, profile_shift=-profile_shift)
3643 : _adendum(circ_pitch, profile_shift=profile_shift, shorten=shorten)
3644 );
3645
3646
3647/// Function: _root_radius()
3648/// Usage:
3649/// rr = _root_radius(circ_pitch, teeth, [helical], [clearance=], [internal=], [profile_shift=]);
3650/// rr = _root_radius(diam_pitch=, teeth=, [helical=], [clearance=], [internal=], [profile_shift=]);
3651/// rr = _root_radius(mod=, teeth=, [helical=], [clearance=], [internal=], [profile_shift=]);
3652/// Topics: Gears
3653/// Description:
3654/// Calculates the root radius for the gear, at the base of the dedendum. Does not apply auto profile shifting.
3655/// Arguments:
3656/// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3657/// teeth = The number of teeth on the gear.
3658/// ---
3659/// clearance = If given, sets the clearance between meshing teeth. Default: module/4
3660/// internal = If true, calculate for an internal gear.
3661/// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
3662/// profile_shift = Profile shift factor x. Default:0
3663/// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3664/// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3665/// Example:
3666/// rr = _root_radius(circ_pitch=5, teeth=11);
3667/// rr = _root_radius(circ_pitch=5, teeth=16, helical=30);
3668/// rr = _root_radius(diam_pitch=10, teeth=11);
3669/// rr = _root_radius(mod=2, teeth=16);
3670/// Example(2D):
3671/// pr = _root_radius(circ_pitch=5, teeth=11);
3672/// #spur_gear2d(pitch=5, teeth=11);
3673/// color("black")
3674/// stroke(circle(r=pr),width=0.1,closed=true);
3675
3676function _root_radius(circ_pitch, teeth, clearance, internal=false, helical=0, profile_shift=0, diam_pitch, mod, pitch) =
3677 let( circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch) )
3678 pitch_radius(circ_pitch, teeth, helical) - (
3679 internal
3680 ? _adendum(circ_pitch, profile_shift=-profile_shift)
3681 : _dedendum(circ_pitch, clearance, profile_shift=profile_shift)
3682 );
3683
3684
3685/// Function: _base_radius()
3686/// Usage:
3687/// br = _base_radius(circ_pitch, teeth, [pressure_angle], [helical]);
3688/// br = _base_radius(diam_pitch=, teeth=, [pressure_angle=], [helical=]);
3689/// br = _base_radius(mod=, teeth=, [pressure_angle=], [helical=]);
3690/// Topics: Gears
3691/// Description:
3692/// Get the base circle for involute teeth, at the base of the teeth.
3693/// Arguments:
3694/// pitch = The circular pitch, or distance between teeth around the pitch circle, in mm.
3695/// teeth = The number of teeth on the gear.
3696/// pressure_angle = Pressure angle in degrees. Controls how straight or bulged the tooth sides are.
3697/// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
3698/// ---
3699/// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3700/// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3701/// Example:
3702/// br = _base_radius(circ_pitch=5, teeth=20, pressure_angle=20);
3703/// br = _base_radius(circ_pitch=5, teeth=20, pressure_angle=20, helical=30);
3704/// br = _base_radius(diam_pitch=10, teeth=20, pressure_angle=20);
3705/// br = _base_radius(mod=2, teeth=18, pressure_angle=20);
3706/// Example(2D):
3707/// pr = _base_radius(circ_pitch=5, teeth=11);
3708/// #spur_gear2d(circ_pitch=5, teeth=11);
3709/// color("black")
3710/// stroke(circle(r=pr),width=0.1,closed=true);
3711
3712function _base_radius(circ_pitch, teeth, pressure_angle=20, helical=0, diam_pitch, mod, pitch) =
3713 let(
3714 circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch),
3715 trans_pa = atan(tan(pressure_angle)/cos(helical))
3716 )
3717 pitch_radius(circ_pitch, teeth, helical) * cos(trans_pa);
3718
3719
3720// Function: bevel_pitch_angle()
3721// Synopsis: Returns the pitch cone angle for a bevel gear.
3722// Topics: Gears, Parts
3723// See Also: bevel_gear(), pitch_radius(), outer_radius()
3724// Usage:
3725// ang = bevel_pitch_angle(teeth, mate_teeth, [drive_angle=]);
3726// Description:
3727// Returns the correct pitch cone angle for a bevel gear with a given number of teeth, that is
3728// matched to another bevel gear with a (possibly different) number of teeth.
3729// Arguments:
3730// teeth = Number of teeth that this gear has.
3731// mate_teeth = Number of teeth that the matching gear has.
3732// drive_angle = Angle between the drive shafts of each gear. Default: 90º.
3733// Example:
3734// ang = bevel_pitch_angle(teeth=18, mate_teeth=30);
3735// Example(2D):
3736// t1 = 13; t2 = 19; pitch=5;
3737// pang = bevel_pitch_angle(teeth=t1, mate_teeth=t2, drive_angle=90);
3738// color("black") {
3739// zrot_copies([0,pang])
3740// stroke([[0,0,0], [0,-20,0]],width=0.2);
3741// stroke(arc(r=3, angle=[270,270+pang]),width=0.2);
3742// }
3743// #bevel_gear(
3744// pitch=5, teeth=t1, mate_teeth=t2,
3745// spiral_angle=0, cutter_radius=1000,
3746// slices=12, anchor="apex", orient=BACK
3747// );
3748
3749function bevel_pitch_angle(teeth, mate_teeth, drive_angle=90) =
3750 atan(sin(drive_angle)/((mate_teeth/teeth)+cos(drive_angle)));
3751
3752
3753// Function: worm_gear_thickness()
3754// Synopsis: Returns the thickness for a worm gear.
3755// Topics: Gears, Parts
3756// See Also: worm(), worm_gear(), pitch_radius(), outer_radius()
3757// Usage:
3758// thick = worm_gear_thickness(pitch, teeth, worm_diam, [worm_arc=], [crowning=], [clearance=]);
3759// thick = worm_gear_thickness(mod=, teeth=, worm_diam=, [worm_arc=], [crowning=], [clearance=]);
3760// Description:
3761// Calculate the thickness of the worm gear.
3762// Arguments:
3763// circ_pitch = The circular pitch, or distance between teeth around the pitch circle, in mm. Default: 5
3764// teeth = Total number of teeth along the rack. Default: 30
3765// worm_diam = The pitch diameter of the worm gear to match to. Default: 30
3766// ---
3767// worm_arc = The arc of the worm to mate with, in degrees. Default: 45 degrees
3768// pressure_angle = Pressure angle in degrees. Controls how straight or bulged the tooth sides are. Default: 20º
3769// 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 fit the work easier. Default: 1
3770// clearance = Clearance gap at the bottom of the inter-tooth valleys. Default: module/4
3771// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3772// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3773// Example:
3774// thick = worm_gear_thickness(circ_pitch=5, teeth=36, worm_diam=30);
3775// thick = worm_gear_thickness(mod=2, teeth=28, worm_diam=25);
3776// Example(2D):
3777// circ_pitch = 5;
3778// teeth = 17;
3779// worm_diam = 30;
3780// worm_starts = 2;
3781// worm_arc = 40;
3782// y = worm_gear_thickness(
3783// circ_pitch=circ_pitch,
3784// teeth=teeth,
3785// worm_diam=worm_diam,
3786// worm_arc=worm_arc
3787// );
3788// #worm_gear(
3789// circ_pitch=circ_pitch,
3790// teeth=teeth,
3791// worm_diam=worm_diam,
3792// worm_arc=worm_arc,
3793// worm_starts=worm_starts,
3794// orient=BACK
3795// );
3796// color("black") {
3797// ycopies(y) stroke([[-25,0],[25,0]], width=0.5);
3798// stroke([[-20,-y/2],[-20,y/2]],width=0.5,endcaps="arrow");
3799// }
3800
3801function worm_gear_thickness(
3802 circ_pitch,
3803 teeth,
3804 worm_diam,
3805 worm_arc=45,
3806 pressure_angle=20,
3807 crowning=0.1,
3808 clearance,
3809 diam_pitch,
3810 mod,
3811 pitch
3812) = let(
3813 circ_pitch = circular_pitch(pitch, mod, circ_pitch, diam_pitch),
3814 thickness = worm_gear(
3815 circ_pitch=circ_pitch,
3816 teeth=teeth,
3817 worm_diam=worm_diam,
3818 worm_arc=worm_arc,
3819 crowning=crowning,
3820 pressure_angle=pressure_angle,
3821 clearance=clearance,
3822 get_thickness=true
3823 )
3824 ) thickness;
3825
3826
3827// Function: worm_dist()
3828// Synopsis: Returns the distance between a worm and a worm gear
3829// Topics: Gears, Parts
3830// See Also: worm(), worm_gear(), pitch_radius(), outer_radius()
3831// Usage:
3832// dist = worm_dist(mod=|diam_pitch=|circ_pitch=, d, starts, teeth, [profile_shift], [pressure_angle=]);
3833// Description:
3834// Calculate the distance between the centers of a worm and its mating worm gear, taking account
3835// possible profile shifting of the worm gear.
3836// Arguments:
3837// d = diameter of worm
3838// starts = number of starts of worm
3839// teeth = number of teeth on worm gear
3840// profile_shift = profile shift of worm gear
3841// ---
3842// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3843// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3844// circ_pitch = distance between teeth around the pitch circle.
3845// pressure_angle = The pressure angle of the gear.
3846// backlash = Add extra space to produce a total of 2*backlash between the two gears.
3847
3848function worm_dist(d,starts,teeth,mod,profile_shift=0,diam_pitch,circ_pitch,pressure_angle=20,backlash=0) =
3849 let(
3850 mod = module_value(mod=mod,diam_pitch=diam_pitch,circ_pitch=circ_pitch),
3851 lead_angle = asin(mod*starts/d),
3852 pitch_diam = mod*teeth/cos(lead_angle)
3853 )
3854 (d+pitch_diam)/2 + profile_shift*mod
3855// + backlash * (cos(lead_angle)+cos(90-lead_angle)) / tan(pressure_angle);
3856// + backlash * cos(45-lead_angle) / tan(pressure_angle);
3857 + backlash * cos(lead_angle) / tan(pressure_angle);
3858
3859
3860
3861// Function: gear_dist()
3862// Synopsis: Returns the distance between two gear centers for spur gears or parallel axis helical gears.
3863// Topics: Gears, Parts
3864// See Also: worm(), worm_gear(), pitch_radius(), outer_radius()
3865// Usage:
3866// dist = gear_dist(mod=|diam_pitch=|circ_pitch=, teeth1, teeth2, [helical], [profile_shift1], [profile_shift2], [pressure_angle=], [backlash=]);
3867// Description:
3868// Calculate the distance between the centers of two spur gears gears or helical gears with parallel axes,
3869// taking into account profile shifting and helical angle. You can give the helical angle as either positive or negative.
3870// If you set one of the tooth counts to zero than that gear will be treated as a rack and the distance returned is the
3871// distance between the rack's pitch line and the gear's center. If you set internal1 or internal2 to true then the
3872// specified gear is a ring gear; the returned distance is still the distance between the centers of the gears. Note that
3873// for a regular gear and ring gear to be compatible the ring gear must have more teeth and at least as much profile shift
3874// as the regular gear.
3875// .
3876// The backlash parameter computes the distance offset that produces a total backlash of `2*backlash` in the
3877// two gear mesh system. This is equivalent to giving the same backlash argument to both gears.
3878// Arguments:
3879// teeth1 = Total number of teeth in the first gear. If given 0, we assume this is a rack or worm.
3880// teeth2 = Total number of teeth in the second gear. If given 0, we assume this is a rack or worm.
3881// helical = The value of the helical angle (from vertical) of the teeth on the two gears (either sign). Default: 0
3882// profile_shift1 = Profile shift factor x for the first gear. Default: 0
3883// profile_shift2 = Profile shift factor x for the second gear. Default: 0
3884// --
3885// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
3886// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
3887// circ_pitch = distance between teeth around the pitch circle.
3888// internal1 = first gear is an internal (ring) gear. Default: false
3889// internal2 = second gear is an internal (ring) gear. Default: false
3890// pressure_angle = The pressure angle of the gear.
3891// backlash = Add extra space to produce a total of 2*backlash between the two gears.
3892// Example(2D,NoAxes): Spur gears (with automatic profile shifting on both)
3893// circ_pitch=5; teeth1=7; teeth2=24;
3894// d = gear_dist(circ_pitch=circ_pitch, teeth1, teeth2);
3895// spur_gear2d(circ_pitch, teeth1, gear_spin=-90);
3896// right(d) spur_gear2d(circ_pitch, teeth2, gear_spin=90-180/teeth2);
3897// Example(3D,NoAxes,Med,VPT=[23.9049,5.42594,-4.68026],VPR=[64.8,0,353.5],VPD=140): Helical gears (with auto profile shifting on one of the gears)
3898// circ_pitch=5; teeth1=7; teeth2=24; helical=37;
3899// d = gear_dist(circ_pitch=circ_pitch, teeth1, teeth2, helical);
3900// spur_gear(circ_pitch, teeth1, helical=helical, gear_spin=-90,slices=15);
3901// right(d) spur_gear(circ_pitch, teeth2, helical=-helical, gear_spin=-90-180/teeth2,slices=9);
3902// Example(2D,NoAxes): Disable Auto Profile Shifting on the smaller gear
3903// circ_pitch=5; teeth1=7; teeth2=24;
3904// d = gear_dist(circ_pitch=circ_pitch, teeth1, teeth2, profile_shift1=0);
3905// spur_gear2d(circ_pitch, teeth1, profile_shift=0, gear_spin=-90);
3906// right(d) spur_gear2d(circ_pitch, teeth2, gear_spin=90-180/teeth2);
3907// Example(2D,NoAxes): Manual Profile Shifting
3908// circ_pitch=5; teeth1=7; teeth2=24; ps1 = 0.5; ps2 = -0.2;
3909// d = gear_dist(circ_pitch=circ_pitch, teeth1, teeth2, profile_shift1=ps1, profile_shift2=ps2);
3910// spur_gear2d(circ_pitch, teeth1, profile_shift=ps1, gear_spin=-90);
3911// right(d) spur_gear2d(circ_pitch, teeth2, profile_shift=ps2, gear_spin=90-180/teeth2);
3912// Example(2D,NoAxes): Profile shifted gear and a rack
3913// mod=3; teeth=8;
3914// d = gear_dist(mod=mod, teeth, 0);
3915// rack2d(mod=mod, teeth=5, bottom=9);
3916// back(d) spur_gear2d(mod=mod, teeth=teeth, gear_spin=180/teeth);
3917// Example(3D,Med,NoAxes,VPT=[-0.0608489,1.3772,-3.68839],VPR=[63.4,0,29.7],VPD=113.336): Profile shifted helical gear and rack
3918// mod=3; teeth=8; helical=29;
3919// d = gear_dist(mod=mod, teeth, 0, helical);
3920// rack(mod=mod, teeth=5, helical=helical, orient=FWD);
3921// color("lightblue")
3922// fwd(d) spur_gear(mod=mod, teeth=teeth, helical=-helical, gear_spin=180/teeth);
3923function gear_dist(
3924 teeth1,
3925 teeth2,
3926 helical=0,
3927 profile_shift1,
3928 profile_shift2,
3929 internal1=false,
3930 internal2=false,
3931 backlash = 0,
3932 pressure_angle=20,
3933 diam_pitch,
3934 circ_pitch,
3935 mod
3936) =
3937 assert(all_nonnegative([teeth1,teeth2]),"Must give nonnegative values for teeth")
3938 assert(teeth1>0 || teeth2>0, "One of the teeth counts must be nonzero")
3939 assert(is_bool(internal1))
3940 assert(is_bool(internal2))
3941 assert(is_finite(helical))
3942 assert(!(internal1&&internal2), "Cannot specify both gears as internal")
3943 assert(!(internal1 || internal2) || (teeth1>0 && teeth2>0), "Cannot specify internal gear with rack (zero tooth count)")
3944 let(
3945 mod = module_value(mod=mod,circ_pitch= circ_pitch, diam_pitch=diam_pitch),
3946 profile_shift1 = auto_profile_shift(teeth1,pressure_angle,helical,profile_shift=profile_shift1),
3947 profile_shift2 = auto_profile_shift(teeth2,pressure_angle,helical,profile_shift=profile_shift2),
3948 teeth1 = internal2? -teeth1 : teeth1,
3949 teeth2 = internal1? -teeth2 : teeth2
3950 )
3951 assert(teeth1+teeth2>0, "Internal gear must have more teeth than the mated external gear")
3952 let(
3953 profile_shift1 = internal2? -profile_shift1 : profile_shift1,
3954 profile_shift2 = internal1? -profile_shift2 : profile_shift2
3955 )
3956 assert(!(internal1||internal2) || profile_shift1+profile_shift2>=0, "Internal gear must have profile shift equal or greater than mated external gear")
3957 teeth1==0 || teeth2==0? pitch_radius(mod=mod, teeth=teeth1+teeth2, helical=helical) + (profile_shift1+profile_shift2)*mod
3958 :
3959 let(
3960 pa_eff = _working_pressure_angle(teeth1,profile_shift1,teeth2,profile_shift2,pressure_angle,helical),
3961 pa_transv = atan(tan(pressure_angle)/cos(helical))
3962 )
3963 mod*(teeth1+teeth2)*cos(pa_transv)/cos(pa_eff)/cos(helical)/2
3964 + (internal1||internal2?-1:1) * backlash*cos(helical)/tan(pressure_angle);
3965
3966function _invol(a) = tan(a) - a*PI/180;
3967
3968function _working_pressure_angle(teeth1,profile_shift1, teeth2, profile_shift2, pressure_angle, helical) =
3969 let(
3970 pressure_angle = atan(tan(pressure_angle)/cos(helical))
3971 )
3972 teeth1==0 || teeth2==0 ? pressure_angle
3973 :
3974 let(
3975 rhs = 2*(profile_shift1+profile_shift2)/(teeth1+teeth2)*cos(helical)*tan(pressure_angle) + _invol(pressure_angle)
3976 )
3977 assert(rhs>0, "Total profile shift is too small, so working pressure angle is negative, and no valid gear separation exists")
3978 let(
3979 pa_eff = root_find(function (x) _invol(x)-rhs, 1, 75)
3980 )
3981 pa_eff;
3982
3983
3984
3985// Function: gear_dist_skew()
3986// Usage:
3987// Synopsis: Returns the distance between two helical gear centers with skew axes.
3988// Topics: Gears, Parts
3989// See Also: gear_dist(), worm(), worm_gear(), pitch_radius(), outer_radius()
3990// Usage:
3991// dist = gear_dist_skew(mod=|diam_pitch=|circ_pitch=, teeth1, teeth2, helical1, helical2, [profile_shift1], [profile_shift2], [pressure_angle=]
3992// Description:
3993// Calculate the distance between two helical gears that mesh with non-parallel axes, taking into account
3994// profile shift and the helical angles.
3995// Arguments:
3996// teeth1 = Total number of teeth in the first gear. If given 0, we assume this is a rack or worm.
3997// teeth2 = Total number of teeth in the second gear. If given 0, we assume this is a rack or worm.
3998// helical1 = The helical angle (from vertical) of the teeth on the first gear.
3999// helical1 = The helical angle (from vertical) of the teeth on the second gear.
4000// profile_shift1 = Profile shift factor x for the first gear. Default: "auto"
4001// profile_shift2 = Profile shift factor x for the second gear. Default: "auto"
4002// --
4003// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
4004// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
4005// circ_pitch = distance between teeth around the pitch circle.
4006// pressure_angle = The pressure angle of the gear.
4007// backlash = Add extra space to produce a total of 2*backlash between the two gears.
4008// Example(3D,Med,NoAxes,VPT=[-0.302111,3.7924,-9.252],VPR=[55,0,25],VPD=155.556): Non-parallel Helical Gears (without any profile shifting)
4009// circ_pitch=5; teeth1=15; teeth2=24; ha1=45; ha2=30; thick=10;
4010// d = gear_dist_skew(circ_pitch=circ_pitch, teeth1, teeth2, helical1=ha1, helical2=ha2);
4011// left(d/2) spur_gear(circ_pitch, teeth1, helical=ha1, thickness=thick, gear_spin=-90);
4012// right(d/2) xrot(ha1+ha2) spur_gear(circ_pitch, teeth2, helical=ha2, thickness=thick, gear_spin=90-180/teeth2);
4013function gear_dist_skew(teeth1,teeth2,helical1,helical2,profile_shift1,profile_shift2,pressure_angle=20,
4014 mod, circ_pitch, diam_pitch, backlash=0) =
4015 assert(all_nonnegative([teeth1,teeth2]),"Must give nonnegative values for teeth")
4016 assert(teeth1>0 || teeth2>0, "One of the teeth counts must be nonzero")
4017 let(
4018 profile_shift1 = auto_profile_shift(teeth1,pressure_angle,helical1,profile_shift=profile_shift1),
4019 profile_shift2 = auto_profile_shift(teeth2,pressure_angle,helical2,profile_shift=profile_shift2),
4020 mod = module_value(circ_pitch=circ_pitch, diam_pitch=diam_pitch, mod=mod)
4021 )
4022 teeth1==0 || teeth2==0? pitch_radius(mod=mod, teeth=teeth1+teeth2, helical=teeth1?helical1:helical2) + (profile_shift1+profile_shift2)*mod
4023 :
4024 let(
4025 pa_normal_eff = _working_normal_pressure_angle_skew(teeth1,profile_shift1,helical1,teeth2,profile_shift2,helical2,pressure_angle),
4026 dist_adj = 0.5*(teeth1/cos(helical1)^3+teeth2/cos(helical2)^3)*(cos(pressure_angle)/cos(pa_normal_eff)-1)
4027 )
4028 mod*(teeth1/2/cos(helical1)+teeth2/2/cos(helical2)+dist_adj)
4029 // This expression is a guess based on finding the cross section where pressure angles match so that there is a single
4030 // pressure angle to reference the movement by.
4031 + backlash * cos((helical1-helical2)/2) / tan(pressure_angle);
4032
4033
4034function _working_normal_pressure_angle_skew(teeth1,profile_shift1,helical1, teeth2, profile_shift2, helical2, pressure_angle) =
4035 let(
4036 inv = function(a) tan(a) + a*PI/180,
4037 rhs = 2*(profile_shift1+profile_shift2)/(teeth1/cos(helical1)^3+teeth2/cos(helical2)^3)*tan(pressure_angle) + _invol(pressure_angle),
4038 pa_eff_normal = root_find(function (x) _invol(x)-rhs, 5, 75)
4039 )
4040 pa_eff_normal;
4041
4042
4043// Function: gear_skew_angle()
4044// Usage:
4045// ang = gear_skew_angle(teeth1, teeth2, helical1, helical2, [profile_shift1], [profile_shift2], [pressure_angle=]
4046// Synopsis: Returns corrected skew angle between two profile shifted helical gears.
4047// Description:
4048// Compute the correct skew angle between the axes of two profile shifted helical gears. When profile shifting is zero, or when one of
4049// the gears is a rack, this angle is simply the sum of the helical angles of the two gears. But with profile shifted gears, a small
4050// correction to the skew angle is needed for proper meshing.
4051// Arguments:
4052// teeth1 = Total number of teeth in the first gear. If given 0, we assume this is a rack or worm.
4053// teeth2 = Total number of teeth in the second gear. If given 0, we assume this is a rack or worm.
4054// helical1 = The helical angle (from vertical) of the teeth on the first gear.
4055// helical1 = The helical angle (from vertical) of the teeth on the second gear.
4056// profile_shift1 = Profile shift factor x for the first gear. Default: "auto"
4057// profile_shift2 = Profile shift factor x for the second gear. Default: "auto"
4058// --
4059// pressure_angle = The pressure angle of the gear.
4060// Example(3D,Med,NoAxes,VPT=[-2.62091,2.01048,-1.31405],VPR=[55,0,25],VPD=74.4017): These gears are auto profile shifted and as a result, do not mesh at the sum of their helical angles, but at 2.5 degrees more.
4061// circ_pitch=5; teeth1=12; teeth2=7; ha1=25; ha2=30; thick=10;
4062// d = gear_dist_skew(circ_pitch=circ_pitch, teeth1, teeth2, ha1, ha2);
4063// ang = gear_skew_angle(teeth1, teeth2, helical1=ha1, helical2=ha2); // Returns 57.7
4064// left(d/2)
4065// spur_gear(circ_pitch, teeth1, helical=ha1, thickness=thick, gear_spin=-90);
4066// right(d/2) color("lightblue")
4067// xrot(ang) spur_gear(circ_pitch, teeth2, helical=ha2, thickness=thick, gear_spin=90-180/teeth2);
4068
4069function gear_skew_angle(teeth1,teeth2,helical1,helical2,profile_shift1,profile_shift2,pressure_angle=20) =
4070 assert(all_nonnegative([teeth1,teeth2]),"Must give nonnegative values for teeth")
4071 assert(teeth1>0 || teeth2>0, "One of the teeth counts must be nonzero")
4072 let(
4073 mod = 1, // This is independent of module size
4074 profile_shift1 = auto_profile_shift(teeth1,pressure_angle,helical1,profile_shift=profile_shift1),
4075 profile_shift2 = auto_profile_shift(teeth2,pressure_angle,helical2,profile_shift=profile_shift2)
4076 )
4077 profile_shift1==0 && profile_shift2==0 ? helical1+helical2
4078 : teeth1==0 || teeth2==0 ? helical1+helical2
4079 : let(
4080 a = gear_dist_skew(mod=mod,teeth1,teeth2,helical1,helical2,profile_shift1,profile_shift2,pressure_angle=pressure_angle),
4081 b = gear_dist_skew(mod=mod,teeth1,teeth2,helical1,helical2,0,0,pressure_angle=pressure_angle),
4082 d1 = 2*pitch_radius(mod=mod,teeth=teeth1,helical=helical1),
4083 d2 = 2*pitch_radius(mod=mod,teeth=teeth2,helical=helical2),
4084 dw1 = 2*a*d1/(d1+d2),
4085 dw2 = 2*a*d2/(d1+d2),
4086 beta1 = atan(dw1/d1*tan(helical1)),
4087 beta2 = atan(dw2/d2*tan(helical2))
4088 )
4089 beta1+beta2;
4090
4091
4092// Function: get_profile_shift()
4093// Usage:
4094// total_shift = get_profile_shift(mod=|diam_pitch=|circ_pitch=, desired, teeth1, teeth2, [helical], [pressure_angle=],
4095// Synopsis: Returns total profile shift needed to achieve a desired spacing between two gears
4096// Description:
4097// Compute the total profile shift, split between two gears, needed to place those gears with a specified separation.
4098// If the requested separation is too small, returns NaN. Note that the profile shift returned may also be impractically
4099// large or small and does not necessarily lead to a valid gear configuration. You will need to split the profile shift
4100// between the two gears. Note that for helical gears, much more adjustment is available by modifying the helical angle.
4101// Arguments:
4102// desired = desired gear center separation
4103// teeth1 = number of teeth on first gear
4104// teeth2 = number of teeth on second gear
4105// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
4106// ---
4107// mod = The metric module/modulus of the gear, or mm of pitch diameter per tooth.
4108// diam_pitch = The diametral pitch, or number of teeth per inch of pitch diameter. Note that the diametral pitch is a completely different thing than the pitch diameter.
4109// circ_pitch = distance between teeth around the pitch circle.
4110// pressure_angle = normal pressure angle of gear teeth. Default: 20
4111// Example(2D,Med,NoAxes,VPT=[37.0558,0.626722,9.78411],VPR=[0,0,0],VPD=496): For a pair of module 4 gears with 19, and 37 teeth, the separation without profile shifting is 112. Suppose we want it instead to be 115. A positive profile shift, split evenly between the gears, achieves the goal, as shown by the red rectangle, with width 115.
4112// teeth1=37;
4113// teeth2=19;
4114// mod=4;
4115// desired=115;
4116// pshift = get_profile_shift(desired,teeth1,teeth2,mod=mod); // Returns 0.82
4117// ps1 = pshift/2;
4118// ps2 = pshift/2;
4119// shorten=gear_shorten(teeth1,teeth2,0,ps1,ps2); // Returns 0.07
4120// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
4121// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,shorten=shorten,gear_spin=-90,shaft_diam=5);
4122// right(d)
4123// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,shorten=shorten,gear_spin=-90,shaft_diam=5);
4124// stroke([rect([desired,40], anchor=LEFT)],color="red");
4125// Example(2D,Med,NoAxes,VPT=[37.0558,0.626722,9.78411],VPR=[0,0,0],VPD=496): For the same pair of module 4 gears with 19, and 37 teeth, suppose we want a closer spacing of 110 instead of 112. A positive profile shift does the job, as shown by the red rectangle with width 110. More of the negative shift is assigned to the large gear, to avoid undercutting the smaller gear.
4126// teeth1=37;
4127// teeth2=19;
4128// mod=4;
4129// desired=110;
4130// pshift = get_profile_shift(desired,teeth1,teeth2,mod=mod); // Returns -0.46
4131// ps1 = 0.8*pshift;
4132// ps2 = 0.2*pshift;
4133// shorten=gear_shorten(teeth1,teeth2,0,ps1,ps2); // Returns 0.04
4134// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
4135// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,shorten=shorten,gear_spin=-90,shaft_diam=5);
4136// right(d)
4137// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,shorten=shorten,gear_spin=-90,shaft_diam=5);
4138// stroke([rect([desired,40], anchor=LEFT)],color="red");
4139function get_profile_shift(desired,teeth1,teeth2,helical=0,pressure_angle=20,mod,diam_pitch,circ_pitch) =
4140 let(
4141 mod = module_value(mod=mod, circ_pitch=circ_pitch, diam_pitch=diam_pitch),
4142 teethsum = teeth1+teeth2,
4143 pressure_angle_trans = atan(tan(pressure_angle)/cos(helical)),
4144 y = desired/mod - teethsum/2/cos(helical),
4145 thing=teethsum*cos(pressure_angle_trans) / (teethsum+2*y*cos(helical)),
4146 pa_eff = acos(teethsum*cos(pressure_angle_trans) / (teethsum+2*y*cos(helical)))
4147 )
4148 teethsum * (_invol(pa_eff)-_invol(pressure_angle_trans))/2/tan(pressure_angle);
4149
4150
4151// Function: auto_profile_shift()
4152// Synopsis: Returns the recommended profile shift for a gear.
4153// Topics: Gears, Parts
4154// See Also: worm(), worm_gear(), pitch_radius(), outer_radius()
4155// Usage:
4156// x = auto_profile_shift(teeth, [pressure_angle], [helical], [profile_shift=]);
4157// x = auto_profile_shift(teeth, [pressure_angle], [helical], get_min=);
4158// x = auto_profile_shift(teeth, min_teeth=);
4159// Description:
4160// Calculates the recommended profile shift to avoid gear tooth undercutting. You can set `min_teeth` to a
4161// value to allow small undercutting, and only activate the profile shift for more extreme cases. Is is common
4162// practice to make gears with 15-17 teeth with undercutting with the standard 20 deg pressure angle.
4163// .
4164// The `get_min` argument returns the minimum profile shift needed to avoid undercutting for the specified
4165// number of teeth. This will be a negative value for gears with a large number of teeth; such gears can
4166// be given a negative profile shift without undercutting.
4167// Arguments:
4168// teeth = Total number of teeth in the gear.
4169// pressure_angle = The pressure angle of the gear.
4170// helical = helical angle
4171// ---
4172// min_teeth = If given, the minimum number of teeth on a gear that has acceptable undercut.
4173// get_min = If true then return the minimum profile shift to avoid undercutting, which may be a negative value for large gears.
4174// profile_shift = If numerical then just return this value; if "auto" or not given then compute the automatic profile shift.
4175function auto_profile_shift(teeth, pressure_angle=20, helical=0, min_teeth, profile_shift, get_min=false) =
4176 assert(is_undef(profile_shift) || is_finite(profile_shift) || profile_shift=="auto", "Profile shift must be \"auto\" or a number")
4177 is_num(profile_shift) ? profile_shift
4178 : teeth==0 ? 0
4179 : let(
4180 pressure_angle=atan(tan(pressure_angle)/cos(helical)),
4181 min_teeth = default(min_teeth, 2 / sin(pressure_angle)^2)
4182 )
4183 !get_min && teeth > floor(min_teeth)? 0
4184 : (1 - (teeth / min_teeth))/cos(helical);
4185
4186
4187// Function: gear_shorten()
4188// Usage:
4189// shorten = gear_shorten(teeth1, teeth2, [helical], [profile_shift1], [profile_shift2], [pressure_angle=]);
4190// Synopsis: Returns the tip shortening parameter for profile shifted parallel axis gears.
4191// Description:
4192// Compute the gear tip shortening factor for gears that have profile shifts. This factor depends on both
4193// gears in a pair and when applied, will results in teeth that meet the specified clearance distance.
4194// Generally if you don't apply it the teeth clearance will be decreased due to the profile shifting.
4195// Because it operates pairwise, if a gear mates with more than one other gear, you may have to decide
4196// which shortening factor to use. The shortening factor is independent of the size of the teeth.
4197// Arguments:
4198// teeth1 = number of teeth on first gear
4199// teeth2 = number of teeth on second gear
4200// helical = The helical angle (from vertical) of the teeth on the gear. Default: 0
4201// profile_shift1 = Profile shift factor x for the first gear. Default: "auto"
4202// profile_shift2 = Profile shift factor x for the second gear. Default: "auto"
4203// ---
4204// pressure_angle = normal pressure angle of gear teeth. Default: 20
4205// Example(2D,Med,VPT=[53.9088,1.83058,26.0319],VPR=[0,0,0],VPD=140): Big profile shift eliminates the clearance between the teeth
4206// teeth1=25;
4207// teeth2=19;
4208// mod=4;
4209// ps1 = 0.75;
4210// ps2 = 0.75;
4211// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
4212// color("lightblue")
4213// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,gear_spin=-90);
4214// right(d)
4215// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,gear_spin=-90);
4216// Example(2D,Med,VPT=[53.9088,1.83058,26.0319],VPR=[0,0,0],VPD=140,NoAxes): Applying the correct shortening factor restores the clearance to its normal value.
4217// teeth1=25;
4218// teeth2=19;
4219// mod=4;
4220// ps1 = 0.75;
4221// ps2 = 0.75;
4222// d = gear_dist(mod=mod, teeth1,teeth2,0,ps1,ps2);
4223// shorten=gear_shorten(teeth1,teeth2,0,ps1,ps2);
4224// color("lightblue")
4225// spur_gear2d(mod=mod,teeth=teeth1,profile_shift=ps1,shorten=shorten,gear_spin=-90);
4226// right(d)
4227// spur_gear2d(mod=mod,teeth=teeth2,profile_shift=ps2,shorten=shorten,gear_spin=-90);
4228function gear_shorten(teeth1,teeth2,helical=0,profile_shift1="auto",profile_shift2="auto",pressure_angle=20) =
4229 teeth1==0 || teeth2==0 ? 0
4230 : let(
4231 profile_shift1 = auto_profile_shift(teeth1,pressure_angle,helical,profile_shift=profile_shift1),
4232 profile_shift2 = auto_profile_shift(teeth2,pressure_angle,helical,profile_shift=profile_shift2),
4233 ax = gear_dist(mod=1,teeth1,teeth2,helical,profile_shift1,profile_shift2,pressure_angle=pressure_angle),
4234 y = ax - (teeth1+teeth2)/2/cos(helical)
4235 )
4236 profile_shift1+profile_shift2-y;
4237
4238
4239// Function: gear_shorten_skew()
4240// Usage:
4241// shorten = gear_shorten_skew(teeth1, teeth2, helical1, helical2, [profile_shift1], [profile_shift2], [pressure_angle=]);
4242// Synopsis: Returns the tip shortening parameter for profile shifted skew axis helical gears.
4243// Description:
4244// Compute the gear tip shortening factor for skew axis helical gears that have profile shifts. This factor depends on both
4245// gears in a pair and when applied, will results in teeth that meet the specified clearance distance.
4246// Generally if you don't apply it the teeth clearance will be decreased due to the profile shifting.
4247// Because it operates pairwise, if a gear mates with more than one other gear, you may have to decide
4248// which shortening factor to use. The shortening factor is independent of the size of the teeth.
4249// Arguments:
4250// teeth1 = Total number of teeth in the first gear. If given 0, we assume this is a rack or worm.
4251// teeth2 = Total number of teeth in the second gear. If given 0, we assume this is a rack or worm.
4252// helical1 = The helical angle (from vertical) of the teeth on the first gear.
4253// helical1 = The helical angle (from vertical) of the teeth on the second gear.
4254// profile_shift1 = Profile shift factor x for the first gear. Default: "auto"
4255// profile_shift2 = Profile shift factor x for the second gear. Default: "auto"
4256// ---
4257// pressure_angle = The pressure angle of the gear.
4258function gear_shorten_skew(teeth1,teeth2,helical1,helical2,profile_shift1="auto",profile_shift2="auto",pressure_angle=20) =
4259 let(
4260 profile_shift1 = auto_profile_shift(teeth1,pressure_angle,helical1,profile_shift=profile_shift1),
4261 profile_shift2 = auto_profile_shift(teeth2,pressure_angle,helical2,profile_shift=profile_shift2),
4262 ax = gear_dist(mod=1,teeth1,teeth2,helical,profile_shift1,profile_shift2,pressure_angle=pressure_angle),
4263 y = ax - (teeth1+teeth2)/2/cos(helical)
4264 )
4265 profile_shift1+profile_shift2-y;
4266
4267
4268module _show_gear_tooth_profile(
4269 circ_pitch,
4270 teeth,
4271 pressure_angle=20,
4272 profile_shift,
4273 helical=0,
4274 internal=false,
4275 clearance,
4276 backlash=0,
4277 show_verts=false,
4278 diam_pitch,
4279 mod
4280) {
4281 mod = module_value(circ_pitch=circ_pitch, diam_pitch=diam_pitch, mod=mod);
4282 profile_shift = default(profile_shift, auto_profile_shift(teeth, pressure_angle, helical));
4283 or = outer_radius(mod=mod, teeth=teeth, clearance=clearance, helical=helical, profile_shift=profile_shift, internal=internal);
4284 pr = pitch_radius(mod=mod, teeth=teeth, helical=helical);
4285 rr = _root_radius(mod=mod, teeth=teeth, helical=helical, profile_shift=profile_shift, clearance=clearance, internal=internal);
4286 br = _base_radius(mod=mod, teeth=teeth, helical=helical, pressure_angle=pressure_angle);
4287 tang = 360/teeth;
4288 rang = tang * 1.075;
4289 tsize = (or-rr) / 20;
4290 clear = (1-profile_shift)*mod;
4291 tooth = _gear_tooth_profile(
4292 mod=mod, teeth=teeth,
4293 pressure_angle=pressure_angle,
4294 clearance=clearance,
4295 backlash=backlash,
4296 helical=helical,
4297 internal=internal,
4298 profile_shift=profile_shift
4299 );
4300 $fn=360;
4301 union() {
4302 color("cyan") { // Pitch circle
4303 stroke(arc(r=pr,start=90-rang/2,angle=rang), width=0.05);
4304 zrot(-tang/2*1.10) back(pr) text("pitch", size=tsize, halign="left", valign="center");
4305 }
4306 color("lightgreen") { // Outer and Root circles
4307 stroke(arc(r=or,start=90-rang/2,angle=rang), width=0.05);
4308 stroke(arc(r=rr,start=90-rang/2,angle=rang), width=0.05);
4309 zrot(-tang/2*1.10) back(or) text("tip", size=tsize, halign="left", valign="center");
4310 zrot(-tang/2*1.10) back(rr) text("root", size=tsize, halign="left", valign="center");
4311 }
4312 color("#fcf") { // Base circle
4313 stroke(arc(r=br,start=90-rang/2,angle=rang), width=0.05);
4314 zrot(tang/2*1.10) back(br) text("base", size=tsize, halign="right", valign="center");
4315 }
4316 color("#ddd") { // Clearance area
4317 if (internal) {
4318 dashed_stroke(arc(r=pr+clear, start=90-rang/2, angle=rang), width=0.05);
4319 back((pr+clear+or)/2) text("clearance", size=tsize, halign="center", valign="center");
4320 } else {
4321 dashed_stroke(arc(r=pr-clear, start=90-rang/2, angle=rang), width=0.05);
4322 back((pr-clear+rr)/2) text("clearance", size=tsize, halign="center", valign="center");
4323 }
4324 }
4325 color("#ddd") { // Tooth width markers
4326 stroke([polar_to_xy(min(rr,br)-mod/10,90-180/teeth),polar_to_xy(or+mod/10,90-180/teeth)], width=0.05, closed=true);
4327 stroke([polar_to_xy(min(rr,br)-mod/10,90+180/teeth),polar_to_xy(or+mod/10,90+180/teeth)], width=0.05, closed=true);
4328 }
4329 zrot_copies([0]) { // Tooth profile overlay
4330 stroke(tooth, width=0.1, dots=(show_verts?"dot":false), endcap_color1="green", endcap_color2="red");
4331 }
4332 }
4333}
4334
4335
4336
4337// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap