You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
345 lines
13 KiB
345 lines
13 KiB
%CODEGENERATOR Class for code generation
|
|
%
|
|
% Objects of the CodeGenerator class automatcally generate robot specific
|
|
% code, as either M-functions or real-time capable SerialLink blocks.
|
|
%
|
|
% The various methods return symbolic expressions for robot kinematic and
|
|
% dynamic functions, and optionally support side effects such as:
|
|
% - M-functions with symbolic robot specific model code
|
|
% - real-time capable robot specific Simulink blocks
|
|
% - mat-files with symbolic robot specific model expressions
|
|
%
|
|
% Example::
|
|
%
|
|
% % load robot model
|
|
% mdl_twolink
|
|
%
|
|
% cg = CodeGenerator(twolink);
|
|
% cg.geneverything();
|
|
%
|
|
% % a new class has been automatically generated in the robot directory.
|
|
% addpath robot
|
|
%
|
|
% tl = @robot();
|
|
% % this class is a subclass of SerialLink, and thus polymorphic with
|
|
% % SerialLink but its methods have been overloaded with robot-specific code,
|
|
% % for example
|
|
% T = tl.fkine([0.2 0.3]);
|
|
% % uses concise symbolic expressions rather than the generalized A-matrix
|
|
% % approach
|
|
%
|
|
% % The Simulink block library containing robot-specific blocks can be
|
|
% % opened by
|
|
% open robot/robotslib.slx
|
|
% % and the blocks dragged into your own models.
|
|
%
|
|
% Methods::
|
|
%
|
|
% gencoriolis generate Coriolis/centripetal code
|
|
% genfdyn generate forward dynamics code
|
|
% genfkine generate forward kinematics code
|
|
% genfriction generate joint frictionc code
|
|
% gengravload generarte gravity load code
|
|
% geninertia general inertia matrix code
|
|
% geninvdyn generate forward dynamics code
|
|
% genjacobian generate Jacobian code
|
|
% geneverything generate code for all of the above
|
|
%
|
|
% Properties (read/write)::
|
|
%
|
|
% basepath basic working directory of the code generator
|
|
% robjpath subdirectory for specialized MATLAB functions
|
|
% sympath subdirectory for symbolic expressions
|
|
% slib filename of the Simulink library
|
|
% slibpath subdirectory for the Simulink library
|
|
% verbose print code generation progress on console (logical)
|
|
% saveresult save symbolic expressions to .mat-files (logical)
|
|
% logfile print modeling progress to specified text file (string)
|
|
% genmfun generate executable M-functions (logical)
|
|
% genslblock generate Embedded MATLAB Function blocks (logical)
|
|
%
|
|
% Object properties (read only)::
|
|
% rob SerialLink object to generate code for (1x1).
|
|
%
|
|
% Notes::
|
|
% - Requires the MATLAB Symbolic Toolbox
|
|
% - For robots with > 3 joints the symbolic expressions are massively
|
|
% complex, they are slow and you may run out of memory.
|
|
% - As much as possible the symbolic calculations are down row-wise to
|
|
% reduce the computation/memory burden.
|
|
%
|
|
% Author::
|
|
% Joern Malzahn
|
|
% 2012 RST, Technische Universitaet Dortmund, Germany.
|
|
% http://www.rst.e-technik.tu-dortmund.de
|
|
%
|
|
% See also SerialLink, Link.
|
|
|
|
% Copyright (C) 1993-2012, by Peter I. Corke
|
|
% Copyright (C) 2012-2013, by Joern Malzahn
|
|
%
|
|
% This file is part of The Robotics Toolbox for Matlab (RTB).
|
|
%
|
|
% RTB is free software: you can redistribute it and/or modify
|
|
% it under the terms of the GNU Lesser General Public License as published by
|
|
% the Free Software Foundation, either version 3 of the License, or
|
|
% (at your option) any later version.
|
|
%
|
|
% RTB is distributed in the hope that it will be useful,
|
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
% GNU Lesser General Public License for more details.
|
|
%
|
|
% You should have received a copy of the GNU Leser General Public License
|
|
% along with RTB. If not, see <http://www.gnu.org/licenses/>.
|
|
%
|
|
% http://www.petercorke.com
|
|
%
|
|
% The code generation module emerged during the work on a project funded by
|
|
% the German Research Foundation (DFG, BE1569/7-1). The authors gratefully
|
|
% acknowledge the financial support.
|
|
|
|
classdef CodeGenerator
|
|
properties (SetAccess = private)
|
|
rob
|
|
end
|
|
properties
|
|
basepath;
|
|
robjpath;
|
|
sympath;
|
|
slib;
|
|
slibpath;
|
|
verbose;
|
|
saveresult;
|
|
logfile;
|
|
genmfun;
|
|
genslblock;
|
|
end
|
|
properties (GetAccess = private)
|
|
debug; % just appears because of tb_optparse, so hide it from the user
|
|
end
|
|
methods
|
|
|
|
function CGen = CodeGenerator(rob,varargin)
|
|
%CodeGenerator.CodeGenerator Construct a code generator object
|
|
%
|
|
% cGen = CodeGenerator(ROB) is a code generator object for the SerialLink
|
|
% object ROB.
|
|
%
|
|
% cGen = CodeGenerator(ROB, OPTIONS) as above but with options described below.
|
|
%
|
|
% Options::
|
|
%
|
|
% The following option sets can be passed as an optional parameter:
|
|
%
|
|
% 'default' set the options: verbose, saveResult, genMFun, genSLBlock
|
|
% 'debug' set the options: verbose, saveResult, genMFun, genSLBlock
|
|
% and create a logfile named 'robModel.log' in the working directory
|
|
% 'silent' set the options: saveResult, genMFun, genSLBlock
|
|
% 'disk' set the options: verbose, saveResult
|
|
% 'workspace' set the option: verbose; just outputs symbolic expressions to workspace
|
|
% 'mfun' set the options: verbose, saveResult, genMFun
|
|
% 'slblock' set the options: verbose, saveResult, genSLBlock
|
|
%
|
|
% If 'optionSet' is ommitted, then 'default' is used. The options control the code generation and user information:
|
|
%
|
|
% 'verbose' write code generation progress to command window
|
|
% 'saveResult save results to hard disk (always enabled, when genMFun and genSLBlock are set)
|
|
% 'logFile',logfile write code generation progress to specified logfile
|
|
% 'genMFun' generate robot specific m-functions
|
|
% 'genSLBlock' generate real-time capable robot specific Simulink blocks
|
|
%
|
|
% Any option may also be modified individually as optional parameter value pairs.
|
|
%
|
|
% Author::
|
|
% Joern Malzahn
|
|
% 2012 RST, Technische Universitaet Dortmund, Germany.
|
|
% http://www.rst.e-technik.tu-dortmund.de
|
|
|
|
if ~isa(rob,'SerialLink')
|
|
error('CodeGenerator:wrongConstructorInput','The input variable %s must be a SerialLink object.',inputname(1));
|
|
end
|
|
|
|
if ~issym(rob)
|
|
CGen.rob = rob.sym;
|
|
else
|
|
CGen.rob = rob;
|
|
end
|
|
|
|
% defaults
|
|
CGen.basepath = fullfile(pwd,CGen.getrobfname);
|
|
CGen.robjpath = fullfile(CGen.basepath,['@',CGen.getrobfname]);
|
|
CGen.sympath = fullfile(CGen.basepath,'symbolicexpressions');
|
|
CGen.slib = [CGen.getrobfname,'slib'];
|
|
CGen.slibpath = fullfile(CGen.basepath,CGen.slib);
|
|
CGen.verbose = false;
|
|
CGen.saveresult = false;
|
|
CGen.logfile = '';
|
|
CGen.genmfun = false;
|
|
CGen.genslblock = false;
|
|
CGen.debug = false;
|
|
|
|
|
|
if nargin < 2
|
|
varargin{1} = 'default';
|
|
end
|
|
|
|
% Determine code generation option set
|
|
switch varargin{1}
|
|
case 'default'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose','saveresult','genmfun','genslblock'},varargin(2:end)]);
|
|
case 'debug'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose','saveresult','genmfun','genslblock','logfile','robModel.log'},varargin(2:end)]);
|
|
case 'silent'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'saveresult','genmfun','genslblock'},varargin(2:end)]);
|
|
case 'disk'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose','saveresult'},varargin(2:end)]);
|
|
case 'workspace'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose'},varargin(2:end)]);
|
|
case 'mfun'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose','saveresult','genmfun'},varargin(2:end)]);
|
|
case 'slblock'
|
|
CGen = tb_optparse(CGen,...
|
|
[{'verbose','saveresult','genslblock'},varargin(2:end)]);
|
|
otherwise
|
|
CGen = tb_optparse(CGen,varargin);
|
|
end
|
|
|
|
if any([CGen.genmfun, CGen.genslblock])
|
|
CGen.saveresult = true;
|
|
end
|
|
|
|
if ~isempty(CGen.logfile)
|
|
logfid = fopen(CGen.logfile,'w+'); % open or create file, discard existing contents
|
|
fclose(logfid);
|
|
end
|
|
CGen.logmsg([datestr(now),' +++++++++++++++++++++++++++++++++++\n']);
|
|
CGen.logmsg([datestr(now),'\tLog for ',CGen.getrobfname,'\n']);
|
|
CGen.logmsg([datestr(now),' +++++++++++++++++++++++++++++++++++\n']);
|
|
|
|
end
|
|
|
|
function robName = getrobfname(CGen)
|
|
robName = CGen.rob.name;
|
|
blanks = isspace(robName)==1;
|
|
robName(blanks)= [];
|
|
robName(robName=='/') = [];
|
|
end
|
|
|
|
function savesym(CGen,sym2save, symname, fname)
|
|
if ~exist(CGen.sympath,'dir')
|
|
mkdir(CGen.sympath)
|
|
end
|
|
|
|
eval([symname,'= sym2save;']);
|
|
save(fullfile(CGen.sympath,fname),symname);
|
|
end
|
|
|
|
function [] = geneverything(CGen)
|
|
[t,allT] = CGen.genfkine;
|
|
[J0,Jn] = CGen.genjacobian;
|
|
[G] = CGen.gengravload;
|
|
[I] = CGen.geninertia;
|
|
[C] = CGen.gencoriolis;
|
|
[F] = CGen.genfriction;
|
|
[Iqdd] = CGen.genfdyn;
|
|
[tau] = CGen.geninvdyn;
|
|
end
|
|
|
|
function CGen = set.genmfun(CGen,value)
|
|
CGen.genmfun = value;
|
|
if value == true
|
|
CGen.saveresult = value;
|
|
end
|
|
|
|
if ~exist(fullfile(CGen.robjpath,CGen.getrobfname),'file')
|
|
CGen.logmsg([datestr(now),'\tCreating ',CGen.getrobfname,' m-constructor ']);
|
|
CGen.createmconstructor;
|
|
CGen.logmsg('\t%s\n',' done!');
|
|
end
|
|
end
|
|
|
|
function CGen = set.genslblock(CGen,value)
|
|
CGen.genslblock = value;
|
|
if value == true
|
|
CGen.saveresult = true;
|
|
end
|
|
end
|
|
function [] = addpath(CGen)
|
|
%CodeGenerator.addpath Adds generated code to search path
|
|
%
|
|
% cGen.addpath() adds the generated m-functions and block library to the
|
|
% MATLAB function search path.
|
|
%
|
|
% Author::
|
|
% Joern Malzahn
|
|
% 2012 RST, Technische Universitaet Dortmund, Germany.
|
|
% http://www.rst.e-technik.tu-dortmund.de
|
|
%
|
|
% See also addpath.
|
|
addpath(CGen.basepath);
|
|
end
|
|
|
|
function [] = rmpath(CGen)
|
|
%CodeGenerator.rmpath Removes generated code from search path
|
|
%
|
|
% cGen.rmpath() removes generated m-functions and block library from the
|
|
% MATLAB function search path.
|
|
%
|
|
% Author::
|
|
% Joern Malzahn
|
|
% 2012 RST, Technische Universitaet Dortmund, Germany.
|
|
% http://www.rst.e-technik.tu-dortmund.de
|
|
%
|
|
% See also rmpath.
|
|
rmpath(CGen.basepath);
|
|
end
|
|
|
|
function [] = purge(CGen,varargin)
|
|
%CodeGenerator.purge Cleanup generated files
|
|
%
|
|
% cGen.purge() deletes all generated files, first displays a question dialog to
|
|
% make sure the user really wants to delete all generated files.
|
|
%
|
|
% cGen.purge(1) as above but skips the question dialog.
|
|
%
|
|
% Author::
|
|
% Joern Malzahn
|
|
% 2012 RST, Technische Universitaet Dortmund, Germany.
|
|
% http://www.rst.e-technik.tu-dortmund.de
|
|
dopurge = 0;
|
|
|
|
if exist(CGen.basepath,'dir')
|
|
if nargin > 1
|
|
dopurge = varargin{1}
|
|
else
|
|
qstn = ['Do you really want to delete ',CGen.basepath, ' and all of it''s contents?'];
|
|
tit = ['Purge: ',CGen.getrobfname];
|
|
str1 = 'Yes';
|
|
str2 = 'No';
|
|
button = questdlg(qstn,tit,str1,str2,str1)
|
|
dopurge = strcmp(button,str1);
|
|
end
|
|
end
|
|
|
|
if dopurge
|
|
bdclose all
|
|
|
|
warning off;
|
|
CGen.rmpath;
|
|
warning on;
|
|
|
|
rmdir(CGen.basepath,'s')
|
|
if ~isempty(CGen.logfile) && exist(CGen.logfile,'file')
|
|
delete(CGen.logfile);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|