Skip to main content

A wrapper around the 'mechanism' library for the 'Algorithm Folding' lecture @ HPI for creating and transforming linkage mechanisms.

Project description

mechanismaf

A wrapper around the "mechanism" library for the "Algorithm Folding" lecture @ HPI

Why mechanismaf?

mechanismaf is a high-level wrapper around the mechanism library designed for the "Algorithm Folding" lecture at HPI. Its primary goal is to simplify the creation, transformation, and animation of linkage mechanisms by abstracting away the low-level complexities of the underlying library.

The underlying mechanism library is very powerful but also very complicated. For example, when creating a linkage directly with mechanism, you must manually:

  • Define each joint and bar (vector).
  • Set up the loop equations for solving the unknown angles.
  • Specify initial guesses, sweep angles, and other details.
  • Build and manage the animation.

mechanismaf provides a more accessible API that allows you to define your mechanism using simple specifications (lists of bars with coordinates and optional properties) while automatically handling:

  • Joint and vector creation.
  • Grounding, sweep configuration, and loop detection.
  • Geometric transformations (scaling, rotation, and translation).
  • Animation enhancements (injecting bar angles and joint names).

Installation

Install mechanismaf using pip:

pip install mechanismaf

What mechanismaf Does

  • Simplifies Linkage Creation: Define mechanisms by listing bars and their properties instead of manually creating joints, vectors, loops, and initial guesses.
  • Reusable Components: Easily combine and transform mechanism specifications with functions such as transform_spec and combine_specs.
  • Enhanced Animations: Automatically inject text annotations (bar angles and joint names) into your mechanism animations using add_angle_joints_texts.
  • Automatic Parameter Management: Functions like set_style_ground and set_angle_sweep let you adjust properties such as fixed (ground) angles and sweep ranges without dealing with the underlying low-level API.

Exposed Functions

The package exposes a number of functions that make working with mechanisms more straightforward:

  • create_linkage_from_spec(spec, follow_points=None, log_level=logging.INFO, log_file=None): Creates and solves a linkage mechanism from a simplified specification list. This function automatically sets up joints, vectors, loops, and iterations.
  • transform_spec(spec, scale=1.0, origin=(0, 0), rotation_deg=0.0): Transforms a mechanism specification by applying scaling, rotation, and translation to all bar coordinates.
  • combine_specs(*specs): Combines multiple mechanism specifications into a single list, removing duplicate bars.
  • set_style_ground(spec, bar_list, decimal=3): Marks specific bars as ground (fixed) in the specification by setting their style attribute.
  • set_angle_sweep(spec, bar_sweep_dict, decimal=3): Configures custom angle sweep ranges for specified bars in the specification.
  • add_angle_joints_texts(mech, ani, ax): Injects annotations for bar angles and joint names into the animation of a mechanism.

Additional helper functions such as round_coord and transform_follow_points further ease the process of working with coordinates and transformations.

Examples

Creating a Peaucellier–Lipkin Linkage Using the Bare mechanism Library

The following example shows the amount of work needed when using the underlying mechanism library directly:

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
from mechanism import *

# Create Joints
O, A, B, C, D, E = get_joints("O A B C D E")
C.follow, D.follow, E.follow = True, True, True

# Define Bars (Vectors)
OA = Vector((O, A), r=1, theta=0, style='ground')  # ground
AB = Vector((A, B), r=1)                           # input
BC = Vector((B, C), r=np.sqrt(2))
CD = Vector((C, D), r=np.sqrt(2))
DE = Vector((D, E), r=np.sqrt(2))
EB = Vector((E, B), r=np.sqrt(2))
OC = Vector((O, C), r=np.sqrt(10))  # pivot about O
OE = Vector((O, E), r=np.sqrt(10))  # pivot about O

# Define the loop equations (6 unknown angles, 3 loops)
def loops(x, input_angle):
    """
    x = [θ_BC, θ_CD, θ_DE, θ_EB, θ_OC, θ_OE]
    input_angle = angle for AB (our driven link)
    """
    theta_bc, theta_cd, theta_de, theta_eb, theta_oc, theta_oe = x

    temp = np.zeros((3, 2))

    # Loop1: O->A->B->C->O
    temp[0] = OA() + AB(input_angle) + BC(theta_bc) - OC(theta_oc)

    # Loop2: O->C->D->E->O
    temp[1] = OC(theta_oc) + CD(theta_cd) + DE(theta_de) - OE(theta_oe)

    # Loop3: B->C->D->E->B
    temp[2] = BC(theta_bc) + CD(theta_cd) + DE(theta_de) + EB(theta_eb)

    return temp.flatten()

