MocoStateTracking

OpenSim Moco is a software toolkit to solve optimal control problems with musculoskeletal models defined in OpenSim using the direct collocation method.
POST REPLY
User avatar
Christian Greve
Posts: 41
Joined: Mon Jun 13, 2016 11:14 pm

MocoStateTracking

Post by Christian Greve » Tue Jul 19, 2022 4:29 am

Dear Moco users and developer team,

I am working on a MocoState Tracking problem. In the end, I want to use MocoTrack to validate some output from ParameterOptimization. I want to establish which muscle-tendon parameter configurations are best to track measured kinematics and GRFs.

As a first step I try to simply track coordinates and apply GRFs. Please see code below. THe problem I am facing is that the solution does not at all look like the measured kinematics. It "walks" backwards and floats through the ground.

I am wondering if you have any suggestions for me to get a stable tracking solution. Are there maybe some peculiarities in the code? I am using Python 3.8 and OpenSim 4.3

Thanks for your time and kind regards

Christian

Code: Select all

for name in dir():
    if not name.endswith('FileName'):
        del globals()[name]
        
import opensim as osim
import os
# 

Path = r'C:\Users\.......'
os.chdir(Path)
Scaled_modelFileName = os.path.join(Path, 'LowerLimbFootModel.osim')
GRF_SourceFilename = os.path.join(Path,'grf_CluFO_01_Okt202112_Filt.xml')
States_Filename = os.path.join(Path,'Okt202112_Kinematics_q.sto')#'MocoInverseWithEMG_Okt202108_Clubfoot_Final_NoMocoProblem.sto')
ReserveActuatorStrength = 25
Output_FilenameMocoTrack = os.path.join(Path,'MocoTrack_Solution_test.sto')
start_time = 0.7
end_time = 1.5#1.87



#%% Construct a ModelProcessor and set it on the tool. The default

modelProcessor = osim.ModelProcessor(Scaled_modelFileName)#('Patient_SCALED.osim')
modelProcessor.append(osim.ModOpAddExternalLoads(GRF_SourceFilename))#('grf_walk_PiG.xml'))
modelProcessor.append(osim.ModOpIgnoreTendonCompliance())
modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016())
modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF())
modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5))
modelProcessor.append(osim.ModOpAddReserves(ReserveActuatorStrength))

track = osim.MocoTrack()
track.setName("CoordTracking")
track.setModel(modelProcessor)

track.setStatesReference(osim.TableProcessor(States_Filename))
track.set_states_global_tracking_weight(50)
track.set_control_effort_weight(0.001)

track.set_allow_unused_references(True)
track.set_track_reference_position_derivatives(True);
track.set_apply_tracked_states_to_guess(True)
# track.set_scale_state_weights_with_range(True)

track.set_initial_time(start_time)
track.set_final_time(end_time)
track.set_mesh_interval(0.04)

#%% Coordinate tracking to create guess file
study = track.initialize()
problem = study.updProblem()
effort = osim.MocoControlGoal.safeDownCast(problem.updGoal("control_effort"))
model = modelProcessor.process()
model.initSystem()
forceSet = model.getForceSet()
for i in range(forceSet.getSize()):
    forcePath = forceSet.get(i).getAbsolutePathString()
    if 'pelvis' in str(forcePath):
        effort.setWeightForControl(forcePath, 10)
 
solution = study.solve()
solution.unseal()
solution.write(Output_FilenameMocoTrack)
study.visualize(solution)

User avatar
Ross Miller
Posts: 375
Joined: Tue Sep 22, 2009 2:02 pm

Re: MocoStateTracking

Post by Ross Miller » Tue Jul 19, 2022 7:12 am

Hi Christian,

My experience in starting out doing problems like this in Moco was that creating your own problem from scratch is hard, there's a lot of pieces to it and when it doesn't work initially, it's hard to figure out what the issue is exactly.

I found it a lot easier to start from the "example2Dwalk" example code that comes with Moco, then modify it one piece at a time to suit my purpose. E.g. first I ran that code and confirmed it worked, then I swapped in my own data for the tracking targets and made sure it still works, then I started changing things about the model, adding/changing one small element of complexity at a time and each time checking that the code still converges on reasonable solutions.

