You are viewing the documentation for OpenSim 3.x. Are you looking for the latest OpenSim 4.0 Documentation?

Performing a Simulation Part Four

The steps covered in part four are:

Add a Prescribed Force

To push the block during the tug-of-war, we create a prescribed force to apply to the block. The prescribed force is applied in the x-direction in the block body's frame. The point of application varies linearly from (0, 0, 0) to (0.1, 0, 0) during the simulation.

// Specify properties of a force function to be applied to the block
double time[2] = {0, finalTime}; // time nodes for linear function
double fXofT[2] = {0, -blockMass*9.80665*3.0}; // force values at t1 and t2
double pXofT[2] = {0, 0.1}; // point in x values at t1 and t2 
 
// Create a new linear functions for the force and point components
PiecewiseLinearFunction *forceX = new PiecewiseLinearFunction(2, time, fXofT);
PiecewiseLinearFunction *pointX = new PiecewiseLinearFunction(2, time, pXofT); 
 
// Create a new prescribed force applied to the block
PrescribedForce *prescribedForce = new PrescribedForce(block);
prescribedForce->setName("prescribedForce"); 
 
// Set the force and point functions for the new prescribed force
prescribedForce->setForceFunctions(forceX, new Constant(0.0), new Constant(0.0));
prescribedForce->setPointFunctions(pointX, new Constant(0.0), new Constant(0.0)); 
 
// Add the new prescribed force to the model
osimModel.addForce(prescribedForce);

Exercise 7: After we compile and run the current main program, we can load the motion in the OpenSim GUI (same file name tugOfWar_states_degrees.mot as before) and visualize the simulation.


Figure: Muscle-actuated block with additional perpendicular prescribed force

Except for the colors, you should see something like the above in the GUI. Using the motion slider and video controls, visualize the motion. You should see that the block now responds to the prescribed force as well as the muscle controls.

Adding a Built-in Analysis

Generally, we would like to report various quantities while running a simulation. In this example, we'd like to report the forces that were applied to the model while running the forward simulation, so that we can troubleshoot the simulation and validate it. To get this effect, we will add in one of the built-in analyses that come with OpenSim. The specific Analysis subclass we will use in this case is ForceReporter. Attaching this analysis to the simulation will cause the values of the forces applied to the model to be reported in a storage file at the end of the simulation.
OpenSim provides a set of Analysis subclasses for convenience, in particular:

  • Kinematics
  • PointKinematics
  • Actuation
  • ForceReporter
  • InverseDynamics
  • StaticOptimization

The last two analyses are more advanced and are used by the corresponding tools in the GUI. To create the analysis for this step requires adding the following lines of code before we integrate the model forward:

 

ForceReporter* reporter = new ForceReporter(&osimModel);
osimModel.addAnalysis(reporter);

After the integration is done, we add the line:

reporter->getForceStorage().print("tugOfWar_forces.mot");

This will create a file with columns corresponding to the forces in the muscles and the applied prescribed forces. 

Add a Constraint

In this section, our goal is to create a constraint such that the motion of the block is along a specified line. The line we specify will be represented by the vector (1, 0, -1), which will constrain the motion of the block on a 45º angle between the two anchor points.

// Specify properties of a constant distance constraint to limit the block's motion
double distance = 0.2;
Vec3 pointOnGround(0, blockSideLength/2 ,0);
Vec3 pointOnBlock(0, 0, 0);
 
// Create a new constant distance constraint
ConstantDistanceConstraint *constDist = 
new ConstantDistanceConstraint(ground, pointOnGround, *block, pointOnBlock, distance);
 
// Add the new point on a line constraint to the model
osimModel.addConstraint(constDist);

Add the following before the block body is added to the model:

Vec3 gravity = osimModel.getGravity();
// Define non-zero default states for the free joint
jointCoordinateSet[3].setDefaultValue(distance); // set x-translation value
double h_start = blockMass*gravity[1]/(stiffness*blockSideLength*blockSideLength);
jointCoordinateSet[4].setDefaultValue(h_start); // set y-translation which is height

 

Exercise 8: This is the final step of this example. The complete program can be found in the file TugOfWar_Complete.cpp. You can use CMake to generate a new solution file with this as the TARGET, or manually replace the previous source file with this one, from within Visual Studio.


Figure: Final simulation.

After we re-compile and run the current main program, we can load the new motion file in the OpenSim GUI (same file name tugOfWar_states_degrees.mot as before) and visualize the simulation. If you look at the animation from a top view as above, you should see that the motion of the block is now restricted to traveling along a curve.

OpenSim is supported by the Mobilize Center , an NIH Biomedical Technology Resource Center (grant P41 EB027060); the Restore Center , an NIH-funded Medical Rehabilitation Research Resource Network Center (grant P2C HD101913); and the Wu Tsai Human Performance Alliance through the Joe and Clara Tsai Foundation. See the People page for a list of the many people who have contributed to the OpenSim project over the years. ©2010-2024 OpenSim. All rights reserved.