3) Kinematic Analysis and Synthesis - RA

The side-view of the mechanism half

spacer

In this section we analyze the kinematics of the automaton mechanism. It is clear that the mobility of the mechanism is 1. We do not describe the gear train in detail since its design is trivial and for any train junction the gear ratio is 1, assuming that there is no energy loss. Thus, we analyze only the arm and leg mechanisms of the robot. Furthermore, we analyze only right side, since the other one is just the inversion which have completely same kinematics. We can split the whole mechanism in three three main parts: two sub-mechanisms of the leg (upper crank-slider, lower slider-crank) and the arm four-bar linkage.


1. Leg crank-slider


Crank-slider sub-mechanism of the leg

spacer


spacer


2. Leg slider-crank


Slider-crank sub-mechanism of the leg

spacer



spacer

3. Arm four-bar linkage


Four-bar linkage of the arm

spacer

Since the four-bar linkage is a mechanism that we have studied in detail throughout the semester, we do not present here the equations for calculating angular positions and velocities, as this would simply be copying formulas from any textbook on the subject. Below, we have provided graphs of all the calculated variables.

spacer

Our mechanism was not aimed at generating any specific speed or force, but simply creating a motion similar to that of a running human. Below you can see graphs of the positions of the end of the arm and leg of the mechanism for a complete revolution of the driven gear.

spacer

We also programmed a full kinematic simulation of the mechanism using the Python language, in order to be able to change design parameters and quickly assess their influence on the motion of the end mechanism. Below, you can see a video of the kinematic simulation of our final design.

Below you can find full listing of the Python program we used to conduct kinematic analysis of our mechanism:

main.my
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation


def crank_slider(a, d, theta_1, theta_2, omega_2):
    theta_4 = np.arctan((a*np.sin(theta_2) + d*np.sin(theta_1)) / ((a*np.cos(theta_2) + d*np.cos(theta_1))))
    theta_4[theta_4 < 0] += np.pi

    c = (a*np.sin(theta_2) + d*np.sin(theta_1)) / (np.sin(theta_4))

    omega_4 = (omega_2*a*np.cos(theta_2 - theta_4)) / c
    dc = (omega_4*c*np.sin(theta_4) - omega_2*a*np.sin(theta_2)) / np.cos(theta_4)

    return theta_4, omega_4, c, dc


def slider_crank(f, g, l, c, theta_4, dc, omega_4):
    h = l + c
    theta_6 = np.arccos((g**2 + h**2 - f**2) / (2*g*h)) + theta_4
    theta_5 = np.arccos((g**2 - f**2 - h**2) / (2*f*h)) + theta_4

    omega_5 = (dc*np.cos(theta_4 - theta_6) - l*omega_4*np.sin(theta_4 - theta_6) \
        - c*omega_4*np.sin(theta_4 - theta_6)) / f*np.sin(theta_6 - theta_5)
    omega_6 = (dc*np.cos(theta_4 - theta_5) - l*omega_4*np.sin(theta_4 - theta_5) \
        - c*omega_4*np.sin(theta_4 - theta_5)) / g*np.sin(theta_5 - theta_6)

    return theta_5, theta_6, omega_5, omega_6


def fourbar(a, b, c, d, theta_2, omega_2, delta):
    K_1 = d / a
    K_2 = d / c
    K_3 = (a**2 - b**2 + c**2 + d**2)/ (2*a*c)

    A = np.cos(theta_2) - K_1 - K_2*np.cos(theta_2) + K_3
    B = - 2*np.sin(theta_2)
    C = K_1 - (K_2 + 1)*np.cos(theta_2) + K_3

    tan_theta_4 = (-B + delta*np.sqrt(B**2 - 4*A*C)) / (2*A)
    theta_4 = 2 * np.arctan(tan_theta_4)

    K_4 = d / b
    K_5 = (c**2 - d**2 - a**2 - b**2) / (2*a*b)

    D = np.cos(theta_2) - K_1 + K_4*np.cos(theta_2) + K_5
    E = -2*np.sin(theta_2)
    F = K_1 + (K_4 - 1)*np.cos(theta_2) + K_5

    tan_theta_3 = (-E + delta*np.sqrt(E**2 - 4*D*F)) / (2*D)
    theta_3 = 2 * np.arctan(tan_theta_3)

    omega_3 = (a / b) * (np.sin(theta_4 - theta_2) / np.sin(theta_3 - theta_4)) * omega_2
    omega_4 = (a / c) * (np.sin(theta_2 - theta_3) / np.sin(theta_4 - theta_3)) * omega_2

    return theta_3, theta_4, omega_3, omega_4


