model.assemble() with multiple coordinate weights

Provide easy-to-use, extensible software for modeling, simulating, controlling, and analyzing the neuromusculoskeletal system.
POST REPLY
User avatar
Ruth Meißner
Posts: 16
Joined: Sat Mar 23, 2019 11:28 am

model.assemble() with multiple coordinate weights

Post by Ruth Meißner » Fri Jun 05, 2020 11:57 am

Hi everybody,

I am creating a model of a person pedaling with the arms (like handbiking) (Matlab scripting, OpenSim 4.1)
To create the movement during pedaling, I created the pedals as a body welded to ground and constrainted both hands to each pedal via two PointConstraints per hand to avoid any closed loop-

To create my movement, I am setting the pedal angle (free DoF around local-z-axis) and want then to assemble the model to this position of the pedal. Due to the point constraints, the model is enforced to move the upper body / arms depending on the pedal position. (This works actually quite nice in the GUI, but not in Matlab). The next step is to extract the coordinate values set in this state and write them to a timetable which can then be exported as mot-file. This second part works without issue, but for the assembling of the states doesn't quite works how I'd like to.

I had three approaches:

1) First, I tried to use the model.assemble(state)-command, which works fine without any coordinate weighting. (see https://simtk.org/api_docs/opensim/api_ ... e84e54f30f). To create a realistic movement I have to set weights on multiple coordinates in the model. ( I know that because beforehands I already developed the exact same movement using IKTool - but we want to change this. Now I want to set up my movement "manually".)
From the API, I know that I can use the assemble-command to set ONE weight like this:

Code: Select all

model.assemble(state, coordinateSet.get('lumbar_bending') , 50);
However multiple weights like

Code: Select all

model.assemble(state, coordinateSet.get('lumbar_bending') , 50, coordinateSet.get('lumbar_rotation') , 0.005); 
are not accepted by the assemble-command.

Is there any possibility to realize this?


2) I already tried using the Assembly Solver for assembling of each state:
(please compare https://simtk.org/api_docs/opensim/api_ ... e182f33fad)

Code: Select all

% Beforehand goes some code to set the pedal angle

%% Create CoordinateReferences
coordRefs = SimTKArrayCoordinateReference();
    for i = 0: model.getCoordinateSet().getSize()-1
        coord = model.getCoordinateSet().get(i);
        name = string(coord.getName());
        simtkfunction = Constant(coord.getValue(state_angleBefore));
        
        if strcmp(name, 'pedalangle')
            weight = 1000;
        elseif strcmp(name, 'lumbar_bending')
            weight = 100;    
        else 
            weight = 1;
        end
        
        coordRef = CoordinateReference(name, simtkfunction);
        coordRef.setWeight(weight); 
        coordRefs.push_back(coordRef);  %assign(i, coordRef);
    end
    
%% Create Assembly Solver and assemble
    as = AssemblySolver(model, coordRefs, Inf);
    as.assemble(state_currentAngle);
Using this approach I have the issue that
1) weighting doesn't seem to work
2) my pedal angle does not stay to the value I set, even if I define pedalangle.set_locked(true) and pedalangle.set_is_free_to_satisfy_constraint(false)



3) I also had the idea to access the Assembler itself but I couldn't get it run in Matlab
on

Code: Select all

as.getAssembler()
I get an Swigtype-ASsembler-Object ('org.opensim.modeling.SWIGTYPE_p_SimTK__Assembler').
I didn't understand yet how I can downcast/change this swigtype-object to an regular SimTK-Assembler-Object so that its methods get available in Matlab.
(see https://simtk.org/api_docs/opensim/api_ ... 6f7709cedb which would made it possible to access the AssemblyCondition to be set)


I'd appreciate any ideas :)

Thanks & best regards
Ruth

Tags:

User avatar
Ruth Meißner
Posts: 16
Joined: Sat Mar 23, 2019 11:28 am

Re: model.assemble() with multiple coordinate weights

Post by Ruth Meißner » Fri Jun 26, 2020 3:35 am

Hi everybody,
since I found a solution to my question, I want to share it here in the case somebody else needs it in the future.

The AssemblySolver Class can be used with different weights, I just defined the CoordinateReferencesArray in a wrong way.

That's how it is done correctly with Matlab

Code: Select all

%% CASE 1 for constant values to be weighted, case 2 from coordinates files --
% !! only use one of both

% Case 2 preparation
        sto_in = Storage(motionfilename);
        model.getSimbodyEngine().convertDegreesToRadians(sto_in);
        coordFunctions = GCVSplineSet(5, sto_in, 0.0);
        index = 0;
        
% Define Coordinate References
coordRefsToTrack = SimTKArrayCoordinateReference();
for i = 0: model.getCoordinateSet().getSize()-1
        coord = model.getCoordinateSet().get(i);
        
        if coord.isDependent(stateBef) == false 
            coordname = string(coord.getName());
            
            %% CASE 1 ---CONSTANT Value to bei weighted -- CASE 1
            val = (model.getCoordinateSet().get(coordname).getDefaultValue());
            weight = getCoordinateWeighting(coordname); % Set manually
            simtkfunction = Constant(val);
            
            %% CASE 2
            weight = weightYouWantToHave;
            index = coordFunctions.getIndex(coordname, index);
            simtkfunction = coordFunctions.get(index);
             
             
            coordRef = CoordinateReference(coordname, simtkfunction);
            coordRef.setWeight(weight);

            coordRefsToTrack.push_back(coordRef);
        end
  end
  
  % Create Assembly Solver
  as = AssemblySolver(model, coordRefsToTrack, Inf);
  as.setAccuracy(model.get_assembly_accuracy() );
  as.setConstraintWeight(Inf); 
            
            
For further understanding, it is always possible to compare the strategy with openSim core in github, here e.g. Github Model::createAssemblySolver() https://github.com/opensim-org/opensim- ... /Model.cpp or directly in the InverseKinematicsTool.run()
--> It is very helpful if you want to re-write parts of certain tools that OpenSim has already implemented.

Best regards
Ruth

POST REPLY