# Robotic Mechanics and Modeling/Kinematics/Additional Examples for Denavit-Hartenberg Parameters

## Example 1 (Spring '20 - Team 1)

A student is given a homework problem that makes use of the Denavit-Hartenberg Notation. The problem considers two joints where the offset along the previous z-axis to the common normal is 5 cm, the angle about the previous z-axis from the old x-axis to the new x-axis is 60 degrees, the length of the common normal between the two joints is 7 cm and the angle about the common normal, from the old z-axis to the new z-axis is 45 degrees. The student considers the transformation matrix between these joints presented in lecture. He wants to prove that the transformation matrix can be found from a sequence of X and Z translation and rotation matrices.

import numpy as np

d1=5; theta1=60*np.pi/180; a1=7; alpha1=45*np.pi/180

T_manual= np.array([[np.cos(theta1), -np.sin(theta1)*np.cos(alpha1), np.sin(theta1)*np.sin(alpha1), a1*np.cos(theta1)],
[np.sin(theta1), np.cos(theta1)*np.cos(alpha1), -np.cos(theta1)*np.sin(alpha1), a1*np.sin(theta1)],
[0, np.sin(alpha1), np.cos(alpha1), d1],
[0, 0, 0, 1]])


The student begins by manually typing in the entire transformation matrix.

Z_T = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, d1],[0, 0, 0, 1]])

Z_R = np.array([[np.cos(theta1), -np.sin(theta1), 0, 0],
[np.sin(theta1), np.cos(theta1), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])

X_T = np.array([[1, 0 ,0, a1],[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])

X_R = np.array([[1, 0, 0, 0],
[0, np.cos(alpha1), -np.sin(alpha1), 0],
[0, np.sin(alpha1), np.cos(alpha1), 0],
[0, 0, 0, 1]])

Z = np.dot(Z_T,Z_R)
X = np.dot(X_T,X_R)

T = np.dot(Z,X)


Next, the student inputs the Z translation and rotation matrices and the X translation and rotation matrices. The Z matrix is found my multiplying the Z rotation and translation matrices together, and the X matrix is found by calculating the X rotation and translation together. The complete transformation matrix is found by multiplying the Z and X matrices together. Note that these multiplications can all happen in the same step and still yield the same T matrix.

print('T matrix')
print(T_manual)

print('T = Z * X matrix')
print(T)
print('Are these matrices the same?')
print(T==T_manual)


The student prints the results from each matrix to observe that they are exactly the same. The code block below shows the results.

T matrix
[[ 0.5        -0.61237244  0.61237244  3.5       ]
[ 0.8660254   0.35355339 -0.35355339  6.06217783]
[ 0.          0.70710678  0.70710678  5.        ]
[ 0.          0.          0.          1.        ]]
T = Z * X matrix
[[ 0.5        -0.61237244  0.61237244  3.5       ]
[ 0.8660254   0.35355339 -0.35355339  6.06217783]
[ 0.          0.70710678  0.70710678  5.        ]
[ 0.          0.          0.          1.        ]]
Are these matrices the same?
[[ True  True  True  True]
[ True  True  True  True]
[ True  True  True  True]
[ True  True  True  True]]


## Example 2 (Spring '20 - Team 2)

Suppose you have a robotic arm composed of 3 links, joints connecting the links, one fixed joint at the base, and a clamp at the end. Assuming all links share the same pose and given the following: the depth of the previous joint’s z direction to the new common normal as 2 ${\displaystyle \mathrm {m} }$, rotation about the previous joint’s z-axis up to the new common normal as ${\displaystyle \mathrm {10^{o}} }$, length of the common normal as 2 ${\displaystyle \mathrm {m} }$, and angle orientation of the new z-axis as ${\displaystyle \mathrm {10^{o}} }$, find out where the end effector is. Assume the fixed base to be the origin (0,0,0). Plot your results.

import numpy as np
import matplotlib.pyplot as plt

d=2
theta=10*np.pi/180;
a=2
alpha=10*np.pi/180

#Define Denavit-Hartenberg Matrix
T= np.array([[np.cos(theta), -np.sin(theta)*np.cos(alpha), np.sin(theta)*np.sin(alpha), a*np.cos(theta)],
[np.sin(theta), np.cos(theta)*np.cos(alpha), -np.cos(theta)*np.sin(alpha), a*np.sin(theta)],
[0, np.sin(alpha), np.cos(alpha), d],
[0, 0, 0, 1]])


Assign the initial conditions to the variables and compute the location of the joints.

#Define starting Coordinate
End_Coord=np.array([[0,0,0,1]])
End_Coord=End_Coord.T

#Compute position of all joints
J1=End_Coord
J2=np.dot(T,End_Coord)
J3=np.dot(T, np.dot(T,End_Coord))
J4=np.dot(T,np.dot(T, np.dot(T,End_Coord)))

print("The end effector is at location:")
print(J4)


Displaying the location coordinates and plotting the results.

The end effector is at location is:

[1.00063397]
[6.08749557]
[1.        ]]

#Plot
fig=plt.figure()

plt.plot(J1[0], J1[1], 'bo')
plt.plot(J2[0], J2[1], 'ro')
plt.plot(J3[0], J3[1], 'go')
plt.plot(J4[0], J4[1], 'ko')
plt.plot([J1[0], J2[0]],[J1[1], J2[1]], 'b-')
plt.plot([J2[0], J3[0]],[J2[1], J3[1]], 'r-')
plt.plot([J3[0], J4[0]],[J3[1], J4[1]], 'g-')
ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20);


