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 solveStateTracking(stateRef): # Predict the optimal trajectory for a minimum time swing-up. study = osim.MocoStudy() study.setName("double_pendulum_track") problem = study.updProblem() # Model (dynamics). problem.setModel(createDoublePendulumModel()) # Bounds. # Arguments are name, [lower bound, upper bound], # initial [lower bound, upper bound], # final [lower bound, upper bound]. finalTime = markersRef.getMarkerTable().getIndependentColumn()[-1] problem.setTimeBounds(0, finalTime) problem.setStateInfo("/jointset/j0/q0/value", [-10, 10], 0) problem.setStateInfo("/jointset/j0/q0/speed", [-50, 50], 0) problem.setStateInfo("/jointset/j1/q1/value", [-10, 10], 0) problem.setStateInfo("/jointset/j1/q1/speed", [-50, 50], 0) problem.setControlInfo("/tau0", [-150, 150]) problem.setControlInfo("/tau1", [-150, 150]) # Cost: track provided state data. stateTracking = osim.MocoStateTrackingGoal() stateTracking.setReference(osim.TableProcessor(stateRef)) problem.addGoal(stateTracking) effort = osim.MocoControlGoal() effort.setName("effort") effort.setWeight(0.001) # TODO problem.addGoal(effort) # Configure the solver. solver = study.initTropterSolver() solver.set_num_mesh_intervals(50) solver.set_verbosity(2) solver.set_optim_solver("ipopt") solver.set_optim_jacobian_approximation("exact") solver.set_optim_hessian_approximation("exact") solver.set_exact_hessian_block_sparsity_mode("dense") # Save the problem to a setup file for reference. study.printToXML("examplePredictAndTrack_track_states.omoco") # Solve the problem. solution = study.solve() solution.write("examplePredictAndTrack_track_states_solution.sto") if visualize: study.visualize(solution) return solution
def create_inverse(self, root_dir, modelProcessor, mesh_interval): coordinates = osim.TableProcessor( os.path.join(root_dir, "resources/Rajagopal2016/coordinates.mot")) coordinates.append(osim.TabOpLowPassFilter(6)) coordinates.append(osim.TabOpUseAbsoluteStateNames()) inverse = osim.MocoInverse() inverse.setModel(modelProcessor) inverse.setKinematics(coordinates) inverse.set_initial_time(self.initial_time) inverse.set_final_time(self.final_time) inverse.set_mesh_interval(mesh_interval) inverse.set_kinematics_allow_extra_columns(True) inverse.set_convergence_tolerance(1e-2) # TODO inverse.set_mesh_interval(mesh_interval) return inverse
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 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 run_inverse_problem(self, root_dir): modelProcessor = self.create_model_processor(root_dir, for_inverse=True) inverse = osim.MocoInverse() inverse.setModel(modelProcessor) tableProcessor = osim.TableProcessor(os.path.join(root_dir, 'resources/Rajagopal2016/coordinates.mot')) tableProcessor.append(osim.TabOpLowPassFilter(6)) tableProcessor.append(osim.TabOpUseAbsoluteStateNames()) inverse.setKinematics(tableProcessor) inverse.set_kinematics_allow_extra_columns(True) inverse.set_initial_time(self.initial_time) inverse.set_final_time(self.half_time) inverse.set_mesh_interval(self.mesh_interval) solution = inverse.solve() solution.getMocoSolution().write( os.path.join(root_dir, self.inverse_solution_relpath))
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)
# squared using the MocoInverse tool. # Part 1a: Load a 19 degree-of-freedom model with 18 lower-limb, # sagittal-plane muscles and a torque-actuated torso. This includes a set of # ground reaction forces applied to the model via ExternalLoads, which is # necessary for the muscle redundancy problem. See the function definition # at the bottom of this file to see how the model is loaded and constructed. model = helpers.getWalkingModel() # Part 1b: Create the MocoInverse tool and set the Model. inverse = osim.MocoInverse() inverse.setModel(model) # Part 1c: Create a TableProcessor using the coordinates file from inverse # kinematics. coordinates = osim.TableProcessor('coordinates.mot') coordinates.append(osim.TabOpLowPassFilter(6)) coordinates.append(osim.TabOpUseAbsoluteStateNames()) # Part 1d: Set the kinematics reference for MocoInverse using the # TableProcessor we just created. inverse.setKinematics(coordinates) inverse.set_kinematics_allow_extra_columns(True) # Part 1e: Provide the solver settings: initial and final time, the mesh # interval, and the constraint and convergence tolerances. inverse.set_initial_time(0.83) inverse.set_final_time(2.0) inverse.set_mesh_interval(0.04) inverse.set_constraint_tolerance(1e-3) inverse.set_convergence_tolerance(1e-3)
solver = study.initCasADiSolver() solver.set_num_mesh_intervals(25) solver.set_optim_convergence_tolerance(1e-4) solver.set_optim_constraint_tolerance(1e-4) if not os.path.isfile('predictSolution.sto'): # Part 1f: Solve! Write the solution to file, and visualize. predictSolution = study.solve() predictSolution.write('predictSolution.sto') study.visualize(predictSolution) ## Part 2: Torque-driven Tracking Problem # Part 2a: Construct a tracking reference TimeSeriesTable using filtered # data from the previous solution. Use a TableProcessor, which accepts a # base table and allows appending operations to modify the table. tableProcessor = osim.TableProcessor('predictSolution.sto') tableProcessor.append(osim.TabOpLowPassFilter(6)) # Part 2b: Add a MocoStateTrackingCost to the problem using the states # from the predictive problem (via the TableProcessor we just created). # Enable the setAllowUnusedReferences() setting to ignore the controls in # the predictive solution. tracking = osim.MocoStateTrackingGoal() tracking.setName('mytracking') tracking.setReference(tableProcessor) tracking.setAllowUnusedReferences(True) problem.addGoal(tracking) # Part 2c: Reduce the control cost weight so it now acts as a regularization # term. problem.updGoal('myeffort').setWeight(0.001)
def run_tracking_problem(self, root_dir, config): modelProcessor = self.create_model_processor(root_dir, for_inverse=False, config=config) model = modelProcessor.process() model.initSystem() # Count the number of Force objects in the model. We'll use this to # normalize the control effort cost. numForces = 0 for actu in model.getComponentsList(): if (actu.getConcreteClassName().endswith('Muscle') or actu.getConcreteClassName().endswith('Actuator')): numForces += 1 # Construct the base tracking problem # ----------------------------------- track = osim.MocoTrack() track.setName('tracking_walking') track.setModel(modelProcessor) if self.coordinate_tracking: tableProcessor = osim.TableProcessor(os.path.join(root_dir, 'resources/Rajagopal2016/coordinates.mot')) tableProcessor.append(osim.TabOpLowPassFilter(6)) tableProcessor.append(osim.TabOpUseAbsoluteStateNames()) track.setStatesReference(tableProcessor) track.set_states_global_tracking_weight( config.tracking_weight / (2 * model.getNumCoordinates())) # Don't track some pelvis coordinates to avoid poor walking motion # solutions. stateWeights = osim.MocoWeightSet() weightList = list() weightList.append(('/jointset/ground_pelvis/pelvis_ty/value', 0)) weightList.append(('/jointset/ground_pelvis/pelvis_tz/value', 0)) weightList.append(('/jointset/ground_pelvis/pelvis_list/value', 0)) weightList.append(('/jointset/ground_pelvis/pelvis_tilt/value', 0)) weightList.append(('/jointset/ground_pelvis/pelvis_rotation/value', 0)) weightList.append(('/jointset/hip_r/hip_rotation_r/value', 0)) # weightList.append(('/jointset/hip_r/hip_adduction_r/value', 0)) weightList.append(('/jointset/hip_l/hip_rotation_l/value', 0)) # weightList.append(('/jointset/hip_l/hip_adduction_l/value', 0)) # weightList.append(('/jointset/ankle_r/ankle_angle_r/value', 10)) # weightList.append(('/jointset/ankle_l/ankle_angle_l/value', 10)) for weight in weightList: stateWeights.cloneAndAppend(osim.MocoWeight(weight[0], weight[1])) track.set_states_weight_set(stateWeights) track.set_apply_tracked_states_to_guess(True) # track.set_scale_state_weights_with_range(True); else: track.setMarkersReferenceFromTRC(os.path.join(root_dir, 'resources/Rajagopal2016/markers.trc')) track.set_markers_global_tracking_weight( config.tracking_weight / (2 * model.getNumMarkers())) iktool = osim.InverseKinematicsTool(os.path.join(root_dir, 'resources/Rajagopal2016/ik_setup_walk.xml')) iktasks = iktool.getIKTaskSet() markerWeights = osim.MocoWeightSet() for marker in model.getComponentsList(): if not type(marker) is osim.Marker: continue for i in np.arange(iktasks.getSize()): iktask = iktasks.get(int(i)) if iktask.getName() == marker.getName(): weight = osim.MocoWeight(iktask.getName(), iktask.getWeight()) markerWeights.cloneAndAppend(weight) track.set_markers_weight_set(markerWeights) track.set_allow_unused_references(True) track.set_track_reference_position_derivatives(True) track.set_control_effort_weight(config.effort_weight / numForces) track.set_initial_time(self.initial_time) track.set_final_time(self.half_time) track.set_mesh_interval(self.mesh_interval) # Customize the base tracking problem # ----------------------------------- study = track.initialize() problem = study.updProblem() problem.setTimeBounds(self.initial_time, [self.half_time-0.2, self.half_time+0.2]) # Set the initial values for the lumbar and pelvis coordinates that # produce "normal" walking motions. problem.setStateInfo('/jointset/back/lumbar_extension/value', [], -0.12) problem.setStateInfo('/jointset/back/lumbar_bending/value', [], 0) problem.setStateInfo('/jointset/back/lumbar_rotation/value', [], 0.04) problem.setStateInfo('/jointset/ground_pelvis/pelvis_tx/value', [], 0.446) problem.setStateInfo('/jointset/ground_pelvis/pelvis_tilt/value', [], 0) problem.setStateInfo('/jointset/ground_pelvis/pelvis_list/value', [], 0) problem.setStateInfo('/jointset/ground_pelvis/pelvis_rotation/value', [], 0) # Update the control effort goal to a cost of transport type cost. effort = osim.MocoControlGoal().safeDownCast( problem.updGoal('control_effort')) effort.setDivideByDisplacement(True) # Weight residual and reserve actuators low in the effort cost since # they are already weak. if config.effort_weight: for actu in model.getComponentsList(): actuName = actu.getName() if actu.getConcreteClassName().endswith('Actuator'): effort.setWeightForControl(actu.getAbsolutePathString(), 0.001) for muscle in ['psoas', 'iliacus']: for side in ['l', 'r']: effort.setWeightForControl( '/forceset/%s_%s' % (muscle, side), 0.25) speedGoal = osim.MocoAverageSpeedGoal('speed') speedGoal.set_desired_average_speed(1.235) problem.addGoal(speedGoal) # MocoFrameDistanceConstraint # --------------------------- if self.coordinate_tracking: distanceConstraint = osim.MocoFrameDistanceConstraint() distanceConstraint.setName('distance_constraint') # Step width is 0.13 * leg_length # distance = 0.10 # TODO Should be closer to 0.11. # Donelan JM, Kram R, Kuo AD. Mechanical and metabolic determinants # of the preferred step width in human walking. # Proc Biol Sci. 2001;268(1480):1985–1992. # doi:10.1098/rspb.2001.1761 # https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1088839/ distanceConstraint.addFramePair( osim.MocoFrameDistanceConstraintPair( '/bodyset/calcn_l', '/bodyset/calcn_r', 0.09, np.inf)) distanceConstraint.addFramePair( osim.MocoFrameDistanceConstraintPair( '/bodyset/toes_l', '/bodyset/toes_r', 0.06, np.inf)) # distanceConstraint.addFramePair( # osim.MocoFrameDistanceConstraintPair( # '/bodyset/calcn_l', '/bodyset/toes_r', distance, np.inf)) # distanceConstraint.addFramePair( # osim.MocoFrameDistanceConstraintPair( # '/bodyset/toes_l', '/bodyset/calcn_r', distance, np.inf)) distanceConstraint.setProjection("vector") distanceConstraint.setProjectionVector(osim.Vec3(0, 0, 1)) problem.addPathConstraint(distanceConstraint) # Symmetry constraints # -------------------- statesRef = osim.TimeSeriesTable('tracking_walking_tracked_states.sto') initIndex = statesRef.getNearestRowIndexForTime(self.initial_time) symmetry = osim.MocoPeriodicityGoal('symmetry') # Symmetric coordinate values (except for pelvis_tx) and speeds. for coord in model.getComponentsList(): if not type(coord) is osim.Coordinate: continue coordName = coord.getName() coordValue = coord.getStateVariableNames().get(0) coordSpeed = coord.getStateVariableNames().get(1) if coordName.endswith('_r'): symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordValue, coordValue.replace('_r/', '_l/'))) symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordSpeed, coordSpeed.replace('_r/', '_l/'))) elif coordName.endswith('_l'): symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordValue, coordValue.replace('_l/', '_r/'))) symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordSpeed, coordSpeed.replace('_l/', '_r/'))) elif (coordName.endswith('_bending') or coordName.endswith('_rotation') or coordName.endswith('_tz') or coordName.endswith('_list')): # This does not include hip rotation, # because that ends with _l or _r. symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordValue)) symmetry.addNegatedStatePair(osim.MocoPeriodicityGoalPair( coordSpeed)) elif not coordName.endswith('_tx'): symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordValue)) symmetry.addStatePair(osim.MocoPeriodicityGoalPair( coordSpeed)) symmetry.addStatePair(osim.MocoPeriodicityGoalPair( '/jointset/ground_pelvis/pelvis_tx/speed')) # Symmetric activations. for actu in model.getComponentsList(): if (not actu.getConcreteClassName().endswith('Muscle') and not actu.getConcreteClassName().endswith('Actuator')): continue if actu.getName().endswith('_r'): symmetry.addStatePair(osim.MocoPeriodicityGoalPair( actu.getStateVariableNames().get(0), actu.getStateVariableNames().get(0).replace('_r/', '_l/'))) elif actu.getName().endswith('_l'): symmetry.addStatePair(osim.MocoPeriodicityGoalPair( actu.getStateVariableNames().get(0), actu.getStateVariableNames().get(0).replace('_l/', '_r/'))) elif (actu.getName().endswith('_bending') or actu.getName().endswith('_rotation') or actu.getName().endswith('_tz') or actu.getName().endswith('_list')): symmetry.addNegatedStatePair(osim.MocoPeriodicityGoalPair( actu.getStateVariableNames().get(0), actu.getStateVariableNames().get(0))) else: symmetry.addStatePair(osim.MocoPeriodicityGoalPair( actu.getStateVariableNames().get(0), actu.getStateVariableNames().get(0))) problem.addGoal(symmetry) # Contact tracking # ---------------- forceNamesRightFoot = ['forceset/contactSphereHeel_r', 'forceset/contactLateralRearfoot_r', 'forceset/contactLateralMidfoot_r', 'forceset/contactLateralToe_r', 'forceset/contactMedialToe_r', 'forceset/contactMedialMidfoot_r'] forceNamesLeftFoot = ['forceset/contactSphereHeel_l', 'forceset/contactLateralRearfoot_l', 'forceset/contactLateralMidfoot_l', 'forceset/contactLateralToe_l', 'forceset/contactMedialToe_l', 'forceset/contactMedialMidfoot_l'] if self.contact_tracking: contactTracking = osim.MocoContactTrackingGoal('contact', 0.001) contactTracking.setExternalLoadsFile( 'resources/Rajagopal2016/grf_walk.xml') contactTracking.addContactGroup(forceNamesRightFoot, 'Right_GRF') contactTracking.addContactGroup(forceNamesLeftFoot, 'Left_GRF') contactTracking.setProjection("plane") contactTracking.setProjectionVector(osim.Vec3(0, 0, 1)) problem.addGoal(contactTracking) # Configure the solver # -------------------- solver = osim.MocoCasADiSolver.safeDownCast(study.updSolver()) solver.resetProblem(problem) solver.set_optim_constraint_tolerance(1e-3) solver.set_optim_convergence_tolerance(1e-3) solver.set_multibody_dynamics_mode('implicit') solver.set_minimize_implicit_multibody_accelerations(True) solver.set_implicit_multibody_accelerations_weight( 1e-6 / model.getNumCoordinates()) solver.set_implicit_multibody_acceleration_bounds( osim.MocoBounds(-200, 200)) # Set the guess # ------------- # Create a guess compatible with this problem. guess = solver.createGuess() # Load the inverse problem solution and set its states and controls # trajectories to the guess. inverseSolution = osim.MocoTrajectory( os.path.join(root_dir, self.inverse_solution_relpath)) inverseStatesTable = inverseSolution.exportToStatesTable() guess.insertStatesTrajectory(inverseStatesTable, True) # Changing this initial guess has a large negative effect on the # solution! Lots of knee flexion. # guess.setState('/jointset/ground_pelvis/pelvis_ty/value', # osim.Vector(guess.getNumTimes(), 1.01)) inverseControlsTable = inverseSolution.exportToControlsTable() guess.insertControlsTrajectory(inverseControlsTable, True) solver.setGuess(guess) # Solve and print solution. # ------------------------- solution = study.solve() solution.write(self.get_solution_path(root_dir, config)) # Create a full gait cycle trajectory from the periodic solution. fullTraj = osim.createPeriodicTrajectory(solution) fullTraj.write(self.get_solution_path_fullcycle(root_dir, config)) # Compute ground reaction forces generated by contact sphere from the # full gait cycle trajectory. externalLoads = osim.createExternalLoadsTableForGait( model, fullTraj, forceNamesRightFoot, forceNamesLeftFoot) osim.writeTableToFile(externalLoads, self.get_solution_path_grfs(root_dir, config))
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 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
#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 # 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(5) # 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. # The IK data doesn't match the GRF data, so specific times need ti be taken from this track.set_initial_time(osim.Storage('coordinates.sto').getFirstTime()) track.set_final_time(osim.Storage('coordinates.sto').getLastTime())