function simulate_twolegs()
m1 =.0393 + .2; m2 =.0368;
m3 = .00783; m4 = .0155;
I1 = 25.1 * 10^-6; I2 = 53.5 * 10^-6;
I3 = 9.25 * 10^-6; I4 = 22.176 * 10^-6;
l_OA=.011; l_OB=.042;
l_AC=.096; l_DE=.091;
l_O_m1=0.032; l_B_m2=0.0344;
l_A_m3=0.0622; l_C_m4=0.0610;
N = 18.75;
Ir = 0.0035/N^2;
g = 9.81;
q1_min = deg2rad(-90);
q1_max = deg2rad(90);
q2_min = deg2rad(25);
q2_max = deg2rad(135);
qlims = [q1_min, q1_max, q2_min, q2_max];
Kt = 0.191;
R_internal = 1.594;
v = 12;
restitution_coeff = 0.;
friction_coeff = 10;
ground_height = 0;
step_th = deg2rad(30);
step_h = 3*0.0254;
step_w = step_h/tan(step_th);
offset_x = 0;
stair_height = @(x) floor((x+offset_x)./step_w).*step_h + ground_height;
p = [m1 m2 m3 m4 I1 I2 I3 I4 Ir N l_O_m1 l_B_m2 l_A_m3 l_C_m4 l_OA l_OB l_AC l_DE g R_internal Kt v]';
p_traj.omega = -10;
L = (l_DE+l_OB);
p_traj.x_off = -L*0.5;
p_traj.y_off = -L*1.4;
p_traj.a = 0.065;
p_traj.b = 0.06;
p_traj.phi = 2*step_th;
p_traj.phase = pi;
p_traj.r = (p_traj.a+p_traj.b)/2;
dt = 0.001;
tf = 5;
num_step = floor(tf/dt);
tspan = linspace(0, tf, num_step);
z0 = [0.0692; 0.1868; -pi/4; pi/3; -pi/4; pi/3; 0; 0; 0; 0; 0; 0];
z_out = zeros(12,num_step);
z_out(:,1) = z0;
torque_comm = zeros(6,num_step);
actual_torques = zeros(4, num_step);
for i=1:num_step-1
dz = dynamics(tspan(i), z_out(:,i), p, p_traj);
z_temp = z_out(:,i) + dz * dt;
z_temp(7:12) = discrete_impact_contact(z_temp, p,restitution_coeff,friction_coeff,stair_height);
z_temp(7:12) = joint_limit_constraint(z_temp, p, qlims);
z_out(:,i+1) = z_temp;
torque_comm(:,i) = control_law(tspan(i), z_out(:,i), p, p_traj);
actual_torques(:,i) = motorDynamics(tspan(i),z_out(:,i),p,torque_comm(:,i));
end
figure(6); clf;
hold on
steps = 70;
stair_X = linspace(-step_w,step_w*steps,1000);
stair_Y = stair_height(stair_X);
plot(stair_X,stair_Y,'k');
animateSol(tspan, z_out,p, p_traj);
end
function tau = control_law(t, z, p, p_traj)
K_x = 500.;
K_y = 500.;
D_x = 10.;
D_y = 10.;
K = [K_x, 0 ; 0, K_y];
D = [D_x, 0 ; 0, D_y];
x_center = z(1) + p_traj.x_off;
y_center = z(2) + p_traj.y_off;
phase = p_traj.phase;
w = p_traj.omega;
a = p_traj.a;
b = p_traj.b;
phi = p_traj.phi;
theta1 = w*t;
theta2 = theta1 + phase;
x_pos = @(theta) x_center + a * cos(theta) * cos(phi) - b * sin(theta) * sin(phi);
y_pos = @(theta) y_center + a * cos(theta) * sin(phi) + b * sin(theta) * cos(phi);
x_vel = @(theta) - a * sin(theta) * cos(phi)*w - b * cos(theta) * sin(phi) * w;
y_vel = @(theta) - a * sin(theta) * sin(phi)*w + b * cos(theta) * cos(phi) * w;
x_acc = @(theta) - a * cos(theta) * cos(phi)*w^2 + b * sin(theta) * sin(phi) * w^2;
y_acc = @(theta) - a * cos(theta) * sin(phi)*w^2 - b * sin(theta) * cos(phi) * w^2;
rEd1 = [x_pos(theta1) y_pos(theta1)]';
vEd1 = [x_vel(theta1) y_vel(theta1)]';
aEd1 = [x_acc(theta1) y_acc(theta1)]';
rEd2 = [x_pos(theta2) y_pos(theta2)]';
vEd2 = [x_vel(theta2) y_vel(theta2)]';
aEd2 = [x_acc(theta2) y_acc(theta2)]';
rE1 = position_foot1(z,p);
vE1 = velocity_foot1(z,p);
rE2 = position_foot2(z,p);
vE2 = velocity_foot2(z,p);
A = A_twolegs(z,p);
inv_A = inv(A);
Corr = Corr_twolegs(z,p);
Grav = Grav_twolegs(z,p);
qdot = qdot_twolegs(z,p);
J1 = jacobian_foot1(z,p);
J2 = jacobian_foot2(z,p);
dJ1 = jacobian_dot_foot1(z,p);
dJ2 = jacobian_dot_foot2(z,p);
J1 = jacobian_foot1(z, p);
J2 = jacobian_foot2(z, p);
lambda = inv (J1 * inv_A * (J1.'));
mu1 = (lambda * J1 * inv_A * Corr) - (lambda * dJ1 * qdot);
rho1 = lambda * J1 * inv_A * Grav;
intermediate1 = aEd1 + K * (rEd1 - rE1(1:2, 1:end)) + D * (vEd1 - vE1(1:2, 1:end));
f1 = lambda * intermediate1 + mu1 + rho1;
lambda2 = inv (J2 * inv_A * (J2.'));
mu2 = (lambda2 * J2 * inv_A * Corr) - (lambda2 * dJ2 * qdot);
rho2 = lambda2 * J2 * inv_A * Grav;
intermediate2 = aEd2+ K * (rEd2 - rE2(1:2, 1:end)) + D * (vEd2 - vE2(1:2, 1:end));
f2 = lambda2 * intermediate2 + mu2 + rho2;
tau1 = J1' * f1;
tau1 = tau1(3:4);
tau2 = J2' * f2;
tau2 = tau2(5:6);
tau = [0;0;tau1; tau2];
end
function dz = dynamics(t,z,p, p_traj)
A = A_twolegs(z,p);
tau = control_law(t,z,p,p_traj);
b = b_twolegs(z,tau,p);
qdd = A\(b);
dz = zeros(size(z));
dz(1:6) = z(7:12);
dz(7:12) = qdd;
end
function qdot = discrete_impact_contact(z,p, rest_coeff, fric_coeff, yC_fun)
rE1 = position_foot1(z,p);
vE1 = velocity_foot1(z,p);
rE2 = position_foot2(z,p);
vE2 = velocity_foot2(z,p);
J1 = jacobian_foot1(z,p);
J2 = jacobian_foot2(z,p);
A = A_twolegs(z,p);
inv_A = inv(A);
osim1 = inv (J1 * inv_A * J1');
osim2 = inv (J2 * inv_A * J2');
xhat = [1,0];
yhat = [0,1];
mass_eff_x1 = 1 / (xhat * inv(osim1) * xhat');
mass_eff_y1 = 1 / (yhat * inv(osim1) * yhat');
mass_eff_x2 = 1 / (xhat * inv(osim2) * xhat');
mass_eff_y2 = 1 / (yhat * inv(osim2) * yhat');
x1 = rE1(1);
x2 = rE2(1);
yC1 = yC_fun(x1);
yC2 = yC_fun(x2);
C_y1 = rE1(2) - yC1;
Cdot_y1 = vE1(2);
C_y2 = rE2(2) - yC2;
Cdot_y2 = vE2(2);
qdot = qdot_twolegs(z,p);
if (C_y1 <= 0) && (Cdot_y1 <= 0)
F_impulse_y1 = mass_eff_y1 * (-rest_coeff * Cdot_y1 - J1(2,:) * qdot);
F_impulse_x1 = mass_eff_x1 * (-J1(1,:) * qdot);
if abs(F_impulse_x1) > abs(fric_coeff * F_impulse_y1)
F_impulse_x1 = sign(F_impulse_x1) * fric_coeff * F_impulse_y1;
end
qdot = qdot + (inv_A * J1(2,:).' * F_impulse_y1) + (inv_A * J1(1,:).' * F_impulse_x1);
end
if (C_y2 <= 0) && (Cdot_y2 <= 0)
F_impulse_y2 = mass_eff_y2 * (-rest_coeff * Cdot_y2 - J2(2,:) * qdot);
F_impulse_x2 = mass_eff_x2 * (-J2(1,:) * qdot);
if abs(F_impulse_x2) > abs(fric_coeff * F_impulse_y2)
F_impulse_x2 = sign(F_impulse_x2) * fric_coeff * F_impulse_y2;
end
qdot = qdot + (inv_A * J2(2,:).' * F_impulse_y2) + (inv_A * J2(1,:).' * F_impulse_x2);
end
qdot = qdot;
end
function totalEnergy = computeMotorEnergySpent (t, torque_comm, Kt, R_internal)
torque_comm = torque_comm(3:6, :);
totalEnergy = zeros(1,length(t));
power = zeros(1,length(t));
for m = 1:4
for c = 1:length(t)
current = torque_comm(m,c)/Kt;
power(c) = (current.^2) / R_internal;
energyTemp = trapz(t, power);
totalEnergy(c) = totalEnergy(c) + energyTemp;
end
power = zeros(1,length(t));
end
totalEnergy = totalEnergy;
end
function actual_torques = motorDynamics (t,z,p,torque_comm)
tau_comm = torque_comm(3:6);
v_max = p(22); Kt = p(21); R = p(20);
w = z(9:12);
I_max = v_max/R;
stall_torque = abs(I_max*Kt);
back_emf = abs(Kt^2/R.*w);
Max_torques = stall_torque - back_emf;
actual_torques = min(Max_torques, abs(tau_comm)).*sign(tau_comm);
end
function qdot = joint_limit_constraint(z, p, limits)
q = z(1:6);
dq = z(7:12);
qdot = dq;
q1min = limits(1);
q1max = limits(2);
q2min = limits(3);
q2max = limits(4);
q1 = q(3);
q2 = q(4);
q3 = q(5);
q4 = q(6);
dth1 = dq(3);
dth2 = dq(4);
dth3 = dq(5);
dth4 = dq(6);
A = A_twolegs(z, p);
inv_mass = inv(A);
if ((q1 <= q1min) && (dth1 < 0)) || ((q1 >= q1max) && (dth1 > 0))
Jc = [0, 0, 1, 0, 0, 0];
e = 0;
Lambda = - (1 + e) * (Jc * dq) / (Jc * inv_mass * Jc');
qdot = qdot + inv_mass * (Jc' * Lambda);
end
if ((q2 <= q2min) && (dth2 < 0)) || ((q2 >= q2max) && (dth2 > 0))
Jc = [0, 0, 0, 1, 0, 0];
A = A_twolegs(z, p);
e = 0;
Lambda = - (1 + e) * (Jc * dq) / (Jc * inv_mass * Jc');
qdot = qdot + inv_mass * (Jc' * Lambda);
end
if ((q3 <= q1min) && (dth3 < 0)) || ((q3 >= q1max) && (dth3 > 0))
Jc = [0, 0, 0, 0, 1, 0];
A = A_twolegs(z, p);
e = 0;
Lambda = - (1 + e) * (Jc * dq) / (Jc * inv_mass * Jc');
qdot = qdot + inv_mass * (Jc' * Lambda);
end
if ((q4 <= q2min) && (dth4 < 0)) || ((q4 >= q2max) && (dth4 > 0))
Jc = [0, 0, 0, 0, 0, 1];
A = A_twolegs(z, p);
e = 0;
Lambda = - (1 + e) * (Jc * dq) / (Jc * inv_mass * Jc');
qdot = qdot + inv_mass * (Jc' * Lambda);
end
end
function animateSol(tspan,x,p,p_traj)
hold on
h_OB = plot([0],[0],'LineWidth',2);
h_AC = plot([0],[0],'LineWidth',2);
h_BD = plot([0],[0],'LineWidth',2);
h_CE = plot([0],[0],'LineWidth',2);
h_OB2 = plot([0],[0],'LineWidth',2);
h_AC2 = plot([0],[0],'LineWidth',2);
h_BD2 = plot([0],[0],'LineWidth',2);
h_CE2 = plot([0],[0],'LineWidth',2);
h_ellipse = plot([0],[0],'LineWidth',2);
h_ref1 = plot([0],[0],'r.');
h_ref2 = plot([0],[0],'b.');
xlabel('x'); ylabel('y');
h_title = title('t=0.0s');
axis equal
axis([-0 3.0 -0 1.8]);
TH = 0:.1:2*pi;
for i = 1:length(tspan)
if mod(i,10)
continue;
end
t = tspan(i);
z = x(:,i);
keypoints = keypoints_twolegs(z,p);
rO = keypoints(:,1);
rA = keypoints(:,2);
rB = keypoints(:,3);
rC = keypoints(:,4);
rD = keypoints(:,5);
rE = keypoints(:,6);
rA2 = keypoints(:,7);
rB2 = keypoints(:,8);
rC2 = keypoints(:,9);
rD2 = keypoints(:,10);
rE2 = keypoints(:,11);
set(h_title,'String', sprintf('t=%.2f',t) );
set(h_OB,'XData',[rO(1) rB(1)]);
set(h_OB,'YData',[rO(2) rB(2)]);
set(h_AC,'XData',[rA(1) rC(1)]);
set(h_AC,'YData',[rA(2) rC(2)]);
set(h_BD,'XData',[rB(1) rD(1)]);
set(h_BD,'YData',[rB(2) rD(2)]);
set(h_CE,'XData',[rC(1) rE(1)]);
set(h_CE,'YData',[rC(2) rE(2)]);
set(h_OB2,'XData',[rO(1) rB2(1)]);
set(h_OB2,'YData',[rO(2) rB2(2)]);
set(h_AC2,'XData',[rA2(1) rC2(1)]);
set(h_AC2,'YData',[rA2(2) rC2(2)]);
set(h_BD2,'XData',[rB2(1) rD2(1)]);
set(h_BD2,'YData',[rB2(2) rD2(2)]);
set(h_CE2,'XData',[rC2(1) rE2(1)]);
set(h_CE2,'YData',[rC2(2) rE2(2)]);
x_center = z(1) + p_traj.x_off;
y_center = z(2) + p_traj.y_off;
X_ell = @(theta) x_center + p_traj.a .* cos(theta) .* cos(p_traj.phi) - p_traj.b .* sin(theta) .* sin(p_traj.phi);
Y_ell = @(theta) y_center + p_traj.a * cos(theta) .* sin(p_traj.phi) + p_traj.b .* sin(theta) .* cos(p_traj.phi);
set(h_ellipse, 'XData',X_ell(TH));
set(h_ellipse, 'YData',Y_ell(TH));
theta1 = t*p_traj.omega;
theta2 = t*p_traj.omega+p_traj.phase;
set(h_ref1, {'XData','YData'}, {X_ell(theta1), Y_ell(theta1)});
set(h_ref2, {'XData','YData'}, {X_ell(theta2), Y_ell(theta2)});
pause(.01)
end
end