MocoOrientationTrackingGoal

OpenSim Moco is a software toolkit to solve optimal control problems with musculoskeletal models defined in OpenSim using the direct collocation method.
POST REPLY
User avatar
Ross Miller
Posts: 371
Joined: Tue Sep 22, 2009 2:02 pm

MocoOrientationTrackingGoal

Post by Ross Miller » Wed Apr 22, 2020 7:07 pm

Hi all,

I'm trying to use MocoOrientationTrackingGoal to keep the torso upright in walking and am having trouble understanding what info I need to pass into Moco and just adding the goal generally. It looks like I need to pass a data file (CSV or STO) containing "rotations of individual frames in ground to be tracked":

Code: Select all

torsoGoal = MocoOrientationTrackingGoal('torsoGoal',weight);
problem.addGoal(torsoGoal);
torsoGoal.setRotationReferenceFile('torso_orientation.csv')
I think I'm not creating that file correctly (the CSV file with target orientations) or providing the right into in it. The CSV file 'torso_orientation.csv' contains a time column from 0:0.01:1.00 and a column labeled "/bodyset/torso" with zeros for its data at each timestep. If I run this code, Matlab hangs when I later call solver.resetProblem(problem). If I comment out the third line above, Matlab gives an error "No source table." It looks like I also need to specify a "table containing values of model state variables":

Code: Select all

torsoGoal.setStatesReference(<tableProcessor object with state values goes here>)
but I'm not sure how I would create this table (I don't know the values of the state variables at this point).

Ross

User avatar
Nicholas Bianco
Posts: 963
Joined: Thu Oct 04, 2012 8:09 pm

Re: MocoOrientationTrackingGoal

Post by Nicholas Bianco » Thu Apr 23, 2020 1:18 pm

Hi Ross,

I think you need to reorder the commands so you add the goal to the problem after you set the reference file.

Code: Select all

torsoGoal = MocoOrientationTrackingGoal('torsoGoal',weight);
torsoGoal.setRotationReferenceFile('torso_orientation.csv')
problem.addGoal(torsoGoal);
Let me know if that doesn't work.
-Nick

User avatar
Ross Miller
Posts: 371
Joined: Tue Sep 22, 2009 2:02 pm

Re: MocoOrientationTrackingGoal

Post by Ross Miller » Thu Apr 23, 2020 2:31 pm

Hi Nick,

I tried that and am still having the same issue (Matlab hangs when executing resetProblem.

I attached the code here if that's helpful. The goWalk "txt" file is a Matlab script (message board wouldn't let me attach a .m file).

Ross
Attachments
goWalk_27DoF_test.txt
(39.44 KiB) Downloaded 56 times
upright_torso.csv
(1.11 KiB) Downloaded 65 times

User avatar
Nicholas Bianco
Posts: 963
Joined: Thu Oct 04, 2012 8:09 pm

Re: MocoOrientationTrackingGoal

Post by Nicholas Bianco » Mon Apr 27, 2020 2:52 pm

Hi Ross,

Thanks for the sending the attachments -- I think I've found the issue. This goal accepts reference tables that are type TimeSeriesTable_<SimTK::Rotation>. That means each "column" of the table contains rows of values of type SimTK::Rotation (not just a scalar value). I realize now that there should be additional logic to load a TimeSeriesTable_<SimTK::Rotation> from a "flattened" file, where there's a column for each of the 9 elements of the rotation matrix.

Unfortunately, passing a Rotation table created programmatically in MATLAB is also not an option, as setRotationTable() isn't currently handled properly in the MATLAB bindings.

It seems like your best option is to use setStatesReference() to set your torso tracking reference. This method accepts a TableProcessor() containing a TimeSeriesTable() whose columns are model state variable values. For your torso tracking application, you'd want a table filled with state variable default values, assuming that the model default pose has the desired torso orientation in ground. This table will get converted to a StateTrajectory internally, which is then used compute tracking reference values for all frames specified by setFramePaths() (i.e., '/bodyset/torso'). I know this is not ideal, but it should let you accomplish what you're trying to do without waiting for fixes to the problems stated above.

If you need assistance assembling the table to pass to setStatesReference() let me know. I'm also happy to chat about this over a Zoom call if that's easier.

Best,
-Nick

User avatar
Ross Miller
Posts: 371
Joined: Tue Sep 22, 2009 2:02 pm

Re: MocoOrientationTrackingGoal

Post by Ross Miller » Tue Apr 28, 2020 2:20 pm

Thanks Nick

When I try to add the torso frame path for tracking I get an error:

Code: Select all

>> torsoGoal.setFramePaths('/bodyset/torso');
No method 'setFramePaths' with matching signature found for class
'org.opensim.modeling.MocoOrientationTrackingGoal'.
Is this the wrong syntax for doing that? Or is it related to how I have the bodies and joints defined in the model? Under the body set there's no <socket_frame> defined although I thought that was just for graphical purposes:

Code: Select all

<Body name="torso">
	<!--The geometry used to display the axes of this Frame.-->
	<FrameGeometry name="frame_geometry">
		<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
		<socket_frame>..</socket_frame>
		...
	</FrameGeometry>
	...
</Body>
Then under the joint set I define some "offset" frame:

Code: Select all

