Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
 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()
Exemple #5
0
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))
Exemple #7
0
    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
Exemple #8
0
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)
Exemple #9
0
# 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)
Exemple #11
0
    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()
Exemple #13
0
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
Exemple #14
0
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
Exemple #15
0
#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())