*Note that there is now a mostly-finished web version of this software.*

A screenshot of the Peaucellier-Lipkin linkage, the first planar linkage to convert circular motion into linear motion. Invented in 1864, it was used in steam engines to convert linear piston motion into rotation.

A Transformable Penrose Tiling. Read more about these linkages here.

A linkage from wikipedia: "Simple linkages are capable of producing complicated motion."

This page provides instructions and Python source code for simulating the behavior of mechanical linkages using Rigidity theory. The software was written to simulate the behavior of transformable Penrose tilings, but is general enough to simulate many planar linkages.

This software requires two very useful Python libraries, Numpy for the linear algebra and PyOpenGL and PIL for the graphics. Once you've installed these, you can download the source code for this software and some example linkages at:

The main program is the file `main.py`; when run it prints its usage to the console, which is:

usage: python main.py [<linkage-file> [<step-size=1> [<max-step=1>]]] click to add vertices click to (de)select a vertex and middle-click (alt-click) another vertex to add an edge click to (de)select an edge and middle-click (alt-click) an adjacent edge to fix their angle right-click (control-click) to place or remove the attractor, which attracts the selected vertex press 'f' to fix the selected vertex press 'd' to delete the selected component press 'c' to clear everything away press 'l' to load from saved_linkage.txt press 's' to save to saved_linkage.txt press 'v' to cycle through viewing options press 'i' to toggle information display press 'm' to maximize/minimize to/from fullscreen press 'p' to print image to screenshot.png press 'r' to toggle motion recording to screenshot0000.png through screenshot9999.png

Also see the Transformable Penrose Tilings, which include linkage files this software can load and simulate.

For example, if you download the second-order transformable Penrose linkage penrose2t.txt, you can run it with:

python main.py penrose2t.txt 10

(the step-size=10 is unnecessary, but makes the software use coarser numerical integration, running faster on a complex linkage like this)

**Left-clicking** creates vertices. A single unconstrained vertex has 2 degrees of freedom in the plane, corresponding to its position. Thus there are 2 different shades of green vector emerging from the vertex, showing a basis of the space of possible velocities in the system:

**Left-clicking on a point** selects it; **middle-clicking (alt-clicking) on another point** connects the two points with a rigid rod. Two points connected by a rod form the simplest rigid linkage, which has 3 degrees of freedom, corresponding to its position and orientation:

Indeed, every unconstrained rigid linkage has 3 degrees of freedom since its structure is constant, so all that can be varied are its position and orientation. A triangle, for example, is rigid, and thus has only 3 degrees of freedom:

**Left-clicking on an edge** selects it; **middle-clicking (alt-clicking) on an adjacent edge** fixes the angle formed by the two edges. The fixed angle below is entirely equivalent to the triangle above, but I think of the two types of constraints as having different semantics—a rod between vertices, as above, corresponds to a physical rod, whereas a fixed angle, as below, corresponds to a rigid joint (as opposed to the default flexible joints):

**Pressing f** fixes the position of the selected vertex. If you fix two vertices of a linkage, you remove the 'trivial' motions of translation and rotation, leaving only structural degrees of freedom. Thus a triangle with two fixed vertices has zero degrees of freedom:

A quadrilateral with two fixed vertices, on the other hand, has one degree of freedom, and is thus a non-rigid structure. **Right-clicking (control-clicking)** places an 'attractor' point, which the selected vertex attempts to move toward, within the constraints of the linkage. **Pressing t** enables tracking for the selected vertex, so that the path the vertex follows towards the attractor point will be drawn. For example, here is a quadrilateral linkage with tracking enabled for the mobile vertices, and the selected vertex moving towards the gray attractor point:

Note the single shade of green vector emerging from the two mobile vertices in the quadrilateral above. These vectors have the same magnitude and direction because the two vertices are constrained by the linkage to move along congruent circles. The two vertices of the right-angle linkage below, on the other hand, must always have perpendicular velocity directions, and the shorter rod's vertex must always have a smaller velocity magnitude, since it traverses a smaller circle:

The software simulates linkages by creating a *rigidity matrix* relating the vertex velocities to one another. It then solves for the possible velocities, and when an 'attractor' point is placed, the vertices are numerically integrated along these velocities (which are continually recomputed) such that the selected vertex moves most towards the attractor.

Suppose we have a vertex with position ** p_{1}**=(0,0) and another vertex at

The constraint imposed by connecting two vertices with a rigid rod is that the velocities of those vertices *along the rod* must agree, since otherwise the rod would deform. Thus we want
** v_{1}**·(

*A*** v**=0
where

The solution to this matrix equation is the *nullspace* of *A* (found numerically using *singular value decomposition*) which in this case is a 3-dimensional space, since both vertices can have any y-velocity, but must have equal x-velocities (lest the rod deform). The three different shades of green vectors emerging from the vertices correspond to three basis vectors of this space. One can see that the dark green basis is ** v_{a}**=(0,1,0,0), i.e. the arbitrary y-velocity of vertex 1, the light-green basis is

If we fix the position of vertex 1, it adds a new constraint to the rigidity matrix. Specifically, it requires ** v_{1}**=0,
which in terms of scalars is the two equations

*A*=(1,0,-1,0; 1,0,0,0; 0,1,0,0)

This new rigidity matrix has a nullspace of dimension 1, with the one basis vector ** v_{a}**=(0,0,0,1)
corresponding to the arbitrary y-velocity of vertex 2; all other velocities are constrained to zero:

Finally, if we fix the position of vertex 2, the rigidity matrix becomes:

*A*=(1,0,-1,0; 1,0,0,0; 0,1,0,0; 0,0,1,0; 0,0,0,1)

This matrix has a nullspace of dimension zero, which means there are no nonzero velocities satisfying the constraints, so the entire system is fixed in place:

Fixed angles affect the rigidity matrix in a similar way to rods, adding one row to the matrix which constrains the rotational velocities from the fixed angle to be equal. For example, the rigidity matrix for the below right-angle linkage would be:

*A*=(1,0,0,0,0,0; 0,1,0,0,0,0; 1,0,-1,0,0,0; 0,1,0,0,0,-1; 0,0,0,1,1,0)

where the first two rows fix vertex 1, the third and fourth row represent the rods, and the final row represents the fixed angle, saying in this case that *v*_{2y}+*v*_{3x}=0, or equivalently *v*_{3x}=-*v*_{2y}, i.e. an upward motion of vertex 2 must be matched by a leftward motion of vertex 3:

Note that the interface for this software requires adjacent rods to fix an angle, and thus fixing an angle is always equivalent to adding a third rod; mathematically, however, if we had no rods but only a fixed angle, more motion would be possible. In the above example, for instance, if there were no rods but the angle was still fixed, then vertex 2 could move freely to the left and right and similarly vertex 3 could move freely up and down, since those motions wouldn't change the angle.

hrldcpr at gmail com 2007-06-15

updated: 2008-12-28