%*************************************************************************
% Script "cam.m" to design the class example of a disk cam with          *
% reciprocating flat-face follower.                                      *
%                                                                        *
% This cam produces a full-rise of 1 inch in 120 degrees of cam rotation *
% using Simple Harmonic Motion (SHM).  This is followed by a full-return *
% using SHM of 1 inch in 240 degrees of cam rotation.                    *
%*************************************************************************

L = 1;          % Rise and return distance (in)
RAD = pi/180;   % Radian conversion factor
DEG = 180/pi;   % Degree conversion factor
STEP = 1;       % Cam angle stepsize (DEG)

% First find the displacement, first and second kinematic coefficient
% functions for the full-rise SHM segment.  This is termed Segment 1.

% Note that for this cam the "beta" durations are 120 and 240 degrees (an
% "even" number of degrees) so we can use an integer stepsize of 1 degree.
% This is not true (for example) in HW Problem 7 (and in my other design
% script).

beta1d = 120;           % Cam duration for segment 1 (DEG)
beta1r = beta1d*RAD;	% Cam duration for segment 1 (RAD)

t1d = [0:STEP:beta1d]';	% Cam angle from 0 to 120 degrees; column vector (')
t1r = t1d*RAD;          % Convert to RAD

% First compute the displacement function y1 and plot it vs t1d (DEG)

