2019-12-18 11:25:45 +00:00
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
%
|
|
|
|
|
|
% Getting base parameters of the UR10 manipulator based on the
|
|
|
|
|
|
%
|
|
|
|
|
|
% Gautier, M., & Khalil, W. (1990). Direct calculation of minimum set
|
|
|
|
|
|
% of inertial parameters of serial robots. IEEE Transactions on Robotics
|
|
|
|
|
|
% and Automation, 6(3), 368–373. https://doi.org/10.1109/70.56655
|
|
|
|
|
|
%
|
|
|
|
|
|
% Here we tried to generilize what was given there to more general
|
|
|
|
|
|
% parametrization compared to their modified DH parameters.
|
|
|
|
|
|
% ------------------------------------------------------------------------
|
2019-12-19 06:48:18 +00:00
|
|
|
|
% Get robot description
|
|
|
|
|
|
run('main_ur.m')
|
|
|
|
|
|
|
|
|
|
|
|
generateBaseRegressorFunction = 0;
|
|
|
|
|
|
generateBaseDynamicsFunctions = 0;
|
2019-12-18 11:25:45 +00:00
|
|
|
|
|
|
|
|
|
|
% Create symbolic parameters
|
|
|
|
|
|
m = sym('m%d',[6,1],'real');
|
|
|
|
|
|
hx = sym('h%d_x',[6,1],'real');
|
|
|
|
|
|
hy = sym('h%d_y',[6,1],'real');
|
|
|
|
|
|
hz = sym('h%d_z',[6,1],'real');
|
|
|
|
|
|
ixx = sym('i%d_xx',[6,1],'real');
|
|
|
|
|
|
ixy = sym('i%d_xy',[6,1],'real');
|
|
|
|
|
|
ixz = sym('i%d_xz',[6,1],'real');
|
|
|
|
|
|
iyy = sym('i%d_yy',[6,1],'real');
|
|
|
|
|
|
iyz = sym('i%d_yz',[6,1],'real');
|
|
|
|
|
|
izz = sym('i%d_zz',[6,1],'real');
|
|
|
|
|
|
im = sym('im%d',[6,1],'real');
|
|
|
|
|
|
|
|
|
|
|
|
% Load parameters attached to the end-effector
|
|
|
|
|
|
syms ml hl_x hl_y hl_z il_xx il_xy il_xz il_yy il_yz il_zz real
|
|
|
|
|
|
|
|
|
|
|
|
% Vector of symbolic parameters
|
|
|
|
|
|
for i = 1:6
|
|
|
|
|
|
pi_ur10(:,i) = [ixx(i),ixy(i),ixz(i),iyy(i),iyz(i),izz(i),...
|
|
|
|
|
|
hx(i),hy(i),hz(i),m(i)]';
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
% Symbolic generilized coordiates, their first and second deriatives
|
|
|
|
|
|
q_sym = sym('q%d',[6,1],'real');
|
|
|
|
|
|
qd_sym = sym('qd%d',[6,1],'real');
|
|
|
|
|
|
q2d_sym = sym('q2d%d',[6,1],'real');
|
|
|
|
|
|
|
|
|
|
|
|
% ------------------------------------------------------------------------
|
|
|
|
|
|
% Getting energy functions, to derive dynamics
|
|
|
|
|
|
% ------------------------------------------------------------------------
|
|
|
|
|
|
T_pk = sym(zeros(4,4,6)); % transformation between links
|
|
|
|
|
|
w_kk(:,1) = sym(zeros(3,1)); % angular velocity k in frame k
|
|
|
|
|
|
v_kk(:,1) = sym(zeros(3,1)); % linear velocity of the origin of frame k in frame k
|
|
|
|
|
|
g_kk(:,1) = sym([0,0,9.81])'; % vector of graviatational accelerations in frame k
|
|
|
|
|
|
p_kk(:,1) = sym(zeros(3,1)); % origin of frame k in frame k
|
|
|
|
|
|
DK(:,1) = sym(zeros(10,1)); % gradient of kinetic energy
|
|
|
|
|
|
DP(:,1) = sym([zeros(1,6),[0,0,9.81],0]'); % gradient of gravitational energy
|
|
|
|
|
|
|
|
|
|
|
|
for i = 1:6
|
|
|
|
|
|
jnt_axs_k = str2num(ur10.robot.joint{i}.axis.Attributes.xyz)';
|
|
|
|
|
|
% Transformation from parent link frame p to current joint frame
|
|
|
|
|
|
rpy_k = sym(str2num(ur10.robot.joint{i}.origin.Attributes.rpy));
|
|
|
|
|
|
R_pj = RPY(rpy_k);
|
|
|
|
|
|
R_pj(abs(R_pj)<sqrt(eps)) = sym(0); % to avoid numerical errors
|
|
|
|
|
|
p_pj = str2num(ur10.robot.joint{i}.origin.Attributes.xyz)';
|
|
|
|
|
|
T_pj = sym([R_pj, p_pj; zeros(1,3), 1]); % to avoid numerical errors
|
|
|
|
|
|
% Tranformation from joint frame of the joint that rotaties body k to
|
|
|
|
|
|
% link frame. The transformation is pure rotation
|
|
|
|
|
|
R_jk = Rot(q_sym(i),sym(jnt_axs_k));
|
|
|
|
|
|
p_jk = sym(zeros(3,1));
|
|
|
|
|
|
T_jk = [R_jk, p_jk; sym(zeros(1,3)),sym(1)];
|
|
|
|
|
|
% Transformation from parent link frame p to current link frame k
|
|
|
|
|
|
T_pk(:,:,i) = T_pj*T_jk;
|
|
|
|
|
|
z_kk(:,i) = sym(jnt_axs_k);
|
|
|
|
|
|
|
|
|
|
|
|
w_kk(:,i+1) = T_pk(1:3,1:3,i)'*w_kk(:,i) + sym(jnt_axs_k)*qd_sym(i);
|
|
|
|
|
|
v_kk(:,i+1) = T_pk(1:3,1:3,i)'*(v_kk(:,i) + cross(w_kk(:,i),sym(p_pj)));
|
|
|
|
|
|
g_kk(:,i+1) = T_pk(1:3,1:3,i)'*g_kk(:,i);
|
|
|
|
|
|
p_kk(:,i+1) = T_pk(1:3,1:3,i)'*(p_kk(:,i) + sym(p_pj));
|
2019-12-19 06:48:18 +00:00
|
|
|
|
|
2019-12-18 11:25:45 +00:00
|
|
|
|
lmda(:,:,i) = getLambda(T_pk(1:3,1:3,i),sym(p_pj));
|
|
|
|
|
|
f(:,i) = getF(v_kk(:,i+1),w_kk(:,i+1),sym(jnt_axs_k),qd_sym(i));
|
|
|
|
|
|
DK(:,i+1) = lmda(:,:,i)*DK(:,i) + qd_sym(i)*f(:,i);
|
|
|
|
|
|
DP(:,i+1) = lmda(:,:,i)*DP(:,i);
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
% Regrouping parameters of the links
|
|
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
pir_ur10_num = zeros(10,6);
|
|
|
|
|
|
pir_ur10_num(:,6) = ur10.pi(:,6);
|
|
|
|
|
|
|
|
|
|
|
|
pir_ur10_sym = sym(zeros(10,6));
|
|
|
|
|
|
pir_ur10_sym(:,6) = pi_ur10(:,6);
|
|
|
|
|
|
for i = 6:-1:2
|
|
|
|
|
|
pi_prv_num = ur10.pi(:,i-1);
|
|
|
|
|
|
[pir_ur10_num(:,i-1),pir_ur10_num(:,i)] = ...
|
|
|
|
|
|
group(pi_prv_num,pir_ur10_num(:,i),lmda(:,:,i),z_kk(:,i));
|
|
|
|
|
|
|
|
|
|
|
|
pi_prv_sym = pi_ur10(:,i-1);
|
|
|
|
|
|
[pir_ur10_sym(:,i-1),pir_ur10_sym(:,i)] = ...
|
|
|
|
|
|
group(pi_prv_sym, pir_ur10_sym(:,i),lmda(:,:,i),z_kk(:,i));
|
|
|
|
|
|
end
|
|
|
|
|
|
pir_ur10_num = double(pir_ur10_num);
|
|
|
|
|
|
|
2019-12-19 06:48:18 +00:00
|
|
|
|
|
2019-12-18 11:25:45 +00:00
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
% Getting base parameters
|
|
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
grad_Lagr = [];
|
|
|
|
|
|
pir_base_vctr = [];
|
|
|
|
|
|
nb = 0; % number of independent parameters
|
|
|
|
|
|
nd = 0; % number of non-identifiable or indeitifiable in combination
|
|
|
|
|
|
Pb = zeros(36,60);
|
|
|
|
|
|
Pd = zeros(24,60);
|
|
|
|
|
|
for i = 1:6
|
|
|
|
|
|
DK_base{i} = sym([]);
|
|
|
|
|
|
DP_base{i} = sym([]);
|
|
|
|
|
|
pir_base_sym{i} = sym([]);
|
|
|
|
|
|
pir_base_num{i} = [];
|
|
|
|
|
|
for j = 1:10
|
|
|
|
|
|
% We try to obtain base parameters, parameters tha affect energy
|
|
|
|
|
|
% of the system, by anlayzing kinetic energy and potenial energy
|
|
|
|
|
|
% as well as vector of regrouped parameters
|
|
|
|
|
|
%
|
|
|
|
|
|
% first condition says that if DK(j,i+1) and DP(j,i+1) are zero
|
|
|
|
|
|
% or DK(j,i+1) is zero and DP(j,i+1) is constant
|
|
|
|
|
|
% the second condition says that if we have regrouped some parmeter
|
|
|
|
|
|
% with parameters of previous link so it is zero now
|
|
|
|
|
|
if (DK(j,i+1) == 0 && (DP(j,i+1)==0 || isempty(symvar(DP(j,i+1)))))...
|
|
|
|
|
|
|| pir_ur10_sym(j,i) == 0
|
|
|
|
|
|
str = strcat('\nlink\t ',num2str(i), ',\tparameter\t',num2str(j));
|
|
|
|
|
|
fprintf(str)
|
|
|
|
|
|
nd = nd + 1;
|
|
|
|
|
|
Pd(nd,(i-1)*10 + j) = 1;
|
|
|
|
|
|
else
|
|
|
|
|
|
nb = nb + 1;
|
|
|
|
|
|
DK_base{i} = vertcat(DK_base{i},DK(j,i+1));
|
|
|
|
|
|
DP_base{i} = vertcat(DP_base{i},DP(j,i+1));
|
|
|
|
|
|
|
|
|
|
|
|
pir_base_sym{i} = vertcat(pir_base_sym{i},pir_ur10_sym(j,i));
|
|
|
|
|
|
pir_base_num{i} = vertcat(pir_base_num{i},pir_ur10_num(j,i));
|
|
|
|
|
|
Pb(nb,(i-1)*10 + j) = 1;
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
% -------------------------------------------------------------------
|
|
|
|
|
|
% DK_base{i} = vertcat(DK_base{i}, 0.5*qd_sym(i)^2);
|
|
|
|
|
|
% DP_base{i} = vertcat(DP_base{i}, 0);
|
|
|
|
|
|
% pir_base_sym{i} = vertcat(pir_base_sym{i}, im(i));
|
|
|
|
|
|
% -------------------------------------------------------------------
|
|
|
|
|
|
fprintf('\n\n')
|
|
|
|
|
|
grad_Lagr = horzcat(grad_Lagr, (DK_base{i} - DP_base{i})');
|
|
|
|
|
|
pir_base_vctr = vertcat(pir_base_vctr,pir_base_num{i});
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2019-12-19 06:48:18 +00:00
|
|
|
|
|
2019-12-18 11:25:45 +00:00
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
% Computing Regressor
|
|
|
|
|
|
% -----------------------------------------------------------------------
|
|
|
|
|
|
dLagr_dq = jacobian(grad_Lagr,q_sym)';
|
|
|
|
|
|
dLagr_dqd = jacobian(grad_Lagr,qd_sym)';
|
|
|
|
|
|
t1 = sym(zeros(6,length(pir_base_vctr)));
|
|
|
|
|
|
for i = 1:6
|
|
|
|
|
|
t1 = t1 + diff(dLagr_dqd,q_sym(i))*qd_sym(i)+...
|
|
|
|
|
|
diff(dLagr_dqd,qd_sym(i))*q2d_sym(i);
|
|
|
|
|
|
end
|
|
|
|
|
|
Y_hat = t1 - dLagr_dq;
|
2019-12-19 06:48:18 +00:00
|
|
|
|
|
|
|
|
|
|
if generateBaseRegressorFunction
|
|
|
|
|
|
matlabFunction(Y_hat,'File','autogen/base_regressor_UR10E',...
|
|
|
|
|
|
'Vars',{q_sym,qd_sym,q2d_sym});
|
|
|
|
|
|
end
|
2019-12-18 11:25:45 +00:00
|
|
|
|
|
|
|
|
|
|
% ------------------------------------------------------------
|
|
|
|
|
|
% Finding mapping from standard parameters to base parameters
|
|
|
|
|
|
% ------------------------------------------------------------
|
|
|
|
|
|
pi_ur10_full = reshape(pi_ur10,[60,1]);
|
|
|
|
|
|
pi_ur10_rdcd = reshape(pir_ur10_sym,[60,1]);
|
|
|
|
|
|
pi_ur10_base = [pir_base_sym{1};pir_base_sym{2};pir_base_sym{3};...
|
|
|
|
|
|
pir_base_sym{4};pir_base_sym{5};pir_base_sym{6}];
|
|
|
|
|
|
dbase_dfull = jacobian(pi_ur10_base,pi_ur10_full);
|
|
|
|
|
|
Kd = jacobian(pi_ur10_base - Pb*pi_ur10_full, Pd*pi_ur10_full);
|
|
|
|
|
|
|
2019-12-19 06:48:18 +00:00
|
|
|
|
|
2019-12-18 11:25:45 +00:00
|
|
|
|
% --------------------------------------------------------------------
|
|
|
|
|
|
% Computing matrices of dynamic equations of motion
|
|
|
|
|
|
% --------------------------------------------------------------------
|
|
|
|
|
|
% Complement gradient Lagrangian with rotor contribution
|
|
|
|
|
|
grad_Lagr = [grad_Lagr, 0.5*qd_sym(3)^2, 0.5*qd_sym(4)^2,...
|
|
|
|
|
|
0.5*qd_sym(5)^2, 0.5*qd_sym(6)^2];
|
|
|
|
|
|
% Gradient of potential energy to find gravity vector
|
|
|
|
|
|
grad_P = [DP_base{1}', DP_base{2}', DP_base{3}', DP_base{4}',...
|
|
|
|
|
|
DP_base{5}', DP_base{6}', 0, 0, 0, 0];
|
|
|
|
|
|
% Create symbolic variable with base parameters of the robot
|
|
|
|
|
|
xi = sym('xi%d',[40,1],'real');
|
|
|
|
|
|
% Lagrangian
|
|
|
|
|
|
Lagr = grad_Lagr*xi;
|
|
|
|
|
|
% Potential energy
|
|
|
|
|
|
Pot_enrgy = grad_P*xi;
|
|
|
|
|
|
|
|
|
|
|
|
% Solving Lagrange equations to find
|
|
|
|
|
|
dLagr_dq = jacobian(Lagr,q_sym)';
|
|
|
|
|
|
dLagr_dqd = jacobian(Lagr,qd_sym)';
|
|
|
|
|
|
M_mtrx_sym = jacobian(dLagr_dqd, qd_sym);
|
|
|
|
|
|
G_vctr_sym = jacobian(Pot_enrgy,q_sym)';
|
|
|
|
|
|
|
|
|
|
|
|
% Finding matrix of Centrifugal and Coriolis forces
|
|
|
|
|
|
cs1 = sym(zeros(6,6,6)); % Christoffel symbols of the first kind
|
|
|
|
|
|
for i = 1:1:6
|
|
|
|
|
|
for j = 1:1:6
|
|
|
|
|
|
for k = 1:1:6
|
|
|
|
|
|
cs1(i,j,k) = 0.5*(diff(M_mtrx_sym(i,j), q_sym(k)) + ...
|
|
|
|
|
|
diff(M_mtrx_sym(i,k), q_sym(j)) - ...
|
|
|
|
|
|
diff(M_mtrx_sym(j,k), q_sym(i)));
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
C_mtrx_sym = sym(zeros(6, 6));
|
|
|
|
|
|
for i = 1:1:6
|
|
|
|
|
|
for j = 1:1:6
|
|
|
|
|
|
for k = 1:1:6
|
|
|
|
|
|
C_mtrx_sym(i,j) = C_mtrx_sym(i,j)+cs1(i,j,k)*qd_sym(k);
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2019-12-19 06:48:18 +00:00
|
|
|
|
if generateBaseDynamicsFunctions
|
|
|
|
|
|
fprintf('Generating dynamic equation elements:\n');
|
2019-12-18 11:25:45 +00:00
|
|
|
|
|
2019-12-19 06:48:18 +00:00
|
|
|
|
fprintf('\t Mass matrix\n');
|
|
|
|
|
|
matlabFunction(M_mtrx_sym,'File','autogen/M_mtrx_fcn','Vars',{q_sym,xi});
|
|
|
|
|
|
|
|
|
|
|
|
fprintf('\t Matrix of Coriolis and Centrifugal Forces\n');
|
|
|
|
|
|
matlabFunction(C_mtrx_sym,'File','autogen/C_mtrx_fcn','Vars',{q_sym,qd_sym,xi});
|
|
|
|
|
|
|
|
|
|
|
|
fprintf('\t Vector of gravitational forces\n');
|
|
|
|
|
|
matlabFunction(G_vctr_sym,'File','autogen/G_vctr_fcn','Vars',{q_sym,xi});
|
|
|
|
|
|
end
|
2019-12-18 11:25:45 +00:00
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
% --------------------------------------------------------------------
|
|
|
|
|
|
% Tests
|
|
|
|
|
|
% --------------------------------------------------------------------
|
|
|
|
|
|
q = rand(6,1);
|
|
|
|
|
|
qd = rand(6,1);
|
|
|
|
|
|
q2d = rand(6,1);
|
|
|
|
|
|
|
|
|
|
|
|
rbt = importrobot('ur10e.urdf');
|
|
|
|
|
|
rbt.DataFormat = 'column';
|
|
|
|
|
|
rbt.Gravity = [0 0 -9.81];
|
|
|
|
|
|
|
|
|
|
|
|
id_matlab = inverseDynamics(rbt,q,qd,q2d);
|
|
|
|
|
|
id_gutier = base_regressor(q,qd,q2d)*pir_base_vctr;
|
|
|
|
|
|
id_screwreg = screw_regressor(q,qd,q2d,ur10)*reshape(ur10.pi_reg,[60,1]);
|
|
|
|
|
|
id_lagrreg = full_regressor(q,qd,q2d)*reshape(ur10.pi,[60,1]);
|
|
|
|
|
|
|