image thumbnail

Cam Simulator

by

 

02 Jan 2009 (Updated )

Given a set of motion programs this interface plots the cam profile and rotates it.

cams(varargin)
function cams(varargin)
global S
%{
Cam Simulator

To launch, simply type cams in the MATLAB command window with this in the current
directory. Alternatively, you can choose Debug -> Run from this editor window,
or press F5.

Helpful Notes:

- The first edit box column is to contain the motion type(s). Each row of it
  should have one of the preset motions written inside it (SHM, CYC, etc...).

- The second edit box is to specify the duration of each of the motion types.
  Each row should contain a duration in degrees for the corresponding respective
  motion type.

- The third edit box contains the respective displacemens for the motion types.

- The durations (second box) have to add up to 360 degrees. Also, while not
  necessary in the typical sense, the displacements should generally add up to 0.

- To understand more, see one of the pre-set examples found at File -> Load.

- As for the axis limits, the first is offline at the current time. The second
  changes the axis for the second plot (Velocity) and the third for the third plot
  (Acceleration).
 
- The number under 'Res' changes the number of points for drawing the cam profile.
  It is the top critereon for the load time above it.

- You can change the speed of rotation (Fast, Slow, Pause) during animation.

- Any comments should be sent to <numandina@gmail.com>. Don't hesitate to send!

- Recommended resolution is 1280 by 800 pixels.

- Works only on MATLAB 7.4 (R2007a) and above.
%}

%% Main Figure and Menus
figure('units','normalized',...
	'position',[.1 .1 .8 .75],...
	'color','w',...
	'numbertitle','off',...
	'menubar','none',...
	'name','Cam Simulator')

m1=uimenu('Label','File');
m2=uimenu('Label','More');

% when you click on a menu the code go to its corresponding callback function
uimenu(m1,'Label','Save Model','Callback',@savv); 
uimenu(m1,'Label','Load Model','Callback',@ladd,'Separator','on');
uimenu(m1,'Label','Quit','Callback',@xq,'Separator','on');
uimenu(m2,'Label','About','Callback',@bott);

%% File -> quit
	function xq(varargin) 
		close(gcf)
	end

