%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % simulation of human arm movements % % by Hiroaki Gomi 21/July/2000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if 0 % arm length L1 = 0.282; L2 = 0.303; end % dynamics parameters for inverse dynamics % Z1_sim = 0.327; % Z2_sim = 0.109; % Z3_sim = 0.106; Simp = 0.001; % sampling interval for data storage (sec) % should not change %Cimp = 3.0; Cimp = 2; % data store period during experiment (sec) % can be change mov_start_time = 0.5; % (sec) %mov_duration_time = 1.0; % (sec) mov_duration_time = 0.75; % (sec) freq = 1.0/Simp; one_length = freq*Cimp; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Minimum Jerk Trajectory Calc x_mj = zeros(one_length,1); y_mj = zeros(one_length,1); xd_mj = zeros(one_length,1); yd_mj = zeros(one_length,1); xdd_mj = zeros(one_length,1); ydd_mj = zeros(one_length,1); th1_mj = zeros(one_length,1); th2_mj = zeros(one_length,1); th1d_mj = zeros(one_length,1); th2d_mj = zeros(one_length,1); th1dd_mj = zeros(one_length,1); th2dd_mj = zeros(one_length,1); des_start = mov_start_time * freq; des_end = (mov_start_time + mov_duration_time)*freq; diffX = TrialEndX - TrialStartX; diffY = TrialEndY - TrialStartY; t = [Simp:Simp:mov_duration_time]; t = (t')/mov_duration_time; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % calc cursor data vector % (pos, vel, acc) x_mj(1:des_start) = TrialStartX * (ones(des_start,1)); y_mj(1:des_start) = TrialStartY * (ones(des_start,1)); x_mj(des_end+1:one_length) = TrialEndX * (ones(one_length-des_end,1)); y_mj(des_end+1:one_length) = TrialEndY * (ones(one_length-des_end,1)); x_mj(des_start+1:des_end) =... diffX*(10.0*(t.^3) - 15*(t.^4) + 6.0*(t.^5)) + TrialStartX; y_mj(des_start+1:des_end) =... diffY*(10.0*(t.^3) - 15*(t.^4) + 6.0*(t.^5)) + TrialStartY; xd_mj(des_start+1:des_end) = diffX*... ( (30.0/mov_duration_time)*(t.^2)... - (60.0/mov_duration_time)*(t.^3)... + (30.0/mov_duration_time)*(t.^4)); yd_mj(des_start+1:des_end) = diffY*... ( (30.0/mov_duration_time)*(t.^2)... - (60.0/mov_duration_time)*(t.^3)... + (30.0/mov_duration_time)*(t.^4)); xdd_mj(des_start+1:des_end) = diffX*... ( (60.0/(mov_duration_time^2))*t... - (180.0/(mov_duration_time^2))*(t.^2)... + (120.0/(mov_duration_time^2))*(t.^3)); ydd_mj(des_start+1:des_end) = diffY*... ( (60.0/(mov_duration_time^2))*t... - (180.0/(mov_duration_time^2))*(t.^2)... + (120.0/(mov_duration_time^2))*(t.^3)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % angular variables % (pos, vel, acc) Kappa = ((x_mj.^2 + y_mj.^2 + L1^2 + L2^2).^2)... - 2.0*((x_mj.^2 + y_mj.^2).^2 + L1^4 + L2^4); Kappa = sqrt(Kappa); th1_mj = atan2(y_mj, x_mj) - atan2(Kappa, x_mj.^2 + y_mj.^2 + L1^2 - L2^2); th2_mj = atan2(Kappa, x_mj.^2 + y_mj.^2 - L1^2 - L2^2); % jacobian matrix component temporal vector produced jacob11v = (-L1 * sin(th1_mj)- L2 * sin(th1_mj+th2_mj)); jacob12v = (- L2 * sin(th1_mj+th2_mj)); jacob21v = L1 * cos(th1_mj)+ L2 * cos(th1_mj+th2_mj); jacob22v = L2 * cos(th1_mj+th2_mj); % inverse jacobian matrix Det = (jacob11v).*(jacob22v) - (jacob12v).*(jacob21v); jacob11v_inv = jacob22v./Det; jacob12v_inv = -jacob12v./Det; jacob21v_inv = -jacob21v./Det; jacob22v_inv = jacob11v./Det; th1d_mj = jacob11v_inv.*xd_mj + jacob12v_inv.*yd_mj; th2d_mj = jacob21v_inv.*xd_mj + jacob22v_inv.*yd_mj; jacob11vd =... -L1*cos(th1_mj).*th1d_mj - L2*cos(th1_mj+th2_mj).*(th1d_mj+th2d_mj); jacob12vd = -L2*cos(th1_mj+th2_mj).*(th1d_mj+th2d_mj); jacob21vd =... -L1*sin(th1_mj).*th1d_mj - L2*sin(th1_mj+th2_mj).*(th1d_mj+th2d_mj); jacob22vd = -L2*sin(th1_mj+th2_mj).*(th1d_mj+th2d_mj); temp1 = (xdd_mj - (jacob11vd.*th1d_mj + jacob12vd.*th2d_mj)); temp2 = (ydd_mj - (jacob21vd.*th1d_mj + jacob22vd.*th2d_mj)); th1dd_mj = jacob11v_inv.* temp1 + jacob12v_inv.* temp2; th2dd_mj = jacob21v_inv.* temp1 + jacob22v_inv.* temp2; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Calc Dynamic Torque p11 = th1dd_mj; p12 = cos(th2_mj).*(2*th1dd_mj + th2dd_mj) ... - sin(th2_mj).*(th2d_mj .* th2d_mj + 2 * th1d_mj .* th2d_mj); p13 = th2dd_mj; p22 = cos(th2_mj).*th1dd_mj + sin(th2_mj) .* (th1d_mj .* th1d_mj); p23 = th1dd_mj + th2dd_mj; tau1_dyn = Z1_sim * p11 + Z2_sim * p12 + Z3_sim * p13; tau2_dyn = Z2_sim * p22 + Z3_sim * p23; tau_ff_h = [tau1_dyn, tau2_dyn]'; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % initialize valiables th_r = [th1_mj,th2_mj,th1d_mj,th2d_mj]'; % reference input th_h = zeros(size(th_r)); % realized theta buffer th_s = zeros(size(th_r)); % predicted theta buffer tau_smith_h = zeros(2,size(th_r,2)); % torque generated by smith predictor tau_h = zeros(2,size(th_r,2)); % torque buffer th0 = [th1_mj(1), th2_mj(1), 0, 0]'; th_h(:,1) = th0; th_s(:,1) = th0; th = th0; thP = th0; %FbGain = [8,0,3,0; 0,8,0,3]; %FbGain = [5,0,2,0; 0,5,0,2]; %delay_t = 0.040; % sec %delayP_t = 0.040; % sec delay = delay_t/Simp; delayP = delayP_t/Simp; mu1 = 1e-6; % gains for parameter adaptation mu2 = mu1; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for i=0:Cimp/Simp-1 t = i*Simp; %%%%%%%%%%%%%%%%%%%%%%%%% % feedback loop th_ref = th_r(:,round(t/Simp)+1); if round(t/Simp)+1-delay < 1 th_obs = th_h(:,1); else th_obs = th_h(:,round(t/Simp)+1-delay); end tau_fb = FbGain*(th_ref - th_obs); %%%%%%%%%%%%%%%%%%%%%%%%% % smith predictor th_p = th_s(:,round(t/Simp)+1); if round(t/Simp)+1-delayP < 1 th_pd = th_s(:,1); else th_pd = th_s(:,round(t/Simp)+1-delayP); end tau_smith = FbGain*(th_pd - th_p); tau_smith_h(:,round(t/Simp)+1) = tau_smith; if sw_smith == 0 tau_smith = 0; end %%%%%%%%%%%%%%%%%%%%%%%%% % feedforward loop if 0 tau1_dy = Z1_sim * p11(round(t/Simp)+1) ... + Z2_sim * p12(round(t/Simp)+1) + Z3_sim * p13(round(t/Simp)+1); tau2_dy = Z2_sim * p22(round(t/Simp)+1) + Z3_sim * p23(round(t/Simp)+1); tau_ff = [tau1_dy, tau2_dy]'; Z1_sim = Z1_sim + mu1*p11(round(t/Simp)+1)*(tau_fb(1)+tau_smith(1)); Z2_sim = Z2_sim + mu1*p12(round(t/Simp)+1)*(tau_fb(1)+tau_smith(1)) ... + mu2*p22(round(t/Simp)+1)*(tau_fb(2)+tau_smith(2)); Z3_sim = Z3_sim + mu1*p13(round(t/Simp)+1)*(tau_fb(1)+tau_smith(1)) ... + mu2*p23(round(t/Simp)+1)*(tau_fb(2)+tau_smith(2)); Z_h(:,round(t/Simp)+1) = [Z1_sim, Z2_sim, Z3_sim]'; end %tau_ff = 0; tau_ff = tau_ff_h(:,round(t/Simp)+1); %%%%%%%%%%%%%%%%%%%%%%%%% % total input to dynamics %tau = tau_fb + tau_smith + tau_ff; tau = tau_fb + tau_smith; % For Smith Predictor %tau = tau_fb + tau_ff; %tau = tau_fb; %%%%%%%%%%%%%%%%%%%%%%%%% % Perturbation %fext = [0, 2]'; %if t > (mov_start_time + 0.15) % if t < (mov_start_time + 0.2) % tau = tau + fext; % end %end tau_h(:,round(t/Simp)+1) = tau; %%%%%%%%%%%%%%%%%%%%%%%%% % forward dynamics for smith predictor thPdot = d2P(t,thP); thP = thP + thPdot *Simp; th_s(:,round(t/Simp)+2) = thP; %%%%%%%%%%%%%%%%%%%%%%%%% thdot = d2(t,th); th = th + thdot * Simp; th_h(:,round(t/Simp)+2) = th; end %%%%%%%%%%%%%%%%%%%%%%%%% figure(2) plot(th_h') hold on; plot(th_r','--') pos_x = L1*cos(th_h(1,:))+L2*cos(th_h(1,:)+th_h(2,:)); pos_y = L1*sin(th_h(1,:))+L2*sin(th_h(1,:)+th_h(2,:)); figure(1) plot(pos_x,pos_y) set(gca,'PlotBoxAspectRatio',[1,1,1]) set(gca,'ylim',[-0.4,0.6]); set(gca,'xlim',[-0.4,0.6]); % figure(3) % plot(Z_h')