5DOF机械臂
一、模型简化
二、模型逆运动学求解
用户给定笛卡尔末端工具坐标系的位姿为X, Y, Z, roll, pitch, yaw;由图上可知,云台角度(控制末端工具坐标的yaw):
θ
0
=
a
t
a
n
2
(
Y
,
X
)
θ_0=atan2(Y,X)
θ0=atan2(Y,X)
转关节角度(控制机械臂工具坐标系的roll):
θ
4
=
r
o
l
l
θ_4=roll
θ4=roll
将坐标转换到中间三个关节的平面:
x
=
√
(
X
2
+
Y
2
)
x=√(X^2+Y^2 )
x=√(X2+Y2)
y
=
Z
y=Z
y=Z
根据上面的图示右下角,可以列出如下方程:
x
=
l
0
c
o
s
θ
1
+
l
1
c
o
s
(
θ
1
+
θ
2
)
+
l
2
c
o
s
(
θ
1
+
θ
2
+
θ
3
)
x=l_0 cosθ_1 +l_1 cos(θ_1+θ_2 )+l_2 cos(θ_1+θ_2+θ_3 )
x=l0cosθ1+l1cos(θ1+θ2)+l2cos(θ1+θ2+θ3)
y
=
l
0
s
i
n
θ
1
+
l
1
s
i
n
(
θ
1
+
θ
2
)
+
l
2
s
i
n
(
θ
1
+
θ
2
+
θ
3
)
y=l_0 sinθ_1+l_1 sin(θ_1+θ_2 )+l_2 sin(θ_1+θ_2+θ_3 )
y=l0sinθ1+l1sin(θ1+θ2)+l2sin(θ1+θ2+θ3)
末端工具坐标系的俯仰角pitch:
p
i
t
c
h
=
θ
1
+
θ
2
+
θ
3
pitch=θ_1+θ_2+θ_3
pitch=θ1+θ2+θ3
下面对上述方程组进行化简,把式pitch代入式(6)(7),得:
x
=
l
0
c
o
s
θ
1
+
l
1
c
o
s
(
θ
1
+
θ
2
)
+
l
2
c
o
s
(
p
i
t
c
h
)
x=l_0 cosθ_1 +l_1 cos(θ_1+θ_2 )+l_2 cos(pitch)
x=l0cosθ1+l1cos(θ1+θ2)+l2cos(pitch)
y
=
l
0
s
i
n
θ
1
+
l
1
s
i
n
(
θ
1
+
θ
2
)
+
l
2
s
i
n
(
p
i
t
c
h
)
y=l_0 sinθ_1+l_1 sin(θ_1+θ_2 )+l_2 sin(pitch)
y=l0sinθ1+l1sin(θ1+θ2)+l2sin(pitch)
为了方便计算,令:
m
=
l
2
c
o
s
(
p
i
t
c
h
)
−
x
m=l_2 cos(pitch)-x
m=l2cos(pitch)−x
n
=
l
2
s
i
n
(
p
i
t
c
h
)
−
y
n=l_2 sin(pitch)-y
n=l2sin(pitch)−y
化简(8)得:
l
1
=
(
l
0
c
o
s
θ
1
+
m
)
2
+
(
l
0
s
i
n
θ
1
+
n
)
2
l_1=(l_0 cosθ_1 +m)^2+(l_0 sinθ_1 +n)^2
l1=(l0cosθ1+m)2+(l0sinθ1+n)2
可将该方程化简成超越方程:
a
c
o
s
θ
+
b
s
i
n
θ
=
c
a cosθ+b sinθ=c
acosθ+bsinθ=c
查阅《机器人导论》书的附录C可求得
θ
1
θ_1
θ1两组解:
θ
1
=
A
t
a
n
2
(
b
,
a
)
±
A
t
a
n
2
(
√
(
a
2
+
b
2
−
c
2
)
,
c
)
θ_1=Atan2(b,a)±Atan2(√(a^2+b^2-c^2 ),c)
θ1=Atan2(b,a)±Atan2(√(a2+b2−c2),c)
同理,可以求出
θ
1
+
θ
2
θ_1+θ_2
θ1+θ2。
两组解怎么选择?
两组解示意图如下:
我用一个想法将它们区分开来, 因为
l
1
l_1
l1、
l
2
l_2
l2的长度不相等,所以会有:
θ
1
+
θ
2
>
θ
1
′
+
θ
2
′
θ_1+θ_2 >θ'_1+θ'_2
θ1+θ2>θ1′+θ2′
注意
θ
2
′
θ'_2
θ2′是小于0的!再加上:
θ
1
′
>
θ
1
θ'_1>θ_1
θ1′>θ1
就可以判断出组合从而求得:
θ
2
θ_2
θ2、
θ
2
′
θ'_2
θ2′;最后加上机械臂关节角度限制选择一组合适的解即可,至此
θ
0
θ_0
θ0 、
θ
1
θ_1
θ1 、
θ
2
θ_2
θ2 、
θ
3
θ_3
θ3 、
θ
4
θ_4
θ4五个关节角度就都求出来了,最后
θ
5
θ_5
θ5是控制夹具夹取的。
三、C++代码
//逆运动学
//只需要输入五个全局参数pose[5]:X Y Z roll pitch
//对于视觉:传入XY z,roll固定 pitch给定
void inverse_Kinematic_Y(float pose[5], vector<float>& v_k)
{
float x_1, y_1, beta_1, alpha_1,roll;
y_1 = pose[2];//Z
x_1 = sqrt(pose[0] * pose[0] + pose[1] * pose[1]);
beta_1 = atan2(pose[1],pose[0])*180/PI;//yaw,有X Y算出
cout <<"beta:"<< beta_1<<endl;
roll = pose[3]*180/PI;//roll
alpha_1 = pose[4];//pitch
float *mmm;
mmm = Kinematic_Analysis(y_1, x_1, beta_1, alpha_1);
//得到六个关节角,最后一暂时还没控制
v_k = { beta_1,*mmm,*(mmm + 1), *(mmm + 2),roll,0 };
}
float* Kinematic_Analysis(float x, float y, float Beta, float Alpha)
{
cout << "111" << cos(Alpha) << endl;
float m, n, k, a, b, c, theta1_1, theta1_2, theta2_1, theta2_2, theta3, s1ps2_1, s1ps2_2, theta1, theta2, s1ps2;
m = l2 * cos(Alpha) - x; //中间变量
n = l2 * sin(Alpha) - y; //中间变量
k = (l1 * l1 - l0 * l0 - m * m - n * n) / 2 / l0;//中间变量
a = m * m + n * n; //解一元二次方程
b = -2 * n * k;
c = k * k - m * m;
if (b * b - 4 * a * c < 0)
{
cout << "该点无法到达!!!" << endl;
system("pause");
exit(0);
return 0; //防止出现非实数解
}
//theta1 = (-b- sqrt(b * b - 4 * a * c)) / 2 / a; //得到一元二次方程的解,只取其中一个,另外一个解是(-b+sqrt(b*b-4*a*c))/2/a
//theta1 = asin(theta1) * 180 / PI; //弧度换成角度
theta1_1 = atan2(n, m) + atan2(sqrt(m * m + n * n - k * k), k);
theta1_1 = theta1_1 * 180 / PI;
theta1_2 = atan2(n, m) - atan2(sqrt(m * m + n * n - k * k), k);
theta1_2 = theta1_2 * 180 / PI;
if (theta1_1 > 90)theta1_1 = theta1_1 - 360;
if (theta1_1 < -90)theta1_1 = theta1_1 + 360;
if (theta1_2 > 90)theta1_2 = theta1_2 - 360;
if (theta1_2 < -90)theta1_2 = theta1_2 + 360;
//if (theta1 > 90)theta1 = 90; //控制舵机的最大角度±90°
//if (theta1 < -90)theta1 = -90;
k = (l0 * l0 - l1 * l1 - m * m - n * n) / 2 / l1; //过程系数
a = m * m + n * n; //解一元二次方程
b = -2 * n * k;
c = k * k - m * m;
if (b * b - 4 * a * c < 0) return 0; //防止出现非实数解
//s1ps2 = (-b + sqrt(b * b - 4 * a * c)) / 2 / a; //得到一元二次方程的解,只取其中一个,另外一个解是(-b+sqrt(b*b-4*a*c))/2/a
//s1ps2 = asin(s1ps2) * 180 / PI; //弧度换成角度
s1ps2_1 = atan2(n, m) + atan2(sqrt(m * m + n * n - k * k), k);
s1ps2_1 = s1ps2_1 * 180 / PI;
s1ps2_2 = atan2(n, m) - atan2(sqrt(m * m + n * n - k * k), k);
s1ps2_2 = s1ps2_2 * 180 / PI;
if (s1ps2_1 > 90)s1ps2_1 = s1ps2_1 - 360;
if (s1ps2_1 < -90)s1ps2_1 = s1ps2_1 + 360;
if (s1ps2_2 > 90)s1ps2_2 = s1ps2_2 - 360;
if (s1ps2_2 < -90)s1ps2_2 = s1ps2_2 + 360;
float bj[4] = { theta1_1 ,theta1_2,s1ps2_1,s1ps2_2 };
cout << bj[0] << bj[1] << bj[2] << bj[3] << endl;
for (int j = 1; j < 4; j++)
{
for (int g = 0; g < j; g++)
{
if (bj[j] > bj[g])
{
int temp;
temp = bj[j];
bj[j] = bj[g];
bj[g] = temp;
}
}
}
cout << bj[0] << bj[1] << bj[2] << bj[3] << endl;
theta1_1 = bj[1];//大theata1角
theta2_1 = bj[3] - bj[1];
theta1_2 = bj[2];//小theata1角
theta2_2 = bj[0] - bj[2];
if (theta1_2 < -90 || theta1_2 > 90)
{
theta1 = theta1_1;
theta2 = theta2_1;
}
else if (theta1_1 < -90 || theta1_1 > 90)
{
theta1 = theta1_2;
theta2 = theta2_2;
}
else if (theta1_1 <= 0 && theta1_1 >= -90)
{
theta1 = theta1_2;
theta2 = theta2_2;
}
else
{
theta1 = theta1_1;
theta2 = theta2_1;
}
//if (s1ps2 > 90)theta2 = 90;
//if (s1ps2 < -90)theta2 = -90;
//theta2 = s1ps2 - theta1;
//if (theta2 > 90)theta2 = 90; //控制舵机的最大角度±90°
//if (theta2 < -90)theta2 = -90; //控制舵机的最大角度±90°
theta3 = Alpha * 180 / PI - theta1 - theta2; //求关节3角度
if (theta3 > 90)theta3 = 90;
if (theta3 < -90)theta3 = -90; //控制舵机的最大角度±90°
cout << theta1 << " " << theta2 << " " << theta3 << endl;
float pp[3] = { theta1 ,theta2,theta3 };
static float u[3];
for (int i = 0; i < 3; ++i)
{
u[i] = pp[i];
cout << i << ":" << u[i] << endl;
}
return u;
}