Commit 1fbfa57b authored by Katharina Stollenwerk's avatar Katharina Stollenwerk

added MATLAB tools

parent c6436e74
function description = filename2description ( motfilename )
%
% description = filename2description ( motfilename )
%
% INPUT
% motionfilename ... filename of the file to extract the description of
% (best with full path)
% OUTPUT
% description ... struct containing information on the file, i.e.
% .experiment ID of the experiment
% .objectid ID of the object interacted with or 'various'
% .object object represented by the object ID
% .subjectid subject taking the experiment
% .hand 'left', 'right' or 'both', which hand was leading in the movement
% .action 'stream' or action the motion contains
% .feixid ID of the grasp following to feix (only for exp 3)
% .angleunit 'rad' or 'raw'
%
description = ...
struct ( ...
'experiment', 0, ... % number of the experiment
'objectid', 0, ... % ID of the object interacted with
'object', 'various', ... % object interacted with
'subjectid', 0, ... % ID of the subject
'hand', '', ... % main hand for interaction
'action', '', ... % action executed 'stream', 'rest', 'interaction', 'open', 'close' 'close fast'
'feixid', 0, ... % grasp id after feix
'angleunit', 'rad' ... %
);
objectlist_de = {
'Ball';
'Stift';
'Flasche';
'Tasse';
'Glas';
'Schale';
'Wurfel';
'Visitenkarte';
'Apfelmusglas';
'Wasserkasten';
'Buch/Heft';
'Zylinder-dunn';
'Zylinder-dick';
'Karton-liegend';
'Karton-stehend';
'Flaschendeckel';
};
objectlist_en = {
'ball';
'pen';
'bottle';
'mug';
'glass';
'bowl';
'cube';
'business card';
'oval jar';
'bottle crate';
'classic notebook';
'cylinder small dia.';
'cylinder larger dia.';
'carton lying flat';
'carton standing'
'bottle-cap';
};
objectlist = objectlist_en;
slashes = strfind( motfilename, filesep );
if ~(isempty(slashes))
lastslash = slashes(end);
filename = lower( motfilename( lastslash+1:end ) );
else
filename = lower( motfilename );
end
dots = strfind( filename, '.' );
if ~(isempty(dots))
lastdot = dots(end);
filename = lower( filename( 1:lastdot-1 ) );
end
% type = 1 => stream
% type = 2 => cut
% type = 3 => sorted
% type = 4 => calibration
type = 0;
% fprintf('%s => %s\n', motfilename, filename );
%%% get experiment/calibration
result = strfind(filename, 'ex');
if ~isempty(result)
% fprintf('Experiment %s\n', filename(result+2:result+3));
description.experiment = str2num(filename(result+2:result+3));
if ~(result(1) == 1) type = 3; end
end
result = strfind(filename, 'rad');
if (isempty(result) )
result = strfind(filename, 'raw');
end
description.angleunit = filename(result:result+2);
% fprintf('Angle unit %s\n', filename(result:result+2));
% if angle unit is at the end of the filename =>
% the data is either the entire recorded stream
% or the stream cut into grasp and rest motions
if (result(1)+2 == length(filename))
type = 1;
else % it is the stream cut if sorted is not already set true
if (~type) type = 2; end
end
result = strfind(filename, 'calib');
if (~(isempty(result)) && type>1 )
% calibration stream file
type = 4;
description.object = 'none';
description.action = 'calibration';
description.hand = 'right';
end
switch type
case 1
handleStreamFile
case 2
handleCutFile
case 3
handleSortedFile
case 4
handleCalibrationFile
otherwise
end
if description.feixid==14
description.objectid = 16;
description.object = objectlist{description.objectid};
end
%%%%%%%%%%%%%%%%%%%% handle types of files
function handleStreamFile
% recorded in the experiments one stream per experiment
% ex01_20141128084032-rad
% retrieve subject
result = strfind(motfilename, 'subject');
% fprintf('Subject %s\n', filename(result+7:result+8));
description.subjectid = str2num(motfilename(result+7:result+8));
description.action = 'stream';
switch description.experiment
case 0
description.hand = 'right';
result = strfind(filename, 'calib');
if ~isempty(result)
description.object = 'calibration';
end
case 1
description.hand = 'right';
case 2
description.hand = 'both';
case 3
description.hand = 'right';
end
end % of funtion handleStreamFile
function handleCutFile
% experiment files cut according to switch states into 'grasp' and 'rest'
% periods
% ex01-rad-000-rest-su01
% ex01-rad-001-grasp-su01
% retrieve subject
result = strfind(filename, 'su');
% fprintf('Subject %s\n', filename(result+2:result+3));
description.subjectid = str2num(filename(result+2:result+3));
% retrieve action
result = strfind(filename, 'rest');
if (isempty(result))
result = strfind(filename, 'grasp');
l=4;
else l=3;
end
% fprintf('Action %s\n', filename(result:result+l));
description.action = filename(result:result+l);
switch description.experiment
case 1
description.hand = 'right';
case 2
description.hand = 'both';
case 3
description.hand = 'right';
end
end % end handleCutFile
function handleSortedFile
% cut experiment files only containing the grasp parts of the motions
% filenames also include the respective actions.
% check for wronly named file (see db-table errata)
if (strcmpi(filename, '08_06_ex03-1-raw-030-grasp-su04') || strcmpi(filename, '08_06_ex03-1-rad-030-grasp-su04') )
warnstring = sprintf('internally changed filename "%s" to', filename);
filename(1:2) = '12';
warning('%s "%s" (check dbtable-errata.html)', warnstring, filename);
end
if (strcmpi(filename, '12_16_ex03-rad-092-grasp-su08') || strcmpi(filename, '12_16_ex03-rad-092-grasp-su08') )
warnstring = sprintf('internally changed filename "%s" to', filename);
filename(4:5) = '08';
warning('%s "%s" (check dbtable-errata.html)', warnstring, filename);
end
if (strcmpi(filename, '01_26_ex03-rad-044-grasp-su02') || strcmpi(filename, '01_26_ex03-rad-044-grasp-su02') )
warnstring = sprintf('this file ("%s") seems to be empty and no valid file has been found.', filename);
warning('%s (check dbtable-errata.html)', warnstring);
% retrieve subject
result = strfind(filename, 'su');
% fprintf('Subject %s\n', filename(result+2:result+3));
description.subjectid = str2num(filename(result+2:result+3));
% retrieve object
description.objectid = str2num(filename(1:2));
description.object = 'nothing';
description.feixid = 0;
description.hand = '';
description.action = '';
return;
end
% 01_ex01-rad-002-grasp-su01
% 12_08_ex03-2-raw-047-grasp-su04
% 03_s_l_ex02-raw-010-grasp-su01
% 03_o_r_ex02-raw-001-grasp-su01
% retrieve subject
result = strfind(filename, 'su');
% fprintf('Subject %s\n', filename(result+2:result+3));
description.subjectid = str2num(filename(result+2:result+3));
% retrieve object
% fprintf('Object %s %s\n', filename(1:2), objectlist{str2num(filename(1:2))});
description.objectid = str2num(filename(1:2));
description.object = objectlist{str2num(filename(1:2))};
% retrieve experiment dependent information
switch (description.experiment)
case 1
% fprintf('Hand %s\n', 'right' );
% fprintf('Action %s\n', 'grasp' );
description.hand = 'right';
description.action = 'grasp';
case 2
% retrieve hand
hand = 'unclear';
switch filename(6)
case 'l'
hand = 'left';
case 'r'
hand = 'right';
end
% fprintf('Hand %s\n', hand );
description.hand = hand;
% retrieve action
action = 'unclear';
switch (filename(4))
case 'o'
action = 'open';
case 'i'
action = 'interaction';
case 's'
action = 'close';
case 'f'
action = 'close tightly';
end
% fprintf('Action %s\n', action );
description.action = action;
case 3
% fprintf('Feix ID %s\n', filename(4:5) );
% fprintf('Hand %s\n', 'right' );
% fprintf('Action %s\n', 'grasp' );
description.feixid = str2num(filename(4:5));
description.hand = 'right';
description.action = 'grasp';
otherwise
% fprintf('?\n');
end
end % of function handleSortedFile
function handleCalibrationFile
% Stream calibration file in database path.
% 00_calib-raw-su07.txt
% 00_calib-ra[d|w]-su##.txt
result = strfind(filename, 'su');
% fprintf('Subject %s\n', filename(result+2:result+3));
description.subjectid = str2num(filename(result+2:result+3));
end % of handleCalibrationFile
% fprintf('\n');
end % of function filename2description
function namemap = namemapCyberglove ( nsensors )
% Constructs a default name map for a CyberGlove sensor "arrangement"
%
% INPUT
% nsensors ... number of sensors in the glove (valid values: 18 and 22)
%
% OUTPUT
% namemap ... <23x2> cell array containing the sensor names (column 1)
% and a second column indicating wether the sensor is active,
% i.e. has in fact been measured (namemap{k,1}=1), or is
% inactove, i.e. has been estimated from other joints or not
% been implemented (namemap{k,1}=0)
%
% EXAMPLE
% namemap = namemapCyberglove ( 18 )
% namemap = namemapCyberglove ( 22 )
%
switch nsensors
case 18
active = {1;1;1;1;1;1;0;0;1;1;0;1;1;1;0;1;1;1;0;1;1;1;1};
case 22
active = {1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1};
otherwise
error ( ['Unknown type of CyberGlove with ', num2str(nsensors), ' sensors.'] );
end % of switch nsensors
namemap = {
'T-TMCJ', % 1
'T-MCPJ', % 2
...'T-IJ', % 3
'T-IPJ', % 3
'TI-AA', % 4
'I-MCPJ', % 5
...'I-PIJ', % 6
'I-PIPJ', % 6
...'I-DIJ', % 7 *
'I-DIPJ', % 7 *
'I-AA', % 8 **
'M-MCPJ', % 9
...'M-PIJ', % 10
'M-PIPJ', % 10
...'M-DIJ', % 11 *
'M-DIPJ', % 11 *
'MI-AA', % 12
'R-MCPJ', % 13
...'R-PIJ', % 14
'R-PIPJ', % 14
...'R-DIJ', % 15 *
'R-DIPJ', % 15 *
'RM-AA', % 16
'L-MCPJ', % 17
...'L-PIJ', % 18
'L-PIPJ', % 18
...'L-DIJ', % 19 *
'L-DIPJ', % 19 *
'LR-AA', % 20
'P-Arch', % 21
'W-FE', % 22
'W-AA' % 23
};
namemap = [namemap, active];
end % of function namemapCyberglove
% /**************************************************************************//**
% * \brief Create a CyberGlove name map
% *
% * Creates a CyberGlove name map
% *
% * cf. p.20 in the CyberGlove Reference Manual. Following table copied from
% * that manual.
% *
% * Byte Index | Sensor Name (Description)
% * ------------+--------------------------------------------------------------
% * 0. | thumb rotation/TMJ (angle of thumb rotating across palm)
% * 1. | thumb MCPJ (joint where the thumb meets the palm)
% * 2. | thumb IPJ (outer thumb joint)
% * 3. | thumb abduction (angle between thumb and index finger)
% * 4. | index MCPJ (joint where the index meets the palm)
% * 5. | index PIPJ (joint second from finger tip)
% * 6.* | index DIPJ (joint closest to finger tip)
% * 7.** | index abduction (sideways motion of index finger)
% * 8. | middle MCPJ [Metacarpophalangeal joint, MCP joint]
% * 9. | middle PIPJ [Proximal interphalangeal joint, PIP joint]
% * 10.* | middle DIPJ [Distal interphalangeal joint, DIP joint]
% * 11. | middle-index abd'n (angle between middle and index fingers)
% * 12. | ring MCPJ
% * 13. | ring PIPJ
% * 14.* | ring DIPJ
% * 15. | ring-middle abduction (angle between ring and middle fingers)
% * 16. | pinkie MCPJ
% * 17. | pinkie PIPJ
% * 18.* | pinkie DIPJ
% * 19. | pinkie-ring abduction (angle between pinkie and ring finger)
% * 20. | palm arch (causes pinkie to rotate across palm)
% * 21. | wrist pitch (flexion/extension)
% * 22. | wrist yaw (abduction/adduction)
% * 23. | (not used)
% *
% * * = 22-sensor CyberGlove only
% * ** = Absolute abduction sensor not yet implemented. Refer to middle-index
% * relative abduction sensor.
% *
% *****************************************************************************/
function motion = readDBKSmotion( motionfilename )
%READDBKSMOTION Summary of this function goes here
% Detailed explanation goes here
%
% INPUT
% motionfilename ... string representing the filename of the motion to
% load
%
% OUTPUT
% motion ... motion structure
%
% EXAMPLE
% motion = readDBKSmotion( 'afilename_with_path' )
existsMAT = false;
writeMAT = false;
filenameMAT = [motionfilename, '.mat'];
% try to load saved mat file
matfilehandle = fopen(filenameMAT);
if (matfilehandle~=-1)
fclose(matfilehandle);
load(filenameMAT, 'motion');
existsMAT = true;
% set correct filename
motion.filename = motionfilename;
else
writeMAT = true;
end
% load from original db file
if (~existsMAT)
% generate namemap (for db-ks!)
namemap = namemapCyberglove(18);
% initialize motion
motion = emptyMotion;
filecontent = dlmread( motionfilename );
% #frames rows
% #joints columns
motion.timestamps = filecontent(:,1:6);
motion.switchstates = filecontent(:,7);
motion.angledata = filecontent(:,8:end);
motion.numberofangles = size(motion.angledata,2);
motion.numberofframes = size(motion.angledata,1);
% compute elapsed seconds
motion.elapsedtime = etime(motion.timestamps, repmat(motion.timestamps(1,:),motion.numberofframes,1));
%'samplingrate', 60, ... % sampling rate (inverse of frame time)
motion.samplingrate = motion.numberofframes/motion.elapsedtime(end);
motion.filename = motionfilename;
%'filename', ' ' ... % name of the source file
motion.sensornames = namemap(:,1);
motion.active = find([namemap{:,2}])';
motion.inactive = find(~[namemap{:,2}])';
if max(max(motion.angledata))>7
motion.angleunit = 'raw';
end
if writeMAT
save(filenameMAT, 'motion');
end % fi
end % fi
end
function [basis] = processBasisNode ( xmljointnode )
% Write here what this function does
%
% [basis] = processBasisNode ( xmllimitsnode )
%
xbasis = zeros(3,1);
ybasis = zeros(3,1);
zbasis = zeros(3,1);
children = xmljointnode.getChildNodes;
for c=0:children.getLength-1
node = children.item(c);
nodetype = node.getNodeType;
switch nodetype
% only handle ELEMENT_NODES
case node.ELEMENT_NODE
nodename = lower(node.getNodeName.toCharArray()');
switch nodename
case 'vecx'
xbasis = str2num(char(node.getFirstChild.getData.toCharArray())')';
case 'vecy'
ybasis = str2num(char(node.getFirstChild.getData.toCharArray())')';
case 'vecz'
zbasis = str2num(char(node.getFirstChild.getData.toCharArray())')';
otherwise
fprintf('- ');
end
otherwise
end %switch node type
end %for
basis = [xbasis ybasis zbasis];
end
function skeleton = processJointNode ( xmljointnode, skeleton, parentid, idx )
%
%
% skeleton = processJointNode ( xmljointnode, skeleton, parentid, idx )
global GLOBAL_VARS_SETTINGS
% the number of joints conveniently also marks the next joint to be
% filled with values
currentnodeindex = skeleton.numberofjoints;
skeleton.joints(currentnodeindex,1) = emptyJoint;
skeleton.joints(currentnodeindex,1).parent = parentid;
parentid=-1;
if (GLOBAL_VARS_SETTINGS.VERBOSE)
q = repmat('#',idx,1);
fprintf('\n%d %s %s', idx, q, char(xmljointnode.getNodeName.toCharArray()));
end % fi VERBOSE
% get all children of the current node
children = xmljointnode.getChildNodes;
% go through children and handle them
for c=0:children.getLength-1
node = children.item(c);
nodetype = node.getNodeType;
switch nodetype
% only handle ELEMENT_NODES
case node.ELEMENT_NODE
switch lower(node.getNodeName.toCharArray()')
case 'joint'
% increasing the number of joints before processing the next
% joint node leads to being able to use this for constructing
% the next joint node (it will be empty if something goes
% wrong)
skeleton.numberofjoints = skeleton.numberofjoints+1;
[skeleton] = processJointNode( node, skeleton, parentid, idx+1 );
case 'name'
if (GLOBAL_VARS_SETTINGS.VERBOSE)
fprintf(' name: %s ', char(node.getFirstChild.getData.toCharArray()));
end % fi VERBOSE
skeleton.joints(currentnodeindex,1).jointname = node.getFirstChild.getData.toCharArray()';
case 'id'
id = str2num(char(node.getFirstChild.getData.toCharArray())');
if (GLOBAL_VARS_SETTINGS.VERBOSE)
fprintf(' ID: %d', id );
end % fi VERBOSE
parentid=id;
skeleton.joints(currentnodeindex,1).id = id;
case 'position'
position = str2num(char(node.getFirstChild.getData.toCharArray())')';
if (GLOBAL_VARS_SETTINGS.VERBOSE)
fprintf(' p: < ');
fprintf('%d ', position );
fprintf('>');
end % fi VERBOSE
skeleton.joints(currentnodeindex,1).position = position;
case 'limits'
if (GLOBAL_VARS_SETTINGS.VERBOSE)
fprintf(' l');
end % fi VERBOSE
[limits, dof] = processLimitsNode( node );
skeleton.joints(currentnodeindex,1).limits = limits;
skeleton.joints(currentnodeindex,1).dof = dof;
case 'basis'
if (GLOBAL_VARS_SETTINGS.VERBOSE)
fprintf(' b');
end % fi VERBOSE
[basis] = processBasisNode( node );
skeleton.joints(currentnodeindex,1).localcoordinatesystem = basis;
otherwise
end % switch node name
otherwise
end %switch node type
end %for
end % of function processJoint
function [limits, dof] = processLimitsNode ( xmljointnode )
% Write here what this function does
%
% [limits,dof] = processLimitsNode ( xmllimitsnode )
%
xminmax = zeros(1,2);
yminmax = zeros(1,2);
zminmax = zeros(1,2);
children = xmljointnode.getChildNodes;
for c=0:children.getLength-1
node = children.item(c);
nodetype = node.getNodeType;
switch nodetype
% only handle ELEMENT_NODES
case node.ELEMENT_NODE
nodename = lower(node.getNodeName.toCharArray()');
switch nodename
case 'rotx'
xminmax = str2num(char(node.getFirstChild.getData.toCharArray())');
case 'roty'
yminmax = str2num(char(node.getFirstChild.getData.toCharArray())');
case 'rotz'
zminmax = str2num(char(node.getFirstChild.getData.toCharArray())');
otherwise
fprintf('- ');
end
otherwise
end %switch node type
end %for
limits = [xminmax;yminmax