fastener - parametric threaded fasteners
Many mechanical designs will contain threaded fasteners of some kind, either in a threaded hole or threaded screws or bolts holding two or more parts together. The fastener sub-package provides a set of classes that create many different types of nuts, screws and washers - as follows:
The holes for the screws in this figure were created with an extension of the Workplane
class clearanceHole()
, the nuts
tapHole()
and the central hole
threadedHole()
.
The washers were automatically placed and all components were add to an Assembly in
their correct position and orientations - see
Custom Holes for details.
Here is a list of the classes (and fastener types) provided:
Nut - the base nut class
BradTeeNut
: HilitchiDomedCapNut
: din1587HeatSetNut
: McMaster-Carr, HilitchiHexNut
: iso4033, iso4035, iso4032HexNutWithFlange
: din1665UnchamferedHexagonNut
: iso4036SquareNut
: din557
Screw - the base screw class
ButtonHeadScrew
: iso7380_1ButtonHeadWithCollarScrew
: iso7380_2CheeseHeadScrew
: iso14580, iso7048, iso1207CounterSunkScrew
: iso2009, iso14582, iso14581, iso10642, iso7046HexHeadScrew
: iso4017, din931, iso4014HexHeadWithFlangeScrew
: din1662, din1665PanHeadScrew
: asme_b_18.6.3, iso1580, iso14583PanHeadWithCollarScrew
: din967RaisedCheeseHeadScrew
: iso7045RaisedCounterSunkOvalHeadScrew
: iso2010, iso7047, iso14584SetScrew
: iso4026SocketHeadCapScrew
: iso4762, asme_b18.3
Washer - the base washer class
PlainWasher
: iso7094, iso7093, iso7089, iso7091ChamferedWasher
: iso7090CheeseHeadWasher
: iso7092
See Extending the fastener sub-package for guidance on how to easily add new sizes or entirely new types of fasteners.
The following example creates a variety of different sized fasteners:
import cadquery as cq
from cq_warehouse.fastener import HexNut, SocketHeadCapScrew, SetScrew
MM = 1
IN = 25.4 * MM
nut = HexNut(size="M3-0.5", fastener_type="iso4032")
setscrew = SetScrew(size="M6-1", fastener_type="iso4026",length=10 * MM)
capscrew = SocketHeadCapScrew(size="#6-32", fastener_type="asme_b18.3", length=(1/2) * IN)
Both metric and imperial sized standard fasteners are directly supported by the fastener sub-package although the majority of the fasteners currently implemented are metric.
Many of the fastener standards provide ranges for some of the dimensions - for example a minimum and maximum head diameter. This sub-package generally uses the maximum sizes when a range is available in-order to ensure clearance between a fastener and another part won’t be compromised by a physical part that is within specification but larger than the CAD model.
Threaded parts are complex for CAD systems to create and significantly increase the storage requirements
thus making the system slow and difficult to use. To minimize these requirements all of the fastener
classes have a simple
boolean parameter that when True
doesn’t create actual threads at all.
Such simple parts have the same overall dimensions and such that they can be used to check for fitment
without dramatically impacting performance.
Hint
⌛CQ-editor⌛ You can increase the Preferences→3D Viewer→Deviation parameter to improve performance by slightly compromising accuracy.
All of the fasteners default to right-handed thread but each of them provide a hand
string
parameter which can either be "right"
or "left"
.
Deprecated since version 0.8.0: Previous versions of cq_warehouse required the used of a cq_object
instance variable to access
the CadQuery cad object. Currently all fastener objects are a sub-class of the CadQuery Solid
object and therefore can be used as any other Solid object without referencing cq_object
.
Future versions of cq_warehouse will remove cq_object
entirely.
The following sections describe each of the provided classes.
Nut
As the base class of all other nut and bolt classes, all of the derived nut classes share the same interface as follows:
- class Nut(size, fastener_type, hand='right', simple=True)
Parametric Nut
Base Class used to create standard threaded nuts
- Parameters
size (str) – standard sizes - e.g. “M6-1”
fastener_type (str) – type identifier - e.g. “iso4032”
hand (Literal["right","left"], optional) – thread direction. Defaults to “right”.
simple (bool, optional) – simplify by not creating thread. Defaults to True.
- Raises
ValueError – invalid size, must be formatted as size-pitch or size-TPI
ValueError – invalid fastener_type
ValueError – invalid hand, must be one of ‘left’ or ‘right’
ValueError – invalid size
Each nut instance creates a set of instance variables that provide the CAD object as well as valuable parameters, as follows (values intended for internal use are not shown):
- Variables
tap_drill_sizes (dict) – dictionary of drill sizes for tapped holes
tap_hole_diameters (dict) – dictionary of drill diameters for tapped holes
clearance_drill_sizes (dict) – dictionary of drill sizes for clearance holes
clearance_hole_diameters (dict) – dictionary of drill diameters for clearance holes
info (str) – identifying information
nut_class (class) – the derived class that created this nut
nut_thickness (float) – maximum thickness of the nut
nut_diameter (float) – maximum diameter of the nut
Nut Selection
As there are many classes and types of nuts to select from, the Nut class provides some methods
that can help find the correct nut for your application. As a reminder, to find the subclasses of
the Nut class, use __subclasses__()
:
>>> Nut.__subclasses__()
[<class 'cq_warehouse.fastener.DomedCapNut'>, ...]
Here is a summary of the class methods:
- classmethod Nut.types()
Return a set of the nut types
- Return type
List
[str
]
>>> HexNut.types()
{'iso4033', 'iso4032', 'iso4035'}
- classmethod Nut.sizes(fastener_type)
Return a list of the nut sizes for the given type
- Return type
List
[str
]
>>> HexNut.sizes("iso4033")
['M1.6-0.35', 'M1.8-0.35', 'M2-0.4', 'M2.5-0.45', 'M3-0.45', 'M3.5-0.6', 'M4-0.7', 'M5-0.8', 'M6-1', 'M8-1.25', 'M10-1.5', 'M12-1.75', 'M14-2', 'M16-2', 'M18-2.5', 'M20-2.5', 'M22-2.5', 'M24-3', 'M27-3', 'M30-3.5', 'M33-3.5', 'M36-4', 'M39-4', 'M42-4.5', 'M45-4.5', 'M48-5', 'M52-5']
- classmethod Nut.select_by_size(size)
Return a dictionary of list of fastener types of this size
- Return type
dict
>>> Nut.select_by_size("M6-1")
{<class 'cq_warehouse.fastener.DomedCapNut'>: ['din1587'], <class 'cq_warehouse.fastener.HexNut'>: ['iso4035', 'iso4032', 'iso4033'], <class 'cq_warehouse.fastener.HexNutWithFlange'>: ['din1665'], <class 'cq_warehouse.fastener.UnchamferedHexagonNut'>: ['iso4036'], <class 'cq_warehouse.fastener.SquareNut'>: ['din557']}
Derived Nut Classes
The following is a list of the current nut classes derived from the base Nut class. Also listed is the type for each of these derived classes where the type refers to a standard that defines the nut parameters. All derived nuts inherit the same API as the base Nut class.
BradTeeNut
: HilitchiDomedCapNut
: din1587HeatSetNut
: McMaster-Carr, HilitchiHexNut
: iso4033, iso4035, iso4032HexNutWithFlange
: din1665UnchamferedHexagonNut
: iso4036SquareNut
: din557
Detailed information about any of the nut types can be readily found on the internet from manufacture’s websites or from the standard document itself.
The BradTeeNut
is a compound object that uses multiple CounterSunkScrew
to fix the
nut to the base object. The size of these brads is stored in the nut_data
instance variable and
can be used to place the brads as shown in the
brad_tee_and_heatset_nuts.py
example.
"""
Brad Tee and HeatSet Nuts Example
name: brad_tee_and_heatset_nuts.py
by: Gumyr
date: February 28th 2022
desc: Example of using the BradTee and HeatSet nuts with pushFastenerLocations()
method to align holes.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import cadquery as cq
from cq_warehouse.fastener import BradTeeNut, CounterSunkScrew, HeatSetNut
import cq_warehouse.extensions
MM = 1
# Create the fasteners used in this example
bradtee_nut = BradTeeNut(size="M8-1.25", fastener_type="Hilitchi", simple=False)
brad = CounterSunkScrew(
size=bradtee_nut.nut_data["brad_size"],
length=20 * MM,
fastener_type="iso10642",
simple=False,
)
heatset = HeatSetNut(
size=bradtee_nut.nut_data["brad_size"] + "-Standard",
fastener_type="McMaster-Carr",
simple=True,
)
# Create an empty Assembly to hold all of the fasteners
fastener_assembly = cq.Assembly(None, name="plate")
# Create a simple plate with appropriate holes to house all the fasteners
plate_size = (50 * MM, 50 * MM, 20 * MM)
plate = (
cq.Workplane("XY")
.box(*plate_size, centered=(True, True, False))
.faces(">Z")
.workplane()
.clearanceHole(fastener=bradtee_nut, baseAssembly=fastener_assembly)
.polarArray(
bradtee_nut.nut_data["bcd"] / 2, 0, 360, bradtee_nut.nut_data["brad_num"]
)
.clearanceHole(fastener=brad, baseAssembly=fastener_assembly)
# Place HeatSetNuts for the brads on the bottom of the plate
.pushFastenerLocations(
fastener=brad,
baseAssembly=fastener_assembly,
offset=-plate_size[2],
flip=True,
)
.insertHole(fastener=heatset, baseAssembly=fastener_assembly)
)
print(fastener_assembly.fastenerQuantities())
print(HeatSetNut.sizes("McMaster-Carr"))
if "show_object" in locals():
show_object(plate, name="plate", options={"alpha": 0.8})
show_object(fastener_assembly, name="fastener_assembly")
{'BradTeeNut(Hilitchi): M8-1.25': 1, 'HeatSetNut(McMaster-Carr): M4-0.7': 3, 'CounterSunkScrew(iso10642): M4-0.7x20': 3}
['M2-0.4-Short', 'M2-0.4-Standard', 'M3-0.5-Short', 'M3-0.5-Standard', 'M4-0.7-Short', 'M4-0.7-Standard', 'M5-0.8-Short', 'M5-0.8-Standard']
Note that a HeatSetNut
can only be placed with an insertHole()
method (see the Custom Holes section of more information). Also note that
the size of a HeatSetNut
includes a length component like “-Standard” or “-Short” but this depends
on the type. Use the sizes method to see the valid values.
>>> HeatSetNut.sizes("McMaster-Carr")
['M2-0.4-Short', 'M2-0.4-Standard', 'M3-0.5-Short', 'M3-0.5-Standard', 'M4-0.7-Short', 'M4-0.7-Standard', 'M5-0.8-Short', 'M5-0.8-Standard']
Screw
As the base class of all other screw and bolt classes, all of the derived screw classes share the same interface as follows:
- class Screw(size, length, fastener_type, hand='right', simple=True, socket_clearance=6)
Parametric Screw
Base class for a set of threaded screws or bolts
- Parameters
size (str) – standard sizes - e.g. “M6-1”
length (float) – distance from base of head to tip of thread
fastener_type (str) – type identifier - e.g. “iso4014”
hand (Literal["right","left"], optional) – thread direction. Defaults to “right”.
simple (bool, optional) – simplify by not creating thread. Defaults to True.
socket_clearance (float, optional) – gap around screw with no recess (e.g. hex head) which allows a socket wrench to be inserted. Defaults to 6mm.
- Raises
ValueError – invalid size, must be formatted as size-pitch or size-TPI
ValueError – invalid fastener_type
ValueError – invalid hand, must be one of ‘left’ or ‘right’
ValueError – invalid size
Each screw instance creates a set of properties that provide the Solid CAD object as well as valuable parameters, as follows (values intended for internal use are not shown):
- Variables
tap_drill_sizes (dict) – dictionary of drill sizes for tapped holes
tap_hole_diameters (dict) – dictionary of drill diameters for tapped holes
clearance_drill_sizes (dict) – dictionary of drill sizes for clearance holes
clearance_hole_diameters (dict) – dictionary of drill diameters for clearance holes
nominal_lengths (list[float]) – list of nominal screw lengths
info (str) – identifying information
screw_class (class) – the derived class that created this screw
head_height (float) – maximum height of the screw head
head_diameter (float) – maximum diameter of the screw head
head (Solid) – cadquery Solid screw head as defined by class attributes
The following method helps with hole creation:
- Screw.min_hole_depth(counter_sunk=True)
Minimum depth of a hole able to accept the screw
- Return type
float
Screw Selection
As there are many classes and types of screws to select from, the Screw class provides some methods that
can help find the correct screw for your application. As a reminder, to find the subclasses of the
Screw class, use __subclasses__()
:
>>> Screw.__subclasses__()
[<class 'cq_warehouse.fastener.ButtonHeadScrew'>, ...]
Here is a summary of the class methods:
- classmethod Screw.types()
Return a set of the screw types
- Return type
List
[str
]
>>> CounterSunkScrew.types()
{'iso14582', 'iso10642', 'iso14581', 'iso2009', 'iso7046'}
- classmethod Screw.sizes(fastener_type)
Return a list of the screw sizes for the given type
- Return type
List
[str
]
>>> CounterSunkScrew.sizes("iso7046")
['M1.6-0.35', 'M2-0.4', 'M2.5-0.45', 'M3-0.5', 'M3.5-0.6', 'M4-0.7', 'M5-0.8', 'M6-1', 'M8-1.25', 'M10-1.5']
- classmethod Screw.select_by_size(size)
Return a dictionary of list of fastener types of this size
- Return type
dict
select_by_size(size:str)
: (dict{class:[type,…],} - e.g.:
>>> Screw.select_by_size("M6-1")
{<class 'cq_warehouse.fastener.ButtonHeadScrew'>: ['iso7380_1'], <class 'cq_warehouse.fastener.ButtonHeadWithCollarScrew'>: ['iso7380_2'], ...}
To see if a given screw type has screws in the length you are looking for, each screw class provides a dictionary of available lengths, as follows:
>>> CounterSunkScrew.nominal_length_range["iso7046"]
[3.0, 4.0, 5.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0]
During instantiation of a screw any value of length
may be used; however, only a subset of
the above nominal_length_range is valid for any given screw size. The valid sub-range is given
with the nominal_lengths
property as follows:
>>> screw = CounterSunkScrew(fastener_type="iso7046",size="M6-1",length=12 * MM)
>>> screw.nominal_lengths
[8.0, 10.0, 12.0, 14.0, 16.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0]
Derived Screw Classes
The following is a list of the current screw classes derived from the base Screw class. Also listed is the type for each of these derived classes where the type refers to a standard that defines the screw parameters. All derived screws inherit the same API as the base Screw class.
ButtonHeadScrew
: iso7380_1ButtonHeadWithCollarScrew
: iso7380_2CheeseHeadScrew
: iso14580, iso7048, iso1207CounterSunkScrew
: iso2009, iso14582, iso14581, iso10642, iso7046HexHeadScrew
: iso4017, din931, iso4014HexHeadWithFlangeScrew
: din1662, din1665PanHeadScrew
: asme_b_18.6.3, iso1580, iso14583PanHeadWithCollarScrew
: din967RaisedCheeseHeadScrew
: iso7045RaisedCounterSunkOvalHeadScrew
: iso2010, iso7047, iso14584SetScrew
: iso4026SocketHeadCapScrew
: iso4762, asme_b18.3
Detailed information about any of the screw types can be readily found on the internet from manufacture’s websites or from the standard document itself.
Washer
As the base class of all other washer and bolt classes, all of the derived washer classes share the same interface as follows:
- class Washer(size, fastener_type)
Parametric Washer
Base class used to create standard washers
- Parameters
size (str) – standard sizes - e.g. “M6”
fastener_type (str) – type identifier - e.g. “iso4032”
- Raises
ValueError – invalid fastener_type
ValueError – invalid size
Each washer instance creates a set of properties that provide the Solid CAD object as well as valuable parameters, as follows (values intended for internal use are not shown):
- Variables
clearance_drill_sizes (dict) – dictionary of drill sizes for clearance holes
clearance_hole_diameters (dict) – dictionary of drill diameters for clearance holes
nominal_lengths (list[float]) – list of nominal screw lengths
info (str) – identifying information
washer_class (str) – display friendly class name
washer_diameter (float) – maximum diameter of the washer
washer_thickness (float) – maximum thickness of the washer
Washer Selection
As there are many classes and types of washers to select from, the Washer class provides some methods
that can help find the correct washer for your application. As a reminder, to find the subclasses of
the Washer class, use __subclasses__()
:
>>> Washer.__subclasses__()
[<class 'cq_warehouse.fastener.PlainWasher'>, <class 'cq_warehouse.fastener.ChamferedWasher'>, <class 'cq_warehouse.fastener.CheeseHeadWasher'>]
Here is a summary of the class methods:
- classmethod Washer.types()
Return a set of the washer types
- Return type
List
[str
]
>>> PlainWasher.types()
{'iso7091', 'iso7089', 'iso7093', 'iso7094'}
- classmethod Washer.sizes(fastener_type)
Return a list of the washer sizes for the given type
- Return type
List
[str
]
>>> PlainWasher.sizes("iso7091")
['M1.6', 'M1.7', 'M2', 'M2.3', 'M2.5', 'M2.6', 'M3', 'M3.5', 'M4', 'M5', 'M6', 'M7', 'M8', 'M10', 'M12', 'M14', 'M16', 'M18', 'M20', 'M22', 'M24', 'M26', 'M27', 'M28', 'M30', 'M32', 'M33', 'M35', 'M36']
- classmethod Washer.select_by_size(size)
Return a dictionary of list of fastener types of this size
- Return type
dict
>>> Washer.select_by_size("M6")
{<class 'cq_warehouse.fastener.PlainWasher'>: ['iso7094', 'iso7093', 'iso7089', 'iso7091'], <class 'cq_warehouse.fastener.ChamferedWasher'>: ['iso7090'], <class 'cq_warehouse.fastener.CheeseHeadWasher'>: ['iso7092']}
Derived Washer Classes
The following is a list of the current washer classes derived from the base Washer class. Also listed is the type for each of these derived classes where the type refers to a standard that defines the washer parameters. All derived washers inherit the same API as the base Washer class.
PlainWasher
: iso7094, iso7093, iso7089, iso7091ChamferedWasher
: iso7090CheeseHeadWasher
: iso7092
Detailed information about any of the washer types can be readily found on the internet from manufacture’s websites or from the standard document itself.
Custom Holes
When designing parts with CadQuery a common operation is to place holes appropriate to a specific fastener into the part. This operation is optimized with cq_warehouse by the following three new Workplane methods:
The API for the first three methods are very similar. The fit
parameter is used
for clearance hole dimensions and to calculate the gap around the head of a countersunk screw.
The material
parameter controls the size of the tap hole as they differ as a function of the
material the part is made of. For clearance and tap holes, depth
values of None
are treated
as thru holes. The threaded hole method requires that depth
be specified as a consequence of
how the thread is constructed.
These methods use data provided by a fastener instance (either a Nut
or a Screw
) to both create
the appropriate hole (possibly countersunk) in your part as well as add the fastener to a CadQuery Assembly
in the location of the hole. In addition, a list of washers can be provided which will get placed under the
head of the screw or nut in the provided Assembly.
For example, let’s re-build the parametric bearing pillow block found in the CadQuery Quickstart:
import cadquery as cq
from cq_warehouse.fastener import SocketHeadCapScrew
from cq_warehouse.bearing import SingleRowDeepGrooveBallBearing
import cq_warehouse.extensions
height = 60.0
width = 80.0
thickness = 10.0
padding = 12.0
# make the bearing
bearing = SingleRowDeepGrooveBallBearing(size="M8-22-7", bearing_type="SKT")
# make the screw
screw = SocketHeadCapScrew(
size="M2-0.4", fastener_type="iso4762", length=16, simple=False
)
# make the assembly
pillow_block = cq.Assembly(None, name="pillow_block")
# make the base
base = (
cq.Workplane("XY")
.box(height, width, thickness)
.faces(">Z")
.workplane()
.pressFitHole(bearing=bearing, baseAssembly=pillow_block)
.faces(">Z")
.workplane()
.rect(height - padding, width - padding, forConstruction=True)
.vertices()
.clearanceHole(fastener=screw, baseAssembly=pillow_block)
.edges("|Z")
.fillet(2.0)
)
pillow_block.add(base, name="base", color=cq.Color(162 / 255, 138 / 255, 255 / 255))
print(pillow_block.fastenerQuantities())
# Render the assembly
if "show_object" in locals():
show_object(pillow_block)
Which results in:
The differences between this code and the Read the Docs version are:
screw and bearing dimensions aren’t required
the bearing is created during instantiation of the
SingleRowDeepGrooveBallBearing
classthe screw is created during instantiation of the
SocketHeadCapScrew
classan assembly is created and later the base is added to that assembly
the call to cskHole is replaced with clearanceHole
Not only were the appropriate holes for the bearing and M2-0.4 screws created but an assembly was created to store all of the parts in this project all without having to research the dimensions of the parts.
Note: In this example the simple=False
parameter creates accurate threads on each of the
screws which significantly increases the complexity of the model. The default of simple is True
which models the thread as a simple cylinder which is sufficient for most applications without
the performance cost of accurate threads. Also note that the default color of the pillow block
“base” was changed to better contrast the screws.
The data used in the creation of these holes is available via three instance methods:
>>> screw = CounterSunkScrew(fastener_type="iso7046", size="M6-1", length=10)
>>> screw.clearance_hole_diameters
{'Close': 6.4, 'Normal': 6.6, 'Loose': 7.0}
>>> screw.clearance_drill_sizes
{'Close': '6.4', 'Normal': '6.6', 'Loose': '7'}
>>> screw.tap_hole_diameters
{'Soft': 5.0, 'Hard': 5.4}
>>> screw.tap_drill_sizes
{'Soft': '5', 'Hard': '5.4'}
Note that with imperial sized holes (e.g. 7/16), the drill sizes could be a fractional size (e.g. 25/64) or a numbered or lettered size (e.g. U). This information can be added to your designs with the drafting sub-package.
Screw and Hole Alignment
If a depth
parameter is provided to the hole methods when placing a screw, the screw will
be located in the provided assembly such that the tip of the screw to bottom out in the hole.
This may result in the screw extending above the top surface. For example:
"""
Example of placing a 20mm long screw into a 10mm deep hole
"""
import cadquery as cq
from cq_warehouse.fastener import SocketHeadCapScrew
import cq_warehouse.extensions
MM = 1
screw_alignment_assembly = cq.Assembly()
capscrew = SocketHeadCapScrew(
size="M6-1", length=20 * MM, fastener_type="iso4762", simple=False
)
plate = (
cq.Workplane("XY")
.box(50 * MM, 50 * MM, 20 * MM)
.faces(">Z")
.clearanceHole(
fastener=capscrew,
depth=10 * MM,
counterSunk=False,
baseAssembly=screw_alignment_assembly,
)
)
screw_alignment_assembly.add(plate, color=cq.Color("darkseagreen"))
if "show_object" in locals():
show_object(screw_alignment_assembly, name="screw_alignment_assembly")
Which results in:
If no depth
is provided, the hole will extend through the part and the screw will be
aligned with the surface.
Captive Nuts
The clearanceHole()
method has a captiveNut
parameter that
when used with a hex or square nut will create a hole that captures the nut such that it
can’t spin. Here is an example:
import cadquery as cq
from cq_warehouse.fastener import HexNut, SquareNut
import cq_warehouse.extensions
hex_nut = HexNut(size="M6-1", fastener_type="iso4033")
square_nut = SquareNut(size="M6-1", fastener_type="din557")
test_assembly = cq.Assembly()
block = (
cq.Workplane("XY")
.box(50, 50, 10)
.faces(">Z")
.workplane()
.pushPoints([(-12.5, 0)])
.clearanceHole(
fastener=hex_nut, fit="Loose", captiveNut=True, baseAssembly=test_assembly
)
.pushPoints([(+12.5, 0)])
.clearanceHole(fastener=square_nut, captiveNut=True, baseAssembly=test_assembly)
)
test_assembly.add(block, color=cq.Color("tan"))
if "show_object" in locals():
show_object(test_assembly, name="test_assembly")
Which results in:
The space around the nuts is controlled by the fit
parameter.
Insert Nuts
The insertHole()
is much like the previous three custom hole
methods but creates holes for heat set inserts in plastic parts - commonly used in 3D printing.
- Workplane.insertHole(fastener, fit='Normal', depth=None, baseAssembly=None, clean=True, manufacturingCompensation=0.0)
Insert Hole
Put a hole appropriate for an insert nut at the provided location
For more information on how to use insertHole() see Custom Holes.
- Parameters
fastener (
Nut
) – An insert nut instancefit (
Optional
[Literal
[‘Close’, ‘Normal’, ‘Loose’]]) – one of “Close”, “Normal”, “Loose” which determines clearance hole diameter. Defaults to “Normal”.depth (
Optional
[float
]) – hole depth. Defaults to through part.baseAssembly (
Optional
[Assembly
]) – Assembly to add faster to. Defaults to None.clean (
Optional
[bool
]) – execute a clean operation remove extraneous internal features. Defaults to True.manufacturingCompensation (float, optional) – used to compensate for over-extrusion of 3D printers. A value of 0.2mm will reduce the radius of an external thread by 0.2mm (and increase the radius of an internal thread) such that the resulting 3D printed part matches the target dimensions. Defaults to 0.0.
- Raises
ValueError – insertHole only accepts fasteners of type HeatSetNut
- Return type
T
- Returns
the shape on the workplane stack with a new clearance hole
Fastener Locations
There are two methods that assist with the location of fastener holes relative to other
parts: fastenerLocations()
and pushFastenerLocations()
.
To aid in the alignment of fasteners fastenerLocations()
scans
the provided Assembly for the given fastener and pushes the Location values onto the CadQuery
Workplane stack. This method provides offset
and flip
options which modify the existing
fastener locations to allow for a fastener to be positioned on the back side of a structure as
shown in the bolt_plates_together.py
example.
"""
Bolt Plates Together Example
name: bolt_plates_together.py
by: Gumyr
date: March 7th 2022
desc: Example of using pushFastenerLocations to align fasteners.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import cadquery as cq
from cq_warehouse.fastener import HexHeadScrew, PlainWasher, HexNutWithFlange
import cq_warehouse.extensions
MM = 1
# Create the fasteners used in this example
hex_bolt = HexHeadScrew(
size="M6-1", length=20 * MM, fastener_type="iso4014", simple=False
)
flanged_nut = HexNutWithFlange(size="M6-1", fastener_type="din1665")
large_washer = PlainWasher(size="M6", fastener_type="iso7093")
# Create an empty Assembly to hold all of the fasteners
fastener_assembly = cq.Assembly(None, name="top")
# Create the top and bottom plates with holes
top_plate_size = (50 * MM, 100 * MM, 5 * MM)
bottom_plate_size = (100 * MM, 50 * MM, 5 * MM)
top_plate = (
cq.Workplane("XY", origin=(0, 0, bottom_plate_size[2]))
.box(*top_plate_size, centered=(True, True, False))
.faces(">Z")
.workplane()
.clearanceHole(
fastener=hex_bolt,
washers=[large_washer],
baseAssembly=fastener_assembly,
counterSunk=False,
)
)
bottom_plate = (
cq.Workplane("XY")
.box(*bottom_plate_size, centered=(True, True, False))
.pushFastenerLocations(
fastener=large_washer,
baseAssembly=fastener_assembly,
offset=-(top_plate_size[2] + bottom_plate_size[2]),
flip=True,
)
.clearanceHole(
fastener=flanged_nut,
baseAssembly=fastener_assembly,
counterSunk=False,
)
)
print(fastener_assembly.fastenerQuantities())
if "show_object" in locals():
show_object(
top_plate, name="top_plate", options={"alpha": 0.8, "color": (170, 0, 255)}
)
show_object(
bottom_plate, name="bottom_plate", options={"alpha": 0.8, "color": (255, 85, 0)}
)
show_object(fastener_assembly, name="fastener_assembly")
{'HexNutWithFlange(din1665): M6-1': 1, 'HexHeadScrew(iso4014): M6-1x20': 1, 'PlainWasher(iso7093): M6': 1}
In more complex situations many Assemblies may be nested together. To cope with this, the Locations are relative to the Assembly provided and shown in the align_fastener_holes.py example.
"""
Align Fastener Holes Example
name: align_fastener_holes.py
by: Gumyr
date: December 11th 2021
desc: Example of using the pushFastenerLocations() method to align cq_warehouse.fastener
holes between to plates in an assembly.
license:
Copyright 2021 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import cadquery as cq
from cq_warehouse.fastener import SocketHeadCapScrew
import cq_warehouse.extensions
# Create the screws that will fasten the plates together
cap_screw = SocketHeadCapScrew(
size="M2-0.4", length=6, fastener_type="iso4762", simple=False
)
# Two assemblies are required - the top will contain the screws
bracket_assembly = cq.Assembly(None, name="top_plate_assembly")
square_tube_assembly = cq.Assembly(None, name="base_plate_assembly")
# --- Angle Bracket ---
# Create an angle bracket and add clearance holes for the screws
angle_bracket = (
cq.Workplane("YZ")
.moveTo(-9, 1)
.hLine(10)
.vLine(-10)
.offset2D(1)
.extrude(10, both=True)
.faces(">Z")
.workplane()
.pushPoints([(5, -5), (-5, -5)])
.clearanceHole(fastener=cap_screw, counterSunk=False, baseAssembly=bracket_assembly)
.faces(">Y")
.workplane()
.pushPoints([(0, -7)])
.clearanceHole(fastener=cap_screw, counterSunk=False, baseAssembly=bracket_assembly)
)
# Add the top plate to the top assembly so it can be placed with the screws
bracket_assembly.add(angle_bracket, name="angle_bracket")
# Add the top plate and screws to the base assembly
square_tube_assembly.add(
bracket_assembly,
name="top_plate_assembly",
loc=cq.Location(cq.Vector(20, 10, 10)),
)
# --- Square Tube ---
# Create the square tube
square_tube = (
cq.Workplane("YZ").rect(18, 18).rect(14, 14).offset2D(1).extrude(30, both=True)
)
# Complete the square tube assembly by adding the square tube
square_tube_assembly.add(square_tube, name="square_tube")
# Add tap holes to the square tube that align with the angle bracket
square_tube = square_tube.pushFastenerLocations(
cap_screw, square_tube_assembly
).tapHole(fastener=cap_screw, counterSunk=False, depth=10)
# Where are the cap screw holes in the square tube?
for loc in square_tube_assembly.fastenerLocations(cap_screw):
print(loc)
# How many fasteners are used in the square_tube_assembly and all sub-assemblies
print(square_tube_assembly.fastenerQuantities())
if "show_object" in locals():
show_object(angle_bracket, name="angle_bracket")
show_object(square_tube, name="square_tube")
show_object(square_tube_assembly, name="square_tube_assembly")
((25.0, 5.0, 12.0), (0.0, -0.0, 0.0))
((15.0, 5.0, 12.0), (0.0, -0.0, 0.0))
((20.0, 12.0, 5.0), (1.5707963267948966, -0.0, 3.141592653589793))
{'SocketHeadCapScrew(iso4762): M2-0.4x6': 3}
Bill of Materials
As previously mentioned, when an assembly is passed into the three hole methods the fasteners
referenced are added to the assembly. A new method has been added to the CadQuery Assembly
class - fastenerQuantities()
- which scans the assembly and returns a dictionary of either:
{fastener: count}, or
{fastener.info: count}
For example, the values for the previous pillow block example are:
>>> print(pillow_block.fastenerQuantities())
{'SocketHeadCapScrew(iso4762): M2-0.4x16': 4}
>>> print(pillow_block.fastenerQuantities(bom=False))
{<cq_warehouse.fastener.SocketHeadCapScrew object at 0x7f90560f3a90>: 4}
Note that this method scans the given assembly and all its children for fasteners. To limit the
scan to just the current Assembly, set the deep=False
optional parameter).
Extending the fastener sub-package
The fastener sub-package has been designed to be extended in the following two ways:
Alternate Sizes
As mentioned previously, the data used to guide the creation of fastener objects is derived
from .csv
files found in the same place as the source code. One can add to the set of standard
sized fasteners by inserting appropriate data into the tables. There is a table for each fastener
class; an example of the ‘socket_head_cap_parameters.csv’ is below:
Size |
iso4762:dk |
iso4762:k |
… |
asme_b18.3:dk |
asme_b18.3:k |
asme_b18.3:s |
|
---|---|---|---|---|---|---|---|
M2-0.4 |
3.98 |
2 |
|||||
M2.5-0.45 |
4.68 |
2.5 |
0.096 |
0.06 |
0.05 |
||
M3-0.5 |
5.68 |
3 |
0.118 |
0.073 |
1/16 |
||
… |
0.118 |
0.073 |
1/16 |
||||
#0-80 |
0.14 |
0.086 |
5/64 |
||||
#1-64 |
|||||||
#1-72 |
|||||||
#2-56 |
The first row must contain a ‘Size’ and a set of ‘{fastener_type}:{parameter}’ values. The parameters are taken from the ISO standards where ‘k’ represents the head height of a screw head, ‘dk’ is represents the head diameter, etc. Refer to the appropriate document for a complete description. The fastener ‘Size’ field has the format ‘M{thread major diameter}-{thread pitch}’ for metric fasteners or either ‘#{guage}-{TPI}’ or ‘{fractional major diameter}-{TPI}’ for imperial fasteners (TPI refers to Threads Per Inch). All the data for imperial fasteners must be entered as inch dimensions while metric data is in millimeters.
There is also a ‘nominal_screw_lengths.csv’ file that contains a list of all the lengths supported by the standard, as follows:
Screw_Type |
Unit |
Nominal_Sizes |
---|---|---|
din931 |
mm |
30,35,40,45,50,55,60,… |
… |
The ‘short’ and ‘long’ values from the first table (not shown) control the minimum and maximum values in the nominal length ranges for each screw.
New Fastener Types
The base/derived class structure was designed to allow the creation of new fastener types/classes. For new fastener classes a 2D drawing of one half of the fastener profile is required. If the fastener has a non circular plan (e.g. a hex or a square) a 2D drawing of the plan is required. If the fastener contains a flange and a plan, a 2D profile of the flange is required. If these profiles or plans are present, the base class will use them to build the fastener. The Abstract Base Class technology ensures derived classes can’t be created with missing components.