cookidooAI/joints.md

22 KiB
Executable File
Raw Permalink Blame History

Joints

Joints enable Solid and Compound objects to be arranged relative to each other in an intuitive manner with the same degree of motion that is found with the equivalent physical joints.

Joints always work in pairs a Joint can only be connected to another Joint as follows:

Joint Type Connects to Example
BallJoint RigidJoint Gimbal
CylindricalJoint RigidJoint Screw
LinearJoint RigidJoint, RevoluteJoint Slider or Pin Slot
RevoluteJoint RigidJoint Hinge
RigidJoint RigidJoint Fixed

Objects may have many joints bound to them, each with an identifying label. All Joint objects have a symbol property that can be displayed to help visualize their position and orientation (the ocp-vscode viewer has built-in support for displaying joints).

Note: If joints are created within the scope of a BuildPart builder, the to_part parameter need not be specified. The builder will, on exit, automatically transfer the joints created in its scope to the part created.

The following sections provide more detail on the available joints and describe how they are used.


Rigid Joint

A rigid joint positions two components relative to each other with no freedom of movement. When a RigidJoint is instantiated, it is assigned a label, a part to bind to (to_part), and a joint_location which defines both the position and orientation of the joint (see Location) as follows:

RigidJoint(label="outlet", to_part=pipe, joint_location=path.location_at(1))

Once a joint is bound to a part this way, the connect_to() method can be used to reposition another part relative to self (which stays fixed) as follows:

pipe.joints["outlet"].connect_to(flange_outlet.joints["pipe"])

Note: Within a part, all of the joint labels must be unique.

The connect_to() method only does a one-time re-position of a part and does not bind them in any way; however, putting them into an Assembly will maintain their relative locations, as will combining parts with boolean operations or within a BuildPart context.

Example: Connecting Flanges to a Pipe

Consider the following code where flanges are attached to the ends of a curved pipe:

import copy
from build123d import *
from bd_warehouse.flange import WeldNeckFlange
from bd_warehouse.pipe import PipeSection
from ocp_vscode import *

flange_inlet = WeldNeckFlange(nps="10", flange_class=300)
flange_outlet = copy.copy(flange_inlet)

with BuildPart() as pipe_builder:
    # Create the pipe
    with BuildLine():
        path = TangentArc((0, 0, 0), (2 * FT, 0, 1 * FT), tangent=(1, 0, 0))
    with BuildSketch(Plane(origin=path @ 0, z_dir=path % 0)):
        PipeSection("10", material="stainless", identifier="40S")
    sweep()

    # Add the joints
    RigidJoint(label="inlet", joint_location=-path.location_at(0))
    RigidJoint(label="outlet", joint_location=path.location_at(1))

# Place the flanges at the ends of the pipe
pipe_builder.part.joints["inlet"].connect_to(flange_inlet.joints["pipe"])
pipe_builder.part.joints["outlet"].connect_to(flange_outlet.joints["pipe"])

show(pipe_builder, flange_inlet, flange_outlet, render_joints=True)

Key Observations:

  • The locations of the joints are determined by the location_at() method.
  • The - (negate) operator is used to reverse the direction of the location without changing its position.
  • The WeldNeckFlange class predefines two joints (one at the pipe end and one at the face end), which are visualized when render_joints=True is set in the viewer.

API Reference

class RigidJoint

class RigidJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None)

A rigid joint fixes two components to one another.

Parameters:

  • label (str): Joint label.
  • to_part (Union[Solid, Compound], optional): Object to attach joint to.
  • joint_location (Location): Global location of joint.

Variables:

  • relative_location (Location): Joint location relative to bound object.

Methods

connect_to

connect_to(other: BallJoint, *, angles: Rotation | tuple[float, float, float] | None = None, **kwargs)
connect_to(other: CylindricalJoint, *, position: float | None = None, angle: float | None = None)
connect_to(other: LinearJoint, *, position: float | None = None)
connect_to(other: RevoluteJoint, *, angle: float | None = None)
connect_to(other: RigidJoint)

