Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gear generator plugin #13

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c77e1ca
Create gear_generator.py
Jojain Mar 21, 2021
39dd06b
Add bevel gear
Jojain Mar 21, 2021
257c409
Update gear_generator.py
Jojain Mar 21, 2021
387743a
Update gear_generator.py
Jojain Mar 21, 2021
73fef2f
Update gear_generator.py
Jojain Mar 21, 2021
e447ff2
add crown gear
Jojain Mar 21, 2021
6aaa39e
Create rack_gear.py
Jojain Mar 22, 2021
1fd4cf4
add docstring, improve organisation
Jojain Mar 25, 2021
ca3f373
changed imports
Jojain Mar 25, 2021
b6da683
add readme and setup files
Jojain Mar 25, 2021
ce9837d
minor corrections
Jojain Mar 25, 2021
b9f8b6d
moved to module dir structure
Jojain Mar 25, 2021
3a5c0f4
update functions calls
Jojain Mar 27, 2021
02b6935
Update __init__.py
Jojain Mar 27, 2021
83845f4
testing import solutions
Jojain Mar 27, 2021
36829b1
Update main.py
Jojain Mar 27, 2021
b4bdb4a
made plugin functions work
Jojain Mar 27, 2021
83978c6
setup test functions
Jojain Mar 27, 2021
69d89db
push
Jojain Mar 27, 2021
b45c856
Update .gitignore
Jojain Mar 27, 2021
63aba81
add working tests
Jojain Mar 27, 2021
78102b3
add auto link of methods in __init__
Jojain Mar 27, 2021
7b46b37
change function names
Jojain Mar 27, 2021
cc92cad
Update cutter_objects.py
Jojain Mar 27, 2021
ea6e4c6
add register fct to modules
Jojain Mar 27, 2021
ef86b88
add imgs for readme
Jojain Mar 27, 2021
c4b05ab
finalize PR version
Jojain Mar 27, 2021
0e7c2ce
Update README.md
Jojain Mar 27, 2021
713933d
Update test_gear_generator.py
Jojain Mar 27, 2021
66ad25a
Merge branch 'dev-gear-generator' of https://github.com/Jojain/cadque…
Jojain Mar 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,5 @@ dmypy.json

# Pyre type checker
.pyre/
*.ipynb
plugins/gear_generator/src/gear-generator/
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "D:\\Programmes\\miniconda\\envs\\test_gear_generator\\python.exe"
}
95 changes: 95 additions & 0 deletions plugins/gear_generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Gear generator

This plugin provide additionals methods to create various gears.
As for now you can create these gears (all the gears are involutes):
* Spur gear

<img src="images/straight_gear.PNG" width="600"/>

* Helical gear

<img src="images/helical_gear.PNG" width="600"/>

* Rack gear

<img src="images/rack_gear_straight.PNG" width="600"/>

* Helical rack gear

<img src="images/rack_gear_helix.PNG" width="600"/>

* Crown (or face) gear

<img src="images/crown_gear.PNG" width="600"/>

* Bevel gear (straight) (experimental)

<img src="images/bevel_gear.PNG" width="600"/>

* Bevel gear system (straight) (very experimental)

<img src="images/bevel_gear_system.PNG" width="600"/>


## Installation

To install this plugin, the following line should be used.

```
pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=gear_generator&subdirectory=plugins/gear_generator"
```


## Dependencies

This plugin has no dependencies other than the cadquery library.

## Usage

To use this plugin after it has been installed, just import it and use the make_... methods to create your gears
```python
import cadquery as cq
import gear_generator # automatically links the plugin functions to the cq.Workplane class

module = 2
nb_teeth = 12
width = 8
gear = cq.Workplane("XY").make_gear(module, nb_teeth, width)
```
<img src="images/readme_example.PNG" width="300"/>

Currently in cq-editor the automatical linking doesn't work so you should try to link it manually as below :
```python
import cadquery as cq
import gear_generator
gear_generator.cutter_objects.register_cutter_objects()
gear_generator.register()
```

Below is the list of implemented methods :
```python
cq.Workplane().make_gear(params)
cq.Workplane().make_rack_gear(params)
cq.Workplane().make_crown_gear(params)
cq.Workplane().make_bevel_gear(params)
cq.Workplane().make_bevel_gear_system(params)

#You can get info about the parameters by running
help(cq.Workplane().make_gear)
>>> _make_gear(m, z, b, alpha=20, helix_angle=None, raw=False) method of cadquery.cq.Workplane instance
>>> Creates a spur or helical involute gear
>>>
>>> Parameters
>>> ----------
>>> m : float
>>> Spur gear modulus
>>> z : int
>>> Number of teeth
>>> b : float
>>> Tooth width
>>> alpha : float
>>> Pressure angle in degrees, industry standard is 20\ufffd
>>> helix_angle : float
>>> Helix angle of the helical gear in degrees
>>> If None creates a spur gear, if specified create a helical gear
```
9 changes: 9 additions & 0 deletions plugins/gear_generator/gear_generator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .main import (
_make_gear,
_make_bevel_gear,
_make_bevel_gear_system,
_make_crown_gear,
_make_rack_gear,
register
)
register()
182 changes: 182 additions & 0 deletions plugins/gear_generator/gear_generator/cutter_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
"""
This module stores functions that are used by the make_XXX_gear functions but are not intended to be used by the final user
"""

