API
4.5.1
For C++ developers
|
To learn how to download, install, and run your first Moco example, see the following page:
Moco provides easy-to-use tools for solving for muscle activity that can achieve an observed motion. See the following pages:
These tools derive from the MocoTool class.
If the MocoTools do not satisfy your needs, you can create and solve your own custom optimal control problem using the MocoStudy class.
MocoStudy: custom optimal control problems
Moco supports most OpenSim models, including those with kinematic constraints, auxiliary (muscle) dynamics, and passive force components.
Moco does not support models with SimTK::Measures, such as Probes. Some Measures rely on time-stepping forward integration, which does not occur with Moco. This prevents using, for example, the metabolics probes with Moco. See Bhargava2004SmoothedMuscleMetabolics for a metabolics model that is compatible with Moco.
Some model components are supported through Moco but may hinder the solvers from converging quickly. Any components with discontinuous functions can cause issues for the derivative-based optimization algorithms used by Moco. We suggest replacing your model's muscles with DeGrooteFregly2016Muscles and replacing your contact forces with SmoothSphereHalfSpaceForces. These components are designed for use with direct collocation.
Moco supports a subset of OpenSim's Controllers. Without a controller, a MocoProblem will contain one control for each ScalarActuator in the model. When a Controller is added to the model, there is no longer necessarily a one-to-one correspondence between model actuators and controls in the optimal control problem.
The following Controllers are currently supported by Moco:
By default, if you add a Controller to your model, Moco will not add optimal control variables for the ScalarActuators (i.e., "Model-controlled" actuators) that the Controller controls to the MocoProblem.
Currently, you cannot add controls from the optimal control problem on top of the control values from the Controller. However, control values from multiple Controllers are additive, since this is the behavior in OpenSim.
Controls associated with "Model-controlled" actuators will not be included the MocoSolution (i.e., the solution controls will match the controls listed in the MocoProblem). Therefore, the solution from a MocoStudy that includes a model Controller can be used as an initial guess for a subsequent problem with the same model, just like any other MocoStudy. The utility method MocoTrajectory::generateControlsFromModelControllers() can be used to populate a MocoTrajectory (or MocoSolution) with the controls defined by Controllers in the model, which may be useful for post-hoc analyses and is required for certain utility functions (e.g., MocoUtilities::analyzeMocoTrajectory()).
Unless explicitly defined otherwise, MocoGoals will use the control values computed from the underlying Model. These controls will be the combination of the controls from the optimal control problem and the controls computed by any Controllers in the model.
Relevant MocoGoals and MocoPathConstraints have the option to ignore the controls computed by model Controllers if you wish to only use the controls from the optimal control problem in a cost function term or constraint (e.g., MocoControlGoal::setIgnoreControlledActuators and MocoControlBoundConstraint::setIgnoreControlledActuators).
The setting MocoPhase::setBoundActivationFromExcitation() applies to all muscles in the MocoProblem, whether they are controlled by a Controller or not.
Certain problems may require a controller that defines actuator controls based on a higher-level control signal from the optimizer. For example, controlling muscles using muscle synergies requires a controller that accepts synergy excitation controls as input and maps them to muscle excitation signals. The synergy excitations would be OCP controls and the synergy controller would use synergy weight vectors to convert them to muscle excitation values.
To support these types of problems, Moco provides InputController, an intermediate abstract class derived from Controller that provides a list Input for mapping scalar control signals from another component to actuator controls. Concrete implementations provide the method getInputControlLabels() which defines the number, order, and labels of Input controls for the InputController. SynergyController is an example of a concrete implementation of InputController that supports the muscle synergy example described above.
Moco adds OCP controls to the MocoProblem for each "Input control" defined by a InputController in the model. The names for Input control variables use the format "<InputController_path>/<Input_control_label>". For example, "/controllerset/synergy_controller/synergy_excitation_0".
Moco separates the notion of a "control", or control variables associated with model actuators, and "Input controls", control variables associated with Inputs to InputControllers. The bounds for an Input control variable can be set using MocoProblem::setInputControlInfo() or MocoProblem::setInputControlInfoPattern(). MocoTrajectory provides get (e.g., getInputControl(), getInputControlNames()), set (e.g., setInputControl()), and utility (e.g., exportToInputControlsTable()) methods for accessing or modifying Input controls. MocoSolutions will include Input controls associated with a solved MocoProblem, and the Input controls trajectory can be accessed via MocoTrajectory::getInputControlsTrajectory(). Finally, the method MocoTrajectory::generateControlsFromModelControllers() also supports Input controls: the Input control trajectories are used to compute the associated model control trajectories via the InputControllers in the model.
MocoGoals and MocoPathConstraints that rely on control variables now also support Input control variables. See MocoControlGoal, MocoControlTrackingGoal, MocoPeriodicityGoal, and MocoControlBoundConstraint for details on how each handle Input control variables.
The following InputControllers are currently supported by Moco:
Moco allows you to compose your cost from multiple existing cost terms. This gives you flexibility and means that you usually do not need to write your cost yourself, even if it has many terms. Moco's existing costs are usually well-tested and work well with Moco's solvers, so we encourage you to use them if possible. In the case that you want to create your own custom cost term, you can derive from MocoGoal in C++. See exampleSlidingMassAdvanced.cpp and exampleMocoCustomEffortGoal.cpp.
If you do not want to write C++ code, you can prototype your cost in MATLAB and we can help convert it to C++. See the Matlab example examplePrototypeCustomGoal.m for more information.
In the future, Moco could allow you to define custom cost terms in Python. If this is of interest to you, please let the Moco developers know (on GitHub).
Moco uses the MocoTrajectory and MocoSolution classes to hold initial guesses and solutions to optimal control problems. Solving a problem (MocoStudy::solve()) returns a MocoSolution. If the solver failed to converge, the solution will be sealed (MocoTrajectory::isSealed()), which means that you cannot do anything with the it (read, edit, or write) until you call MocoTrajectory::unseal(). The sealing forces you to acknowledge that the solver failed.
OpenSim and Moco contain utilities for creating models, modifying models, working with data, and postprocessing results.
opensim
Python package).See Moco frequently asked questions.
This short PDF shows common Moco commands, and makes for a nice desk-side companion.