## Example 3 (Spring '20 - Team 3)

A bus driver wants to imagine his stops as joints in a mechanism and the straight line paths that he follows on his route between them as the links in that mechanism. He starts from a local origin. The driver uses conventional Denavit Hartengerg parameters where d is the offset along the previous z axis to the common normal, theta is the angle about the previous z axis, from the old one to the new one, a is the length of the common normal (if assuming that this is a revolute joint, this is the radius about the previous z axis), and alpha is the angle about the common normal from the old z axis to the new z axis.

The bus drive has five different stops on his route. The values of d are 0.1, 0.3, 0.1, 0.12, 0.1 in miles. This vertical motion from the factor d is assumed to be easily reached by the driver. The values of a are 1, 2, 3.25, 1, 4 in miles. The values of alpha are 25, 0, 152, 0, 0 in degrees.  The values of theta are 45, 0, 26, 256, 45 in degrees.

%reset -f
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

d1=0.1; theta1=45*np.pi/180; a1=1; alpha1=25*np.pi/180
d2=0.3; theta2=0*np.pi/180; a2=2; alpha2=0*np.pi/180
d3=0.1; theta3=26*np.pi/180; a3=3.25; alpha3=152*np.pi/180
d4=0.12; theta4=256*np.pi/180; a4=1; alpha4=0*np.pi/180
d5=0.1; theta5=45*np.pi/180; a5=1; alpha5=0*np.pi/180

[np.sin(theta1), np.cos(theta1)*np.cos(alpha1), -np.cos(theta1)*np.sin(alpha1), a1*np.sin(theta1)],
[0, np.sin(alpha1), np.cos(alpha1), d1],
[0, 0, 0, 1]])
[np.sin(theta2), np.cos(theta2)*np.cos(alpha2), -np.cos(theta2)*np.sin(alpha2), a2*np.sin(theta2)],
[0, np.sin(alpha2), np.cos(alpha2), d2],
[0, 0, 0, 1]])
[np.sin(theta3), np.cos(theta3)*np.cos(alpha3), -np.cos(theta3)*np.sin(alpha3), a3*np.sin(theta3)],
[0, np.sin(alpha3), np.cos(alpha3), d3],
[0, 0, 0, 1]])

[np.sin(theta4), np.cos(theta4)*np.cos(alpha4), -np.cos(theta4)*np.sin(alpha4), a4*np.sin(theta4)],
[0, np.sin(alpha4), np.cos(alpha4), d4],
[0, 0, 0, 1]])

[np.sin(theta5), np.cos(theta5)*np.cos(alpha5), -np.cos(theta5)*np.sin(alpha5), a5*np.sin(theta5)],
[0, np.sin(alpha5), np.cos(alpha5), d5],
[0, 0, 0, 1]])

End_Coord=np.array([[0,0,0,1]])
End_Coord=End_Coord.T


Top Down
fig=plt.figure()

plt.plot(x[0], y[0], 'bo')
plt.plot(x[1], y[1], 'ro')
plt.plot(x[2], y[2], 'go')
plt.plot(x[3], y[3], 'ko')
plt.plot(x[4], y[4], 'yo')
plt.plot(x[5], y[5], 'yo')
plt.plot([x[0], x[1]],[y[0], y[1]], 'b-')
plt.plot([x[1], x[2]],[y[1], y[2]], 'r-')
plt.plot([x[2], x[3]],[y[2], y[3]], 'g-')
plt.plot([x[3], x[4]],[y[3], y[4]], 'k-')
plt.plot([x[4], x[5]],[y[4], y[5]], 'y-')
ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20)
ax.set_title('Top-Down Projection',size=20)