# Build "Up-and-Down" Angles for sweeping the mechanism.
angles_up   = np.linspace(-25, 25, 50)   # 50 points
angles_down = np.linspace(25, -25, 50)    # 50 points
angles_full = np.concatenate([angles_up, angles_down[1:]])
angles_rad = np.deg2rad(angles_full)

# Initial guess for the 6 unknown angles
guess0 = np.deg2rad([45, -45, -135, 135, 18, -18])

# Construct the Mechanism
mechanism = Mechanism(
    vectors=(OA, AB, BC, CD, DE, EB, OC, OE),
    origin=O,
    loops=loops,
    pos=angles_rad,
    guess=(guess0,)
)

# Solve and animate
mechanism.iterate()
ani, fig, ax = mechanism.get_animation(cushion=1.0)
ax.set_title("Peaucellier–Lipkin linkage")
plt.show()

Creating a Peaucellier–Lipkin Linkage Using mechanismaf

With mechanismaf, creating the same mechanism is much simpler. You simply define a specification that describes the bars and their properties:

#!/usr/bin/env python3

from mechanismaf import create_linkage_from_spec
import matplotlib.pyplot as plt

if __name__ == "__main__":
    spec = [
        ["bar", (0.0, 0.0), (2, 1)],
        ["bar", (0.0, 0.0), (2, -1)],
        ["bar", (2, 1), (1, 0)],
        ["bar", (1, 0), (2, -1)],
        ["bar", (2, -1), (3, 0)],
        ["bar", (3, 0), (2, 1)],
        ["bar", (0, 0), (0.5, 0.0), {"style": "ground", "angle": 0}],
        ["bar", (0.5, 0.0), (1.0, 0.0), {"angle_sweep": (-25, 25, 50)}],
    ]

    follow_points = [(2, 1), (2, -1), (3, 0)]
    mechanism = create_linkage_from_spec(spec, follow_points=follow_points)
    ani, fig, ax = mechanism.get_animation(cushion=1.0)
    ax.set_title("Peaucellier–Lipkin linkage")
    plt.show()

Further Examples

Create & Use Resuable Components

This example will show you how to create reusable components and how to use them. Let's define a simple rectangle:

from mechanismaf import (
    create_linkage_from_spec,
)
import matplotlib.pyplot as plt

spec = [
        ["bar", (0, 0), (0, 1), {"style": "ground"}],
        ["bar", (0, 1), (1, 1), {"angle_sweep": (20, -20, 20)}],
        ["bar", (1, 1), (1, 0)],
        ["bar", (1, 0), (0, 0)],
    ]

mech = create_linkage_from_spec(spec)
ani, fig, ax = mech.get_animation()
ax.set_title("Simple rectangle")
plt.show()

To make this rectangle reusable, all we need to do is to create a function that defines our bars and calls the functions to tranform the spec. Please note that you should remove the ground and angle_sweep bar and set their role later:

from mechanismaf import (
    set_style_ground,
    set_angle_sweep,
    transform_spec,
    transform_follow_points
)

def create_rectangle(
    scale=1.0,
    origin=(0, 0),
    rotation_deg=0.0,
    bars_to_ground=None,
    sweep_bars_dict=None,
    base_follow_points=None
):
    # Bare-bones spec (no ground, no angle_sweep)
    base_spec = [
        ["bar", (0, 0), (0, 1)],
        ["bar", (0, 1), (1, 1)],
        ["bar", (1, 1), (1, 0)],
        ["bar", (1, 0), (0, 0)],
    ]

    # Optionally set bars as ground
    if bars_to_ground:
        set_style_ground(base_spec, bars_to_ground)

    # Optionally set bars to angle_sweep
    if sweep_bars_dict:
        set_angle_sweep(base_spec, sweep_bars_dict)

    # Transform the geometry:
    transformed_spec = transform_spec(base_spec, scale=scale, origin=origin, rotation_deg=rotation_deg)
    
    # Transform follow points (if provided)
    if base_follow_points:
        transformed_follow = transform_follow_points(base_follow_points, scale=scale, 
                                                       rotation_deg=rotation_deg, origin=origin)
    else:
        transformed_follow = None

    return transformed_spec, transformed_follow

We can use this now by adding this snippet that actually creates the spec:

from mechanismaf import (
    create_linkage_from_spec,
    add_angle_joints_texts
)
import matplotlib.pyplot as plt

bars_ground1 = [((0.0, 0.0), (0.0, 1.0))]
bars_sweep_dict = {
    ((0.0, 1.0), (1, 1)): (-30, 30, 30),
}
base_follow_points1 = [(1, 1)]

