双连杆机械臂运动学正向和逆向 Python 仿真
source link: http://thinkhard.tech/2019/12/03/kinematics-dh-method/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
双连杆机械臂运动学正向和逆向 Python 仿真
DH(Denavit-Hartenberg)方法
DH 方法描述了相邻坐标系之间的旋转与移动的关系,只需要找到 4 个参数,以基座坐标 \((x_0, y_0, z_0)\) 为参考,就可以依次求出相连接的连杆坐标系 \((x_i, y_i, z_i)\) 和末端执行器坐标系 \((x_n, y_n, z_n)\) 的远点与方向。
DH 方法要求相邻坐标系之间满足下面约定
- \(x_i\) 和 \(z_{i-1}\) 轴垂直;
- \(x_i\) 和 \(z_{i-1}\) 轴相交;
4 个 DH 参数分别为:
- 关节转角(joint angle) \(\theta_{i}\)
- 连杆扭角(link twist) \(\alpha_{i}\)
- 连杆距离(link offset) \(d_{i}\)
- 连杆长度(link length) \(a_{i}\)
正运动学公式
逆运动学公式
\[ \theta _ { 2 } = \tan ^ { - 1 } \left( \frac { \sin \theta _ { 2 } } { \cos \theta _ { 2 } } \right) = \tan ^ { - 1 } \left( \frac { \frac { - S _ { 1 } ^ { \theta } p _ { x } ^ { 0 } + C _ { 1 } ^ { \theta } p _ { y } ^ { 0 } } { l _ { 2 } } } { \frac { C _ { 1 } ^ { \theta } p _ { x } ^ { 0 } + S _ { 1 } ^ { \theta } p _ { y } ^ { 0 } - l _ { 1 } } { l _ { 2 } } } \right) = \tan ^ { - 1 } \left( \frac { - S _ { 1 } ^ { \theta } p _ { x } ^ { 0 } + C _ { 1 } ^ { \theta } p _ { y } ^ { 0 } } { C _ { 1 } ^ { \theta } p _ { x } ^ { 0 } + S _ { 1 } ^ { \theta } p _ { y } ^ { 0 } - l _ { 1 } } \right) \]
平面连杆正运动学仿真
import numpy as np from numpy import sin, cos import matplotlib.pyplot as plt def dhmat(delta, d, a, alpha): return np.array([[cos(delta), -sin(delta)*cos(alpha), sin(delta)*sin(alpha), a*cos(delta)], [sin(delta), cos(delta)*cos(alpha), -cos(delta)*sin(alpha), a*sin(delta)], [0, sin(alpha), cos(alpha), d], [0, 0, 0, 1]]) def main(): theta_1 = np.radians(np.arange(20, 50, 1)) theta_2 = np.radians(np.arange(0, 30, 1)) d_1 = 0 d_2 = 0 l_1 = 0.1 l_2 = 0.2 alpha_1 = 0 alpha_2 = 0 P_0 = np.array([0, 0, 0, 1]).T P_1 = np.array([0, 0, 0, 1]).T P_2 = np.array([0, 0, 0, 1]).T fig, ax = plt.subplots() for i in range(len(theta_1)): P1_0 = dhmat(theta_1[i], d_1, l_1, alpha_1).dot(P_1) P2_0 = dhmat(theta_1[i], d_1, l_1, alpha_1).dot(dhmat(theta_2[i], d_2, l_2, alpha_2)).dot(P_2) ax.plot([P_0[0], P1_0[0], P2_0[0]], [P_0[1], P1_0[1], P2_0[1]], '-bo') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') fig.savefig('./twp_link_planar_robot.png') plt.show() if __name__ == '__main__': main()
平面连杆逆运动学仿真
import numpy as np from numpy import linalg as LA from numpy import sin, cos, arctan import matplotlib.pyplot as plt def dhmat(delta, d, a, alpha): return np.array([[cos(delta), -sin(delta)*cos(alpha), sin(delta)*sin(alpha), a*cos(delta)], [sin(delta), cos(delta)*cos(alpha), -cos(delta)*sin(alpha), a*sin(delta)], [0, sin(alpha), cos(alpha), d], [0, 0, 0, 1]]) def main(): d_1 = 0 d_2 = 0 l_1 = 0.1 l_2 = 0.2 alpha_1 = 0 alpha_2 = 0 theta_1 = np.radians(np.arange(20, 50, 1)) theta_2 = np.zeros(len(theta_1)) st = 1 des_P2_0 = np.array([0.22, 0.2, 0, 1]).T err_dist = np.zeros(len(theta_1)) P_0 = np.array([0, 0, 0, 1]).T P_1 = np.array([0, 0, 0, 1]).T P_2 = np.array([0, 0, 0, 1]).T fig, ax = plt.subplots() for i in range(len(theta_1)): P1_0 = dhmat(theta_1[i], d_1, l_1, alpha_1).dot(P_1) theta_2[i] = arctan((-sin(theta_1[i]) * des_P2_0[0] + cos(theta_1[i]) * des_P2_0[1]) / (cos(theta_1[i]) * des_P2_0[0] + sin(theta_1[i]) * des_P2_0[1] - l_1)) P2_0 = dhmat(theta_1[i], d_1, l_1, alpha_1).dot(dhmat(theta_2[i], d_2, l_2, alpha_2)).dot(P_2) err_dist[i] = LA.norm(des_P2_0 - P2_0) ax.plot([P_0[0], P1_0[0], P2_0[0]], [P_0[1], P1_0[1], P2_0[1]], '-bo') # 双连杆平面机械运动逆向运动学仿真 ax.plot(des_P2_0[0], des_P2_0[1], '-rx') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') fig.savefig('./ik_two_link_planar_robot_0.png') plt.show() # theta_1, theta_2 角度变化轨迹 fig, ax = plt.subplots(nrows=2) ax[0].plot(theta_1, 'k') ax[0].set_ylabel('theta_1') ax[1].plot(theta_2, 'k') ax[1].set_ylabel('theta_2') ax[1].set_xlabel('time (s)') fig.savefig('./ik_two_link_planar_robot_1.png') plt.show() # 目标点与实际点之间的距离误差 fig, ax = plt.subplots() ax.plot(err_dist, 'k') ax.set_ylabel('distance error (m)') ax.set_xlabel('time (s)') fig.savefig('./ik_two_link_planar_robot_2.png') plt.show() if __name__ == '__main__': main()
参考
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK