opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
758 stars 308 forks source link

Adding support for `InputController` in Moco #3769

Closed nickbianco closed 1 month ago

nickbianco commented 2 months ago

Fixes issues #3698, #3747, #3772.

Brief summary of changes

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:

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:

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.

CHANGELOG.md (choose one)

[perf-win]

Performance analysis

Platform: Windows, self-hosted runner

Test Name lhs [secs] stderr [secs] rhs [secs] stderr [secs] Speedup
Arm26 0.34 0.00 0.35 0.00 0.98
ellipsoid_wrap 4.12 0.00 4.12 0.00 1.00
ellipsoid_wrap_function_based_paths 3.43 0.00 3.41 0.00 1.01
Gait2354 0.41 0.00 0.41 0.00 1.01
MocoSlidingMass 1.48 0.00 1.48 0.00 1.00
MocoSquatToStand 11.32 0.57 11.27 0.10 1.00
passive_dynamic 5.60 0.01 5.53 0.00 1.01
passive_dynamic_noanalysis 3.41 0.00 3.37 0.00 1.01
RajagopalModel 8.90 0.01 8.83 0.00 1.01
ToyDropLanding 13.44 0.01 13.53 0.11 0.99
ToyDropLanding_fbp_stepwisereg 12.36 0.08 12.28 0.02 1.01
ToyDropLanding_function_based_paths 12.48 0.10 12.42 0.02 1.00
ToyDropLanding_nomuscles 0.58 0.00 0.57 0.00 1.01

This change is Reviewable

nickbianco commented 1 month ago

Thanks @chrisdembia!