def animate(i, ax, ln_l, ln_a, leg, arm):
    # UPDATE LEG
    A, O4, L_top, L_bot, L_knee, L_A, L_foot = leg

    A_x, A_y = A
    O4_x, O4_y = O4
    L_top_x, L_top_y = L_top
    L_bot_x, L_bot_y = L_bot
    L_knee_x, L_knee_y = L_knee
    L_A_x, L_A_y = L_A
    L_foot_x, L_foot_y = L_foot

    x_l = [0, A_x[i], O4_x[i], L_top_x[i], L_bot_x[i], L_knee_x[i],
           L_A_x[i], L_bot_x[i], L_foot_x[i]]
    y_l = [0, A_y[i], O4_y[i], L_top_y[i], L_bot_y[i], L_knee_y[i],
           L_A_y[i], L_bot_y[i], L_foot_y[i]]
    ln_l.set_xdata(x_l)
    ln_l.set_ydata(y_l)

    # UPDATE ARM
    O5, B, C, O6, D, E = arm

    O5_x, O5_y = O5
    B_x, B_y = B
    C_x, C_y = C
    O6_x, O6_y = O6
    D_x, D_y = D
    E_x, E_y = E

    x_a = [O5_x[i], B_x[i], C_x[i], O6_x[i], D_x[i], E_x[i]]
    y_a = [O5_y[i], B_y[i], C_y[i], O6_y[i], D_y[i], E_y[i]]
    ln_a.set_xdata(x_a)
    ln_a.set_ydata(y_a)

    return ln_l, ln_a