Connect the RigidJoint to another Joint.

  • Parameters:
    • other (Joint): Joint to connect to.
    • angle (float, optional): Angle in degrees. Defaults to range min.
    • angles (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
    • position (float, optional): Linear position. Defaults to linear range min.

relative_to

relative_to(other: BallJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
relative_to(other: CylindricalJoint, *, position: float | None = None, angle: float | None = None)
relative_to(other: LinearJoint, *, position: float | None = None)
relative_to(other: RevoluteJoint, *, angle: float | None = None)
relative_to(other: RigidJoint)

Relative location of RigidJoint to another Joint.

  • Parameters:
    • other (RigidJoint): Relative to joint.
    • angle (float, optional): Angle in degrees. Defaults to range min.
    • angles (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
    • position (float, optional): Linear position. Defaults to linear range min.
  • Raises:
    • TypeError: other must be of a type in: BallJoint, CylindricalJoint, LinearJoint, RevoluteJoint, RigidJoint.

Properties

  • location: Location
    • Location of joint.
  • symbol: Compound
    • A CAD symbol (XYZ indicator) as bound to part.

Revolute Joint

A Revolute Joint functions effectively as a hinge, allowing a component to rotate around a specific axis.

Reference: The Joint Tutorial covers Revolute Joints in detail.

During the instantiation of a RevoluteJoint, there are three additional parameters compared to RigidJoints that allow the circular motion to be fully defined:

  • axis: Defines the line around which rotation occurs.
  • angle_reference: Defines the starting point (0 degrees) for rotation.
  • range: Limits the rotation (min, max).

When using connect_to() with a Revolute Joint, an extra angle parameter is available. This allows you to change the relative position of the joined parts by modifying a single value.

API Reference

class RevoluteJoint

class RevoluteJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), angle_reference: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | None = None, angular_range: tuple[float, float] = (0, 360))

Component rotates around axis like a hinge.

Parameters:

  • label (str): Joint label.
  • to_part (Union[Solid, Compound], optional): Object to attach joint to.
  • axis (Axis): Axis of rotation.
  • angle_reference (VectorLike, optional): Direction normal to axis defining where angles will be measured from. Defaults to None.
  • range (tuple[float, float], optional): (min, max) angle of joint. Defaults to (0, 360).

Variables:

  • angle (float): Current angle of the joint.
  • angle_reference (Vector): Reference vector for angular positions.
  • angular_range (tuple[float, float]): Min and max angular position of joint.
  • relative_axis (Axis): Joint axis relative to the bound part.

Raises:

  • ValueError: If angle_reference is not normal to axis.

Methods

connect_to

connect_to(other: RigidJoint, *, angle: float | None = None)

Connect RevoluteJoint and RigidJoint.

  • Parameters:
    • other (RigidJoint): The joint to connect to.
    • angle (float, optional): Angle in degrees. Defaults to range min.
  • Raises:
    • TypeError: If other is not of type RigidJoint.
    • ValueError: If angle is out of the specified range.

relative_to

relative_to(other: RigidJoint, *, angle: float | None = None)

Relative location of RevoluteJoint to RigidJoint.

  • Parameters:
    • other (RigidJoint): The joint to connect to.
    • angle (float, optional): Angle in degrees. Defaults to range min.
  • Raises:
    • TypeError: If other is not of type RigidJoint.
    • ValueError: If angle is out of the specified range.

Properties

  • location: Location
    • Global location of the joint.
  • symbol: Compound
    • A CAD symbol representing the axis of rotation as bound to the part.

Linear Joint

A Linear Joint constrains a component to move along a single axis, similar to a sliding latch.

Example: Sliding Latch

The code below demonstrates how to generate a latch and a slider, and then connect them using a LinearJoint for the latch and a RigidJoint for the slider.

from build123d import *
from ocp_vscode import *

with BuildPart() as latch:
    # Basic box shape to start with filleted corners
    Box(70, 30, 14)
    end = latch.faces().sort_by(Axis.X)[-1]  # save the end with the hole
    fillet(latch.edges().filter_by(Axis.Z), 2)
    fillet(latch.edges().sort_by(Axis.Z)[-1], 1)
    # Make screw tabs
    with BuildSketch(latch.faces().sort_by(Axis.Z)[0]) as l4:
        with Locations((-30, 0), (30, 0)):
            SlotOverall(50, 10, rotation=90)
        Rectangle(50, 30)
        fillet(l4.vertices(Select.LAST), radius=2)
    extrude(amount=-2)
    with GridLocations(60, 40, 2, 2):
        Hole(2)
    # Create the hole from the end saved previously
    with BuildSketch(end) as slide_hole:
        add(end)
        offset(amount=-2)
        fillet(slide_hole.vertices(), 1)
    extrude(amount=-68, mode=Mode.SUBTRACT)
    # Slot for the handle to slide in
    with BuildSketch(latch.faces().sort_by(Axis.Z)[-1]):
        SlotOverall(32, 8)
    extrude(amount=-2, mode=Mode.SUBTRACT)
    
    # The slider will move align the x axis 12mm in each direction
    LinearJoint("latch", axis=Axis.X, linear_range=(-12, 12))

with BuildPart() as slide:
    # The slide will be a little smaller than the hole
    with BuildSketch() as s1:
        add(slide_hole.sketch)
        offset(amount=-0.25)
    # The extrusions aren't symmetric
    extrude(amount=46)
    extrude(slide.faces().sort_by(Axis.Z)[0], amount=20)
    # Round off the ends
    fillet(slide.edges().group_by(Axis.Z)[0], 1)
    fillet(slide.edges().group_by(Axis.Z)[-1], 1)
    # Create the knob
    with BuildSketch() as s2:
        with Locations((12, 0)):
            SlotOverall(15, 4, rotation=90)
        Rectangle(12, 7, align=(Align.MIN, Align.CENTER))
        fillet(s2.vertices(Select.LAST), 1)
        split(bisect_by=Plane.XZ)
    revolve(axis=Axis.X)
    
    # Align the joint to Plane.ZY flipped
    RigidJoint("slide", joint_location=Location(-Plane.ZY))

# Position the slide in the latch: -12 >= position <= 12
latch.part.joints["latch"].connect_to(slide.part.joints["slide"], position=12)

show(latch.part, slide.part, render_joints=True)

Key Concepts:

  1. LinearJoint Definition: The latch defines a LinearJoint with an axis (Axis.X) and movement limits (linear_range=(-12, 12)).
  2. RigidJoint Definition: The slider uses a RigidJoint with a specific location/orientation (Location(-Plane.ZY)) so the knob points "up".
  3. Connection: The connect_to method links the joints and specifies a position (12mm) which must be within the defined range.
  4. Movement: The slider can be moved by changing the position value. Values outside the linear_range limits will raise an exception.
  5. Orientation: Note that the slide is constructed in a different orientation than the direction of motion, which is handled by the joint definitions.

API Reference

class LinearJoint

class LinearJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), linear_range: tuple[float, float] = (0, inf))