rectangle, follow_points1 = create_rectangle(
    scale=2.0,
    rotation_deg=60,
    bars_to_ground=bars_ground1,
    sweep_bars_dict=bars_sweep_dict,
    base_follow_points=base_follow_points1
)

mech = create_linkage_from_spec(rectangle, follow_points=follow_points1)
ani, fig, ax = mech.get_animation()
ax.set_title("Reusable rectangle")
add_angle_joints_texts(mech, ani, ax)
ani
plt.show()

This code now calls the function to create the rectangle, scales it, rotates it etc. We can also create a second rectangle on the other side as well:

from mechanismaf import (
    combine_specs,
    create_linkage_from_spec,
    add_angle_joints_texts
)
import matplotlib.pyplot as plt

bars_ground1 = [((0.0, 0.0), (0.0, 1.0))]
bars_sweep_dict = {
    ((0.0, 1.0), (1, 1)): (-30, 30, 30),
}
base_follow_points1 = [(1, 1)]

rectangle, follow_points1 = create_rectangle(
    scale=2.0,
    rotation_deg=60,
    bars_to_ground=bars_ground1,
    sweep_bars_dict=bars_sweep_dict,
    base_follow_points=base_follow_points1
)

rectangle2, follow_points2 = create_rectangle(
    scale=2.0,
    rotation_deg=-120,
    bars_to_ground=bars_ground1,
    sweep_bars_dict=bars_sweep_dict,
    base_follow_points=base_follow_points1
)

spec=combine_specs(rectangle, rectangle2)
follow_points=follow_points1 + follow_points2
mech = create_linkage_from_spec(spec, follow_points=follow_points)
ani, fig, ax = mech.get_animation()
ax.set_title("Reusable contra-parallelogram")
add_angle_joints_texts(mech, ani, ax)
ani
plt.show()

We now use the combine_spec function to combine the two rectangles into one spec to pass it to mechanismaf.

What You Don't Need to Do with mechanismaf

When using mechanismaf:

  • No Manual Joint/Vector Creation: You do not need to create joints and vectors manually.
  • No Loop Equations: There is no need to write your own loop equations; the library automatically detects loops and sets up the equations.
  • No Initial Guess Management: The mechanism’s unknown angles and sweep parameters are automatically handled.
  • Enhanced Transformations: Functions for transforming and combining specifications allow you to work at a higher level of abstraction.

Extra Features

  • Reusable Components: Easily transform and merge specifications using functions like transform_spec and combine_specs.
  • Animation Annotations: Automatically inject angle and joint annotations into your mechanism animations via add_angle_joints_texts.
  • Parameter Flexibility: Quickly set or update bar properties (such as ground style or sweep ranges) without delving into the underlying mechanism details.

Additional Information

For more details, visit the PyPI project page.

mechanismaf was developed to enable researchers, educators, and students to experiment with and animate linkage mechanisms with minimal boilerplate code. By wrapping the complexities of the underlying mechanism library, it lets you focus on design and analysis rather than implementation details. mechanismaf has been created as part of the HCI project seminar at HPI.

License

mechanismaf is licensed under the MIT license.

Contributing

Contributions, feature requests, and bug reports are welcome! Please open an issue or submit a pull request on the GitHub repository.

Acknowledgements

Special thanks to the developers of the underlying mechanism library and to the HPI community for their support.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mechanismaf-0.1.4.tar.gz (20.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mechanismaf-0.1.4-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file mechanismaf-0.1.4.tar.gz.

File metadata

  • Download URL: mechanismaf-0.1.4.tar.gz
  • Upload date:
  • Size: 20.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.21

File hashes

Hashes for mechanismaf-0.1.4.tar.gz
Algorithm Hash digest
SHA256 1b0efecf1ac973a374ae9c70820c36ad4434874c19f1ff68accade2c5ca49cb6
MD5 841b496956fa83b94ff8944a48b2e3f1
BLAKE2b-256 af6cfea90359d4cefaff39968dbb00957658eaf138c1f3b4419d7554ed699f5b

See more details on using hashes here.

File details

Details for the file mechanismaf-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: mechanismaf-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 18.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.21

File hashes

Hashes for mechanismaf-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 084ec0b08fecda046ecc0f85e4446df338390fdeac44df595407d0ad7b701705
MD5 8cee12626812515562ac6a30f8ff6672
BLAKE2b-256 fae38bd3fa37bf871c0ef6b33622da083de2ba1586c85c866ddb3a2f30e932a6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page