def main() -> int:
    ### LEG ANALYSIS
    a, d = 5, 15 # mm
    omega_2 = 10 # rad / s

    leg2pin = 21
    leg_long = 60
    l = leg_long - leg2pin 

    f, g = 12, 53
    k = 60

    theta_1 = np.deg2rad(90)
    theta_knee = np.deg2rad(45)

    # generate the array of input angles in the global coordinate system
    theta_2 = np.linspace(0, 2*np.pi, 360)[::-1]

    theta_4, omega_4, c, dc = crank_slider(a, d, theta_1, theta_2, omega_2)
    theta_5, theta_6, omega_5, omega_6 = slider_crank(f, g, l, c, theta_4, dc, omega_4)
    
    ### LEG FORWARD KINEMATICS
    O2_x, O2_y = np.zeros(len(theta_2)), np.zeros(len(theta_2))
    O2 = O2_x, O2_y

    A_x, A_y = a * np.cos(theta_2), a * np.sin(theta_2)
    A = A_x, A_y

    O4_x, O4_y = A_x - c * np.cos(theta_4), A_y - c * np.sin(theta_4)
    O4 = O4_x, O4_y

    L_top_x, L_top_y = O4_x + leg2pin * np.cos(theta_4), O4_y + leg2pin * np.sin(theta_4)
    L_top = L_top_x, L_top_y

    L_bot_x, L_bot_y = L_top_x - leg_long * np.cos(theta_4), L_top_y - leg_long * np.sin(theta_4)
    L_bot = L_bot_x, L_bot_y

    L_knee_x, L_knee_y = L_bot_x - f * np.cos(theta_5), L_bot_y - f * np.sin(theta_5)
    L_knee = L_knee_x, L_knee_y

    L_A_x, L_A_y = L_knee_x + g * np.cos(theta_6), L_knee_y + g * np.sin(theta_6)
    L_A = L_A_x, L_A_y

    L_foot_x, L_foot_y = L_bot_x + k * np.cos(theta_5 + theta_knee), L_bot_y + k * np.sin(theta_5 + theta_knee)
    L_foot = L_foot_x, L_foot_y


    ### ARM ANALYSIS
    m, n, p, q = 5, 51.25, 12, 51.25
    t, s = 30 ,35

    theta_7 = theta_1
    theta_8 = theta_2.copy() + np.pi
    theta_arm = np.deg2rad(45)
    theta_elbow = np.deg2rad(-60)
    omega_8 = omega_2

    theta_9, theta_10, omega_9, omega_10 = fourbar(m, n, p, q, theta_8, omega_8, delta=-1)

    theta_8 += theta_7
    theta_9 += theta_7
    theta_10 += theta_7

    ### ARM FORWARD KINEMATICS
    d_gear = 21.25
    O5_x, O5_y = np.zeros(len(theta_2)), np.full(len(theta_2), d_gear)
    O5 = O5_x, O5_y

    B_x, B_y = O5_x + m * np.cos(theta_8), O5_y + m * np.sin(theta_8)
    B = B_x, B_y

    C_x, C_y = B_x + n * np.cos(theta_9), B_y + n * np.sin(theta_9)
    C = C_x, C_y

    # O6_x, O6_y = C_x - p * np.cos(theta_10), C_y - p * np.sin(theta_10)
    # O6 = O6_x, O6_y

    O6_x, O6_y = O5_x + q * np.cos(theta_7), O5_y + q * np.sin(theta_7)
    O6 = O6_x, O6_y

    D_x, D_y = O6_x + t * np.cos(theta_10 + theta_arm), O6_y + t * np.sin(theta_10 + theta_arm)
    D = D_x, D_y

    E_x, E_y = D_x + s * np.cos(theta_10 + theta_arm - theta_elbow), D_y + s * np.sin(theta_10 + theta_arm - theta_elbow)
    E = E_x, E_y


    ### PLOTS
    fig, ax = plt.subplots()
    ax.set_aspect('equal')

    # draw the leg gear 
    inner_r_gear = 5 
    r_gear = d_gear / 2

    inner_leg_circle = plt.Circle((0, 0), radius=inner_r_gear, linewidth=1, fill=False)
    ax.add_artist(inner_leg_circle)

    leg_circle = plt.Circle((0, 0), radius=r_gear, linewidth=3, fill=False)
    ax.add_artist(leg_circle)

    # draw arm gear
    inner_arm_circle = plt.Circle((0, d_gear), radius=inner_r_gear, linewidth=1, fill=False)
    ax.add_artist(inner_arm_circle)

    arm_circle = plt.Circle((0, d_gear), radius=r_gear, linewidth=3, fill=False)
    ax.add_artist(arm_circle)

    # set axis limits
    offset = 5
    x_min = np.min(np.concatenate([O2_x, A_x, O4_x, L_top_x, L_bot_x, L_knee_x,
                                   L_A_x, L_bot_x, L_foot_x,
                                   O5_x, B_x, C_x, O6_x, D_x, E_x])) - offset
    x_max = np.max(np.concatenate([O2_x, A_x, O4_x, L_top_x, L_bot_x, L_knee_x,
                                   L_A_x, L_bot_x, L_foot_x,
                                   O5_x, B_x, C_x, O6_x, D_x, E_x])) + offset
    y_min = np.min(np.concatenate([O2_y, A_y, O4_y, L_top_y, L_bot_y, L_knee_y,
                                   L_A_y, L_bot_y, L_foot_y,
                                   O5_y, B_y, C_y, O6_y, D_y, E_y])) - offset
    y_max = np.max(np.concatenate([O2_y, A_y, O4_y, L_top_y, L_bot_y, L_knee_y,
                                   L_A_y, L_bot_y, L_foot_y,
                                   O5_y, B_y, C_y, O6_y, D_y, E_y])) + offset

    ax.set_xlim([x_min, x_max])
    ax.set_ylim([y_min, y_max])
    ax.set_xlabel(r'$x$')
    ax.set_ylabel(r'$y$')

    # plot the mechanism at the initial position
    x_l = [O2_x[0], A_x[0], O4_x[0], L_top_x[0], L_bot_x[0], L_knee_x[0],
           L_A_x[0], L_bot_x[0], L_foot_x[0]]
    y_l = [O2_y[0], A_y[0], O4_y[0], L_top_y[0], L_bot_y[0], L_knee_y[0],
           L_A_y[0], L_bot_y[0], L_foot_y[0]]
    ln_l, = ax.plot(x_l, y_l, 'ko-', linewidth=3)

    x_a = [O5_x[0], B_x[0], C_x[0], O6_x[0], D_x[0], E_x[0]]
    y_a = [O5_y[0], B_y[0], C_y[0], O6_y[0], D_y[0], E_y[0]]
    ln_a, = ax.plot(x_a, y_a, 'ko-', linewidth=3)

    # animate the mechanism
    leg = A, O4, L_top, L_bot, L_knee, L_A, L_foot
    arm = O5, B, C, O6, D, E
    ani = animation.FuncAnimation(fig, animate, fargs=(ax, ln_l, ln_a, leg, arm),
                                  interval=20, frames=len(theta_2), blit=True)
    writer = animation.FFMpegWriter(fps=30) 
    ani.save('./robot.mp4', writer=writer, dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), c, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$c$, mm')
    plt.title(r'Linear position of slider $c$')
    plt.grid()
    plt.savefig('./figures/c.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), dc, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\dot{c}$, mm/s')
    plt.title(r'Linear speed of slider $c$')
    plt.grid()
    plt.savefig('./figures/dc.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), np.rad2deg(theta_4), 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\theta_c$, deg')
    plt.title(r'Angular position of link $c$')
    plt.grid()
    plt.savefig('./figures/theta_4.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), omega_4, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\omega_c$, rad/s')
    plt.title(r'Angular velocity of link $c$')
    plt.grid()
    plt.savefig('./figures/omega_4.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), np.rad2deg(theta_5), 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\theta_f$, deg')
    plt.title(r'Angular position of link $f$')
    plt.grid()
    plt.savefig('./figures/theta_5.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), omega_5, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\omega_f$, rad/s')
    plt.title(r'Angular velocity of link $f$')
    plt.grid()
    plt.savefig('./figures/omega_5.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), np.rad2deg(theta_6), 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\theta_g$, deg')
    plt.title(r'Angular position of link $g$')
    plt.grid()
    plt.savefig('./figures/theta_6.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), omega_6, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\omega_g$, rad/s')
    plt.title(r'Angular velocity of link $g$')
    plt.grid()
    plt.savefig('./figures/omega_6.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_8), np.rad2deg(theta_9), 'k-', linewidth=2)
    plt.xlabel(r'$\theta_8$, deg')
    plt.ylabel(r'$\theta_n$, deg')
    plt.title(r'Angular position of link $n$')
    plt.grid()
    plt.savefig('./figures/theta_9.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), omega_9, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\omega_n$, rad/s')
    plt.title(r'Angular velocity of link $n$')
    plt.grid()
    plt.savefig('./figures/omega_9.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_8), np.rad2deg(theta_10), 'k-', linewidth=2)
    plt.xlabel(r'$\theta_8$, deg')
    plt.ylabel(r'$\theta_p$, deg')
    plt.title(r'Angular position of link $p$')
    plt.grid()
    plt.savefig('./figures/theta_10.png', dpi=300)
    plt.show()

    plt.plot(np.rad2deg(theta_2), omega_10, 'k-', linewidth=2)
    plt.xlabel(r'$\theta_a$, deg')
    plt.ylabel(r'$\omega_p$, rad/s')
    plt.title(r'Angular velocity of link $p$')
    plt.grid()
    plt.savefig('./figures/omega_10.png', dpi=300)
    plt.show()

    plt.plot(L_foot_x, L_foot_y, 'k-', linewidth=2)
    plt.xlabel(r'$X$, mm')
    plt.ylabel(r'$Y$, mm')
    plt.title(r'Position of the foot tip')
    plt.grid()
    plt.savefig('./figures/foot.png', dpi=300)
    plt.show()

    plt.plot(E_x, E_y, 'k-', linewidth=2)
    plt.xlabel(r'$X$, mm')
    plt.ylabel(r'$Y$, mm')
    plt.title(r'Position of the hand tip')
    plt.grid()
    plt.savefig('./figures/hand.png', dpi=300)
    plt.show()

    return 0


if __name__ == '__main__':
    sys.exit(main())