XZ Side Projection
fig=plt.figure()

plt.plot(x[0], z[0], 'bo')
plt.plot(x[1], z[1], 'ro')
plt.plot(x[2], z[2], 'go')
plt.plot(x[3], z[3], 'ko')
plt.plot(x[4], z[4], 'yo')
plt.plot(x[5], z[5], 'yo')
plt.plot([x[0], x[1]],[z[0], z[1]], 'b-')
plt.plot([x[1], x[2]],[z[1], z[2]], 'r-')
plt.plot([x[2], x[3]],[z[2], z[3]], 'g-')
plt.plot([x[3], x[4]],[z[3], z[4]], 'k-')
plt.plot([x[4], x[5]],[z[4], z[5]], 'y-')
ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Z',size=20)
ax.set_title('Side 1 Projection',size=20)

YZ Side Projection
fig=plt.figure()

plt.plot(y[0], z[0], 'bo')
plt.plot(y[1], z[1], 'ro')
plt.plot(y[2], z[2], 'go')
plt.plot(y[3], z[3], 'ko')
plt.plot(y[4], z[4], 'yo')
plt.plot(y[5], z[5], 'yo')
plt.plot([y[0], y[1]],[z[0], z[1]], 'b-')
plt.plot([y[1], y[2]],[z[1], z[2]], 'r-')
plt.plot([y[2], y[3]],[z[2], z[3]], 'g-')
plt.plot([y[3], y[4]],[z[3], z[4]], 'k-')
plt.plot([y[4], y[5]],[z[4], z[5]], 'y-')
ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('Y',size=20)
ax.set_ylabel('Z',size=20)
ax.set_title('Side 2 Projection',size=20)

3D Projection of the DH parameters
fig=plt.figure()

ax.plot3D(x[0], y[0], z[0], 'bo')
ax.plot3D(x[1], y[1], z[1], 'ro')
ax.plot3D(x[2], y[2], z[2], 'go')
ax.plot3D(x[3], y[3], z[3], 'ko')
ax.plot3D(x[4], y[4], z[4], 'yo')
ax.plot3D(x[5], y[5], z[5], 'yo')

x1,y1,z1 = np.array([x[0], x[1]]),np.array([y[0], y[1]]),np.array([z[0], z[1]])
x2,y2,z2 = np.array([x[1], x[2]]),np.array([y[1], y[2]]),np.array([z[1], z[2]])
x3,y3,z3 = np.array([x[2], x[3]]),np.array([y[2], y[3]]),np.array([z[2], z[3]])
x4,y4,z4 = np.array([x[3], x[4]]),np.array([y[3], y[4]]),np.array([z[3], z[4]])
x5,y5,z5 = np.array([x[4], x[5]]),np.array([y[4], y[5]]),np.array([z[4], z[5]])

ax.plot_wireframe(x1, y1, z1, color = 'b')
ax.plot_wireframe(x2, y2, z2, color = 'r')
ax.plot_wireframe(x3, y3, z3, color = 'g')
ax.plot_wireframe(x4, y4, z4, color = 'k')
ax.plot_wireframe(x5, y5, z5, color = 'y')

'J1L0',None,size=20)
'J2L1',None,size=20)
'J3L2',None,size=20)
'J4L3',None,size=20)
'J5L4',None,size=20)
'J6L5',None,size=20)

ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20)
ax.set_zlabel('Z',size=20)
ax.view_init(30,-115)


We can also calculate the distance between the first and last bus stop.

d_x = (x[5]-x[1])**2
d_y = (y[5]-y[1])**2
d_z = (z[5]-z[1])**2
d = np.sqrt(d_x + d_y + d_z)
print("The distance between the first and last bus stop is:")
print(d)


The distance between the first and last bus stop is 7.68 miles.

</gallery>

## Example 4 (Spring '20 - Team 4)

You are a worker in a factory that uses robotic arms to move boxes from one conveyor belt to another that is located on the same elevation.  During a quality control check, you have reason to believe that the boxes are taken off the first conveyor belt and not put in the correct second conveyor belt. Given the angles ${\displaystyle \theta =\langle 20,15,45\rangle \ {\mathsf {degrees}}}$ and distances ${\displaystyle {\mathsf {a=}}\langle 1,1,1\rangle \ {\mathsf {meters}}}$ between each link, verify that the boxes are being put in the right location ${\displaystyle \langle 1.93,1.90\rangle \ {\mathsf {meters}}}$

from numpy import cos, sin, pi, array, transpose, dot,round
import matplotlib.pyplot as plt

