Designing and creating a Suspended Strandbeest

Note: This GIF has been sped up x 2


I took one look at Theo Jansen’s Strandbeest moving machines and thought to myself, “Wow I’d like to recreate that”. And recreate I did, but on a smaller scale. I also inadvertently made them less creepy as well. Here’s a video showing the originals models in movement. Pretty cool, right?

Theo Jansen has also designed several more cool machines, do check them out on the official Strandbeest website [3].  

According to the Strandbeest website and this paper [6], the model adheres to a group of Holy Numbers. The model and its respective Holy Numbers are shown above. The linkage is made up of two 3 bar linkages (our triangles) and 2 four bar linkages. [2]

Image obtained from [2]

The overall trajectory of the end-point forms a specific shape, known as the locus. Apparently, the locus’ phases have dedicated names, shown above. The set of Holy Numbers affect the shape of the locus. One can optimize the locus’ shape to fit their requirements. For instance, if you want more contact between the Strandbeest’s legs and the floor, you can go about increasing the length of the stride phase. To do this you will have to play around with the link lengths. But be careful, changing too much without giving much thought may result in unfeasible configurations. Try it out on this Java Applet [1].

Position Analysis, Velocity Analysis were done in papers [2] and [4]. In my case, because I wanted to understand what the trajectories looked like for each joint, I also carried out position analysis. I used the OpenSCAD code given in [5] and adapted that in C++. Using the graphics.h header file I was able to animate the model’s movement. I used the same naming convention as the one in this paper [4]. The annotated linkage was shown previously. Each point’s coordinates were found using the Law of Cosines method. The equations are given in the C++ code at the end of the post.


The locus' shape is shown in red.

While Theo Jansen used PVC pipes and a blowtorch to create his machines, I used PLA and bolts. The first version of the Strandbeest that I created was powered by a standard 3 V DC motor. The original Strandbeest uses windpower to move. The DC motor rotated a wheel which would originally have been the crank. I scaled down the linkages’ lengths to make the end model tiny. Scaling down only works if you scale down ALL the linkages with the same factor.


There were some issues with this. Firstly, you have to be mindful of the fact that the linkages will get in the way of each other if they’re not spaced out properly. Which unfortunately was something I hadn’t thought of at the time. Secondly, the joint C has to be fixed properly. In this case, I stuck the bolt in a cardboard, but a more sturdy alternative would have been better.

The second design involved creating 2 Jansen linkages suspended together. One would rotate the wheel, and both would start moving. Ideally, you can place them out of phase with respect to one another, so that the motion looks more reminiscent of somebody walking. This time I took into account the spacing of the different linkages.




I used M3 nuts and bolts for all the holes, except for the joint at the top. I used an M5 8mm long bolt instead. A wooden 5 mm diameter stick served as the central shaft between the two linkages and the middle wheel. 

Completed one side of the assembly.

Lodging the wooden stick through. Not the easiest of tasks!

Because I felt that the middle wheel didn't grip the wooden stick well enough, I had to place junk 3d printed material between the holes to increase friction. (Pictured Below)



Here is the final assembled design:





Included are the links to the STL on Thingiverse.

C++ Code if you want to play around with different link lengths:


/* Created by roboticsbytk
Blog: roboticsbytk.blogspot.com
Date: 29/10/2020
This code serves to animate the motion of a Strandbeest linkage.

This code was adapted from OPENSCAD's User Manual (https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Example/Strandbeest ) for C++.
My contribution is to simulate it using graphics.h and printing out the coordinates to a text file.
All the equations were obtained from the aforementioned link.
*/


#include <graphics.h>
#include <dos.h>
#include <math.h>
#define PI 3.14159265
#include <iostream>
#include <stdlib.h>
#include <fstream>

