Page 1 of 1

Classes to use MOT file in MATLAB to move model and analyse actuators

Posted: Tue Aug 22, 2023 7:28 am
by rejinjv
Dear experts,

I am not able to understand the methods and classes to use a MOT file (generated from MoCap data applied to an OpenSim model) to a different model (same base model, but with different actuators etc.). I tried to have the MOT file into a STO object, and access the data as StateVectors etc., but could not find how to do the same. I have ended up treating the MOT file as a txt file and then iterating over the coordinates and setting values. Could someone please help me with how to use some OpenSim API functions/classes instead of using nested loops (code below).

Secondly, just to improve my understanding - as I was looking to just assign the coordinate values to the bodies to see how the body was moving (and potentially how cable actuators would behave), I did not need muscles etc. However, even after removing the muscles, if I don't use the following line: model.equilibrateMuscles(state)

I get the following error (why would that be ?)

Error:

Code: Select all

Error using torsoStabiliserOpenSimSimulation
Java exception occurred:
java.lang.RuntimeException: SimTK Exception thrown at State.cpp:974:
  Error detected by Simbody method getCacheEntry: State Cache entry was out of date at Stage Time.
  This entry depends on version 1 of Stage Instance but was last updated at version 0.
  (Required condition 'version == m_dependsOnVersionWhenLastComputed' was not met.)

	at org.opensim.modeling.opensimSimulationJNI.Point_calcDistanceBetween__SWIG_1(Native Method)
	at org.opensim.modeling.Point.calcDistanceBetween(Point.java:153)


Regards,

Rejin

Code:

Code: Select all


clc
clear

%% Initialization

% import Opensim classes
org.opensim.modeling.opensimCommon.GetVersion()
import org.opensim.modeling.*

basefilename = 'Model_9x10_Wheelchair_2';
modfilename = strcat(basefilename, ...
    datestr(now,'_ddmmyy_HHMM'),'.osim');

% Load model and get model components
model = Model(strcat(basefilename,'.osim'));

% Load MOT file
motData = readtable('Limit01_9x10.mot','FileType','text');
timeVec = motData.time;
coordinateDataMatrix = motData{:,2:end};

% Initialize the sytem
state = model.initSystem();


bodySet = model.getBodySet();
numBodies = bodySet.getSize();

coordinateSet = model.getCoordinateSet();
numCoordinates = coordinateSet.getSize();

forceSet = model.getForceSet();
numForces = forceSet.getSize();

markerSet = model.getMarkerSet();
numMarkers = markerSet.getSize();


%% Get relevant marker info

for i = 1:numMarkers
    tempMarker = markerSet.get(i-1);
    tempMarkerName(i) = tempMarker.getName();
    fprintf("Marker Name: %i: %s \n",i-1,tempMarkerName(i));
    if strcmp(tempMarkerName(i),'T2_4')
        T2_4_Marker = tempMarker;
        T2_4_Marker.set_fixed(true);
        T2_4_MarkerLoc = tempMarker.get_location();
    elseif strcmp(tempMarkerName(i),'T2_8')
        T2_8_Marker = tempMarker;
        T2_8_Marker.set_fixed(true);
        T2_8_MarkerLoc = tempMarker.get_location();
    elseif strcmp(tempMarkerName(i),'wheelchair1')
        wheelchair1Marker = tempMarker;
        wheelchair1Marker.set_fixed(true);
        wheelchair1MarkerLoc = tempMarker.get_location();
    elseif strcmp(tempMarkerName(i),'wheelchair3')
        wheelchair3Marker = tempMarker;
        wheelchair3Marker.set_fixed(true);
        wheelchair3MarkerLoc = tempMarker.get_location();
    end
end

scapula_R = model.getBodySet().get('scapula_R');
scapula_L = model.getBodySet().get('scapula_L');
ground = model.getGround();

pathSpring1_restingLength = wheelchair1Marker.calcDistanceBetween(state,scapula_L,T2_8_Marker.get_location());
fprintf('Path Spring 1 Resting Length:%.04f \n',pathSpring1_restingLength)

pathSpring2_restingLength = wheelchair3Marker.calcDistanceBetween(state,scapula_R,T2_4_Marker.get_location());
fprintf('Path Spring 2 Resting Length:%.04f \n',pathSpring2_restingLength)

%% Remove all muscles


% Get the MuscleSet
muscleSet = model.getMuscles();

% Number of muscles in the model
numMuscles = muscleSet.getSize();

% Iterate through all the muscles and remove them
for i = numMuscles+1:-1:1  % Start from the last muscle; OpenSim uses 0-indexing
    % Remove the muscle from the model
    model.updForceSet().remove(i-1);
end


%% Add Actuator between markers

