opensim-org / opensim-moco

Solve optimal control problems for musculoskeletal models using OpenSim and direct collocation.
https://opensim.stanford.edu/moco
Apache License 2.0
58 stars 16 forks source link

MocoSolution not consistent with the set kinematics #664

Open Cynantares opened 3 years ago

Cynantares commented 3 years ago

I tried to input the moco result to the forward dynamics tool in opensim, but the simulation is far-off from the motion file that I set for Moco.

There was an error reported while running the code.

[error] Model unable to assemble: SimTK Exception thrown at Optimizer.h:133: Value out of range in OptimizerSystem Constructor: expected 1 <= number of parameters <= 2.14748e+09 but number of parameters=0..Model relaxing constraints and trying again. [error] Model unable to assemble with relaxed constraints: SimTK Exception thrown at Optimizer.h:133: Value out of range in OptimizerSystem Constructor: expected 1 <= number of parameters <= 2.14748e+09 but number of parameters=0.

import opensim as osim

inverse = osim.MocoInverse()

# Construct a ModelProcessor and set it on the tool. The default
# muscles in the model are replaced with optimization-friendly
# DeGrooteFregly2016Muscles, and adjustments are made to the default muscle
# parameters.
modelProcessor = osim.ModelProcessor(r'C:\Users\fxgcy\PycharmProjects\OpenSim Moco\MOBL_ARMS_fixed_41.osim')
modelProcessor.append(osim.ModOpIgnoreTendonCompliance())
modelProcessor.append(osim.ModOpReplaceMusclesWithDeGrooteFregly2016())
# Only valid for DeGrooteFregly2016Muscles.
modelProcessor.append(osim.ModOpIgnorePassiveFiberForcesDGF())
# Only valid for DeGrooteFregly2016Muscles.
modelProcessor.append(osim.ModOpScaleActiveFiberForceCurveWidthDGF(1.5))
modelProcessor.append(osim.ModOpAddReserves(1.0))
inverse.setModel(modelProcessor)

# Construct a TableProcessor of the coordinate data and pass it to the
# inverse tool. TableProcessors can be used in the same way as
# ModelProcessors by appending TableOperators to modify the base table.
# A TableProcessor with no operators, as we have here, simply returns the
# base table.
inverse.setKinematics(osim.TableProcessor(r'C:\Users\fxgcy\PycharmProjects\OpenSim Moco\bicep_curl.sto'))
# Initial time, final time, and mesh interval.
inverse.set_initial_time(0.00)
inverse.set_final_time(6.75)
inverse.set_mesh_interval(0.01)
# By default, Moco gives an error if the kinematics contains extra columns.
# Here, we tell Moco to allow (and ignore) those extra columns.
inverse.set_kinematics_allow_extra_columns(True)
# Solve the problem and write the solution to a Storage file.
solution = inverse.solve()
solution.getMocoSolution().write(r'C:\Users\fxgcy\PycharmProjects\OpenSim Moco\MoBL_ARMS_MocoInverse_solution.sto')

I also tried to use a simpler model (arm26), the optimization error didn't occur but the simulation of forward dynamics was still inconsistent with the set kinematics.

nickbianco commented 3 years ago

@Cynantares I wouldn't expect a solution from Moco (or any other direct collocation tool) to produce a realistic motion when using forward dynamics. The accumulation of small numerical errors when running a forward simulation from controls produced from direct collocation will usually produce an unstable forward simulation. You'd need a controller to produce a stable problem.

Regarding the model assembly error: these errors show up when the model tries to resolve kinematic constraints during initialization. Usually they can be ignored, as the assembly procedure will relax constraints and try again until assembly succeeds.