Component moves along a single axis.

Parameters:

  • label (str): Joint label.
  • to_part (Union[Solid, Compound], optional): Object to attach joint to.
  • axis (Axis): Axis of linear motion.
  • range (tuple[float, float], optional): (min, max) position of joint. Defaults to (0, inf).

Variables:

  • axis (Axis): Joint axis.
  • angle (float): Angle of joint.
  • linear_range (tuple[float, float]): Min and max positional values.
  • position (float): Joint position.
  • relative_axis (Axis): Joint axis relative to bound part.

Methods

connect_to

connect_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)
connect_to(other: RigidJoint, *, position: float | None = None)

Connect LinearJoint to another Joint.

  • Parameters:
    • other (Joint): Joint to connect to.
    • angle (float, optional): Angle in degrees. Defaults to range min.
    • position (float, optional): Linear position. Defaults to linear range min.
  • Raises:
    • TypeError: If other is not of type RevoluteJoint or RigidJoint.
    • ValueError: If position is out of range.
    • ValueError: If angle is out of range.

relative_to

relative_to(other: RigidJoint, *, position: float | None = None)
relative_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)

Relative location of LinearJoint to RevoluteJoint or RigidJoint.

  • Parameters:
    • other (Joint): Joint to connect to.
    • angle (float, optional): Angle in degrees. Defaults to range min.
    • position (float, optional): Linear position. Defaults to linear range min.
  • Raises:
    • TypeError: If other is not of type RevoluteJoint or RigidJoint.
    • ValueError: If position is out of range.
    • ValueError: If angle is out of range.

