Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Moco] Adding support for PrescribedController and future controller types #3701

Merged
merged 53 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
d868133
Outline for PrescribedController support in Moco
nickbianco Nov 22, 2023
22a96b1
Update TropterProblem with new DiscreteController logic
nickbianco Nov 25, 2023
6ce6fad
Properly handle non-scalar actuators
nickbianco Nov 27, 2023
df78e9b
Update utilities functions for controls to account for user-added Con…
nickbianco Nov 28, 2023
31ea193
Add sliding mass w/ PrescribedController test
nickbianco Nov 28, 2023
c0a857e
Use bracket include
nickbianco Nov 28, 2023
cc3a485
Move DiscreteController to Simulation library
nickbianco Nov 28, 2023
157034a
Ignore .idea/editor.xml
nickbianco Nov 28, 2023
a5059d7
Update docs for skipping controller actuators in SimulationUtilities
nickbianco Nov 28, 2023
2c2a3e9
Update logic for excluding actuators associated with DiscreteControllers
nickbianco Nov 29, 2023
e0484c6
Double check that controls in DiscreteController are in the correct o…
nickbianco Nov 29, 2023
679f817
Start refactoring crude first implementation: adding InputController …
nickbianco Dec 8, 2023
7a22f03
Exploring support for list Sockets
nickbianco Dec 11, 2023
f8b0bcd
Merge branch 'main' into moco_prescribed_controllers
nickbianco Dec 20, 2023
95e1246
Merge branch 'controller_actuators_list_socket' into moco_prescribed_…
nickbianco Jan 24, 2024
f1687f2
Switch to list Sockets for Controller actuators
nickbianco Jan 24, 2024
7198b6e
Add ControlAllocator // revert stuff in SimulationUtilities
nickbianco Jan 25, 2024
b5ba1bf
Update all goals after reverting SimulationUtilities
nickbianco Jan 25, 2024
b40bed1
Wiring everything together
nickbianco Jan 26, 2024
8d74b5b
Use raw controls from ControlAllocator in solvers
nickbianco Jan 29, 2024
7a6d422
Remove DiscreteController
nickbianco Jan 29, 2024
9d4c7c4
Revert sandbox changes
nickbianco Jan 29, 2024
a96551d
Correct docs for ModelFactory sliding mass
nickbianco Jan 31, 2024
d54d682
Merge branch 'controller_actuators_list_socket' into moco_prescribed_…
nickbianco Feb 8, 2024
4947078
static cast to int warnings // revert ModelFactory changes to fix tests
nickbianco Feb 11, 2024
28a89ee
Remove InputController noexcepts
nickbianco Feb 11, 2024
b79f086
Various small updates
nickbianco Feb 11, 2024
d3924e6
Merge branch 'main' into moco_prescribed_controllers
nickbianco Feb 13, 2024
7d4999c
Use 'inputs' name everywhere
nickbianco Feb 13, 2024
360a6b5
Add a TODO about checking for ActuatorInputControllers added by users…
nickbianco Feb 13, 2024
67f2d8b
Responding to review comments
nickbianco Feb 15, 2024
8a50a02
Add docs for ControlAllocator
nickbianco Feb 15, 2024
87e7d98
Get the correct control index map when using raw controls in MocoGoals
nickbianco Feb 15, 2024
459a7da
Use correct control index map for MocoInitialActivationGoal
nickbianco Feb 15, 2024
e18b834
ControlAllocator --> ControlDistributor // compute model controls in …
nickbianco Feb 20, 2024
4408507
Update TropterProblem to compute controls from model // address other…
nickbianco Feb 20, 2024
d71461b
Merge branch 'main' into moco_prescribed_controllers
nickbianco Feb 20, 2024
ca8defb
Fix endpoint controls
nickbianco Feb 20, 2024
de26be0
Merge branch 'moco_prescribed_controllers' of https://github.com/open…
nickbianco Feb 20, 2024
a9a90c7
Add interface to InputController for specifying expected Input channe…
nickbianco Feb 20, 2024
d9bb1fb
Fix new InputController interface // start working on Moco user guide…
nickbianco Feb 21, 2024
ab5f052
Convert values to int for Ubuntu builds
nickbianco Feb 22, 2024
512c305
Convert values to int for Ubuntu builds pt. 2
nickbianco Feb 22, 2024
d99579c
Add high-level documentation for Controllers with Moco
nickbianco Feb 22, 2024
7684b60
Ubuntu build fix
nickbianco Feb 22, 2024
ea5f0e8
Update incorrect comments, CasADi --> tropter
nickbianco Feb 23, 2024
a619ab1
Add tests // add helper function for solver post-processing steps
nickbianco Mar 2, 2024
6aa8c84
Exclude helper functions if tropter/CasADi not build
nickbianco Mar 2, 2024
a54c94f
Improve comments related to new control behavior
nickbianco Mar 5, 2024
d276d8c
Avoid thread_local control memory in MocoCasOCProblem // move helper …
nickbianco Mar 6, 2024
dccea4c
Whitespace and comment corrections
nickbianco Mar 6, 2024
4185d93
Realize MocoPeriodicityGoal stage to SimTK::Stage::Velocity
nickbianco Mar 6, 2024
cc4e06e
Improve docs related to computing and returning model controls
nickbianco Mar 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ delete_this_to_stop_optimization*.txt
.idea/editor.xml
.idea/codeStyles/codeStyleConfig.xml
.idea/codeStyles/Project.xml
.idea/editor.xml

