These changes add generic support for using InputControllers in Moco. Moco will detect any InputControllers in the model and create OCP control variables for each "Input control" that the InputController requires. The number, order, and labels of Input control variables are determined based on getInputControlLabels() (renamed from getExpectedInputChannelAliases()) which each concrete implementation of InputController must provide. The behavior of InputController was modified so that if no Output channels are connected to its list Input the InputController will not compute controls, and if the incorrect number of Output channels are connected an exception is thrown.
MocoGoal::IntegrandInput and MocoGoal::GoalInput have a new slots for passing Input control variables from solvers to MocoGoals. Solvers can use MocoProblemRep::getInputControls() to get a vector containing Input control values; this vector contains all control values (i.e., including those from ActuatorInputController), so we also provide MocoGoal::getInputControlIndexMap() and MocoPathConstraint::getInputControlIndexMap() to get Input control indexes for user-added InputControllers only. The following MocoGoals and MocoPathConstraints have been updated to support Input controls:
MocoControlGoal
MocoControlTrackingGoal
MocoPeriodicityGoal
MocoControlBoundConstraint
Bounds for Input controls can be set via MocoProblem::setInputControlInfo() and MocoTrajectory was updated with get, set, and utility methods for accessing and modifiying Input controls in a trajectory. With these changes, controls for actuators associated with user-added Controllers no longer get populated in a MocoSolution automatically (to support using a solution as an initial guess in a subsequent problem). To compensate, the method MocoTrajectory::generateControlsFromModelControllers() can be used to populate a trajectory with the full model controls vector for use in post-hoc analyses.
Some other changes include:
ActuatorInputController and ControlDistributor are designated as internal classes for Moco use only.
Added the static utility function ControlDistributor::addControlDistributorAndConnectInputControllers().
MocoProblemRep::getInputControlIndexes() was added to facilitate conversion between MocoTrajectory and solver trajectory types.
MocoUtilities::prescribeControlsToModel() now adds SignalGenerators to models with InputControllers to drive Input controls.
Removed ignore_controlled_actuators from MocoPeriodicityGoal and MocoControlBoundConstraint since users can simply choose to not add these controls to the goal/constraint.
Various minor drive-by fixes.
Testing I've completed
Added testMocoControllers.cpp, which covers all aspects of the changes outlined above. These tests feature a toy controller, TriplePendulumController, which derives from InputController and has two "synergy" Input controls that map to three actuator controls.
Looking for feedback on...
I think conversions between MocoTrajectory and solver trajectory types could be cleaner. The current implementation avoids having to rewrite CasOC::Iterate::resample(), but since this method shouldn't depend on MocoCasOCProblem anyway, maybe rewriting it is the solution here.
Fixes issues #3698, #3747, #3772.
Brief summary of changes
These changes add generic support for using
InputController
s in Moco. Moco will detect anyInputController
s in the model and create OCP control variables for each "Input control" that theInputController
requires. The number, order, and labels of Input control variables are determined based ongetInputControlLabels()
(renamed fromgetExpectedInputChannelAliases()
) which each concrete implementation ofInputController
must provide. The behavior ofInputController
was modified so that if noOutput
channels are connected to its listInput
theInputController
will not compute controls, and if the incorrect number ofOutput
channels are connected an exception is thrown.MocoGoal::IntegrandInput
andMocoGoal::GoalInput
have a new slots for passing Input control variables from solvers toMocoGoal
s. Solvers can useMocoProblemRep::getInputControls()
to get a vector containing Input control values; this vector contains all control values (i.e., including those fromActuatorInputController
), so we also provideMocoGoal::getInputControlIndexMap()
andMocoPathConstraint::getInputControlIndexMap()
to get Input control indexes for user-addedInputController
s only. The followingMocoGoal
s andMocoPathConstraint
s have been updated to support Input controls:MocoControlGoal
MocoControlTrackingGoal
MocoPeriodicityGoal
MocoControlBoundConstraint
Bounds for Input controls can be set via
MocoProblem::setInputControlInfo()
andMocoTrajectory
was updated with get, set, and utility methods for accessing and modifiying Input controls in a trajectory. With these changes, controls for actuators associated with user-addedController
s no longer get populated in aMocoSolution
automatically (to support using a solution as an initial guess in a subsequent problem). To compensate, the methodMocoTrajectory::generateControlsFromModelControllers()
can be used to populate a trajectory with the full model controls vector for use in post-hoc analyses.Some other changes include:
ActuatorInputController
andControlDistributor
are designated as internal classes for Moco use only.ControlDistributor::addControlDistributorAndConnectInputControllers()
.MocoProblemRep::getInputControlIndexes()
was added to facilitate conversion betweenMocoTrajectory
and solver trajectory types.MocoUtilities::prescribeControlsToModel()
now addsSignalGenerator
s to models withInputController
s to drive Input controls.ignore_controlled_actuators
fromMocoPeriodicityGoal
andMocoControlBoundConstraint
since users can simply choose to not add these controls to the goal/constraint.Testing I've completed
Added
testMocoControllers.cpp
, which covers all aspects of the changes outlined above. These tests feature a toy controller,TriplePendulumController
, which derives fromInputController
and has two "synergy" Input controls that map to three actuator controls.Looking for feedback on...
I think conversions between
MocoTrajectory
and solver trajectory types could be cleaner. The current implementation avoids having to rewriteCasOC::Iterate::resample()
, but since this method shouldn't depend onMocoCasOCProblem
anyway, maybe rewriting it is the solution here.CHANGELOG.md (choose one)
[perf-win]
Performance analysis
Platform: Windows, self-hosted runner
This change is![Reviewable](https://reviewable.io/review_button.svg)