Properties

  • location: Location
    • Location of the joint.
  • symbol: Compound
    • A CAD symbol of the linear axis positioned relative to to_part.

Cylindrical Joint

A CylindricalJoint allows a component to rotate around and move along a single axis, effectively acting like a screw. It combines the functionality of a LinearJoint and a RevoluteJoint.

The connect_to method for these joints accepts both position and angle parameters.

API Reference

class CylindricalJoint

class CylindricalJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), angle_reference: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | None = None, linear_range: tuple[float, float] = (0, inf), angular_range: tuple[float, float] = (0, 360))

Component rotates around and moves along a single axis like a screw.

Parameters:

  • label (str): Joint label.
  • to_part (Union[Solid, Compound], optional): Object to attach joint to.
  • axis (Axis): Axis of rotation and linear motion.
  • angle_reference (VectorLike, optional): Direction normal to axis defining where angles will be measured from. Defaults to None.
  • linear_range (tuple[float, float], optional): (min, max) position of joint. Defaults to (0, inf).
  • angular_range (tuple[float, float], optional): (min, max) angle of joint. Defaults to (0, 360).

Variables:

  • axis (Axis): Joint axis.
  • linear_position (float): Linear joint position.
  • rotational_position (float): Revolute joint angle in degrees.
  • angle_reference (Vector): Reference for angular positions.
  • angular_range (tuple[float, float]): Min and max angular position of joint.
  • linear_range (tuple[float, float]): Min and max positional values.
  • relative_axis (Axis): Joint axis relative to bound part.
  • position (float): Joint position.
  • angle (float): Angle of joint.

Raises:

  • ValueError: If angle_reference must be normal to axis.

Methods

connect_to

connect_to(other: RigidJoint, *, position: float | None = None, angle: float | None = None)

Connect CylindricalJoint and RigidJoint.

  • Parameters:
    • other (Joint): Joint to connect to.
    • position (float, optional): Linear position. Defaults to linear range min.
    • angle (float, optional): Angle in degrees. Defaults to range min.
  • Raises:
    • TypeError: If other is not of type RigidJoint.
    • ValueError: If position is out of range.
    • ValueError: If angle is out of range.

relative_to

relative_to(other: RigidJoint, *, position: float | None = None, angle: float | None = None)

Relative location of CylindricalJoint to RigidJoint.

  • Parameters:
    • other (Joint): Joint to connect to.
    • position (float, optional): Linear position. Defaults to linear range min.
    • angle (float, optional): Angle in degrees. Defaults to range min.
  • Raises:
    • TypeError: If other is not of type RigidJoint.
    • ValueError: If position is out of range.
    • ValueError: If angle is out of range.

Properties

  • location: Location
    • Location of joint.
  • symbol: Compound
    • A CAD symbol representing the cylindrical axis as bound to part.

Ball Joint

A Ball Joint allows a component to rotate around all 3 axes using a gimbal system (3 nested rotations). A common example is a rod end.

Example: Rod End

The following code demonstrates creating a rod end with a threaded shaft and a ball, connecting them via a BallJoint.