import cadquery as cq
from math import *
from .helpers import involute, test_bevel_parameters, rotate_vector_2D


def _make_rack_tooth_gap(self, m, b, alpha = 20, helix_angle = None):
"""
Creates a solid which represents the gap between the teeth of the rack gear

Parameters
----------
m : float
Crown gear modulus
b : float
Tooth width
alpha : float
Pressure angle in degrees, industry standard is 20°
helix_angle : float
Helix angle in degrees to create a helical rack gear

Returns
-------
cq.Workplane
Returns the tooth gap solid in a cq.Workplane using eachpoint method
"""
p = pi*m
alpha = radians(alpha)

A = (-2.25*m*sin(alpha)-(p/2 - 2*m*sin(alpha)),0)
B = (-(p/2 - 2*m*sin(alpha)), -2.25*m*cos(alpha))
C = (B[0] + (p/2 - 2*m*sin(alpha)), -2.25*m*cos(alpha))
D = (C[0] + 2.25*m*sin(alpha), 0)
tooth_wire = (cq.Workplane("XY").polyline([A,B,C,D])).close()
if helix_angle is None:
tooth = tooth_wire.extrude(b)
else:
helix_angle = radians(helix_angle)
tooth = tooth_wire.center(tan(helix_angle)*b, 0).workplane(offset=b).polyline([A,B,C,D]).close().loft()
return self.eachpoint(lambda loc: tooth.val().located(loc), True)

def _make_bevel_tooth_gap_wire(self, Z_W, m, phi, r_a, r_f, r_base):
"""
Creates the bevel tooth gap wire that will be lofted to a vertex to make the cutter object

Parameters
----------
Z_W : float
Z position of the top of the complementary cone in the coord system which as it's origin at the bevel gear cone top point
m : float
Bevel gear modulus
phi : float
Complementary cone angle in radians
r_a : float
Associated virtual spur gear top radius
r_f : float
Associated virtual spur gear root radius
r_base : float
Associated virtual spur gear base radius

Returns
-------
cq.Workplane
Returns a wire in a cq.Workplane that defines the tooth gap cross section at the bevel outer radius
"""
STOP = 2*sqrt((r_a/r_base)**2 - 1) # 2* To be sure to have extra working room
#right side
right = (cq.Workplane("XY", origin=(0,0,Z_W)).transformed(rotate=(-pi*m,-90+degrees(phi),0))
.tag("baseplane")
.parametricCurve(involute(r_base), N=8, stop=STOP, makeWire=False))
bot_right = right.moveTo(r_f,0).hLine(r_base-r_f)
#left side
left = (cq.Workplane("XY", origin=(0,0,Z_W)).transformed(rotate=(pi*m,-90+degrees(phi),0))
.moveTo(r_f,0)
.hLine(r_base-r_f)
.parametricCurve(involute(r_base, sign=-1), N=8, stop=STOP, makeWire=False))
bot_left = left.moveTo(r_f,0).hLine(r_base-r_f)
#Getting points to close the wire
pt_top_right = right.vertices(">X").val()
pt_bot_right = bot_right.vertices("<X").val()
pt_top_left = left.vertices(">X").val()
pt_bot_left = bot_left.vertices("<X").val()
pt_bot_mid = cq.Workplane("XY", origin=(0,0,Z_W)).transformed(rotate=(0,-90+degrees(phi),0)).pushPoints([(r_f,0)]).val()
#TODO : make top an arc instead of a straight line
top = cq.Edge.makeLine(cq.Vector(pt_top_right.toTuple()), cq.Vector(pt_top_left.toTuple()))
bot = cq.Edge.makeThreePointArc(cq.Vector(pt_bot_left.toTuple()),
cq.Vector(pt_bot_mid.toTuple()),
cq.Vector(pt_bot_right.toTuple()))
wire = cq.Wire.assembleEdges([bot_right.val(), right.val(), top, left.val(), bot_left.val(), bot])
return self.eachpoint(lambda loc: wire.located(loc), True)

def _make_crown_gear_tooth_gap(self, m, r, alpha = 20):
"""
Create a solid which represents the gap between the teeth of the crown gear

Parameters
----------
m : float
Crown gear modulus
r : float
Crown gear outer radius
alpha : float
Pressure angle in degrees, industry standard is 20°

Returns
-------
cq.Workplane
Returns the tooth gap solid in a cq.Workplane using eachpoint method
"""