<CustomJoint name="lumbar">
	...
	<!--Path to a Component that satisfies the Socket 'child_frame' of type PhysicalFrame (description: The child frame for the joint.).-->
	<socket_child_frame>torso_offset</socket_child_frame>
	...
	<frames>
		...
		<PhysicalOffsetFrame name="torso_offset">
			<!--The geometry used to display the axes of this Frame.-->
			<FrameGeometry name="frame_geometry">
				<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
				<socket_frame>..</socket_frame>
				<!--Scale factors in X, Y, Z directions respectively.-->
				<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
			</FrameGeometry>
			<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
			<socket_parent>/bodyset/torso</socket_parent>
			<!--Translational offset (in meters) of this frame's origin from the parent frame's origin, expressed in the parent frame.-->
			<translation>0 0 0</translation>
			<!--Orientation offset (in radians) of this frame in its parent frame, expressed as a frame-fixed x-y-z rotation sequence.-->
			<orientation>0 0 0</orientation>
		</PhysicalOffsetFrame>
	</frames>
</CustomJoint>
I was starting from the Rajagopal model which does bodies/joints/frames this way.

Ross

User avatar
Nicholas Bianco
Posts: 963
Joined: Thu Oct 04, 2012 8:09 pm

Re: MocoOrientationTrackingGoal

Post by Nicholas Bianco » Tue Apr 28, 2020 2:44 pm

Hi Ross,

The setFramePaths() methods accepts a vector of strings, so in MATLAB you have to do this:

Code: Select all

paths = StdVectorString()
paths.add('/bodyset/torso')
torsoGoal.setFramePaths(paths)
Let me know if that works.

Best,
-Nick

User avatar
Ross Miller
Posts: 371
Joined: Tue Sep 22, 2009 2:02 pm

Re: MocoOrientationTrackingGoal

Post by Ross Miller » Tue Apr 28, 2020 5:35 pm

It's working now, thanks Nick!

User avatar
Aaron Fox
Posts: 271
Joined: Sun Aug 06, 2017 10:54 pm

Re: MocoOrientationTrackingGoal

Post by Aaron Fox » Sun Sep 13, 2020 8:31 pm

Hi Nick,

I'm trying to implement something similar to this (basically providing a lowly weighted goal to keep the pelvis level), but with the Pelvis and in Python. I'm wondering whether the bindings to use a rotation table are available in Python?

I managed to create a rotation table using (I think this is right?):

Code: Select all

import opensim as osim

#Create rotation time series table
rotTable = osim.TimeSeriesTableRotation()

#Set column labels for pelvis bodyset
rotLabels = osim.StdVectorString()
rotLabels.append('/bodyset/pelvis')
rotTable.setColumnLabels(rotLabels)

#Create a zero rotation value
zeroRot = osim.Rotation()
zeroRot.setToZero()

#Set the data to zeros
#Use length of reference kinematic data as a reference
nrows = len(osim.TimeSeriesTable('refQ.sto').getIndependentColumn())
for ii in range(nrows):
    #Get an opensim row vector rotation with a zero value
    row = osim.RowVectorRotation(1,zeroRot)
    #Append to the table
    rotTable.appendRow(ii,row)
    
#Set the time data
for ii in range(nrows):
    rotTable.setIndependentValueAtIndex(ii,osim.TimeSeriesTable('refQ.sto').getIndependentColumn()[ii])
I then create and add the goal:

Code: Select all

#Create goal
pelvisGoal = osim.MocoOrientationTrackingGoal('pelvisOrientation',0.1)

#Set path to pelvis frame
framePaths = osim.StdVectorString()
framePaths.append('/bodyset/pelvis')
pelvisGoal.setFramePaths(framePaths)

#Add rotation table of zeros to goal
pelvisGoal.setRotationReference(rotTable)
But this generates an error:

Code: Select all

TypeError: in method 'MocoOrientationTrackingGoal_setRotationReference', argument 2 of type 'OpenSim::TimeSeriesTable_< OpenSim::Rotation > const &'
It seems like my rotation table is of the wrong type for using 'setRotationReference.' It is an object of type:

Code: Select all

<opensim.common.TimeSeriesTableRotation; proxy of <Swig Object of type 'std::shared_ptr< OpenSim::TimeSeriesTable_< SimTK::Rotation_< double > > > *' at 0x00000192A19C6C00> >
Am I missing a step or potentially consturcting things wrong here? I tried to use the approach you mentioned in having a states reference file with all zero values (to specify a neutral pelvis), but I keep getting a 'nan' result as the pelvisGoal output so there is clearly another issue in how I'm implementing that approach.

Aaron

User avatar
Aaron Fox
Posts: 271
Joined: Sun Aug 06, 2017 10:54 pm

Re: MocoOrientationTrackingGoal

Post by Aaron Fox » Mon Sep 14, 2020 3:15 am

An FYI update on this. I managed to get the states reference approach to work. With locked coordinates in a model the createStatesFromStorage step in processing the table input appears to generate 'nan's - and this generates the nan in the output goal.

I'd still be interested to know whether the rotation table approach is possible, as this would be easier to implement in certain scenarios.

Aaron

User avatar
Nicholas Bianco
Posts: 963
Joined: Thu Oct 04, 2012 8:09 pm

Re: MocoOrientationTrackingGoal

Post by Nicholas Bianco » Mon Sep 14, 2020 11:27 am

Hi Aaron,

It looks like the tables are implemented using smart pointers in the bindings. Try updating your script where you set the rotation table to this:

Code: Select all

#Add rotation table of zeros to goal
pelvisGoal.setRotationReference(rotTable.get())
The get() method should return the underlying pointer which should be the correct type for setRotationReference().

Regarding the NaNs issue -- it's usually a good idea to remove all locked coordinates from your model and replace them with WeldJoints. The ModelOperator ModOpReplaceJointsWithWelds makes that easy to do.

Let me know if either of these approaches work for you.

-Nick

POST REPLY