from build123d import *
from bd_warehouse.thread import IsoThread
from ocp_vscode import *

# Create the thread so the min radius is available below
thread = IsoThread(major_diameter=6, pitch=1, length=20, end_finishes=("fade", "raw"))
inner_radius = 15.89 / 2
inner_gap = 0.2

with BuildPart() as rod_end:
    # Create the outer shape
    with BuildSketch():
        Circle(22.25 / 2)
        with Locations((0, -12)):
            Rectangle(8, 1)
        make_hull()
        split(bisect_by=Plane.YZ)
    revolve(axis=Axis.Y)
    # Refine the shape
    with BuildSketch(Plane.YZ) as s2:
        Rectangle(25, 8, align=(Align.MIN, Align.CENTER))
        Rectangle(9, 10, align=(Align.MIN, Align.CENTER))
        chamfer(s2.vertices(), 0.5)
    revolve(axis=Axis.Z, mode=Mode.INTERSECT)
    # Add the screw shaft
    Cylinder(
        thread.min_radius,
        30,
        rotation=(90, 0, 0),
        align=(Align.CENTER, Align.CENTER, Align.MIN),
    )
    # Cutout the ball socket
    Sphere(inner_radius, mode=Mode.SUBTRACT)
    # Add thread
    with Locations((0, -30, 0)):
        add(thread, rotation=(-90, 0, 0))
    # Create the ball joint
    BallJoint(
        "socket",
        joint_location=Location(),
        angular_range=((-14, 14), (-14, 14), (0, 360)),
    )

with BuildPart() as ball:
    Sphere(inner_radius - inner_gap)
    Box(50, 50, 13, mode=Mode.INTERSECT)
    Hole(4)
    ball.part.color = Color("aliceblue")
    RigidJoint("ball", joint_location=Location())

rod_end.part.joints["socket"].connect_to(ball.part.joints["ball"], angles=(5, 10, 0))

show(rod_end.part, ball.part, s2)

Key Observations:

  • Limits: Limits are defined during the instantiation of the BallJoint to ensure that the pin or bolt within the rod end does not interfere with the rod end itself.
  • Connection: The connect_to method sets the three angles (angles=(5, 10, 0)), though in this specific example only two might be significant depending on the constraints.

API Reference

class BallJoint

class BallJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None, angular_range: tuple[tuple[float, float], tuple[float, float], tuple[float, float]] = ((0, 360), (0, 360), (0, 360)), angle_reference: Plane = Plane((0, 0, 0), (1, 0, 0), (0, 0, 1)))

A component rotates around all 3 axes using a gimbal system (3 nested rotations).

Parameters:

  • label (str): Joint label.
  • to_part (Union[Solid, Compound], optional): Object to attach joint to.
  • joint_location (Location): Global location of joint.
  • angular_range (tuple[tuple[float, float], ...], optional): X, Y, Z angle (min, max) pairs. Defaults to ((0, 360), (0, 360), (0, 360)).
  • angle_reference (Plane, optional): Plane relative to part defining zero degrees of rotation. Defaults to Plane.XY.

Variables:

  • relative_location (Location): Joint location relative to bound part.
  • angular_range (tuple): X, Y, Z angle (min, max) pairs.
  • angle_reference (Plane): Plane relative to part defining zero degrees.

Methods

connect_to

connect_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)

Connect BallJoint and RigidJoint.

  • Parameters:
    • other (RigidJoint): Joint to connect to.
    • angles (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
  • Raises:
    • TypeError: Invalid other joint type.
    • ValueError: If angles are out of range.

relative_to

relative_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)

Return the relative location from this joint to the RigidJoint of another object.

  • Parameters:
    • other (RigidJoint): Joint to connect to.
    • angles (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
  • Raises:
    • TypeError: Invalid other joint type.
    • ValueError: If angles are out of range.

Properties

  • location: Location
    • Location of joint.
  • symbol: Compound
    • A CAD symbol representing joint as bound to part.