int main()
{

    //Initializes the window
    int i, j = 0, gd = DETECT, gm;

    initgraph(&gd,&gm,"C:\\TC\\BGI");

    settextstyle(DEFAULT_FONT,HORIZ_DIR,2);
    outtextxy(25,240,"Press Any button");

    getch(); //Only starts animation when user presses any key

    cleardevice(); //clears screen

    //////calculation///

    //If you want to scale the linkage's lengths by a certain factor
    //change this variable
    float magn=2;
    //Stores the XY coordinates in all the float variables
    float x_o,y_o,x_a,y_a,x_b,y_b,x_c,y_c,x_f,y_f,x_p,y_p,x_d,y_d,x_e,y_e,prev_x,prev_y;
    float l_0,l_1,l_2,l_3,l_4,l_5,l_6,l_7,l_8,l_9,l_10,l_11,l_0x,l_0y;
    float theta_1;

    //Defines the origin
    x_o=200;
    y_o=100 ;

    //These two variables are used to store the previous coordinates of the
    //point who's trajectory you want to plot
    prev_x=x_o;
    prev_y=y_o;

    //The linkage lengths are defined by the set of Holy Numbers
    l_0x=38*magn; //a
    l_0y=7.8*magn; //b
    l_0=38.79226;
    l_1=15*magn;
    l_2=50*magn;
    l_3=41.5*magn;
    l_7=61.9*magn;
    l_4=39.3*magn;
    l_8=40.1*magn;
    l_6=36.7*magn;
    l_5=39.4*magn;
    l_9=55.8*magn;
    l_10=49*magn;
    l_11 =65.7*magn;


    //Defining the original angle value
    theta_1=(11.599*2*PI)/360;

    //These variables are to carry out the Law of Cossines calculation
    float test,temp1,temp2,test2;
    float beta,phi,angle;

    std::ofstream myfile; //Printing to a text file
    myfile.open ("example.txt");
    myfile.clear();
    for(i=0; i<=360*10; i++) //This will show the full rotation 10 times, Feel free to change it

    {
        cleardevice(); //Clear Screen at each loop
                       // If you want to print the locus' shape, comment it out

        theta_1+=(2*PI/360); //Increments the theta_1 value
        if((i%360==0)&&(i!=360*10))

        {
            theta_1=(11.599*2*PI)/360; //Resets to original value at each iteration
            cleardevice(); //Clear Screen after a full rotation

        }

//Calculation of Point A
        l_0=sqrt(l_0x*l_0x+l_0y*l_0y);
        x_a=(l_1*cos(theta_1)+x_o);
        y_a=(+l_1*sin(  theta_1)+y_o);


//Calculation of Point C
        x_c=x_o+l_0x;
        y_c=y_o+l_0y;

//Calculation of Point B

//Uses law of cosine to find the angle value
        temp1=(x_a-x_c); //Delta X
        temp2=(y_a-y_c); //Delta Y
        beta=atan2(temp1,temp2); //Arctan will give respective angle value
        test2=sqrt(temp1*temp1+temp2*temp2); //Note the value will be equivalent to the link length --> l_0
        phi=acos((-test2*test2-l_2*l_2+l_3*l_3)/-abs(2*test2*l_2)); //Using Law of Cosine
        angle=beta+phi-PI/2; //Angle between x axis and the link

        x_b=x_a-l_2*cos(angle);
        y_b=y_a+l_2*sin(angle);

//Calculation of point E

        temp1=(x_b-x_c);
        temp2=(y_b-y_c);
        beta=atan2(temp1,temp2);
        test2=sqrt(temp1*temp1+temp2*temp2);
        phi=acos((-test2*test2-l_9*l_9+l_8*l_8)/-abs(2*test2*l_9));
        angle=beta+phi-PI/2;

        x_e= x_b-l_9*cos(angle);
        y_e= y_b+l_9*sin(angle);


//Calculation of Point D
        temp1=(x_c-x_a);
        temp2=(y_c-y_a);
        beta=atan2(temp1,temp2);
        test2=sqrt(temp1*temp1+temp2*temp2);
        phi=acos((-test2*test2-l_4*l_4+l_7*l_7)/-abs(2*test2*l_7));
        angle=beta+phi-PI/2;

        x_d=x_c-l_4*cos(angle);
        y_d=y_c+l_4*sin(angle);

//Calculation of Point F
        temp1=(x_e-x_d);
        temp2=(y_e-y_d);
        beta=atan2(temp1,temp2);
        test2=sqrt(temp1*temp1+temp2*temp2);
        phi=acos((-test2*test2-l_5*l_5+l_6*l_6)/-abs(2*test2*l_5));
        angle=beta+phi-PI/2;

        x_f=x_e-l_5*cos(angle);
        y_f=y_e+l_5*sin(angle);

//Calculation of Point P

        temp1=(x_f-x_d);
        temp2=(y_f-y_d);
        beta=atan2(temp1,temp2);
        test2=sqrt(temp1*temp1+temp2*temp2);
        phi=acos((-test2*test2-l_11*l_11+l_10*l_10)/-abs(2*test2*l_11));
        angle=beta+phi-PI/2;

        x_p=x_f-l_11*cos(angle);
        y_p=y_f+l_11*sin(angle);


        if(i==0)
        {  //Will not draw the linkage in the first iteration
            //Will store the current P coordinate so that it may be used
            //to plot the locus shape in the next iteration
            prev_x=x_p;
            prev_y=y_p;

        }
        else
        {
            //Prints out the linkage's motion
            //Note each line correspond to an actual linkage
            //From point A to point B will be l_2 etc...
            setcolor(WHITE);
            line(x_o,y_o,x_a,y_a);
            line(  x_a,y_a,    x_b, y_b);
            line(  x_a,y_a,    x_d, y_d);
            line(  x_c,y_c,    x_d, y_d);
            line(  x_c,y_c,    x_e, y_e);
            line(  x_b,y_b,    x_e, y_e);
            line(  x_b,y_b,    x_c, y_c);
            line(  x_e,y_e,    x_f, y_f);
            line(  x_d,y_d,    x_f, y_f);
            line(  x_d,y_d,    x_p, y_p);
            line(  x_f,y_f,    x_p, y_p);

            //Uncomment block of code below to print the locus shape
            //You will also need to comment cleardevice() so that the continuous motion is printed
         /*
            setcolor(RED);
            line( prev_x,prev_y,    x_p, y_p);
            prev_x=x_p;
            prev_y=y_p;
        */
        }

        //Printing the coordinates to a text file so that you can plot it on a graph
        myfile<<x_p<<"  "<<y_p<<std::endl;
    }


    //Print out the final linkage configuration
    setcolor(WHITE);
    line(x_o,y_o,x_a,y_a);
    line(  x_a,y_a,    x_b, y_b);
    line(  x_a,y_a,    x_d, y_d);
    line(  x_c,y_c,    x_d, y_d);
    line(  x_c,y_c,    x_e, y_e);
    line(  x_b,y_b,    x_e, y_e);
    line(  x_b,y_b,    x_c, y_c);
    line(  x_e,y_e,    x_f, y_f);
    line(  x_d,y_d,    x_f, y_f);
    line(  x_d,y_d,    x_p, y_p);
    line(  x_f,y_f,    x_p, y_p);


    myfile.close(); //Close text file
    getch(); //User will press any key to close screen
    closegraph();
    return 0;
}



References Used:

[1] https://javalab.org/en/theo_jansen_en/

[2] Mohsenizadeh, M., & Zhou, J. (2015). Kinematic analysis and simulation of Theo Jansen mechanism (Doctoral dissertation, Lamar University).

3] https://www.strandbeest.com/

[4] Moldovan, F., Dolga, V., Ciontos, O., & Pop, C. (2011). Cad design and analytical model of a twelve bar walking mechanism. University" Politehnica" of Bucharest Scientific Bulletin, Series D: Mechanical Engineering73(2), 35-48.

[5] https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Example/Strandbeest

[6] Wang, C. Y., & Hou, J. H. (2018). Analysis and Applications of Theo Jansen's Linkage Mechanism-Theo Jansen's Linkage Mechanism on Kinetic Architecture.


Comments

Popular posts from this blog

Fixing the "A software problem has caused Meshmixer to close unexpectedly" Problem

Making an 8DOF Quadruped

Digital Sculpting with MeshMixer...