# Sensitive or high-churn files:
.idea/**/dataSources/
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ v4.6
- Bumped the version of `ezc3d` to 1.5.8, which can now deal properly with Type-3 force platforms and c3d from Shadow
- Added `StationDefinedFrame` component, which is a `Frame` component that automatically computes its position and
orientation from `Station`s in the model
- Models with `PrescribedController`s are now supported by Moco (#3701). Controls for actuators controlled by
`PrescribedController`s are now excluded from the optimization problem.

v4.5
====
Expand Down
1 change: 1 addition & 0 deletions OpenSim/Actuators/ModelFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ Model ModelFactory::createSlidingPointMass() {
Model model;
model.setName("sliding_mass");
auto* body = new Body("body", 1.0, SimTK::Vec3(0), SimTK::Inertia(0));
body->attachGeometry(new Sphere(0.05));
model.addComponent(body);

// Allows translation along x.
Expand Down
7 changes: 4 additions & 3 deletions OpenSim/Actuators/ModelFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ class OSIMACTUATORS_API ModelFactory {
/// This is a convenience for `createNLinkPendulum(2)`.
static Model createDoublePendulum() { return createNLinkPendulum(2); }
/// This model contains:
/// - 1 body: mass 1.0 kg, `/bodyset/body`.
/// - 1 body: mass 1.0 kg, `/body`.
/// - 1 joint: SliderJoint along x axis, `/jointset/slider`, with
/// coordinate `/jointset/slider/position`.
/// - 1 actuator: CoordinateActuator, controls [-10, 10], `/actuator`.
/// coordinate `/slider/position`.
/// - 1 actuator: CoordinateActuator, controls [-10, 10],
/// `/forceset/actuator`.
/// Gravity is default; that is, (0, -g, 0).
static Model createSlidingPointMass();
/// This model contains:
Expand Down
4 changes: 2 additions & 2 deletions OpenSim/Moco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ set(MOCO_SOURCES
MocoFrameDistanceConstraint.cpp
MocoOutputConstraint.h
MocoOutputConstraint.cpp
Components/DiscreteController.cpp
Components/DiscreteController.h
Components/StationPlaneContactForce.h
Components/StationPlaneContactForce.cpp
Components/DiscreteForces.h
Components/DiscreteForces.cpp
Components/AccelerationMotion.h
Components/AccelerationMotion.cpp
Components/ControlDistributor.h
Components/ControlDistributor.cpp
MocoCasADiSolver/MocoCasADiSolver.h
MocoCasADiSolver/MocoCasADiSolver.cpp
MocoInverse.cpp
Expand Down
106 changes: 106 additions & 0 deletions OpenSim/Moco/Components/ControlDistributor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* -------------------------------------------------------------------------- *
* OpenSim: ControlDistributor.cpp *
* -------------------------------------------------------------------------- *
* Copyright (c) 2024 Stanford University and the Authors *
* *
* Author(s): Nicholas Bianco *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain a *
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* -------------------------------------------------------------------------- */

#include "ControlDistributor.h"

using namespace OpenSim;

//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
ControlDistributor::ControlDistributor() = default;

ControlDistributor::~ControlDistributor() noexcept = default;

ControlDistributor::ControlDistributor(const ControlDistributor&) = default;

ControlDistributor::ControlDistributor(ControlDistributor&&) = default;

ControlDistributor& ControlDistributor::operator=(
const ControlDistributor&) = default;

ControlDistributor& ControlDistributor::operator=(
ControlDistributor&&) = default;

//=============================================================================
// GET AND SET
//=============================================================================
void ControlDistributor::addControl(const std::string& controlName) {
const int index = (int)m_controlIndexMap.size();
m_controlIndexMap[controlName] = index;
}

void ControlDistributor::setControls(SimTK::State& s,
const SimTK::Vector& controls) const {
updControls(s) = controls;
}

SimTK::Vector& ControlDistributor::updControls(SimTK::State& s) const {
const SimTK::Subsystem& subSys = getSystem().getDefaultSubsystem();
auto& dv = subSys.updDiscreteVariable(s, m_discreteVarIndex);
auto& discreteControls =
SimTK::Value<SimTK::Vector>::updDowncast(dv).upd();
return discreteControls;
}

const SimTK::Vector& ControlDistributor::getControls(
const SimTK::State& s) const {
const SimTK::Subsystem& subSys = getSystem().getDefaultSubsystem();
auto& dv = subSys.getDiscreteVariable(s, m_discreteVarIndex);
auto& discreteControls = SimTK::Value<SimTK::Vector>::downcast(dv).get();
return discreteControls;
}

double ControlDistributor::getControlForOutputChannel(const SimTK::State& s,
const std::string& channel) const {
return getControls(s)[m_controlIndexMap.at(channel)];
}

std::vector<std::string> ControlDistributor::getControlNamesInOrder() const {
// Return the control names in ascending order of their indices.
std::vector<std::string> names;
names.reserve(m_controlIndexMap.size());
for (const auto& kv : m_controlIndexMap) {
names.push_back(kv.first);
}
std::sort(names.begin(), names.end(),
[&](const std::string& a, const std::string& b) {
return m_controlIndexMap.at(a) < m_controlIndexMap.at(b);
});
return names;
}

//=============================================================================
// MODEL COMPONENT INTERFACE
//=============================================================================
void ControlDistributor::extendRealizeTopology(SimTK::State& state) const {
Super::extendRealizeTopology(state);
const SimTK::Subsystem& subSys = getSystem().getDefaultSubsystem();
const SimTK::Vector initControls(
static_cast<int>(m_controlIndexMap.size()), 0.0);
m_discreteVarIndex =
subSys.allocateDiscreteVariable(state, SimTK::Stage::Dynamics,
new SimTK::Value<SimTK::Vector>(initControls));
}

void ControlDistributor::extendFinalizeFromProperties() {
Super::extendFinalizeFromProperties();
for (const auto& kv : m_controlIndexMap) {
updOutput("controls").addChannel(kv.first);
}
}
156 changes: 156 additions & 0 deletions OpenSim/Moco/Components/ControlDistributor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#ifndef OPENSIM_CONTROL_DISTRIBUTOR_H
#define OPENSIM_CONTROL_DISTRIBUTOR_H
/* -------------------------------------------------------------------------- *
* OpenSim: ControlDistributor.h *
* -------------------------------------------------------------------------- *
* Copyright (c) 2024 Stanford University and the Authors *
* *
* Author(s): Nicholas Bianco *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain a *
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* -------------------------------------------------------------------------- */

#include <OpenSim/Simulation/Model/ModelComponent.h>
#include <OpenSim/Moco/osimMocoDLL.h>

namespace OpenSim {

/**
* This component stores a vector of control values that can be used to
* allocate controls to other components in a model.
*
* A control value can be added to the ControlDistributor using `addControl()`.
* This adds a channel to the Output `controls` which is then available to
* distribute to other components via `Input` connections.
*
* The control values are stored in a discrete variable in the state. The
* control values are stored in the same order they were added to the
* distributor. The control values can be set and retrieved using the
* `setControls()`, `updControls()`, and `getControls()` methods.
*
* This class is primarily intended for use in Moco where it is used to
* distribute control values from an optimal control problem to InputControllers
* in a model. Therefore, "controls" in the context of this class do not
* necessarily correspond to controls in a model (i.e., from
* Model::getControls()). However, this class is generally useful for
* distributing scalar values stored in a discrete variable to other components
* in a model that accept an `Input`.
*
* ## Usage
*
* Constructing a ControlDistributor and adding controls:
* @code
* auto controlDistributor = make_unique<ControlDistributor>();
* controlDistributor->addControl("/forceset/soleus_r");
* controlDistributor->addControl("/my_input_controller_value");
* controlDistributor->addControl("/my_custom_component_input");
* model.addComponent(controlDistributor.release());
* @endcode
*
* Connecting all `Output` controls to another component:
* @code
* const auto& output = controlDistributor->getOutput("controls");
* auto& controller =
* model.updComponent<ActuatorInputController>("/my_actu_controller");
* controller.connectInput_inputs(output);
*@endcode
*
* Connecting an individual control channel using an alias:
* @code
* const auto& output = controlDistributor->getOutput("controls");
* const auto& channel = output.getChannel("/forceset/soleus_r");
* auto& controller =
* model.updComponent<ActuatorInputController>("/my_actu_controller");
* controller.connectInput_inputs(channel, "/forceset/soleus_r");
* @endcode
*/
class OSIMMOCO_API ControlDistributor : public ModelComponent {
OpenSim_DECLARE_CONCRETE_OBJECT(ControlDistributor, ModelComponent);

public:
//=============================================================================
// OUTPUTS
//=============================================================================
OpenSim_DECLARE_LIST_OUTPUT(controls, double, getControlForOutputChannel,
SimTK::Stage::Dynamics);

//=============================================================================
// METHODS
//=============================================================================

// CONSTRUCTION AND DESTRUCTION
ControlDistributor();
~ControlDistributor() noexcept override;

ControlDistributor(const ControlDistributor&);
ControlDistributor(ControlDistributor&&);

ControlDistributor& operator=(const ControlDistributor&);
ControlDistributor& operator=(ControlDistributor&&);

// GET AND SET
/**
* Add a control to the control distributor.
*/
void addControl(const std::string& controlName);

/**
* Set the distributor controls stored in the discrete variable.
*
* The `controls` vector must be the same size as the number of controls
* added to the distributor by `addControl()`.
*/
void setControls(SimTK::State& s, const SimTK::Vector& controls) const;

/**
* Get a writable reference to the distributor controls stored in the
* discrete variable.
*/
SimTK::Vector& updControls(SimTK::State& s) const;

/**
* Get a const reference to the distributor controls stored in the discrete
* variable.
*/
const SimTK::Vector& getControls(const SimTK::State& s) const;

/**
* Get the control value for the requested output channel.
*/
double getControlForOutputChannel(
const SimTK::State& s, const std::string& channel) const;

/**
* Get the names of the controls in the order they were added to the
* distributor.
*/
std::vector<std::string> getControlNamesInOrder() const;

/**
* Get a map of control names to their indices in the control vector.
*/
std::unordered_map<std::string, int> getControlIndexMap() const {
return m_controlIndexMap;
}

protected:
// MODEL COMPONENT INTERFACE
void extendRealizeTopology(SimTK::State& state) const override;
void extendFinalizeFromProperties() override;

private:
std::unordered_map<std::string, int> m_controlIndexMap;
mutable SimTK::DiscreteVariableIndex m_discreteVarIndex;
};

} // namespace OpenSim

#endif // OPENSIM_CONTROL_DISTRIBUTOR_H
62 changes: 0 additions & 62 deletions OpenSim/Moco/Components/DiscreteController.cpp

This file was deleted.

Loading
Loading