% syringe actuator specs
% L_ser = 0.015; L_syr = 0.018; k_ser = 400; gearing = 1/2.25;
% get syringe actuator force as a function of displacement (x)
% syringeActuatorFunc = @(x) syringeActuator_simplified2(x,[L_ser L_syr k_ser gearing]);
% d = linspace(0,(L_ser+L_syr)*gearing,1000);
% syringeActForce = syringeActuatorFunc(d);
% plot(d,syringeActForce)


% Create Path Actuator between selected marker locations
actuator1 = PathSpring();
actuator1.setName('Actuator1');

% Set the location of the first point in the tibia frame. These numbers
% were determined from placing a marker on the desired location in the GUI.
actuator1.getGeometryPath().appendNewPathPoint('wheelchairLoc1',ground,wheelchair1MarkerLoc);
% Set the locaton of the second point in the Calcn frame
actuator1.getGeometryPath().appendNewPathPoint('scapulaL_Loc', scapula_L,T2_8_MarkerLoc);


% Create Path Actuator between selected marker locations
actuator2 = PathSpring();
actuator2.setName('Actuator2');

% Set the location of the first point in the tibia frame. These numbers
% were determined from placing a marker on the desired location in the GUI.
actuator2.getGeometryPath().appendNewPathPoint('wheelchairLoc3',ground,wheelchair3MarkerLoc);
% Set the locaton of the second point in the Calcn frame
actuator2.getGeometryPath().appendNewPathPoint('scapulaR_Loc', scapula_R,T2_4_MarkerLoc);


% actuator1 - Path Spring Characteristics
actuator1.setStiffness(0);
actuator1.setDissipation(0);
actuator1.setRestingLength(pathSpring1_restingLength);

% actuator2 - Path Spring Characteristics
actuator2.setStiffness(0);
actuator2.setDissipation(0);
actuator2.setRestingLength(pathSpring2_restingLength);



% Add the force to the model
model.addForce(actuator1);
model.addForce(actuator2);
model.finalizeConnections();

% print model - save as new file
model.print(modfilename)

%% Traverse MOT File kinematics

% get number of timesteps
numTimesteps = length(timeVec);

model.setUseVisualizer(false);


% Re-initialise system
state = model.initSystem();


% iterate over time
for i = 1:numTimesteps

    % iterate over model coordinates
    for j = 1:numCoordinates
        currCoord = coordinateSet.get(j-1);
        currCoord.setValue(state,coordinateDataMatrix(i,j),false);
    end
%     model.equilibrateMuscles(state);

    L_pathSpring1_a(i) = wheelchair1Marker.calcDistanceBetween(state,scapula_L,T2_8_Marker.get_location());
    L_pathSpring1_b(i) = actuator1.getLength(state);

    L_pathSpring2_a(i) = wheelchair3Marker.calcDistanceBetween(state,scapula_R,T2_4_Marker.get_location());
    L_pathSpring2_b(i) = actuator2.getLength(state);
    %     fprintf('Time: %03f \n',timeVec(i))

    fprintf('Time: %03f Path Spring 1 Length: %.04f %.04f Path Spring 2 Length: %.04f %.04f  \n',...
        timeVec(i),L_pathSpring1_a(i),L_pathSpring1_b(i),...
        L_pathSpring2_a(i),L_pathSpring2_b(i));
end

%% Save Data

save('ModelOpenSim_wActuators.mat')



Re: Classes to use MOT file in MATLAB to move model and analyse actuators

Posted: Thu Aug 24, 2023 1:26 pm
by aymanh
Hello,

Generally speaking,
1. If you don't need muscles in your model, you're better off removing them from the file to begin with rather than programmatically removing them one by one.
2. The assumptions about the ordering of values/coordinates in the state can be tricky, so assigning values from a vector that has built-in ordering after making model changes may be problematic. You're better off finding each coordinate by name and assigning a value to it directly.
3. I strongly recommend you check the documentation of the state class/behavior described here:
https://simtk-confluence.stanford.edu/d ... n+Concepts
In particular, the various stages.
Any time you set the time in the state, the stage is brought down to time and you need to "realize" before you can ask about distances (position dependent quantities) or invoke code that depends on the stage being realized.
4. You don't need to use Storage object, you can use the more modern TimeSeriesTable classes to read mot files but that doesn't change anything in the above discussion as all these different formats/classes are vehicles to save/retrieve timeseries data from a file. Your issue seems to be related to applying the data to the model rather than the save/retrieve mechanism.

Hope this helps,
-Ayman

Re: Classes to use MOT file in MATLAB to move model and analyse actuators

Posted: Sun Sep 03, 2023 11:57 am
by rejinjv
Thanks a lot Ayman for the detailed reply.

Regards,

Rejin