def solveMocoInverse(): #Construct the MocoInverse tool. inverse = osim.MocoInverse() inverse.setName('inverseTorqueTracking') #Construct a ModelProcessor and set it on the tool. The muscles are removed #and reserve actuators added to generate a torque driven solution modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpRemoveMuscles()) modelProcessor.append(osim.ModOpAddReserves(300)) inverse.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #inverse tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. inverse.setKinematics(osim.TableProcessor('ikResults_states.sto')) # Initial time, final time, and mesh interval. inverse.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) inverse.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) inverse.set_mesh_interval(0.02) # By default, Moco gives an error if the kinematics contains extra columns. # Here, we tell Moco to allow (and ignore) those extra columns. inverse.set_kinematics_allow_extra_columns(True) # Solve the problem and write the solution to a Storage file. solution = inverse.solve() #Return the solution as an object that we can use return solution
def solveMocoInverse(): # Construct the MocoInverse tool. inverse = osim.MocoInverse() # Construct a ModelProcessor and set it on the tool. The default # muscles in the model are replaced with optimization-friendly # DeGrooteFregly2016Muscles, and adjustments are made to the default muscle # parameters. modelProcessor = osim.ModelProcessor('subject_walk_armless.osim') modelProcessor.append(osim.ModOpAddExternalLoads('grf_walk.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(1.0)) inverse.setModel(modelProcessor) # Construct a TableProcessor of the coordinate data and pass it to the # inverse tool. TableProcessors can be used in the same way as # ModelProcessors by appending TableOperators to modify the base table. # A TableProcessor with no operators, as we have here, simply returns the # base table. inverse.setKinematics(osim.TableProcessor('coordinates.sto')) # Initial time, final time, and mesh interval. inverse.set_initial_time(0.81) inverse.set_final_time(1.79) inverse.set_mesh_interval(0.02) # By default, Moco gives an error if the kinematics contains extra columns. # Here, we tell Moco to allow (and ignore) those extra columns. inverse.set_kinematics_allow_extra_columns(True) # Solve the problem and write the solution to a Storage file. solution = inverse.solve() solution.getMocoSolution().write( 'example3DWalking_MocoInverse_solution.sto') # Generate a PDF with plots for the solution trajectory. model = modelProcessor.process() report = osim.report.Report(model, 'example3DWalking_MocoInverse_solution.sto', bilateral=True) # The PDF is saved to the working directory. report.generate()
def getWalkingModel(): # Load the 19 DOF, 18 muscle model from file. model = osim.Model('subject_walk_armless_18musc.osim'); # Add actuators representing the pelvis residual actuators and lumbar # torques. These actuators are only as strong as they need to be for the # problem to converge. addCoordinateActuator(model, 'pelvis_tx', 60) addCoordinateActuator(model, 'pelvis_ty', 300) addCoordinateActuator(model, 'pelvis_tz', 35) addCoordinateActuator(model, 'pelvis_tilt', 60) addCoordinateActuator(model, 'pelvis_list', 35) addCoordinateActuator(model, 'pelvis_rotation', 25) addCoordinateActuator(model, 'lumbar_bending', 40) addCoordinateActuator(model, 'lumbar_extension', 40) addCoordinateActuator(model, 'lumbar_rotation', 25) # We need additional actuators for hip rotation and hip adduction since the # existing muscle act primarily in the sagittal plane. addCoordinateActuator(model, 'hip_rotation_r', 100) addCoordinateActuator(model, 'hip_rotation_l', 100) addCoordinateActuator(model, 'hip_adduction_r', 100) addCoordinateActuator(model, 'hip_adduction_l', 100) # Create a ModelProcessor to make additional modifications to the model. modelProcessor = osim.ModelProcessor(model) # Weld the subtalar and toe joints. jointsToWeld = osim.StdVectorString() jointsToWeld.append('subtalar_r') jointsToWeld.append('subtalar_l') jointsToWeld.append('mtp_r') jointsToWeld.append('mtp_l') modelProcessor.append(osim.ModOpReplaceJointsWithWelds(jointsToWeld)) # Apply the ground reaction forces to the model. modelProcessor.append(osim.ModOpAddExternalLoads('external_loads.xml')) # Update the muscles: ignore tendon compliance and passive forces, replace # muscle types with the DeGrooteFregly2016Muscle type, and scale the width # of the active force length curve. modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) # Add a set a weak reserves to the sagittal-plane joints in the model. modelProcessor.append(osim.ModOpAddReserves(1.0)) return modelProcessor
def solveMocoInverseMuscle(): #Construct the MocoInverse tool. inverse = osim.MocoInverse() inverse.setName('inverseMuscleTracking') #Construct a ModelProcessor and set it on the tool. #Currently the coordinate actuators for the pelvis, along with the reserve #actuators are fairly generally set, and not weighted at all in cost function. #These actuators could be more carefully considered to generate an appropriate #muscle driven simulation. For example, if they max and min control to 1 - the #pelvis actuators may not produce enough torque. modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. # modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(2)) inverse.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #inverse tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. inverse.setKinematics(osim.TableProcessor('ikResults_states.sto')) #Initial time, final time, and mesh interval. inverse.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) inverse.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) inverse.set_mesh_interval(0.02) # By default, Moco gives an error if the kinematics contains extra columns. # Here, we tell Moco to allow (and ignore) those extra columns. inverse.set_kinematics_allow_extra_columns(True) # Solve the problem and write the solution to a Storage file. solution = inverse.solve() #Return the solution as an object that we can use return solution
def track(self, prediction_solution, exponent=2): track = osim.MocoTrack() track.setName('suspended_mass_tracking') track.setModel(osim.ModelProcessor(self.build_model())) track.setStatesReference( osim.TableProcessor(prediction_solution.exportToStatesTable())) track.set_states_global_tracking_weight(10.0) track.set_allow_unused_references(True) # track.set_control_effort_weight(1.0) track.set_mesh_interval(0.003) study = track.initialize() problem = study.updProblem() problem.setStateInfo("/jointset/tx/tx/value", [-self.width, self.width], self.xinit) problem.setStateInfo("/jointset/ty/ty/value", [-2 * self.width, 0], self.yinit) problem.setStateInfo("/forceset/left/activation", [0, 1], 0) problem.setStateInfo("/forceset/middle/activation", [0, 1], 0) problem.setStateInfo("/forceset/right/activation", [0, 1], 0) problem.updPhase().setDefaultSpeedBounds(osim.MocoBounds(-15, 15)) tracking = osim.MocoStateTrackingGoal.safeDownCast( problem.updGoal('state_tracking')) tracking.setPattern('.*(value|speed)$') effort = osim.MocoControlGoal.safeDownCast( problem.updGoal('control_effort')) effort.setExponent(exponent) solver = osim.MocoCasADiSolver.safeDownCast(study.updSolver()) solver.set_optim_convergence_tolerance(-1) solver.set_optim_constraint_tolerance(-1) solution = study.solve() return solution
def muscleDrivenStateTracking(): # Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName("muscle_driven_state_tracking") # Construct a ModelProcessor and set it on the tool. The default # muscles in the model are replaced with optimization-friendly # DeGrooteFregly2016Muscles, and adjustments are made to the default muscle # parameters. modelProcessor = osim.ModelProcessor("subject_walk_armless.osim") modelProcessor.append(osim.ModOpAddExternalLoads("grf_walk.xml")) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) track.setModel(modelProcessor) # Construct a TableProcessor of the coordinate data and pass it to the # tracking tool. TableProcessors can be used in the same way as # ModelProcessors by appending TableOperators to modify the base table. # A TableProcessor with no operators, as we have here, simply returns the # base table. track.setStatesReference(osim.TableProcessor("coordinates.sto")) track.set_states_global_tracking_weight(10) # This setting allows extra data columns contained in the states # reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data in the states references, # this setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. track.set_initial_time(0.81) track.set_final_time(1.65) track.set_mesh_interval(0.08) # Instead of calling solve(), call initialize() to receive a pre-configured # MocoStudy object based on the settings above. Use this to customize the # problem beyond the MocoTrack interface. study = track.initialize() # Get a reference to the MocoControlCost that is added to every MocoTrack # problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast( problem.updGoal("control_effort")) # Put a large weight on the pelvis CoordinateActuators, which act as the # residual, or 'hand-of-god', forces which we would like to keep as small # as possible. 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) # Solve and visualize. solution = study.solve() study.visualize(solution)
def torqueDrivenMarkerTracking(): # Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName("torque_driven_marker_tracking") # Construct a ModelProcessor and add it to the tool. ModelProcessors # accept a base model and allow you to easily modify the model by appending # ModelOperators. Operations are performed in the order that they are # appended to the model. # Create the base Model by passing in the model file. modelProcessor = osim.ModelProcessor("subject_walk_armless.osim") # Add ground reaction external loads in lieu of a ground-contact model. modelProcessor.append(osim.ModOpAddExternalLoads("grf_walk.xml")) # Remove all the muscles in the model's ForceSet. modelProcessor.append(osim.ModOpRemoveMuscles()) # Add CoordinateActuators to the model degrees-of-freedom. This ignores the # pelvis coordinates which already have residual CoordinateActuators. modelProcessor.append(osim.ModOpAddReserves(250)) track.setModel(modelProcessor) # Use this convenience function to set the MocoTrack markers reference # directly from a TRC file. By default, the markers data is filtered at # 6 Hz and if in millimeters, converted to meters. track.setMarkersReferenceFromTRC("marker_trajectories.trc") # There is marker data in the 'marker_trajectories.trc' associated with # model markers that no longer exists (i.e. markers on the arms). Set this # flag to avoid an exception from being thrown. track.set_allow_unused_references(True) # Increase the global marker tracking weight, which is the weight # associated with the internal MocoMarkerTrackingCost term. track.set_markers_global_tracking_weight(10) # Increase the tracking weights for individual markers in the data set # placed on bony landmarks compared to markers located on soft tissue. markerWeights = osim.MocoWeightSet() markerWeights.cloneAndAppend(osim.MocoWeight("R.ASIS", 20)) markerWeights.cloneAndAppend(osim.MocoWeight("L.ASIS", 20)) markerWeights.cloneAndAppend(osim.MocoWeight("R.PSIS", 20)) markerWeights.cloneAndAppend(osim.MocoWeight("L.PSIS", 20)) markerWeights.cloneAndAppend(osim.MocoWeight("R.Knee", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("R.Ankle", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("R.Heel", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("R.MT5", 5)) markerWeights.cloneAndAppend(osim.MocoWeight("R.Toe", 2)) markerWeights.cloneAndAppend(osim.MocoWeight("L.Knee", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("L.Ankle", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("L.Heel", 10)) markerWeights.cloneAndAppend(osim.MocoWeight("L.MT5", 5)) markerWeights.cloneAndAppend(osim.MocoWeight("L.Toe", 2)) track.set_markers_weight_set(markerWeights) # Initial time, final time, and mesh interval. The number of mesh points # used to discretize the problem is computed internally using these values. track.set_initial_time(0.81) track.set_final_time(1.65) track.set_mesh_interval(0.05) # Solve! Use track.solve() to skip visualizing. solution = track.solveAndVisualize()
osimHelper.addCoordinateActuator(osimModel, coordName, 1.0, [1.0, -1.0], '_reserve') #Finalise model osimModel.finalizeFromProperties() #Something weird going on later if I try and call the model processor directly #from the model object here (says the model has no subcomponents?). A workaround #is to process print out the model and call it to the processor via its filename, #and then get a variable to call the processed model. #Print out the edited model osimModel.printToXML('simModel.osim') #Set up a model processor to configure model modelProcessor = osim.ModelProcessor('simModel.osim') #Convert model muscles to DeGrooteFregly type modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) #Append settings for muscle models #Set to ignore tendon compliance modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) #Set to ignore conservative passive fiber forces modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) #Set the fiber damping low to limit non-conservative passive forces #This may also serve to limit the negative muscle forces that can happen modelProcessor.append(osim.ModOpFiberDampingDGF(1e-02)) ####### this parameter could be a factor in the different results coming up ####### along with te active force width (if that didn't change). default is 0.1
trackingSolution = study.solve() trackingSolution.write('trackingSolution.sto') study.visualize(trackingSolution) ## Part 3: Compare Predictive and Tracking Solutions # This is a convenience function provided for you. See mocoPlotTrajectory.m plot.mocoPlotTrajectory('predictSolution.sto', 'trackingSolution.sto', 'predict', 'track') ## Part 4: Muscle-driven Inverse Problem # Create a MocoInverse tool instance. inverse = osim.MocoInverse() # Part 4a: Provide the model via a ModelProcessor. Similar to the TableProcessor, # you can add operators to modify the base model. modelProcessor = osim.ModelProcessor(muscleDrivenModel) modelProcessor.append(osim.ModOpAddReserves(2)) inverse.setModel(modelProcessor) # Part 4b: Set the reference kinematics using the same TableProcessor we used # in the tracking problem. inverse.setKinematics(tableProcessor) # Part 4c: Set the time range, mesh interval, and convergence tolerance. inverse.set_initial_time(0) inverse.set_final_time(1) inverse.set_mesh_interval(0.05) inverse.set_convergence_tolerance(1e-4) inverse.set_constraint_tolerance(1e-4) # Allow extra (unused) columns in the kinematics and minimize activations.
def create_model_processor(self, root_dir, for_inverse=False, config=None): flags = [] if config: flags = config.flags model = osim.Model(os.path.join(root_dir, 'resources/Rajagopal2016/' 'subject_walk_armless_contact_bounded_80musc.osim')) # for imusc in range(model.getMuscles().getSize()): # musc = model.updMuscles().get(imusc) # musc = osim.Millard2012EquilibriumMuscle.safeDownCast(musc) # musc.upd_FiberForceLengthCurve().set_strain_at_one_norm_force( # 3.0) # for muscle in ['vasmed', 'vasint', 'vaslat', 'recfem', 'semimem', # 'semiten']: # for side in ['_l', '_r']: # musc = model.updMuscles().get('%s%s' % (muscle, side)) # musc = osim.Millard2012EquilibriumMuscle.safeDownCast(musc) # musc.upd_FiberForceLengthCurve().set_strain_at_one_norm_force( # 3.5) if for_inverse: forceSet = model.getForceSet() numContacts = 0 for i in np.arange(forceSet.getSize()): forceName = forceSet.get(int(i)).getName() if 'contact' in forceName: numContacts += 1 print('Removing contact force elements from model...') contactsRemoved = 0 while contactsRemoved < numContacts: for i in np.arange(forceSet.getSize()): forceName = forceSet.get(int(i)).getName() if 'contact' in forceName: print(' --> removed', forceSet.get(int(i)).getName()) forceSet.remove(int(i)) contactsRemoved += 1 break stiffnessModifier = 0.8 print(f'Modifying contact element stiffnesses by factor {stiffnessModifier}...') for actu in model.getComponentsList(): if actu.getConcreteClassName() == 'SmoothSphereHalfSpaceForce': force = osim.SmoothSphereHalfSpaceForce.safeDownCast(actu) force.set_stiffness(stiffnessModifier * force.get_stiffness()) print(f' --> modified contact element {force.getName()}') def add_reserve(model, coord, optimal_force, max_control): actu = osim.ActivationCoordinateActuator() actu.set_coordinate(coord) if coord.startswith('pelvis'): prefix = 'residual_' elif coord.startswith('lumbar'): prefix = 'torque_' else: prefix = 'reserve_' actu.setName(prefix + coord) actu.setOptimalForce(optimal_force) actu.setMinControl(-max_control) actu.setMaxControl(max_control) model.addForce(actu) add_reserve(model, 'lumbar_extension', 1, 50) add_reserve(model, 'lumbar_bending', 1, 50) add_reserve(model, 'lumbar_rotation', 1, 50) reserves_max = 250 if for_inverse else 1 add_reserve(model, 'pelvis_tilt', 1, reserves_max) add_reserve(model, 'pelvis_list', 1, reserves_max) add_reserve(model, 'pelvis_rotation', 1, reserves_max) add_reserve(model, 'pelvis_tx', 1, reserves_max) add_reserve(model, 'pelvis_ty', 1, reserves_max) add_reserve(model, 'pelvis_tz', 1, reserves_max) optimal_force = 0.1 add_reserve(model, 'hip_flexion_r', optimal_force, reserves_max) add_reserve(model, 'hip_adduction_r', optimal_force, reserves_max) add_reserve(model, 'hip_rotation_r', optimal_force, reserves_max) add_reserve(model, 'knee_angle_r', optimal_force, reserves_max) add_reserve(model, 'ankle_angle_r', optimal_force, reserves_max) add_reserve(model, 'hip_flexion_l', optimal_force, reserves_max) add_reserve(model, 'hip_adduction_l', optimal_force, reserves_max) add_reserve(model, 'hip_rotation_l', optimal_force, reserves_max) add_reserve(model, 'knee_angle_l', optimal_force, reserves_max) add_reserve(model, 'ankle_angle_l', optimal_force, reserves_max) def add_device(model, coord): actu = osim.ActivationCoordinateActuator() actu.set_coordinate(coord) actu.setName(f'device_{coord}') actu.setOptimalForce(1000.0) actu.setMinControl(-1.0) actu.setMaxControl(1.0) model.addForce(actu) if 'assistankle' in flags: add_device(model, 'ankle_angle_r') add_device(model, 'ankle_angle_l') if 'weaksoleus' in flags: soleus_r = model.updMuscles().get('soleus_r') soleus_r.set_max_isometric_force( 0.25 * soleus_r.get_max_isometric_force()) soleus_l = model.updMuscles().get('soleus_l') soleus_l.set_max_isometric_force( 0.25 * soleus_l.get_max_isometric_force()) if 'weakvasti' in flags: for muscle in ['vasmed', 'vasint', 'vaslat']: for side in ['_l', '_r']: musc = model.updMuscles().get('%s%s' % (muscle, side)) musc.set_max_isometric_force( 0.10 * musc.get_max_isometric_force()) if 'trendelenburg-lite' in flags: for muscle in ['glmin1','glmin2','glmin3','glmed1','glmed2','glmed3', 'glmax1','glmax2','glmax3','addbrev', 'addlong', 'addmagDist', 'addmagIsch', 'addmagMid', 'addmagProx', 'piri', 'bflh', 'sart', 'grac']: for side in ['_l', '_r']: musc = model.updMuscles().get('%s%s' % (muscle, side)) musc.set_max_isometric_force( 0.10 * musc.get_max_isometric_force()) if 'trendelenburg' in flags: for muscle in ['glmin1','glmin2','glmin3','glmed1','glmed2','glmed3', 'glmax1','glmax2','glmax3','addbrev', 'addlong', 'addmagDist', 'addmagIsch', 'addmagMid', 'addmagProx', 'iliacus', 'psoas', 'piri', 'grac', 'bflh', 'recfem', 'sart', 'semimem', 'semiten', 'tfl']: for side in ['_l', '_r']: musc = model.updMuscles().get('%s%s' % (muscle, side)) musc.set_max_isometric_force( 0.10 * musc.get_max_isometric_force()) if 'weakpfs' in flags: for muscle in ['soleus', 'gasmed', 'gaslat', 'perbrev', 'perlong', 'tibpost', 'fdl', 'fhl']: for side in ['_l', '_r']: musc = model.updMuscles().get('%s%s' % (muscle, side)) musc.set_max_isometric_force( 0.10 * musc.get_max_isometric_force()) modelProcessor = osim.ModelProcessor(model) modelProcessor.append(osim.ModOpReplaceJointsWithWelds( ['subtalar_r', 'mtp_r', 'subtalar_l', 'mtp_l'])) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) # modelProcessor.append(osim.ModOpPassiveFiberStrainAtOneNormForceDGF(4.0)) modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # modelProcessor.append(osim.ModOpFiberDampingDGF(0.001)) if for_inverse: ext_loads_xml = os.path.join(root_dir, 'resources/Rajagopal2016/grf_walk.xml') modelProcessor.append(osim.ModOpAddExternalLoads(ext_loads_xml)) model = modelProcessor.process() model.initSystem() muscles = model.updMuscles() for imusc in np.arange(muscles.getSize()): muscle = muscles.get(int(imusc)) if 'gas' in muscle.getName() or 'soleus' in muscle.getName(): muscle.set_ignore_tendon_compliance(False) modelProcessorTendonCompliance = osim.ModelProcessor(model) modelProcessorTendonCompliance.append( osim.ModOpUseImplicitTendonComplianceDynamicsDGF()) return modelProcessorTendonCompliance
def solveMocoInverseWithEMG(): # This initial block of code is identical to the code above. inverse = osim.MocoInverse() modelProcessor = osim.ModelProcessor('subject_walk_armless.osim') modelProcessor.append(osim.ModOpAddExternalLoads('grf_walk.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(1.0)) inverse.setModel(modelProcessor) inverse.setKinematics(osim.TableProcessor('coordinates.sto')) inverse.set_initial_time(0.81) inverse.set_final_time(1.79) inverse.set_mesh_interval(0.02) inverse.set_kinematics_allow_extra_columns(True) study = inverse.initialize() problem = study.updProblem() # Add electromyography tracking. emgTracking = osim.MocoControlTrackingGoal('emg_tracking') emgTracking.setWeight(50.0) # Each column in electromyography.sto is normalized so the maximum value in # each column is 1.0. controlsRef = osim.TimeSeriesTable('electromyography.sto') # Scale the tracked muscle activity based on peak levels from # "Gait Analysis: Normal and Pathological Function" by # Perry and Burnfield, 2010 (digitized by Carmichael Ong). soleus = controlsRef.updDependentColumn('soleus') gasmed = controlsRef.updDependentColumn('gastrocnemius') tibant = controlsRef.updDependentColumn('tibialis_anterior') for t in range(0, controlsRef.getNumRows()): soleus[t] = 0.77 * soleus[t] gasmed[t] = 0.87 * gasmed[t] tibant[t] = 0.37 * tibant[t] emgTracking.setReference(osim.TableProcessor(controlsRef)) # Associate actuators in the model with columns in electromyography.sto. emgTracking.setReferenceLabel('/forceset/soleus_r', 'soleus') emgTracking.setReferenceLabel('/forceset/gasmed_r', 'gastrocnemius') emgTracking.setReferenceLabel('/forceset/gaslat_r', 'gastrocnemius') emgTracking.setReferenceLabel('/forceset/tibant_r', 'tibialis_anterior') problem.addGoal(emgTracking) # Solve the problem and write the solution to a Storage file. solution = study.solve() solution.write('example3DWalking_MocoInverseWithEMG_solution.sto') # Write the reference data in a way that's easy to compare to the solution. controlsRef.removeColumn('medial_hamstrings') controlsRef.removeColumn('biceps_femoris') controlsRef.removeColumn('vastus_lateralis') controlsRef.removeColumn('vastus_medius') controlsRef.removeColumn('rectus_femoris') controlsRef.removeColumn('gluteus_maximus') controlsRef.removeColumn('gluteus_medius') controlsRef.setColumnLabels( ['/forceset/soleus_r', '/forceset/gasmed_r', '/forceset/tibant_r']) controlsRef.appendColumn('/forceset/gaslat_r', gasmed) osim.STOFileAdapter.write(controlsRef, 'controls_reference.sto') # Generate a report comparing MocoInverse solutions without and with EMG # tracking. model = modelProcessor.process() output = 'example3DWalking_MocoInverseWithEMG_report.pdf' ref_files = [ 'example3DWalking_MocoInverseWithEMG_solution.sto', 'controls_reference.sto' ] report = osim.report.Report(model, 'example3DWalking_MocoInverse_solution.sto', output=output, bilateral=True, ref_files=ref_files) # The PDF is saved to the working directory. report.generate()
def create_model_processor(self, root_dir): # Create base model without reserves. model = osim.Model(os.path.join(root_dir, 'resources/Rajagopal2016/' 'subject_walk_contact_bounded_80musc.osim')) forceSet = model.getForceSet() numContacts = 0 for i in np.arange(forceSet.getSize()): forceName = forceSet.get(int(i)).getName() if 'contact' in forceName: numContacts += 1 print('Removing contact force elements from model...') contactsRemoved = 0 while contactsRemoved < numContacts: for i in np.arange(forceSet.getSize()): forceName = forceSet.get(int(i)).getName() if 'contact' in forceName: print(' --> removed', forceSet.get(int(i)).getName()) forceSet.remove(int(i)) contactsRemoved += 1 break modelProcessor = osim.ModelProcessor(model) modelProcessor.append(osim.ModOpReplaceJointsWithWelds( ['subtalar_r', 'mtp_r', 'subtalar_l', 'mtp_l', 'radius_hand_r', 'radius_hand_l'])) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpFiberDampingDGF(0)) baseModel = modelProcessor.process() # Create model for CMC modelProcessorCMC = osim.ModelProcessor(baseModel) modelProcessorCMC.append(osim.ModOpAddReserves(1)) cmcModel = modelProcessorCMC.process() tasks = osim.CMC_TaskSet() for coord in cmcModel.getCoordinateSet(): cname = coord.getName() if cname.endswith('_beta'): continue task = osim.CMC_Joint() task.setName(cname) task.setCoordinateName(cname) task.setKP(100, 1, 1) task.setKV(20, 1, 1) task.setActive(True, False, False) tasks.cloneAndAppend(task) tasks.printToXML( os.path.join(root_dir, 'code', 'motion_prescribed_walking_cmc_tasks.xml')) cmcModel.printToXML(os.path.join(root_dir, 'resources/Rajagopal2016/' 'subject_walk_for_cmc.osim')) # Create direct collocation model: # - TODO reserves # - implicit tendon compliance mode # - add external loads def add_reserve(model, coord, max_control): actu = osim.CoordinateActuator(coord) if coord.startswith('lumbar'): prefix = 'torque_' elif coord.startswith('pelvis'): prefix = 'residual_' else: prefix = 'reserve_' actu.setName(prefix + coord) actu.setMinControl(-1) actu.setMaxControl(1) actu.setOptimalForce(max_control) model.addForce(actu) add_reserve(baseModel, 'lumbar_extension', 50) add_reserve(baseModel, 'lumbar_bending', 50) add_reserve(baseModel, 'lumbar_rotation', 20) for side in ['_l', '_r']: add_reserve(baseModel, f'arm_flex{side}', 15) add_reserve(baseModel, f'arm_add{side}', 15) add_reserve(baseModel, f'arm_rot{side}', 5) add_reserve(baseModel, f'elbow_flex{side}', 5) add_reserve(baseModel, f'pro_sup{side}', 1) add_reserve(baseModel, f'hip_rotation{side}', 0.5) add_reserve(baseModel, 'pelvis_tilt', 60) add_reserve(baseModel, 'pelvis_list', 30) add_reserve(baseModel, 'pelvis_rotation', 15) add_reserve(baseModel, 'pelvis_tx', 100) add_reserve(baseModel, 'pelvis_ty', 200) add_reserve(baseModel, 'pelvis_tz', 35) baseModel.initSystem() muscles = baseModel.updMuscles() for imusc in np.arange(muscles.getSize()): muscle = muscles.get(int(imusc)) if 'gas' in muscle.getName() or 'soleus' in muscle.getName(): muscle.set_ignore_tendon_compliance(False) modelProcessorDC = osim.ModelProcessor(baseModel) modelProcessorDC.append(osim.ModOpFiberDampingDGF(0.01)) modelProcessorDC.append(osim.ModOpAddReserves(1, 2.5, True)) modelProcessorDC.append( osim.ModOpTendonComplianceDynamicsModeDGF('implicit')) ext_loads_xml = os.path.join(root_dir, "resources/Rajagopal2016/grf_walk.xml") modelProcessorDC.append(osim.ModOpAddExternalLoads(ext_loads_xml)) return modelProcessorDC
def muscleDrivenStateTracking(): #Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName('muscleDrivenStateTracking') #Construct a ModelProcessor and set it on the tool. #Currently the coordinate actuators for the pelvis, along with the reserve #actuators are fairly generally set, and not weighted at all in cost function. #These actuators could be more carefully considered to generate an appropriate #muscle driven simulation. For example, if they max and min control to 1 - the #pelvis actuators may not produce enough torque. modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) modelProcessor.append(osim.ModOpAddReserves(2)) track.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #tracking tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. track.setStatesReference(osim.TableProcessor('ikResults_states.sto')) track.set_states_global_tracking_weight(5) ##### TODO: add more specific weights for different state coordinates like in RRA #This setting allows extra data columns contained in the states #reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data the states references, this # setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. track.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) track.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) track.set_mesh_interval(0.08) #Instead of calling solve(), call initialize() to receive a pre-configured #MocoStudy object based on the settings above. Use this to customize the #problem beyond the MocoTrack interface. study = track.initialize() #Get a reference to the MocoControlCost that is added to every MocoTrack #problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast(problem.updGoal('control_effort')) effort.setWeight(1) # # Put a large weight on the pelvis CoordinateActuators, which act as the # # residual, or 'hand-of-god', forces which we would like to keep as small # # as possible. # model = modelProcessor.process() # model.initSystem() # forceSet = model.getForceSet() # for ii in range(forceSet.getSize()): # forcePath = forceSet.get(ii).getAbsolutePathString() # if 'pelvis' in str(forcePath): # effort.setWeightForControl(forcePath, 10) #Get solver and set the mesh interval solver = study.initCasADiSolver() #50 mesh intervals for half gait cycle recommended, keep smaller for now #19 will produce the same as inverse solution above # solver.set_num_mesh_intervals(19) #Set solver parameters solver.set_optim_constraint_tolerance(1e-3) solver.set_optim_convergence_tolerance(1e-3) # Solve and visualize. solution = study.solve() #Return the solution as an object that we can use return solution
def torqueDrivenStateTracking(): #Create and name an instance of the MocoTrack tool. track = osim.MocoTrack() track.setName('torqueDrivenStateTracking') #Construct a ModelProcessor and set it on the tool. Remove the muscles and #add reserve actuators modelProcessor = osim.ModelProcessor('scaledModelMuscle.osim') modelProcessor.append(osim.ModOpAddExternalLoads('Jog05_grf.xml')) modelProcessor.append(osim.ModOpRemoveMuscles()) modelProcessor.append(osim.ModOpAddReserves(300)) track.setModel(modelProcessor) #Construct a TableProcessor of the coordinate data and pass it to the #tracking tool. TableProcessors can be used in the same way as #ModelProcessors by appending TableOperators to modify the base table. #A TableProcessor with no operators, as we have here, simply returns the #base table. track.setStatesReference(osim.TableProcessor('ikResults_states.sto')) track.set_states_global_tracking_weight(5) ##### TODO: add more specific weights for different state coordinates like in RRA #This setting allows extra data columns contained in the states #reference that don't correspond to model coordinates. track.set_allow_unused_references(True) # Since there is only coordinate position data the states references, this # setting is enabled to fill in the missing coordinate speed data using # the derivative of splined position data. track.set_track_reference_position_derivatives(True) # Initial time, final time, and mesh interval. track.set_initial_time(osim.Storage('ikResults_states.sto').getFirstTime()) track.set_final_time(osim.Storage('ikResults_states.sto').getLastTime()) track.set_mesh_interval(0.08) #Instead of calling solve(), call initialize() to receive a pre-configured #MocoStudy object based on the settings above. Use this to customize the #problem beyond the MocoTrack interface. study = track.initialize() #Get a reference to the MocoControlCost that is added to every MocoTrack #problem by default. problem = study.updProblem() effort = osim.MocoControlGoal.safeDownCast(problem.updGoal('control_effort')) effort.setWeight(1) # # Put a large weight on the pelvis CoordinateActuators, which act as the # # residual, or 'hand-of-god', forces which we would like to keep as small # # as possible. # model = modelProcessor.process() # model.initSystem() # forceSet = model.getForceSet() # for ii in range(forceSet.getSize()): # forcePath = forceSet.get(ii).getAbsolutePathString() # if 'pelvis' in str(forcePath): # effort.setWeightForControl(forcePath, 10) #Get solver and set the mesh interval solver = study.initCasADiSolver() #50 mesh intervals for half gait cycle recommended, keep smaller for now #19 will produce the same as inverse solution above # solver.set_num_mesh_intervals(19) #Set solver parameters solver.set_optim_constraint_tolerance(1e-3) solver.set_optim_convergence_tolerance(1e-3) #Set guess from inverse solution using the convenience function to transfer #an inverse solution to a solver guess osimHelper.inverseSolutionToTrackGuess(guessFile = 'inverseTorqueSolution_fromIK.sto', mocoSolver = solver) # Solve and visualize. solution = study.solve() #Return the solution as an object that we can use return solution
# for ii in range(0,trackModel.updForceSet().getSize()-1): # #Get current force name # currForce = trackModel.updForceSet().get(ii).getName() # #Turn off if a contact element # if 'contact' in currForce: # trackModel.updForceSet().get(ii).set_appliesForce(False) ##### TODO: keep the spheres, but these haven't been adjusted yet... # #Finalize # trackModel.finalizeConnections() # Construct a ModelProcessor and set it on the tool. The default # muscles in the model are replaced with optimization-friendly # DeGrooteFregly2016Muscles, and adjustments are made to the default muscle # parameters. modelProcessor = osim.ModelProcessor("scaledModelAdjusted.osim") modelProcessor.append(osim.ModOpAddExternalLoads("Jog05_grf.xml")) # modelProcessor.append(osim.ModOpIgnoreTendonCompliance()) # modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016()) #Remove all the muscles in the model's ForceSet. modelProcessor.append(osim.ModOpRemoveMuscles()) # Only valid for DeGrooteFregly2016Muscles. # modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF()) # Only valid for DeGrooteFregly2016Muscles. # modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5)) #Add reserves modelProcessor.append(osim.ModOpAddReserves(300)) track.setModel(modelProcessor) # Construct a TableProcessor of the coordinate data and pass it to the # tracking tool. TableProcessors can be used in the same way as