alpha = radians(alpha)
pitch = pi*m
P = (pitch/4 , 0)
A = (r, P[0] + m*sin(alpha), m*cos(alpha))
B = (r, P[0] - 1.25*m*sin(alpha), -1.25*m*cos(alpha))
C = (r, -P[0] + 1.25*m*sin(alpha), -1.25*m*cos(alpha))
D = (r, -P[0] - m*sin(alpha), m*cos(alpha))

edge = cq.Workplane("XZ", origin=(0,0,-1.25*m*cos(alpha))).line(0,2.25*m*cos(alpha))
U = edge.val().endPoint()
V = edge.val().startPoint()
profile = cq.Workplane("XY").polyline([A,B,C,D,A]).wire()
faces_to_shell = [cq.Face.makeFromWires(profile.val())]
shell_wires = []
shell_wires.append(
cq.Wire.assembleEdges([
cq.Edge.makeLine(cq.Vector(A),
cq.Vector(D)),
cq.Edge.makeLine(cq.Vector(D),
cq.Vector(U)),
cq.Edge.makeLine(cq.Vector(U),
cq.Vector(A)),
]))
shell_wires.append(
cq.Wire.assembleEdges([
cq.Edge.makeLine(cq.Vector(A),
cq.Vector(U)),
cq.Edge.makeLine(cq.Vector(U),
cq.Vector(V)),
cq.Edge.makeLine(cq.Vector(V),
cq.Vector(B)),
cq.Edge.makeLine(cq.Vector(B),
cq.Vector(A)),
]))
shell_wires.append(
cq.Wire.assembleEdges([
cq.Edge.makeLine(cq.Vector(B),
cq.Vector(V)),
cq.Edge.makeLine(cq.Vector(V),
cq.Vector(C)),
cq.Edge.makeLine(cq.Vector(C),
cq.Vector(B)),
]))
shell_wires.append(
cq.Wire.assembleEdges([
cq.Edge.makeLine(cq.Vector(C),
cq.Vector(V)),
cq.Edge.makeLine(cq.Vector(V),
cq.Vector(U)),
cq.Edge.makeLine(cq.Vector(U),
cq.Vector(D)),
cq.Edge.makeLine(cq.Vector(D),
cq.Vector(C)),
]))

U = edge.val().endPoint()
V = edge.val().startPoint()

for wire in shell_wires:
faces_to_shell.append(cq.Workplane("XY").interpPlate(cq.Workplane("XY", obj=wire)).val())
shell = cq.Shell.makeShell(faces_to_shell)
tooth = cq.Solid.makeSolid(shell)
tooth = tooth.translate(cq.Vector(0,0,-m*cos(alpha)))

return self.eachpoint(lambda loc: tooth.located(loc), True)
def register_cutter_objects():
cq.Workplane._make_rack_tooth_gap = _make_rack_tooth_gap
cq.Workplane._make_crown_gear_tooth_gap = _make_crown_gear_tooth_gap
cq.Workplane._make_bevel_tooth_gap_wire = _make_bevel_tooth_gap_wire
65 changes: 65 additions & 0 deletions plugins/gear_generator/gear_generator/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from math import cos, sin, radians
import cadquery as cq
def involute(r, sign = 1):
"""
Defines an involute curve to create the flanks of the involute gears

Parameters
----------
r : float
Radius of the involute (for a gear it's the pitch radius)
sign : positive or negative int
To draw the involute in positive or negative direction

Returns
-------
function
Returns a function to be used in cq.Workplane parametricCurve function
"""
def curve(t):
x = r*(cos(t) + t*sin(t))
y = r*(sin(t) - t*cos(t))
return x,sign*y
return curve

def test_bevel_parameters(m, z, b, r_inner, delta, alpha, phi, clearance, r_f_equiv, r_b_equiv):
"""
Test the provided parameters to see if they lead to a valid bevel gear

Giving the way bevel gears are made in this plugin, there is parameters combinaison that leads
to an unvalid bevel gear geometry.

This function aims to provide more informations to the user by raising more understandables errors
that the ones OCP raises.

"""
if z % 2 != 0:
raise ValueError(f"Number of teeths z must be even, try with {z-1} or {z+1}")
if r_b_equiv < r_f_equiv:
raise ValueError(f"Base radius < root radius leads to undercut gear. Undercut gears are not supported.\nTry with different values of parameters m, z or alpha")
h_f = 1.25*m
r_f_inner = r_inner - h_f*cos(delta)
clearance_max = r_f_inner / sin(phi)
if clearance > clearance_max:
raise ValueError(f"Too much clearance, for this set of parameters clearance must be <= {round(clearance_max,3)}")

def rotate_vector_2D(vector, angle):
"""
Rotates a 2D cq.Vector

Parameters
----------
vector : cq.Vector
Vector to be rotated
angle : float
The angle in degrees

Returns
-------
cq.Vector
Returns a vector rotated by the specified angle
"""
angle = radians(angle)
x = cos(angle)*vector.x - sin(angle)*vector.y
y = sin(angle)*vector.x + cos(angle)*vector.y
return cq.Vector((x,y))
Loading