y1 = (L/2)*(1-cos(pi*t1r/beta1r));
plot(t1d,y1,'k-','linewidth',2);
axis([0 beta1d min(y1)*1.1 max(y1)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('Follower motion y (in)','fontsize',20);
title('Displacement Function for Segment 1','fontsize',20);
pause;
delete(gcf);

% Next the first kinematic coefficient y1p (y1p*omega = velocity ydot)

y1p = ((pi*L)/(2*beta1r))*sin(pi*t1r/beta1r);
plot(t1d,y1p,'k-','linewidth',2);
axis([0 beta1d min(y1p)*1.1 max(y1p)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('1st Kin. Coeff. (VEL)','fontsize',20);
title('First Kinematic Coeff ("VEL") for Segment 1','fontsize',20);
pause;
delete(gcf);

% Finally the second kinematic coefficient y1pp (y1pp*omega^2 = accel yddot)

y1pp = ((pi^2*L)/(2*beta1r^2))*cos(pi*t1r/beta1r);
plot(t1d,y1pp,'k-','linewidth',2);
axis([0 beta1d min(y1pp)*1.1 max(y1pp)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('2nd Kin. Coeff. (ACCEL)','fontsize',20);
title('Second Kinematic Coeff ("ACCEL") for Segment 1','fontsize',20);
pause;
delete(gcf);

% Now plot all three on the same plot
plot(t1d,y1,'k-','linewidth',2); hold on;
plot(t1d,y1p,'r-','linewidth',2);
plot(t1d,y1pp,'b-','linewidth',2);
legend('Displ','"Vel"','"Accel"','location','best');
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('Displ, 1st & 2nd Coeff. (in)','fontsize',20);
title('Displ, "Vel", "Accel" for Segment 1','fontsize',20);
pause;
delete(gcf);

% Next find the displacement, first and second kinematic coefficient
% functions for the full-return SHM segment.  This is termed Segment 2.
% Note that we start segment 2 from zero angle, even though it "really"
% starts at 120 degrees.  Much easier if you start from zero.

beta2d = 240;       % Cam duration for segment 2 (DEG)
beta2r = beta2d*RAD;	% Cam duration for segment 2 (RAD)

t2d = [0:STEP:240]';	% Cam angle from 0 to 240 degrees; column vector (')
t2r = t2d*RAD;          % Convert to RAD

% Same drill here; first compute the displacement function y2 and plot

y2 = (L/2)*(1+cos(pi*t2r/beta2r));
plot(t2d,y2,'k-','linewidth',2);
axis([0 beta2d min(y2)*1.1 max(y2)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('Follower motion y (in)','fontsize',20);
title('Displacement Function for Segment 2','fontsize',20);
pause;
delete(gcf);

% Next compute the first and second kinematic coefficients yp and ypp and
% plot

y2p = (-(pi*L)/(2*beta2r))*sin(pi*t2r/beta2r);
plot(t2d,y2p,'k-','linewidth',2);
axis([0 beta2d min(y2p)*1.1 max(y2p)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('1st Kin. Coeff. (VEL)','fontsize',20);
title('First Kinematic Coeff ("VEL") for Segment 2','fontsize',20);
pause;
delete(gcf);

y2pp = (-(pi^2*L)/(2*beta2r^2))*cos(pi*t2r/beta2r);
plot(t2d,y2pp,'k-','linewidth',2);
axis([0 beta2d min(y2pp)*1.1 max(y2pp)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('2nd Kin. Coeff. (ACCEL)','fontsize',20);
title('Second Kinematic Coeff ("ACCEL") for Segment 2','fontsize',20);
pause;
delete(gcf);

% Now plot all three on the same plot

plot(t2d,y2,'k-','linewidth',2); hold on;
plot(t2d,y2p,'r-','linewidth',2);
plot(t2d,y2pp,'b-','linewidth',2);
axis([0 beta2d min([min(y2) min(y2p) min(y2pp)])*1.1 ...
    max([max(y2) max(y2p) max(y2pp)])*1.1]);
legend('Displ','"Vel"','"Accel"','location','best');
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('Displ, 1st & 2nd Coeff. (in)','fontsize',20);
title('Displ, "Vel", "Accel" for Segment 2','fontsize',20);
pause;
delete(gcf);

% Even though the minimum follower radius may have been computed, one can
% get that value from the numerical values just computed.  We want to
% find the maximum value of the magnitude of y1p (the max velocity will
% occur during Segment 1).

r_min = max(abs(y1p));  % Find the maximum of the absolute value of y1p

s = sprintf('\nMinimum follower radius is: %.2f inches\n', r_min); % Display
disp(s);

% Next find the minimum base circle radius.  We will find the minimum base
% circle radius so that the cam profile has no cusps, then give the user
% the option of entering the desired base circle radius.  For no cusps, the
% minimum base circle radius Ro is equal to the maximum value of (-y-ypp).
% Since we've computed both of those, finding the max should be easy.  We
% do need to check both segments 1 and 2, although intuitively segment 1
% has the fastest motion, so it should determine.

R(1) = max(-y1-y1pp);
R(2) = max(-y2-y2pp);

Ro = max(R);

s = sprintf('Minimum base circle radius is: %.4f inches\n', Ro); % Display
disp(s);

Ro = input('Enter desired base circle radius: ');

% Now we can calculate the cam profile using the xc and yc equations from
% the cam/follower geometric analysis.  However, this will require
% concatenating the two motions.  Whenever one does this, there will be a
% duplicate point between the two that should be removed.

N1 = length(t1r);   % Length of segment 1 (samples)
N2 = length(t2r);   % Length of segment 2 (samples)

% Now to "cement" the two segments together.  Since they are both column
% vectors, we can just stack them one on top of the other.  Before we do
% that, however, remove the last point from the first segment, since it's a
% duplicate

y1 = y1(1:N1-1);    % Remove the last point from 
y1p = y1p(1:N1-1);	% Segment 1 for all three
y1pp = y1p(1:N1-1);	% motion functions

% Now stack them on top of one another

y = [y1;y2];    % The ";" operator means new row, so the two cols are stacked
yp = [y1p;y2p];
ypp = [y1pp;y2pp];

% Finally create a vector of cam angle from start (0 DEG) to finish (360
% DEG).  The stepsize is 1 DEG; if another step

thetad = [0:STEP:360]';   % Total cam angle (DEG), STEP increment
thetar = thetad*RAD;  % Convert to RAD

% Now plot the entire motion: displacement, "velocity", and "acceleration"

plot(thetad,y,'k-','linewidth',2);
axis([0 360 min(y)*1.1 max(y)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('Follower motion y (in)','fontsize',20);
title('Displacement Function for Entire Motion','fontsize',20);
pause;
delete(gcf);

plot(thetad,yp,'k-','linewidth',2);
axis([0 360 min(yp)*1.1 max(yp)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('1st Kin. Coeff. (VEL)','fontsize',20);
title('First Kinematic Coeff ("VEL") for Entire Motion','fontsize',20);
pause;
delete(gcf);

plot(thetad,ypp,'k-','linewidth',2);
axis([0 360 min(ypp)*1.1 max(ypp)*1.1]);
grid;
set(gca,'fontsize',20);
xlabel('Cam angle (DEG)','fontsize',20);
ylabel('2nd Kin. Coeff. (ACCEL)','fontsize',20);
title('Second Kinematic Coeff ("ACCEL") for Entire Motion','fontsize',20);
pause;
delete(gcf);

% This is enough.  The parameters can now be passed to the camprofile.m
% function, which will produce the (xc,yc) profile points.  These can
% easily plotted.

disp('Files y, yp, theta created...ready for camprofile.m to');
disp('generate (x,y) coordinates of cam profile.');
disp(' ');  % Blank line