d1=0; theta1=20*pi/180; a1=1; alpha1=0*pi/180
d2=0; theta2=15*pi/180; a2=1; alpha2=0*pi/180
d3=0; theta3=45*pi/180; a3=1; alpha3=0*pi/180

[cos(theta1), -sin(theta1)*cos(alpha1), sin(theta1)*sin(alpha1), a1*cos(theta1)],
[sin(theta1), cos(theta1)*cos(alpha1) , -cos(theta1)*sin(alpha1), a1*sin(theta1)],
[0          ,sin(alpha1), cos(alpha1), d1],
[0          ,            0, 0, 1]])

[cos(theta2), -sin(theta2)*cos(alpha2), sin(theta2)*sin(alpha2), a2*cos(theta2)],
[sin(theta2), cos(theta2)*cos(alpha2) , -cos(theta2)*sin(alpha2), a2*sin(theta2)],
[0          ,sin(alpha2), cos(alpha2), d2],
[0          ,          0,           0,  1]])

[cos(theta3), -sin(theta3)*cos(alpha3),  sin(theta3)*sin(alpha3), a3*cos(theta3)],
[sin(theta3), cos(theta3)*cos(alpha3) , -cos(theta3)*sin(alpha3), a3*sin(theta3)],
[0          , sin(alpha3)             , cos(alpha3)              ,            d3],
[0          ,                        0,                         0,             1]])

end_Coord=transpose(array([[0,0,0,1]]))

fig = plt.figure()

plt.plot(x_ar,y_ar,'-o')
plt.grid()

ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20)

display(round(joint4Link3,2)) #final position relative to initial position


This displays the expected answer, where the third entry is the height (each link is modeled as 0.1 meters high) and the fourth is to match it with the DH notation.

array([[1.93],
[1.9 ],
[0. ],
[1.  ]])


## Example (Team 5,Spring 20)

### An example for Modified Denavit-Hartenberg Notation

Result from Ipython
%reset -f
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

# length and rotation of joints
d1=0; theta1=45*np.pi/180; a1=1; alpha1=0
d2=0; theta2=0*np.pi/180; a2=1; alpha2=0
d3=0; theta3=45*np.pi/180; a3=1; alpha3=0
d4=0; theta4=0*np.pi/180; a4=1; alpha4=0

# Modified DH matrices for each joint
J2J1T = np.array([[np.cos(theta1), -np.sin(theta1), 0, a1],
[np.sin(theta1)*np.cos(alpha1), np.cos(theta1)*np.cos(alpha1), -np.sin(alpha1), -d1*np.sin(alpha1)],
[np.sin(theta1)*np.sin(alpha1), np.cos(theta1)*np.sin(alpha1), np.cos(alpha1), d1*np.cos(alpha1)],
[0, 0, 0, 1]])
J3J2T = np.array([[np.cos(theta2), -np.sin(theta2), 0, a2],
[np.sin(theta2)*np.cos(alpha2), np.cos(theta2)*np.cos(alpha2), -np.sin(alpha2), -d2*np.sin(alpha2)],
[np.sin(theta2)*np.sin(alpha2), np.cos(theta2)*np.sin(alpha2), np.cos(alpha2), d2*np.cos(alpha2)],
[0, 0, 0, 1]])
J4J3T = np.array([[np.cos(theta3), -np.sin(theta3), 0, a3],
[np.sin(theta3)*np.cos(alpha3), np.cos(theta3)*np.cos(alpha3), -np.sin(alpha3), -d3*np.sin(alpha3)],
[np.sin(theta3)*np.sin(alpha3), np.cos(theta3)*np.sin(alpha3), np.cos(alpha3), d3*np.cos(alpha3)],
[0, 0, 0, 1]])
J5J4T = np.array([[np.cos(theta4), -np.sin(theta4), 0, a4],
[np.sin(theta4)*np.cos(alpha4), np.cos(theta4)*np.cos(alpha4), -np.sin(alpha4), -d3*np.sin(alpha4)],
[np.sin(theta4)*np.sin(alpha4), np.cos(theta4)*np.sin(alpha4), np.cos(alpha4), d3*np.cos(alpha4)],
[0, 0, 0, 1]])

# building the joints from each previous joint and the Modified DH matrices
Joint1 = np.array([[0, 0, 0, 1]]).T
Joint2 = np.dot(J2J1T,Joint1)
Joint3 = np.dot(np.dot(J2J1T,J3J2T),Joint1)
Joint4 = np.dot(np.dot(np.dot(J2J1T,J3J2T),J4J3T),Joint1)
Joint5 = np.dot(np.dot(np.dot(np.dot(J2J1T,J3J2T),J4J3T),J5J4T),Joint1)

