-
Notifications
You must be signed in to change notification settings - Fork 319
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
Implementation of floating-base task space control #3703
base: main
Are you sure you want to change the base?
Implementation of floating-base task space control #3703
Conversation
Update 3Nov2022 See merge request Biomechanics/tools/3rd-party/opensim-core-mirror!1
Cfdrc cmc point jacobian See merge request Biomechanics/tools/3rd-party/opensim-core-mirror!2
wip: Added in new task classes wip: Add in TaskSpaceTorqueController feat: All code migrated and initial example working wip: Trying to get all Stanev examples working checkpoint: Got Perreault example output to match original code checkpoint: Figured out issue with ExampleClosedKinematicChain.cpp. Jacobian hits singularity at Pi/2 wip: All examples work. Starting cleanup fix: Resolve issues with constraint null space chore: Cleaned up from debugging chore: Update license
wip: Added in new task classes wip: Add in TaskSpaceTorqueController feat: All code migrated and initial example working wip: Trying to get all Stanev examples working checkpoint: Got Perreault example output to match original code checkpoint: Figured out issue with ExampleClosedKinematicChain.cpp. Jacobian hits singularity at Pi/2 wip: All examples work. Starting cleanup fix: Resolve issues with constraint null space chore: Cleaned up from debugging chore: Update license
…/tools/3rd-party/opensim-core-mirror into cfdrc-taskspace-release
Build failures are due to the latest PR to use sockets instead of actuator names |
Thanks @aymanhab, I'll take a look at it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start, @nathantpickle-cfdrc! I used my first pass to get a feel for the layout of the files, to make some general formatting suggestions, and comment on some of the changes to existing CMC classes. On the next pass I can make more detailed file-by-file review comments. This will probably take multiple review passes given the amount of files, but what I've looked through so far seems well organized and commented, so hopefully it shouldn't take too much time.
One more high-level comment: based on the amount of files added, I think it would make sense to group everything in the Tools
directory under a subdirectory called TaskSpace
.
Reviewed 64 of 64 files at r1, all commit messages.
Reviewable status: all files reviewed, 44 unresolved discussions (waiting on @nathantpickle-cfdrc)
CMakeLists.txt
line 803 at r1 (raw file):
if(OPENSIM_WITH_CASADI) find_package(casadi 3.4.4 REQUIRED HINTS "${OPENSIM_DEPENDENCIES_DIR}/casadi")
Was this addition necessary for creating local builds?
CMakeLists.txt
line 836 at r1 (raw file):
else() find_package(Ipopt REQUIRED CONFIG HINTS "${OPENSIM_DEPENDENCIES_DIR}/ipopt/lib/cmake/Ipopt")
Same question as above.
OpenSim/Examples/TaskSpace/ExampleAbsoluteCoordinates/CMakeLists.txt
line 23 at r1 (raw file):
# "${OpenSim_INCLUDE_DIRS}/OpenSim" # ${Simbody_INCLUDE_DIR} # "${OpenSim_INCLUDE_DIRS}/../spdlog/include")
Remove dead code?
Nice work using the existing CMake macros!
OpenSim/Examples/TaskSpace/ExampleAbsoluteCoordinates/ExampleAbsoluteCoordinates.cpp
line 12 at r1 (raw file):
* * @see <a href="http://ieeexplore.ieee.org/document/8074739/">[Publication]</a> */
For your examples, use an OpenSim-style header that includes the Apache 2.0 license. Example here: https://github.com/opensim-org/opensim-core/blob/main/OpenSim/Simulation/Model/AbstractGeometryPath.h.
OpenSim/Examples/TaskSpace/ExampleArm26/arm26.osim
line 1 at r1 (raw file):
<?xml version="1.0" encoding="UTF-8" ?>
If this is a copy of the arm26 model from somewhere else in the repo, consider copying the file during the install step via CMake so we don't introduce additional copies into the codebase.
Here's an example of copy code resources from one directory to another: https://github.com/opensim-org/opensim-core/blob/main/OpenSim/Examples/Moco/example3DWalking/CMakeLists.txt.
OpenSim/Examples/TaskSpace/ExamplePerreault2001Experiment/ExamplePerreault2001Experiment.cpp
line 13 at r1 (raw file):
* * @see <a href="http://ieeexplore.ieee.org/document/8074739/">[Publication]</a> */
Use OpenSim-style header.
OpenSim/Examples/TaskSpace/ExamplePerreault2001Experiment/opensim.log
line 1 at r1 (raw file):
[2024-01-18 08:29:30.166] [info] Updating Model file from 30000 to latest format...
This log file should be removed.
OpenSim/Examples/TaskSpace/ExampleStandingBalance2D/ExampleStandingBalance2D.cpp
line 17 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Ah, I see you do have header format! A couple of comments:
- Since you are merging this into
opensim-core
, the copyright line should read: "Copyright (c) 2005-2024 Stanford University and the Authors". Be sure to give yourself credit via author lines and references below the header, but the copyright line should reflect the rest ofopensim-core
. - You don't need "OpenSim TaskSpace" here, just "OpenSim".
These apply to all other headers in the added files.
OpenSim/Examples/TaskSpace/ExampleStandingBalance2D/ExampleStandingBalance2D.cpp
line 20 at r1 (raw file):
/** * @file ExampleStandingBalance2D.cpp
Use camel case for all example names, e.g., exampleStandingBalance2D.cpp
. You can apply camel case to the folder names as well.
OpenSim/Examples/TaskSpace/ExampleStandingBalance2D/gait2d.osim
line 1 at r1 (raw file):
<?xml version="1.0" encoding="UTF-8" ?>
Duplicate model?
OpenSim/Examples/TaskSpace/ExampleUpperLimb/mobl_2016_ideal_muscles.osim
line 3 at r1 (raw file):
<?xml version="1.0" encoding="UTF-8" ?> <OpenSimDocument Version="30000"> <Model name="MoBL_2016_Ideal_Muscles">
Similar to previous comments, avoid duplicate models wherever possible.
OpenSim/Tools/CMC_Joint.h
line 65 at r1 (raw file):
// Work Variables const Coordinate *_q;
Why is this const
introduced here? Does it affect the CMC interface in any meaningful way?
There are several more instances of this change in the CMC classes, and this comment applies to those as well (so I don't make the same comment a bunch of times).
OpenSim/Tools/CMC_Orientation.h
line 77 at r1 (raw file):
// COMPUTATIONS //-------------------------------------------------------------------------- void computeJacobian(const SimTK::State& s) override;
Why was the SimTK::State
argument added here?
OpenSim/Tools/TaskSpaceBodyTask.h
line 14 at r1 (raw file):
* * * Please refer to the following publication for mathematical details, and * * cite this paper if you use this code in your own work: *
Make sure all *
's are aligned.
OpenSim/Tools/TaskSpaceBodyTask.h
line 17 at r1 (raw file):
* * * Pickle and Sundararajan. "Predictive simulation of human movement in * * OpenSim using floating-base task space control". *
Citations can be included in the doc string for classes, not in the header.
OpenSim/Tools/TaskSpaceBodyTask.h
line 32 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceBodyTask.h
line 83 at r1 (raw file):
// virtual void computeJacobian(const SimTK::State& s); // virtual void computeBias(const SimTK::State& s); // virtual void update(const SimTK::State& s);
Unused code?
OpenSim/Tools/TaskSpaceBodyTask.cpp
line 30 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceComputeControlsEventHandler.h
line 33 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceConstraintModel.h
line 33 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 1 at r1 (raw file):
#ifndef OPENSIM_TASK_SPACE_COORDINATE_TASK_H_
I used this class to make some general comments about formatted, mostly related to comments. Your comments are descriptive and clear, which is great, but some formatting changes could reduce visual clutter, especially in the .cpp file. You don't need to repeat comments in the header in the .cpp files.
The following class is a good reference for comment style: https://github.com/opensim-org/opensim-core/blob/main/OpenSim/Simulation/Model/AbstractGeometryPath.h.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 4 at r1 (raw file):
#define OPENSIM_TASK_SPACE_COORDINATE_TASK_H_ /* -------------------------------------------------------------------------- * * OpenSim: TaskSpaceCoordinateTask.h *
Mis-aligned *
.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 32 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 36 at r1 (raw file):
//============================================================================ // INCLUDE //============================================================================
Unnecessary for includes.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 47 at r1 (raw file):
//============================================================================= //=============================================================================
Extra horizontal lines like these could be remove. They appear in other parts of OpenSim code, but add more clutter than organization IMO.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 92 at r1 (raw file):
* * @param aTask Joint task to be copied. */
Generic copy constructors like this one usually don't need a doc string.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 93 at r1 (raw file):
* @param aTask Joint task to be copied. */ CoordinateTask(const CoordinateTask& aTask);
If you're defining a copy constructor and destructor, you should define a copy assignment operator as well (re: https://en.cppreference.com/w/cpp/language/rule_of_three).
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 98 at r1 (raw file):
* Destructor. */ virtual ~CoordinateTask();
Similarly, generic destructors can go without a doc string.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 145 at r1 (raw file):
void computeDesiredAccelerations( const SimTK::State& s, double aTI, double aTF) override;
Remove extra spaces (I like to let my IDE do this automatically for me).
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 196 at r1 (raw file):
*/ double computeJointLimitMatrix(const SimTK::State& s);
Extra spaces.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 224 at r1 (raw file):
*/ void setNull();
Extra spaces.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 247 at r1 (raw file):
//-------------------------------------------------------------------------- // OPERATORS //--------------------------------------------------------------------------
Comment header in the wrong location?
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 249 at r1 (raw file):
//-------------------------------------------------------------------------- //==========================================================================
Can be removed.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 250 at r1 (raw file):
//========================================================================== }; // END of class CoordinateTask
class CoordinateTask
is descriptive enough here.
OpenSim/Tools/TaskSpaceCoordinateTask.h
line 251 at r1 (raw file):
//========================================================================== }; // END of class CoordinateTask //==========================================================================
Can be removed.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 30 at r1 (raw file):
* See the License for the specific language governing permissions and * * limitations under the License. * * -------------------------------------------------------------------------- */
Use an OpenSim-style header.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 34 at r1 (raw file):
//============================================================================= // INCLUDES //=============================================================================
Unnecessary.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 44 at r1 (raw file):
//============================================================================= // STATICS //=============================================================================
Unnecessary. Only use comment headers if content for them exists.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 49 at r1 (raw file):
// CONSTRUCTOR(S) AND DESTRUCTOR //============================================================================= //_____________________________________________________________________________
Similar to my comment in the header file, I would suggest avoiding extra horizontal lines like this one.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 62 at r1 (raw file):
* @todo Instead of an integer id, the name of the coordinate * should be used. */
Doxygen-style comments won't appear in autogenerated docs when included in .cpp files, so you can reserve them for the header files.
In general, you can use categorical comment headers like:
//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
But anything more than this will clutter the .cpp IMO.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 175 at r1 (raw file):
//----------------------------------------------------------------------------- // ASSIGNMENT //-----------------------------------------------------------------------------
This "sub-header" could be excluded.
OpenSim/Tools/TaskSpaceCoordinateTask.cpp
line 411 at r1 (raw file):
//----------------------------------------------------------------------------- // UPDATE FROM XML NODE //-----------------------------------------------------------------------------
This "sub-header" could be excluded.
OpenSim/Tools/TaskSpaceUtilities.h
line 32 at r1 (raw file):
* -------------------------------------------------------------------------- */ #ifndef OPENSIM_TASK_SPACE_UTILITIES_H_ #define OPENSIM_TASK_SPACE_UTILITIES_H_
Header guards should go above file headers.
OpenSim/Tools/TrackingTask.h
line 65 at r1 (raw file):
/** Model. */ const Model *_model;
Similar to the CMC class changes, why the switch to const
here?
A few more thoughts:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(forgot to submit these comments the other day)
I didn't have time to read everything yet, but here are some of the things I noticed in a few files. I can read it more as it evolves
virtual void setModel(OpenSim::Model& aModel); | ||
Model* getModel() const; | ||
virtual void setModel(const OpenSim::Model& aModel); | ||
const Model* getModel() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice change (no disagreements there) but it's a drive-by that breaks the API
* Pickle and Sundararajan. "Predictive simulation of human movement in * | ||
* OpenSim using floating-base task space control". * | ||
* * | ||
* Copyright (c) 2023 CFD Research Corporation and the Authors * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd consult with the primary project maintainers (e.g. @aymanhab , @nickbianco ) whether having mixed copyright notices within one project's codebase is standard or not - the legality of mixing copyrights into one final product with its own copyright constraints isn't obvious.
#include "simbody/internal/MobilizedBody.h" | ||
#include "OpenSim/Simulation/Model/Model.h" | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment doesn't match code
* @param model | ||
* @return Matrix | ||
*/ | ||
SimTK::Matrix calcM( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a helper function that should be hidden in a CPP file or in an appropriate namespace (e.g. OpenSim::detail
, OpenSim::internal
, or similar) so that users don't get ideas.
SimTK::Matrix calcM( | ||
const SimTK::State& s, const OpenSim::Model& model); | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar idea for the remaining funcs here: if they get exported to downstream API users then you'll pollute the OpenSim
namespace with a bunch of functions that then need to be maintained by project maintainers for backwards-compat
FactorSVD AInvSVD(A); | ||
try { | ||
AInvSVD.inverse(Ainv); | ||
} catch (...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch (...)
with your own custom error message seems unusual, almost all exceptions coming out of SimTK
inherit from std::exception
, so you can usually just catch (const std::exception& ex)
and append that exception's message to your own (with extra information), but what you're doing here is Pokemon-catching with your own explanation (which may mismatch the explanation given by the actual implementation)
} | ||
Matrix SInv = diagonalize(dInv); | ||
Ainv = VT.transpose() * SInv * U.transpose(); | ||
} catch (...) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
♪ Gotta catch em' alllllll, that's true - our courage will pull us through ♪
But seriously, catch (...)
is the kind of thing that's usually reserved for a top-level application: you should be catching std::exception
and ensuring information in the exception is correctly propagated upwards/swallowed.
void extendConnectToModel(Model& model) override; | ||
|
||
/** Selection matrix \f$ \tau^{'} = B \tau \f$ for under-actuation. */ | ||
mutable SimTK::Matrix B; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mutable
, the sussest of keywords
std::vector<SimTK::Vector> bt_p; | ||
|
||
/** Stores the applied generalized forces. */ | ||
mutable Storage appliedForces; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mutable
, and your member naming conventions switch halfway through this: OpenSim usually uses underscore-prefixed member variables.
void computeControls( | ||
const SimTK::State& s, SimTK::Vector& controls) const override; | ||
|
||
SimTK::Vector _tau; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rando member field? Member fields are usually hidden in a private
block
Thanks @nickbianco and @adamkewley for the initial review! I'll get started on the suggested changes. @nickbianco I'm on board with your suggestion to separate out the examples into a separate PR. I can remove the examples and add tests that will exercise the new classes. |
Fixes issue #3636
Brief summary of changes
New classes for task space control have been added in OpenSim/Tools. Currently the files are all prefixed with "TaskSpace", but could be renamed and/or moved as needed. Examples are located in OpenSim/Examples/TaskSpace.
A manuscript preprint with the associated mathematical derivation can be found here:
https://www.biorxiv.org/content/10.1101/2024.02.13.580044v1
Testing I've completed
All examples have been tested and are working correctly. All new functionality is located in new classes and does not affect existing code/tests.
Looking for feedback on...
CHANGELOG.md (choose one)
This change is