我的毕设题目定为《基于机械臂触觉伺服的物体操控研究》,这个系列主要用于记录做毕设的过程。
前言:UR系列是优傲公司的代表产品,也是目前比较通用的产品级机械臂。所以我打算用该机械臂进行毕设的仿真实现。关于其运动学建模,网上有很多参考的博客及文献,但是很多都与《机器人学导论》第四版中的建模方式有所出入(不是指建模有问题,只是坐标系定义不太一致)。所以我按照自己的理解进行了运动学模型搭建,并使用webots进行了仿真验证。
1. 正运动学
模型的坐标系建立如下图所示。
DH参数表
注:列表的长度参考了webots中的模型,可能跟实体的参数有所出入。
a | α \alpha α | d | θ \theta θ |
---|---|---|---|
0 | 0 | 0.1625 | θ 1 |
0 | − π / 2 | 0 | − π / 2 + θ 2 |
0.425 | 0 | 0 | θ 3 |
0.3922 | 0 | 0.127 | π / 2 + θ 4 |
0 | π / 2 | 0.1 | θ 5 |
0 | − π / 2 | 0.1 | θ 6 |
求解
将DH参数列表转为变换矩阵
坐标系变换
代码实现
#include <vector>
#include <eigen3/Eigen/Dense>
std::vector<Vec4<T>> getDHparams(void){
/* define link length */
_worldBaseDistance = 0.1625;
_shoulderLinkLength = 0.138;
_upperarmLinkLength = 0.425;
_forearmLinkLength = 0.3922;
_wrist1LinkLength = 0.127;
_wrist2LinkLength = 0.1;
_wrist3LinkLength = 0.1;
Vec4<T> dh_param;
std::vector<Vec4<T>> DH_params;
DH_params.clear();
dh_param << 0,0, _worldBaseDistance, 0; DH_params.push_back(dh_param);
dh_param << 0, -M_PI_2, 0, -M_PI_2; DH_params.push_back(dh_param);
dh_param << _upperarmLinkLength, 0, 0, 0; DH_params.push_back(dh_param);
dh_param << _forearmLinkLength, 0, _wrist1LinkLength, M_PI_2; DH_params.push_back(dh_param);
dh_param << 0, M_PI_2, _wrist2LinkLength, 0; DH_params.push_back(dh_param);
dh_param << 0, -M_PI_2, _wrist3LinkLength, 0; DH_params.push_back(dh_param);
}
/**
* @brief forward kinematics
* @param q joints angle 1 - 6
* @param p data order is x, y, z, pitch, roll, yaw
*/
template <typename T>
void forwardKinematics(const Vec6<T>& q, Vec6<T>* p){
std::vector<Vec4<T>> DH_params = getDHparams();
Mat4<T> Pro_Mat[4];
Mat4<T> Trans_Mat = Mat4<T>::Identity();
for(int i = 0; i < JOINTS_NUM; i ++){
/* init */
for(int j = 0; j < 4; j ++){
Pro_Mat[j] = Mat4<T>::Identity();
}
/* create transform matrix refer to DH params */
Mat2<T> rot;
/* a trans */
T a = DH_params[i][0];
Pro_Mat[0](0, 3) = a;
/* alpha trans */
T alpha = DH_params[i][1];
rot << cos(alpha), -sin(alpha), sin(alpha), cos(alpha);
Pro_Mat[1].block(1, 1, 2, 2) = rot;
/* d trans */
T d = DH_params[i][2];
Pro_Mat[2](2, 3) = d;
/* theta trans */
T theta = q[i] + DH_params[i][3];
rot << cos(theta), -sin(theta), sin(theta), cos(theta);
Pro_Mat[3].block(0, 0, 2, 2) = rot;
/* combine trans matrix */
Trans_Mat = Trans_Mat * Pro_Mat[0] * Pro_Mat[1] * Pro_Mat[2] * Pro_Mat[3];
}
/* xyz */
p->operator()(0) = Trans_Mat(0, 3);
p->operator()(1) = Trans_Mat(1, 3);
p->operator()(2) = Trans_Mat(2, 3);
/* rpy */
Mat3<T> rot = Trans_Mat.block(0,0,3,3);
Vec3<T> rpy = ori::rotationMatrixToRPY(rot);
p->operator()(3) = rpy(0);
p->operator()(4) = rpy(1);
p->operator()(5) = rpy(2);
}
2. 逆运动学
因为UR5e满足Pieper准则(末端三个关节轴相交于一点),所以其逆运动学具有封闭解。这里采用解析法进行求解。求解过程参考如下的文章,因为建模方式不同,求解的公式也有一定的区别,但思路一致。
UR机械臂正逆运动学求解
角度求解用到的公式(推导过程参考上述文章)
已知:
c o s ( θ ) p y − s i n ( θ ) p x = d
可求得:
参数定义
以下的推导公式中, c 1 c_1 c1表示 c o s ( θ 1 ) , s 1 2 表示 s i n ( θ 1 + θ 2 )
求解 θ 1 \theta_1 θ1, θ 5 \theta_5 θ5, θ 6 \theta_6 θ6
根据变换矩阵公式可得以下关系
1 0 T − 1 ∗ T ∗ 6 5 T − 1 = 5 1
等式左边
等式右边
求解 θ 1
利用等式左右两边第二行,第四列对应相等进行求解。
求解 θ 5
利用等式左右两边第二行,第二列对应相等进行求解。
l y c 1 − l x s 1 = c 5
θ 5 = ± A c o s ( l y c 1 − l x s 1 )
求解 θ 6
利用等式左右两边第二行,第一列对应相等进行求解。
r y c 1 c 6 − o y c 1 s 6 − r x c 6 s 1 + o x s 1 s 6 = s 5
求解 θ 2 , θ 3 , θ 4
根据变换矩阵公式可得以下关系
1 0 T − 1 ∗ T ∗ 6 5 T − 1 ∗ 5 4 T − 1 = 4 1 T
等式左边
等式右边
求解 θ 3
利用等式左右两边第一行,第四列,以及第三行,第四列对应相等进行求解。
因为
s 23 s 2 + c 23 c 2 = c 3
则
θ 3 = ± A c o s ( m 2 + n 2 − a 3 2 − a 4 2 2 a 3 a 4 )
求解 θ 2
将(1)(2)式进行展开
a 4 ( s 2 c 3 + s 3 c 2 ) + a 3 s 2 = m
a 4 ( c 2 c 3 − s 2 s 3 ) + a 3 c 2 = n
整理得
( a 4 c 3 + a 3 ) s 2 + ( a 4 s 3 ) c 2 = m
( a 4 c 3 + a 3 ) c 2 − ( a 4 s 3 ) s 2 = n
(a_4c_3+a_3)s_2+(a_4s_3)c_2 =m
解得
s 2 = m ( a 4 c 3 + a 3 ) − a 4 s 3 n a 4 2 + 2 a 4 a 3 c 3 + a 3 2
c 2 = n + ( a 4 s 3 ) s 2 a 4 c 3 + a 3 θ 2 = A t a n 2 ( s 2 , c 2 )
求解 θ 4
利用等式左右两边第三行,第一列,以及第三行,第二列对应相等进行求解。
s 234 = − ( r z c 5 c 6 − l z s 5 − o z c 5 s 6 ) c 234 = − ( o z c 6 + r z s 6 )
则
θ 4 = A t a n 2 ( s 234 , c 234 ) − θ 2 − θ 3
奇异点
- θ 5 = 0 θ5=0时, θ 2 , θ 3 , θ 4 与 θ 6 θ2,θ3,θ4与θ6平行,此时需要自定义 θ 6 的值使系统可解。
- θ 3 = π 时, θ 2 可以为任何值。
对于解析解而言,只要找出求解公式中超出函数定义域或者值域的取值,并将其重新定义为有效值即可避免到达奇异位点。当然,前提是保证目标点位于机械臂的工作空间内,
结果筛选
因为上述推导公式可以得到8组解,所以需要筛选出最合适的那个解进行输出。筛选的方法要根据情景而定,一般是选择与当前位姿最接近的解或者与最优位姿最接近的解。
下面给出一种筛选思路。
参数定义
X i :逆运动学求取的一组解
r e f :参考点
ω :权重系数
d ( x , y ) :x,y两点的距离函数
对每组解分别求取误差
e r r i = ω ∗ d ( X i , r e f )
选取最优解
X o p t i m a l = X j e r r j = m i n ( e r r )
- 权重系数可以设置为各个驱动关节对应的连杆长度,这样子越长的连杆权重越大,最终得到的结果会趋向于移动短连杆,节省能量。
- 距离函数可以选择为绝对值距离或者欧氏距离等。
代码实现
/**
* @brief inverse kinematics
* @param p data order is x, y, z, pitch, roll, yaw
* @param q joints angle 1 - 6
*/
template <typename T>
bool inverseKinematics(const Vec6<T>& p, Vec6<T>* q, const Vec6<T>* ref_q){
/* convert to rotation matrix */
Vec3<T> rpy(p(3), p(4), p(5));
Mat3<T> rot = ori::rpyToRotMat(rpy);
T rx = rot(0, 0); T ox = rot(0, 1); T lx = rot(0, 2); T px = p(0);
T ry = rot(1, 0); T oy = rot(1, 1); T ly = rot(1, 2); T py = p(1);
T rz = rot(2, 0); T oz = rot(2, 1); T lz = rot(2, 2); T pz = p(2);
/* define DH params */
T a3 = DH_params[2][0];
T a4 = DH_params[3][0];
T d1 = DH_params[0][2];
T d4 = DH_params[3][2];
T d5 = DH_params[4][2];
T d6 = DH_params[5][2];
/* consider multiple solution */
Vec6<T> solve_angles[8];
for(int i = 0; i < 8; i ++){
/* change sign */
T signs[3];
for(int s = 0; s < 3; s ++){
signs[s] = i & (1 << s) ? -1 : 1;
}
/* theta1 */
T m = py - d6 * ly;
T n = px - d6 * lx;
T verify = pow(m,2) + pow(n,2) - pow(d4,2);
if(verify < 0) {
verify = 0;
}
T t1 = atan2(m, n) - atan2(d4, signs[0] * sqrt(verify));
/* theta5 */
T t5 = signs[1] * acos(ly * cos(t1) - lx * sin(t1));
/* theta6 */
m = ry * cos(t1) - rx * sin(t1);
n = oy * cos(t1) - ox * sin(t1);
T t6;
if(t5 == 0){
t6 = 0;
}
else{
t6 = atan2(m, n) - atan2(sin(t5), 0);
}
/* theta3 */
m = px*cos(t1) + py*sin(t1) - d6*lx*cos(t1) - d6*ly*sin(t1) + d5*ry*sin(t1)*sin(t6)
+ d5*ox*cos(t1)*cos(t6) + d5*oy*cos(t6)*sin(t1) + d5*rx*cos(t1)*sin(t6);
n = pz - d1 - d6*lz + d5*oz*cos(t6) + d5*rz*sin(t6);
verify = (pow(m,2) + pow(n,2) - pow(a3,2) - pow(a4,2)) / (2*a3*a4);
if(verify > 1) {
verify = 1;
}
else if(verify < -1) {
verify = -1;
}
T t3 = signs[2] * acos(verify);
/* theta2 */
T s2 = (m * (a4*cos(t3) + a3) - a4*sin(t3)*n) / (pow(a4,2) + 2*a4*a3*cos(t3) + pow(a3,2));
T c2 = (n + a4*sin(t3)*s2) / (a4*cos(t3) + a3);
T t2 = atan2(s2, c2);
/* theta4 */
T s234 = -rz*cos(t5)*cos(t6) + lz*sin(t5) + oz*cos(t5)*sin(t6);
T c234 = -oz*cos(t6) - rz*sin(t6);
T t4 = atan2(s234, c234) - t2 - t3;
solve_angles[i] << t1, t2, t3, t4, t5, t6;
}
/* filter optimal solution */
if(ref_q == NULL){
*q = solve_angles[0];
}
else{
uint8_t optimal_index = 0;
T min_err = 0;
for(int i = 0; i < 8; i ++){
T err = 0;
for(int j = 0; j < JOINTS_NUM; j ++){
err += abs(ref_q->operator()(j) - solve_angles[i][j]) * (*links_length[j]);
}
if(!i){
min_err = err;
}
else if(err < min_err){
min_err = err;
optimal_index = i;
}
}
*q = solve_angles[optimal_index];
}
return true;
}
评论(0)
您还未登录,请登录后发表或查看评论