fig=plt.figure()

# plotting the joints
ax.plot([Joint1[0][0],Joint2[0][0]],[Joint1[1][0],Joint2[1][0]],'bo-')
ax.plot([Joint2[0][0],Joint3[0][0]],[Joint2[1][0],Joint3[1][0]],'ro-')
ax.plot([Joint3[0][0],Joint4[0][0]],[Joint3[1][0],Joint4[1][0]],'go-')
ax.plot([Joint4[0][0],Joint5[0][0]],[Joint4[1][0],Joint5[1][0]],'yo-')

ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20)
ax.set_title('Top-Down Projection',size=20)


## Example 6 (Spring '20 - Team 6)

The Canadarm aboard the ISS needs to extend and rotate itself in order to dock with the new cargo capsule, built and developed by the Rutgers Rocket Propulsion Lab. The Canadarm needs to rotate 30 degrees about the x-axis and then translate 3 meters about the x-direction, then it needs to rotate -45 degrees and translate 2 meters along the y-axis. It then will rotate the second link 45 degrees about the y-axis while translating 1 meter, followed by a 25 degree rotation about the x-axis and a 3 meter translation. The 3rd link has to rotate -20 degrees about the x, translate 2 meters, then rotate -30 degrees about the y while translating 3 meters. The final link needs to rotate 60 degrees about the x, translate 2 meters, then rotate another 60 degrees but about the y, and translate 3 meters. This will result in the Canadarms docking clamp to be positioned perfectly with the spacecrafts docking mechanism.

First Link: 30 Rotation about x-axis with 3 m translation ---> -45 Rotation about y-axis with 2 m translation Second Link: 45 Rotation about y-axis with 1 m translation ---> 25 Rotation about x-axis with 3 m translation Third Link: -20 Rotation about x-axis with 2 m translation ---> -30 Rotation about y-axis with 3 m translation Fourth Link: 60 Rotation about x-axis with 2 m translation ---> 60 Rotation about y-axis with 3 meter translation


%reset -f
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

# Link1 (theta is rotation angle with x axis, a is translation distance along x axis, Beta is rotation angle with y axis, and y is translation distance along y axis)
a1=3;theta1=30*np.pi/180; y1=2;Beta1=-45*np.pi/180;
a2=3;theta2=25*np.pi/180; y2=1;Beta2=45*np.pi/180;
a3=2;theta3=-20*np.pi/180; y3=3;Beta3=-30*np.pi/180;
a4=2;theta4=60*np.pi/180; y4=3;Beta4=60*np.pi/180;

# D-H Matrices
[np.sin(Beta1)*np.sin(theta1), np.cos(theta1), -np.sin(theta1)*np.cos(Beta1), y1*np.cos(theta1)],
[-np.sin(Beta1)*np.cos(theta1), np.sin(theta1), np.cos(Beta1)*np.cos(theta1), y1*np.sin(theta1)],
[0, 0, 0, 1]])
[np.sin(Beta2)*np.sin(theta2), np.cos(theta2), -np.sin(theta2)*np.cos(Beta2), y2*np.cos(theta2)],
[-np.sin(Beta2)*np.cos(theta2), np.sin(theta2), np.cos(Beta2)*np.cos(theta2), y2*np.sin(theta2)],
[0, 0, 0, 1]])
[np.sin(Beta3)*np.sin(theta3), np.cos(theta3), -np.sin(theta3)*np.cos(Beta3), y3*np.cos(theta3)],
[-np.sin(Beta3)*np.cos(theta3), np.sin(theta3), np.cos(Beta3)*np.cos(theta3), y3*np.sin(theta3)],
[0, 0, 0, 1]])
[np.sin(Beta4)*np.sin(theta4), np.cos(theta4), -np.sin(theta4)*np.cos(Beta4), y4*np.cos(theta4)],
[-np.sin(Beta4)*np.cos(theta4), np.sin(theta4), np.cos(Beta4)*np.cos(theta4), y4*np.sin(theta4)],
[0, 0, 0, 1]])

End_Coord=np.array([[0,0,0,1]])
End_Coord=End_Coord.T

# Coordinates of each joint

fig=plt.figure()
# plot of Links in Top-Down view

Robotics7 Graph Output
plt.plot()
ax.set_xlim([0, 1])
plt.axis('equal')
ax.set_xlabel('X',size=20)
ax.set_ylabel('Y',size=20)
ax.set_title('Top-Down Projection',size=20)

fig=plt.figure()