%% File -> Save
	function savv(varargin)

		% make a small figure with a button, text and edit
		figure('units','normalized','position',[0.1 .6 .2 .2],'color','w','numbertitle','off','menubar','none','name','Save')
		uicontrol('style','text','units','normalized','position',[.05 .7 .9 .2],'string','Save Model As','backgroundcolor','w',...
			'fontsize',15,'fontweight','b','fontname','arial','horizontalalignment','left')
		se=uicontrol('style','edit','units','normalized','position',[.05 .525 .7 .2],'string','','backgroundcolor','w',...
			'fontsize',15,'fontweight','b','fontname','arial','horizontalalignment','left');
		uicontrol('style','pushbutton','units','normalized','position',[.1 .25 .5 .2],'string','Save','backgroundcolor','w',...
			'fontsize',15,'fontweight','b','fontname','arial','horizontalalignment','left','callback',@savvy)
		
		% what happens when you press 'Save'
		function savvy(varargin)						
			ns=get(se,'string'); % get name in edit box
			close(gcf) % close the 'Save' figure window
			
			% get important values from edit boxes
			Types=get(MT,'string');%#ok
			Disps=(get(MA,'string'));%#ok
			Durations=(get(MD,'string'));%#ok
			rb=(get(BC,'string'));%#ok
			
			if get(hr,'selectedobject')==hb1 % flat face follower has less variables to save ;)
				
				%this variable is to indicate how many variables are saved. it
				%will be used when we load
				kk=1; %#ok
				
			    % save needed variables in the name in the directory Models\
				save(['Models\',ns,'.mat'],'Types','Disps','Durations','rb','kk')
			else
				kk=2; %#ok
				rd=(get(t2,'string')); %#ok
				e=(get(t4,'string')); %#ok
				kc=(get(t6,'string')); %#ok
				save(['Models\',ns,'.mat'],'Types','Disps' ,'Durations' ,'rb','rd','e','kc','kk')				
			end
		end
		
	end

%% File -> Load
	function ladd(varargin) 
		
		% make a small figure window with a button, edit and text
		figure('units','normalized','position',[0.1 .6 .4 .2],'color','w','numbertitle','off','menubar','none','name','Load')
		uicontrol('style','text','units','normalized','position',[.05 .7 .9/2 .2],'string','Enter Name of Model','backgroundcolor','w',...
			'fontsize',11,'fontweight','b','fontname','arial','horizontalalignment','left')
		uicontrol('style','text','units','normalized','position',[.05+.9/2+.1-.1 .7 .9/2 .2],'string','Available Models','backgroundcolor','w',...
			'fontsize',11,'fontweight','b','fontname','arial','horizontalalignment','left')
		se=uicontrol('style','edit','units','normalized','position',[.05 .525 .7/2 .2],'string','','backgroundcolor','w',...
			'fontsize',15,'fontweight','b','fontname','arial','horizontalalignment','left');
		uicontrol('style','pushbutton','units','normalized','position',[.1 .25 .5/2 .2],'string','Load','backgroundcolor','w',...
			'fontsize',15,'fontweight','b','fontname','arial','horizontalalignment','left','callback',@laddy)
		
		% get all files in the folder 'Models' that end with '.mat'
		pW=dir('Models\*.mat');
		
		% save their names as a character matrix
		hol=strvcat(pW.name); 
		
		% change '.mat' into spaces for each name
		for lopp=1:size(hol,1)
			hol(lopp,:)=strrep(hol(lopp,:),'.mat',repmat(' ',1,4)); 
		end
		
		% make a listbox with the previous names matrix as string
		pl=uicontrol('style','listbox','max',2,'units','normalized','position',[.05+.9/2 .1 .9/2 .7],'string',hol,'backgroundcolor','w',...
			'fontsize',11,'fontweight','b','fontname','arial','horizontalalignment','left','callback',@yah);
		
		% every time you click a name in the listbox the name is displayed in
		% the edit box as per the following function
		function yah(varargin)
			sh=get(pl,'value'); % get value of chosen element in the listbox
			sg=(get(pl,'string')); 
			sj=sg(sh,:); % get the string respective to that value
 			set(se,'string',sj) % put said string in edit box
		end
		
		% what happens when you press the 'Load' button in the Load figure window
		function laddy(varargin)
			ns=get(se,'string'); % get the name in the edit box
			ns(ns==' ')=[]; % delete spaces that strvcat produced at the end of names
			close(gcf) % close the Load figure window
			
			% load the variable kk from name (used to see how many variables are to
			% be loaded, since flat face follower has less characteristics to load)
			load(['Models\',ns,'.mat'],'kk') 
			
			if kk==1 % flat face follower
				
				% select flat face radio button			
				set(hr,'selectedobject',hb1)
				
				% load variables from Models\'filename'
				load(['Models\',ns,'.mat'],'Types','Disps' ,'Durations' ,'rb')
				
				% set edit boxes as per loaded variables
				set(MT,'string',Types)
				set(MA,'string',Disps)
				set(MD,'string',Durations)
				set(BC,'string',rb)
				
			else % same as before, but roller follower has more variables to be loaded
				set(hr,'selectedobject',hb2)
				load(['Models\',ns,'.mat'],'Types','Disps' ,'Durations' ,'rb','rd','e','kc')				
				set(MT,'string',Types)
				set(MA,'string',Disps)
				set(MD,'string',Durations)
				set(BC,'string',rb)
				set(t2,'string',rd)
				set(t4,'string',e)
				set(t6,'string',kc)
			end
			CGMT % go to the function of changing follower type (to set some things visible on/off)
		end		
	end

%% More -> About
	function bott(varargin)
		figure('units','normalized','position',[0.1 .7 .25 .1],'color','w','numbertitle','off','menubar','none','name','About');
		uicontrol('style','text','units','normalized','position',[.05 .25 .6 .2],'string','numandina@gmail.com','backgroundcolor','w',...
			'fontsize',11,'fontweight','b','fontname','arial','horizontalalignment','left');		
		uicontrol('style','text','units','normalized','position',[.05 .65 .6 .2],'string','Husam Aldahiyat 28/12/2008','backgroundcolor','w',...
			'fontsize',11,'fontweight','b','fontname','arial','horizontalalignment','left');		
	end

%% Main Figure uicontrols (edits, text, etc...)

% some texts
uicontrol('style','text','units','normalized','position',[.025 .9 .08 .05],'backgroundcolor','w','max',2,...
	'fontsize',12,'fontname','calibri','string','Motion Type')
uicontrol('style','text','units','normalized','position',[.125 .9 .08 .075],'backgroundcolor','w','max',2,...
	'fontsize',12,'fontname','calibri','string','Motion Duration')
uicontrol('style','text','units','normalized','position',[.225 .875 .085 .075],'backgroundcolor','w','max',2,...
	'fontsize',11,'fontname','calibri','string','Displacement')

% this is the black axis that acts as a seperator
axes('position',[.35 0 .025 1],'color','k','xcolor','w','ycolor','w','zcolor','w','xtick',100,'ytick',100)

% the little squares above 'Res'. they act as a loading bar
hl(1)=uicontrol('style','text','units','normalized','position',[.335 .95 .005 .0075],'backgroundcolor','r');
hl(2)=uicontrol('style','text','units','normalized','position',[.335 .94 .005 .0075],'backgroundcolor','r');
hl(3)=uicontrol('style','text','units','normalized','position',[.335 .93 .005 .0075],'backgroundcolor','r');
hl(4)=uicontrol('style','text','units','normalized','position',[.335 .92 .005 .0075],'backgroundcolor','r');
hl(5)=uicontrol('style','text','units','normalized','position',[.335 .91 .005 .0075],'backgroundcolor','r');
hl(6)=uicontrol('style','text','units','normalized','position',[.335 .9 .005 .0075],'backgroundcolor','r');
hl(7)=uicontrol('style','text','units','normalized','position',[.335 .89 .005 .0075],'backgroundcolor','r');
hl(8)=uicontrol('style','text','units','normalized','position',[.335 .88 .005 .0075],'backgroundcolor','r');
hl(9)=uicontrol('style','text','units','normalized','position',[.335 .87 .005 .0075],'backgroundcolor','r');
hl(10)=uicontrol('style','text','units','normalized','position',[.335 .86 .005 .0075],'backgroundcolor','r');

% dummy text, used only to store certain values so that they would be retrieved
% later by another function
dummy1=uicontrol('style','text','visible','off','max',2);
dummy2=uicontrol('style','text','visible','off','max',2);
dummy3=uicontrol('style','text','visible','off','max',2);

% some more stuff
uicontrol('style','text','units','normalized','position',[.31 .82 .035 .025],'string','Res','backgroundcolor','w');
rR=uicontrol('style','edit','units','normalized','position',[.31 .79 .035 .025],'string','100','backgroundcolor','w');
MT=uicontrol('style','edit','units','normalized','position',[.025 .6 .08 .3],'backgroundcolor','w','max',2,...
	'fontsize',14,'fontname','calibri');
MD=uicontrol('style','edit','units','normalized','position',[.125 .6 .08 .3],'backgroundcolor','w','max',2,...
	'fontsize',14,'fontname','calibri');
MA=uicontrol('style','edit','units','normalized','position',[.225 .6 .08 .3],'backgroundcolor','w','max',2,...
	'fontsize',14,'fontname','calibri');
uicontrol('style','text','units','normalized','position',[.025 .5 .2 .05],'backgroundcolor','w',...
	'fontsize',12,'fontname','calibri','string','SHM: Simple Harmonic Motion','horizontalalignment','left');
uicontrol('style','text','units','normalized','position',[.025 .45 .3 .05],'backgroundcolor','w',...
	'fontsize',12,'fontname','calibri','string','DWL: Dwell        CSV: Constant Velocity','horizontalalignment','left');
uicontrol('style','text','units','normalized','position',[.025 .4 .2 .05],'backgroundcolor','w',...
	'fontsize',12,'fontname','calibri','string','PAR: Parabolic Motion','horizontalalignment','left');
uicontrol('style','text','units','normalized','position',[.025 .35 .2 .05],'backgroundcolor','w',...
	'fontsize',12,'fontname','calibri','string','CYC: Cycloidal Motion','horizontalalignment','left');
uicontrol('style','text','units','normalized','position',[.025 .3 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','Base Circle Radius: ','horizontalalignment','left');
BC=uicontrol('style','edit','units','normalized','position',[.145 .32 .03 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string',' ','horizontalalignment','center');

% 'Go' pushbutton
BB=uicontrol('style','pushbutton','units','normalized','position',[.225 .025 .08 .05],'backgroundcolor','w',...
	'fontsize',14,'fontname','calibri','string','Go','callback',@go);

D3=uicontrol('style','pushbutton','units','normalized','position',[.225 .4 .08 .05],'backgroundcolor','w',...
	'fontsize',14,'fontname','calibri','string','3D','callback',@go3,'visible','off');

% choose follower type radio group
hr=uibuttongroup('Units','normalized',...
'Position',[.025 .25 .3 .05],'SelectionChangeFcn',@CGMT);
hb1=uicontrol('Style','Radiobutton','String','Flat Face Follower','Units','normalized',...
'Position',[0 0 1/2 1],'Parent',hr,'backgroundcolor',[1 1 1],'foregroundcolor',[0 0 0]);
hb2=uicontrol('Style','Radiobutton','String','Translating Roller Follower','Units','normalized',...
'Position',[1/2 0 1/2 1],'Parent',hr,'backgroundcolor',[1 1 1],'foregroundcolor',[0 0 0]);

% speed of animation radio group
hr2=uibuttongroup('Units','normalized',...
'Position',[.175 .1 .15 .05]);
hbs=uicontrol('Style','Radiobutton','String','Fast','Units','normalized',...
'Position',[0 0 1/3 1],'Parent',hr2,'backgroundcolor',[1 1 1],'foregroundcolor',[0 0 0]);
hbk=uicontrol('Style','Radiobutton','String','Slow','Units','normalized',...
'Position',[1/3 0 1/3 1],'Parent',hr2,'backgroundcolor',[1 1 1],'foregroundcolor',[0 0 0]);
uicontrol('Style','Radiobutton','String','Pause','Units','normalized',...
'Position',[2/3 0 1/3 1],'Parent',hr2,'backgroundcolor',[1 1 1],'foregroundcolor',[0 0 0]);

% texts that are set on/off depending on follower type
t1=uicontrol('style','text','units','normalized','position',[.025 .18 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','Roller Radius: ','horizontalalignment','left');
t2=uicontrol('style','edit','units','normalized','position',[.125 .2 .03 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string',' ','horizontalalignment','center');
t3=uicontrol('style','text','units','normalized','position',[.025 .14 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','Offset: ','horizontalalignment','left');
t4=uicontrol('style','edit','units','normalized','position',[.125 .16 .03 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string',' ','horizontalalignment','center');
t5=uicontrol('style','text','units','normalized','position',[.025 .1 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','Inside/Ouside(~): ','horizontalalignment','left');
t6=uicontrol('style','edit','units','normalized','position',[.125 .12 .03 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','0','horizontalalignment','center');

% text and edits at the lower left corner of the main figure window
uicontrol('style','text','units','normalized','position',[.025 .065 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','Axis Limits: ','horizontalalignment','left');
uicontrol('style','text','units','normalized','position',[.025 -.005 .15 .05],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','[y1 y2]','horizontalalignment','left','fontweight','b');

uicontrol('style','edit','units','normalized','position',[.025 .05 .05 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','','horizontalalignment','center','callback',@ca1,'enable','off');
al2=uicontrol('style','edit','units','normalized','position',[.08 .05 .05 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','','horizontalalignment','center','callback',@ca2);
al3=uicontrol('style','edit','units','normalized','position',[.13 .05 .05 .035],'backgroundcolor','w',...
	'fontsize',10,'fontname','calibri','string','','horizontalalignment','center','callback',@ca3);

% create the four axes and hide them for now
a1=axes('position',[.4 .65 .55/3 .3]); % Displacement
a2=axes('position',[.4+.55/3+.025 .65 .55/3 .3]); % Velocity
a3=axes('position',[.4+.55/3*2+.05 .65 .55/3 .3]); % Acceleration
a4=axes('position',[.4 .025 .55 .55]); % cam profile axes
set(findobj('type','axes','-not','color','k'),'visible','off') % hide them

% evaluate this function which sets certain uicontrols' visiblity on/off
CGMT 

%% Change Axis Limits

	function ca2(varargin)
		an1=str2num(get(al2,'string')); %#ok % get limits from edit box 
		set(a2,'ylim',an1(1:2)); % set these limits for the corresponding axes
	end

	function ca3(varargin)
		an1=str2num(get(al3,'string')); %#ok
		set(a3,'ylim',an1(1:2));
	end

%{
	function ca1(varargin)
 		an1=str2num(get(al1,'string'));
 		set(a1,'ylim',an1(1:2));
 	end
%}

%% Change Follower Type

	function CGMT(varargin)		
		if get(hr,'selectedobject')==hb1 % flat face
			set(t1,'visible','off') % rf text
			set(t2,'visible','off') % rf edit
			set(t3,'visible','off') % offset text
			set(t4,'visible','off') % offset edit
			set(t5,'visible','off') % inside/outside text
			set(t6,'visible','off') % inside/outside edit
		else
			set(t1,'visible','on')
			set(t2,'visible','on')
			set(t3,'visible','on')
			set(t4,'visible','on')
			set(t5,'visible','on')
			set(t6,'visible','on')
		end
	end

%% Motion Program Functions

% Dwell
	function [s,si,ti]=DWL(si,ti,a)
		s=sym(si); % create motion equation
		ezplot(s,[ti,ti+a]) % plot motion equation
		ti=ti+a;
	end

% Simple Harmonic Motion
	function [s,si,ti]=SHM(si,ti,h,a)
		s=si+h/2*(1-cos(pi/a*(sym('x')-ti)));
		si=subs(s,a+ti);
		ezplot(s,[ti,ti+a])
		ti=ti+a;
	end

% Parabolic Motion
	function [s1,s2,si,ti]=PAR(si,ti,h,a)
		s1=si+2*h/a^2*(sym('x')-ti)^2;
		s2=si+h*(-1+4*(sym('x')-ti)/a-2*(sym('x')-ti)^2/a^2);
		si=subs(s2,ti+a);
		ezplot(s1,[ti,ti+a/2])
		hold on
		ezplot(s2,[ti+a/2,ti+a])
		xlim([ti ti+a])
		ti=ti+a;
	end

% Cycloidal Motion
	function [s,si,ti]=CYC(si,ti,h,a)
		s=si+h*((sym('x')-ti)/a-1/2/pi*sin(2*pi*(sym('x')-ti)/a));
		si=subs(s,ti+a);
		ezplot(s,[ti,ti+a])
		ti=ti+a;
	end

% Constant Velocity
	function [s,si,ti]=CV(si,ti,h,a)
		s=si+h/a*((sym('x')-ti));
		si=subs(s,ti+a);
		ezplot(s,[ti,ti+a])
		ti=ti+a;
	end

%% The 'Go' Button

	function go(varargin)
		
		% make 3D button disappear until after loading
		set(D3,'visible','off')
		
		% if the button's string is 'stop', do just that
		if strcmp(get(BB,'string'),'Stop')
			set(BB,'string','Go')			
			if get(hr,'selectedobject')==hb1 % flat face chosen
				set(D3,'visible','on') % make 3D button appear
			end
			return
		end
		
		% reset all loading 'blocks' to red colour
		set(hl,'backgroundcolor','r')
		
		% get values for the three main edit boxes
		Types=get(MT,'string');
		Disps=[str2num(get(MA,'string'));0];%#ok
		Durations=str2num(get(MD,'string')).*pi/180;%#ok
		
		% reveal axes
		set(findobj('type','axes'),'visible','on')
		
		si=0; % initial displacement is zero
		ti=0; % initial theta is zero
		S=[]; % motion equation(s) matrix
		T=ti; % theta timeline-esque vector
		
		% set displacement axes as current one (i.e. all subsequent plots will
		% be done on it)
		axes(a1)		
		cla
		hold on
		
%% Displacement Diagram

		% the following loop obtains for us the motion equation(s) for the
		% follower as well as plots the displacement diagram
		
		for lp1=1:length(Durations) % go through loop once for every motion type entered			                     
			pp=ti; % variable used for parabolic motion
			
			switch Types(lp1,:)
				case 'DWL'
					[s,si,ti]=DWL(si,ti,Durations(lp1));
					S=[S;s]; % stack latest motion equation					
					T=[T;ti]; % put latest theta in theta timeline
				case 'SHM'
					[s,si,ti]=SHM(si,ti,Disps(lp1),Durations(lp1));
					S=[S;s];
					T=[T;ti];
				case 'PAR'
					[s1,s2,si,ti]=PAR(si,ti,Disps(lp1),Durations(lp1));
					S=[S;s1;s2];
					T=[T;(ti+pp)/2;ti];	
				case 'CYC'
					[s,si,ti]=CYC(si,ti,Disps(lp1),Durations(lp1));
					S=[S;s];
					T=[T;ti];	
				case 'CSV'
					[s,si,ti]=CV(si,ti,Disps(lp1),Durations(lp1));
					S=[S;s];
					T=[T;ti];						
			end
			
		end
		
		JJ=zeros(length(S),1); %Preallocate to save time!
		
		for klp=1:length(S)
			% get displacements of follower at each of the critical values of theta
			JJ(klp)=subs(S(klp),T(klp+1));
		end
		
		% using previous JJ vector set axis limits for displacement diagram
		axis([0 ti min(JJ)-(max(JJ)-min(JJ))/10-1e-9 max(JJ)+(max(JJ)-min(JJ))/10+1e-9])
		title('Displacement')
		xlabel('Radians')
		
%% Velocity Diagram

		axes(a2) 
		cla
		hold on
		
		% velocity is the derivative of displacement ;)
		S1=diff(S);
		
		% plot each velocity equation for its equivalent theta range
		for lp1=1:length(S1)
			ezplot(S1(lp1),[T(lp1) T(lp1+1)]);
		end		
		xlim([0 ti])
		title('Velocity')
 		xlabel('')
		
%% Acceleration Diagram

		axes(a3) 
		cla
		hold on
		
		% derivate velocity to obtain acceleration
		S2=diff(S1);
		
		% plot resultant equations for their matching theta ranges
		for lp1=1:length(S)
			ezplot(S2(lp1),[T(lp1) T(lp1+1)]);
		end			
		xlim([0 ti])
		title('Acceleration')
		xlabel('Radians')
		
		drawnow() % give user something to look at while he waits for the rest of the
		          % computations

%% Cam Profile

		reR=str2double(get(rR,'string')); % get number of points used to plot
		x=zeros(1,reR+1); % x points of profile
		y=zeros(1,reR+1); % y points of profile
		pa=zeros(1,reR+1); % pressure angles. there is a different pressure angle for each theta,
		                   % where it is the angle between the vertical line of motion and the normal
						   % to the tangent of the two contact surfaces
						   
		rb=str2double(get(BC,'string')); % get base circle radius
		cc=0; % counter
		QM=10; % used for loading blocks
		
		if get(hr,'selectedobject')==hb1 % flat face chosen
			who=1;
			e=0;
			rd=0;
			beta=0;
		else % translating roller follower
			who=0;
			rd=str2double(get(t2,'string')); % roller radius
			e=str2double(get(t4,'string'));  % roller offset
			beta=asin(e/sum([rb,rd]));
		end
		
		% change theta from zeros to 360 degrees
		for k=0:2*pi/reR:2*pi
			% increment counter
			cc=cc+1; 
			
			% obtain where the current angle is in terms of theta timeline
			% (i.e. get in which range of angles it is)
			for p=1:length(T)-1
				if k<=T(p+1)
					a=p;
					break
				end
			end
			
			% every time theta is increased 10% of the 2*pi radians, change a
			% loading block's colour to green
			if (k/2/pi*100)>QM
				set(hl(QM/10),'backgroundcolor','g')
				drawnow()
				QM=QM+10;
			end
			
			% equations for the cam profile.
			% remember: 
			% - different followers call for different equations and profiles
			% - we need s and s', which can be obtained by substituting our
			%   angle into its matching motion equation and velocity equation
			
			if get(hr,'selectedobject')==hb1 % flat face follower
				x(cc)=-(rb+subs(S(a),k))*sin(k)-subs(S1(a),k)*cos(k);
				y(cc)=(rb+subs(S(a),k))*cos(k)-subs(S1(a),k)*sin(k);
				
			else % translating roller follower
				
				if strcmp(get(t6,'string'),'1') % inside
					koin=-1;					
				else                            % outside
					koin=1;
				end
				
				% can be found in your machinery textbook
				xc=-(rb+rd)*sin(k+beta)-subs(S(a),k)*sin(k);
				yc=(rb+rd)*cos(k+beta)+subs(S(a),k)*cos(k);
				dxc=-(rb+rd)*cos(k+beta)-subs(S(a),k)*cos(k)-subs(S1(a),k)*sin(k);
				dyc=-(rb+rd)*sin(k+beta)-subs(S(a),k)*sin(k)+subs(S1(a),k)*cos(k);
				x(cc)=xc-koin*rd*dyc*(dxc^2+dyc^2)^-.5;
				y(cc)=yc+koin*rd*dxc*(dxc^2+dyc^2)^-.5;
				pa(cc)=atan(((subs(S1(a),k))-e)/(subs(S(a),k)+sqrt((rb+rd)^2-e^2)));
			end
			
		end
		
		% just to make sure, set all loading block colours to green
		set(hl,'backgroundcolor','g') 
		
		% set push button string to 'Stop', since soon we'll be animating
		set(BB,'string','Stop') 
		
		% store x and y vectors in dummy texts
		set(dummy1,'string',mat2str(x))
		set(dummy2,'string',mat2str(y))
		set(dummy3,'string',mat2str(T))
		
		% send a bunch of information to the cam animation function
		Untitled6(x,y,S,T,a4,a1,rb,max(JJ),BB,who,beta,e,rd,pa,reR) 
	end

%% Cam Animation

% We'll be concerned with rotating the cam around and round in clockwise
% rotation. the following function will do that

	function Untitled6(x,y,S,T,fi2,agl,rb,last,BB,who,beta,varargin)
		
		reR=varargin{4}; % number of points
		pA=varargin{3}; % pressure angles vector
				
		axes(fi2) % big axes
		cla
		hold on
		
% 	    h=plot(x,y);
		
        % plot the cam profile and fill it in grey
		h=fill(x,y,[.5 .5 .5]);
		set(h,'linewidth',2)
		
		% plot the base circle, just for reference
		circle([0 0],rb,reR,'c--')
		plot(0,0,'c.')
		
		% thicken the digrams and soon to be drawn follower
		set(findobj('type','line','color','b'),'linewidth',2)
		
		% set appropriate axis limits
		axis([min(x)-(max(x)-min(x))/2-varargin{2} max(x)+(max(x)-min(x))/2+varargin{2} min(y)-(max(y)-min(y))/2-varargin{2} last+rb+(max(y)-min(y))/2+varargin{2}])		
		axis equal
		
		p2=0; % initially, cam is rotated 0 degrees
		
		% the following is the rotation loop
		while strcmp((get(BB,'string')),'Stop') % keep rotating until the user presses the 'Stop' button
			
			% change speed radio buttons
			if get(hr2,'selectedobject')==hbs     % fast
				fsf=10;                                       % rotate by 10 degrees each time
			elseif get(hr2,'selectedobject')==hbk % slow
				fsf=1;
			else                                  % pause
				fsf=0;
			end
			
			rotate(h,[0 0 1],-fsf,[0 0 1]) % rotate cam around centre of base circle
			
			% p2 gives us how many radians the cam has already rotated
			p2=p2+fsf/180*pi;
			if p2>2*pi
				p2=p2-2*pi;
			end
			
			% next comes the follower motion
			
			% get in what range of angles theta lies
			for p=1:length(T)-1
				if p2<=T(p+1)
					a=p;
					break
				end
			end
			
			% then substitute our angle in its consequent motion equations
			ch=subs(S(a),p2)+rb; % this value gives us the y location of our follower
			
			if who % flat face follower								
				ppp=line([min(x)+(max(x)-min(x))/4,max(x)-(max(x)-min(x))/4],[ch ch]);
			else
				% the follower circle, varargin{1} is the horizontal offest (e)
				ppp=circle([-varargin{1} ch+(rb+varargin{2})*cos(beta)-rb],varargin{2},100);
				
				% line representing the line of motion
				lll=line([-varargin{1} -varargin{1}],[0 rb*2+ch]);
				set(lll,'linestyle','-','color','r')
				
				% get pressure angle for current theta
				pa=interp1(0:2*pi/reR:2*pi,pA,p2);
				
				% draw line that represents the pressure line
				ooo=line([-varargin{1}-2*sin(pa) -varargin{1}+(2*varargin{2}+2)*sin(pa)],...
					[ch+(rb+varargin{2})*cos(beta)-rb-2*cos(pa) (ch+(rb+varargin{2})*cos(beta)-rb)+(2+2*(varargin{2}))*cos(pa)]);
				set(ooo,'linestyle','-','color','r')
				
				title(['\phi = ',num2str(pa/pi*180,3)])
			end
						
			if exist('hag','var')
				delete(hag)
			end
			hag=ang([0 0],rb/2,[0 -p2],'w.'); % draw an arc from 0 to theta degrees
			
			set(ppp,'linewidth',3,'color','b')
			
			% show follower displacement on the motion diagram from before
			axes(agl)
			delete(findobj('marker','*'))
			plot(p2,ch-rb,'m*') % show current position on the axes
			drawnow()
			
			% return to our cam profile axes and tidy it up
			axes(fi2)
			axis([min(x)-(max(x)-min(x))/2-varargin{2} max(x)+(max(x)-min(x))/2+varargin{2} min(y)-(max(y)-min(y))/2-varargin{2} last+rb+(max(y)-min(y))/2+varargin{2}])			
			
			pause(.001) % duration between our 'frames'
			
			delete(ppp)
			if ~who
				delete(lll)
				delete(ooo)
			end
		end
	end

%% '3D' Button

	function go3(varargin)
		x=str2num(get(dummy1,'string')); %#ok
		y=str2num(get(dummy2,'string')); %#ok
		T=str2num(get(dummy3,'string')); %#ok	
		rb=str2double(get(BC,'string'));
		
		if get(hr,'selectedobject')==hb1		
			e=0;
			hok=1;
			rd=0;
		else
			e=str2double(get(t4,'string'));
			hok=0;
			rd=str2double(get(t2,'string'));
		end
		
		Durations=str2num(get(MD,'string')).*pi/180; %#ok		
		Disps=[str2num(get(MA,'string'));1e-9;-1e-9];%#ok		
		z1=sum(-abs(Disps));
		z2=sum(abs(Disps));		
		dg(x,y,S,T,e,rb,z1,z2,hok,rd)
	end

end

%% Angle Function

% function that draws an arc based on it centre, radius and angle span.
% burrows from the function CIRCLE
function h = ang(centre,radius,span,style)
theta = linspace(span(1),span(2),100);
rho = ones(1,100) * radius;
[x,y] = pol2cart(theta,rho);
x = x + centre(1);
y = y + centre(2);
x=x(end);
y=y(end);
h = plot(x,y,style);
end

%% Circle Function

% function that draws a circle based on its centre and radius. I didn't make it;
% it was created by Zhenhai Wang on the MATLAB File Exchange
function H=circle(center,radius,NOP,style)

if (nargin==3)
    style='b-';
end

THETA=linspace(0,2*pi,NOP);
RHO=ones(1,NOP)*radius;
[X,Y] = pol2cart(THETA,RHO);
X=X+center(1);
Y=Y+center(2);
H=plot(X,Y,style);
axis square
end

%% 3D Animation 
function dg(x,y,S,T,e,rb,z1,z3,hok,rd)
S
T
figure
hold on
set(gcf,'color','w','numbertitle','off','menubar','none','name','3D (Demo)')
set(gca,'xcolor','w','ycolor','w','zcolor','w')
z=zeros(size(x));
z2=ones(size(x));
view(3)
f1=fill3(x,z,y,[.5 .5 .5],'edgecolor',[.7 .7 .7],'FaceVertexAlphaData',0.9,'FaceAlpha','flat');
f2=fill3(x,z2,y,[.5 .5 .5],'edgecolor',[.5 .5 .5]);
% [gg,hh,jj]=cylinder(repmat(rb,1,100));
% jj=[-flipud(jj);jj];
% jj=jj*6;
% for p=1:size(jj,1)/2
% 	jj(p,:)=[];
% end
% hhh=surf(gg,jj,hh);
kk=[f1;f2];
p2=0;
while true
	rotate(kk,[0 1 0],5,[0 1 0])
	p2=p2+5/180*pi;
	if p2>2*pi
		p2=p2-2*pi;
	end
	axis([(z1-rb) z3+rb -5 5 z1 z3].*2)
	for p=1:length(T)-1
		if p2<=T(p+1)
			a=p;
			break
		end
	end
	ch=subs(S(a),p2)+rb;	

	if hok
	a=[min(x)+(max(x)-min(x))/4 0 0;
		max(x)-(max(x)-min(x))/4 0 0;
		max(x)-(max(x)-min(x))/4 1 0;
		min(x)+(max(x)-min(x))/4 1 0;
		min(x)+(max(x)-min(x))/4 0 z3/2;
		max(x)-(max(x)-min(x))/4 0 z3/2;
		max(x)-(max(x)-min(x))/4 1 z3/2;
		min(x)+(max(x)-min(x))/4 1 z3/2];
	else
	a=[0 0 0;
		1 0 0;
		1 1 0;
		0 1 0;
		0 0 z3/2;
		1 0 z3/2;
		1 1 z3/2;
		0 1 z3/2];
	a(:,1)=a(:,1)*.3;
	end
	a(:,1)=a(:,1)+e;
	a(:,2)=a(:,2)*.3;
	a(:,3)=a(:,3)+(ch)+rd;
	b=[1 2 6 5;2 3 7 6;3 4 8 7;4 1 5 8;1 2 3 4;5 6 7 8];
	ppp=patch('vertices',a,'faces',b,'edgecolor','r','facecolor','k','linewidth',2,'FaceVertexAlphaData',0.5);	
	rotate3d on	
	pause(.001)
	delete(ppp)
end
end

%% EOF

Contact us