Hope this helps,
Ross

User avatar
Carlos Gonçalves
Posts: 135
Joined: Wed Jun 08, 2016 4:56 am

Re: MocoStateTracking

Post by Carlos Gonçalves » Tue Aug 02, 2022 5:19 pm

Hello Christian and Ross,

Complementing on what Ross said, I created some kind of checklist for those optimizations. Maybe it can help you and others:
  • Always try to use a guess file, so the states have a good starting point to initiate the solution
  • Check if for your problem the state bounds are correct to your motion. In your sample code, there is no part where the states are bounded by you. Maybe there are restricted to values outside your solution (flying behavior). Sometimes is better to leave the start and final bound undeclared.
  • Check if the time bounds are also feasible. Sometimes leave them open.
  • Start just tracking the coordinates and add the GRF later so that you can catch other issues with code/files.
I had a good result with MocoStateTrackingGoal, and MocoContactTrackingGoal called into a MocoProblem. If needed, I can clarify that.

Best regards.

PS: a long time ago my models jumped backward after walking because I left the pelvis final translation bound equal to the start :lol:

User avatar
Christian Greve
Posts: 41
Joined: Mon Jun 13, 2016 11:14 pm

Re: MocoStateTracking

Post by Christian Greve » Wed Dec 14, 2022 4:20 am

Hi Carlos,

thanks for your suggestions....some time ago but still relevant......;) .

Could you maybe clarify how you integrated the MocoStateTrackingGoal and MocoContactTrackingGoal into a MocoProblem?

Thanks and kindregards

Christian

User avatar
Carlos Gonçalves
Posts: 135
Joined: Wed Jun 08, 2016 4:56 am

Re: MocoStateTracking

Post by Carlos Gonçalves » Wed Dec 14, 2022 6:15 pm

Hello Christian,

The first step is to create the files for state tracking and GRF tracking. I think the GRF is already solved since you already used.

In my simulation, I used a subset of states to pass to the MocoStateTrackingGoal. At the time, it was easier than using a complete state solution and filtering the states as in void OpenSim::MocoStateTrackingGoal::setPattern ( std::string pattern ):
The regular expression must match the entire state path for a state path to be tracked (that is, we use std::regex_match, not std::regex_search). To track only generalized coordinates, use .value$. To track generalized coordinates and speeds, use .(value|speed)$. To track only activations, use .*activation$. If the reference contains columns for states whose path does not match this pattern, you will get an error unless you use setAllowUnusedReferences(true).
With the file, is just a matter of creating the object and setting some parameters:

Code: Select all

stateTracking = osim.MocoStateTrackingGoal()
stateTracking.setWeight(listParam[parmDict['trackingWeight']])
stateTracking.setName('tracking')
stateTracking.setReference(osim.TableProcessor(listParam[parmDict['trackFile']]))
problem.addGoal(stateTracking)
For the GRF, it takes more steps, but as Ross mentioned, there are good examples available in the forum and in the documentation page. Here is what I did to set all the contact spheres into groups that the resulting force would be tracking a GRF magnitude. In my case, only vertical.

Code: Select all

 
        contactTracking = osim.MocoContactTrackingGoal("grf", listParam[parmDict['grfWeight']])
        contactTracking.setExternalLoadsFile(listParam[parmDict['grfFile']])

        contact_r = osim.StdVectorString()
        contact_l = osim.StdVectorString()
        prefixContactForce = "forceset/SmoothSphereHalfSpaceForce_s"
        for i in range(1, 7):
            contact_r.append(prefixContactForce + '{0:d}'.format(i) + '_r')
            contact_l.append(prefixContactForce + '{0:d}'.format(i) + '_l')

        trackRightGRF = osim.MocoContactTrackingGoalGroup(contact_r, "Right_GRF")
        trackLeftGRF = osim.MocoContactTrackingGoalGroup(contact_l, "Left_GRF")
        contactTracking.addContactGroup(trackRightGRF)
        contactTracking.addContactGroup(trackLeftGRF)

        contactTracking.setProjection("plane")
        contactTracking.setProjectionVector(osim.Vec3(0, 1, 0))

        problem.addGoal(contactTracking)
Hope it helps.

Best regards.

Carlos

POST REPLY