Skip to content

OpenSim API Example

Ayman Habib edited this page Dec 9, 2022 · 6 revisions

This page provides an example that simulates a simple arm formed by two bodies and actuated by a muscle. The example is available in C++, Python and Matlab.

See the OpenSim's C++ API Reference, the Scripting and Development website, and the Documentation website for more information.

Table of Contents

C++

Let's simulate a simple arm whose elbow is actuated by a muscle, using the C++ interface.

#include <OpenSim/OpenSim.h>
using namespace SimTK;
using namespace OpenSim;

int main() {
    Model model;
    model.setName("bicep_curl");
    model.setUseVisualizer(true);

    // Create two links, each with a mass of 1 kg, center of mass at the body's
    // origin, and moments and products of inertia corresponding to an
    // ellipsoid with radii of 0.1, 0.5 and 0.1, in the x, y and z directions,
    // respectively.
    OpenSim::Body* humerus = new OpenSim::Body(
        "humerus", 1.0, Vec3(0), Inertia(0.052, 0.004, 0.052));
    OpenSim::Body* radius  = new OpenSim::Body(
        "radius",  1.0, Vec3(0), Inertia(0.052, 0.004, 0.052));

    // Connect the bodies with pin joints. Assume each body is 1 m long.
    PinJoint* shoulder = new PinJoint("shoulder",
            // Parent body, location in parent, orientation in parent.
            model.getGround(), Vec3(0), Vec3(0),
            // Child body, location in child, orientation in child.
            *humerus, Vec3(0, 0.5, 0), Vec3(0));
    PinJoint* elbow = new PinJoint("elbow",
            *humerus, Vec3(0, -0.5, 0), Vec3(0),
            *radius, Vec3(0, 0.5, 0), Vec3(0));

    // Add a muscle that flexes the elbow.
    Millard2012EquilibriumMuscle* biceps = new
        Millard2012EquilibriumMuscle("biceps", 200, 0.6, 0.55, 0);
    biceps->addNewPathPoint("origin",    *humerus, Vec3(0, 0.3, 0));
    biceps->addNewPathPoint("insertion", *radius,  Vec3(0, 0.2, 0));

    // Add a controller that specifies the excitation of the muscle.
    PrescribedController* brain = new PrescribedController();
    brain->addActuator(*biceps);
    // Muscle excitation is 0.3 for the first 0.5 seconds, then increases to 1.
    brain->prescribeControlForActuator("biceps",
            new StepFunction(0.5, 3, 0.3, 1));

    // Add components to the model.
    model.addBody(humerus);    model.addBody(radius);
    model.addJoint(shoulder);  model.addJoint(elbow);
    model.addForce(biceps);
    model.addController(brain);

    // Add a console reporter to print the muscle fiber force and elbow angle.
    ConsoleReporter* reporter = new ConsoleReporter();
    reporter->set_report_time_interval(1.0);
    reporter->addToReport(biceps->getOutput("fiber_force"));
    reporter->addToReport(
        elbow->getCoordinate(PinJoint::Coord::RotationZ).getOutput("value"),
        "elbow_angle");
    model.addComponent(reporter);

    // Add display geometry.
    Ellipsoid bodyGeometry(0.1, 0.5, 0.1);
    bodyGeometry.setColor(Gray);
    // Attach an ellipsoid to a frame located at the center of each body.
    PhysicalOffsetFrame* humerusCenter = new PhysicalOffsetFrame(
        "humerusCenter", *humerus, Transform(Vec3(0)));
    humerus->addComponent(humerusCenter);
    humerusCenter->attachGeometry(bodyGeometry.clone());
    PhysicalOffsetFrame* radiusCenter = new PhysicalOffsetFrame(
        "radiusCenter", *radius, Transform(Vec3(0)));
    radius->addComponent(radiusCenter);
    radiusCenter->attachGeometry(bodyGeometry.clone());

    // Configure the model.
    State& state = model.initSystem();
    // Fix the shoulder at its default angle and begin with the elbow flexed.
    shoulder->getCoordinate().setLocked(state, true);
    elbow->getCoordinate().setValue(state, 0.5 * Pi);
    model.equilibrateMuscles(state);

    // Configure the visualizer.
    model.updMatterSubsystem().setShowDefaultGeometry(true);
    Visualizer& viz = model.updVisualizer().updSimbodyVisualizer();
    viz.setBackgroundType(viz.SolidColor);
    viz.setBackgroundColor(White);

    // Simulate.
    simulate(model, state, 5.0);

    return 0;
};

Python

Let's simulate a simple arm whose elbow is actuated by a muscle, using the Python interface.

import opensim as osim 

arm = osim.Model()
arm.setName("bicep_curl")
arm.setUseVisualizer(True)

# ---------------------------------------------------------------------------
# Create two links, each with a mass of 1 kg, center of mass at the body's
# origin, and moments and products of inertia corresponding to an ellipsoid
# with radii of 0.1, 0.5 and 0.1, in the x, y and z directions, respectively.
# ---------------------------------------------------------------------------

humerus = osim.Body("humerus",
                    1.0,
                    osim.Vec3(0),
                    osim.Inertia(0.052, 0.004, 0.052))
radius = osim.Body("radius",
                   1.0,
                   osim.Vec3(0),
                   osim.Inertia(0.052, 0.004, 0.052))

# ---------------------------------------------------------------------------
# Connect the bodies with pin joints. Assume each body is 1m long.
# ---------------------------------------------------------------------------

shoulder = osim.PinJoint("shoulder",
                         arm.getGround(), # PhysicalFrame
                         osim.Vec3(0),
                         osim.Vec3(0),
                         humerus, # PhysicalFrame
                         osim.Vec3(0, 0.5, 0),
                         osim.Vec3(0))

elbow = osim.PinJoint("elbow",
                      humerus, # PhysicalFrame
                      osim.Vec3(0, -0.5, 0),
                      osim.Vec3(0),
                      radius, # PhysicalFrame
                      osim.Vec3(0, 0.5, 0),
                      osim.Vec3(0))

# ---------------------------------------------------------------------------
# Add a muscle that flexes the elbow (actuator for robotics people).
# ---------------------------------------------------------------------------

biceps = osim.Millard2012EquilibriumMuscle("biceps",  # Muscle name
                                           100.0,  # Max isometric force
                                           0.6,  # Optimal fibre length
                                           0.55,  # Tendon slack length
                                           0.0)  # Pennation angle
biceps.addNewPathPoint("origin",
                       humerus,
                       osim.Vec3(0, 0.3, 0))

biceps.addNewPathPoint("insertion",
                       radius,
                       osim.Vec3(0, 0.2, 0))

# ---------------------------------------------------------------------------
# Add a controller that specifies the excitation of the muscle.
# ---------------------------------------------------------------------------

brain = osim.PrescribedController()
brain.addActuator(biceps)
brain.prescribeControlForActuator("biceps",
                                  osim.StepFunction(0.5, 3.0, 0.3, 1.0))

# ---------------------------------------------------------------------------
# Build model with components created above.
# ---------------------------------------------------------------------------

arm.addBody(humerus)
arm.addBody(radius)
arm.addJoint(shoulder) # Now required in OpenSim4.0
arm.addJoint(elbow)
arm.addForce(biceps)
arm.addController(brain)

# ---------------------------------------------------------------------------
# Add a console reporter to print the muscle fibre force and elbow angle.
# ---------------------------------------------------------------------------

# We want to write our simulation results to the console.
reporter = osim.ConsoleReporter()
reporter.set_report_time_interval(1.0)
reporter.addToReport(biceps.getOutput("fiber_force"))
elbow_coord = elbow.getCoordinate().getOutput("value")
reporter.addToReport(elbow_coord, "elbow_angle")
arm.addComponent(reporter)

# ---------------------------------------------------------------------------
# Add display geometry. 
# ---------------------------------------------------------------------------

bodyGeometry = osim.Ellipsoid(0.1, 0.5, 0.1)
bodyGeometry.setColor(osim.Vec3(0.5)) # Gray
humerusCenter = osim.PhysicalOffsetFrame()
humerusCenter.setName("humerusCenter")
humerusCenter.setParentFrame(humerus)
humerusCenter.setOffsetTransform(osim.Transform(osim.Vec3(0)))
humerus.addComponent(humerusCenter)
humerusCenter.attachGeometry(bodyGeometry.clone())

radiusCenter = osim.PhysicalOffsetFrame()
radiusCenter.setName("radiusCenter")
radiusCenter.setParentFrame(radius)
radiusCenter.setOffsetTransform(osim.Transform(osim.Vec3(0)))
radius.addComponent(radiusCenter)
radiusCenter.attachGeometry(bodyGeometry.clone())

# ---------------------------------------------------------------------------
# Configure the model.
# ---------------------------------------------------------------------------

state = arm.initSystem()
# Fix the shoulder at its default angle and begin with the elbow flexed.
shoulder.getCoordinate().setLocked(state, True)
elbow.getCoordinate().setValue(state, 0.5 * osim.SimTK_PI)
arm.equilibrateMuscles(state)

# ---------------------------------------------------------------------------
# Configure the visualizer.
# ---------------------------------------------------------------------------

viz = arm.updVisualizer().updSimbodyVisualizer()
viz.setBackgroundColor(osim.Vec3(0)) # white
viz.setGroundHeight(-2)

# ---------------------------------------------------------------------------
# Simulate.
# ---------------------------------------------------------------------------

manager = osim.Manager(arm)
state.setTime(0)
manager.initialize(state)
state = manager.integrate(5.0)

Matlab

Let's simulate a simple arm whose elbow is actuated by a muscle, using the Matlab interface.

%% Import Java libraries
import org.opensim.modeling.*

arm = Model();
arm.setName('bicep_curl');
arm.setUseVisualizer(true);

% ---------------------------------------------------------------------------
% Create two links, each with a mass of 1 kg, center of mass at the body's
% origin, and moments and products of inertia corresponding to an ellipsoid
% with radii of 0.1, 0.5 and 0.1, in the x, y and z directions, respectively.
% ---------------------------------------------------------------------------

humerus = Body('humerus',...
                    1.0,...
                    Vec3(0),...
                    Inertia(0.052, 0.004, 0.052));
radius = Body('radius',...
                   1.0,...
                   Vec3(0),...
                   Inertia(0.052, 0.004, 0.052));

% ---------------------------------------------------------------------------
% Connect the bodies with pin joints. Assume each body is 1m long.
% ---------------------------------------------------------------------------

shoulder = PinJoint('shoulder',...
                         arm.getGround(),... % PhysicalFrame
                         Vec3(0),...
                         Vec3(0),...
                         humerus,... % PhysicalFrame
                         Vec3(0, 0.5, 0),...
                         Vec3(0));

elbow = PinJoint('elbow',...
                      humerus,... % PhysicalFrame
                      Vec3(0, -0.5, 0),...
                      Vec3(0),...
                      radius,... % PhysicalFrame
                      Vec3(0, 0.5, 0),...
                      Vec3(0));

% ---------------------------------------------------------------------------
% Add a muscle that flexes the elbow (actuator for robotics people).
% ---------------------------------------------------------------------------

biceps = Millard2012EquilibriumMuscle('biceps',...  % Muscle name
                                           100.0,...  % Max isometric force
                                           0.6,...  % Optimal fibre length
                                           0.55,...  % Tendon slack length
                                           0.0);  % Pennation angle
biceps.addNewPathPoint('origin',...
                       humerus,...
                       Vec3(0, 0.3, 0));

biceps.addNewPathPoint('insertion',...
                       radius,...
                       Vec3(0, 0.2, 0));

% ---------------------------------------------------------------------------
% Add a controller that specifies the excitation of the muscle.
% ---------------------------------------------------------------------------

brain = PrescribedController();
brain.addActuator(biceps);
brain.prescribeControlForActuator('biceps',...
                                  StepFunction(0.5, 3.0, 0.3, 1.0));

% ---------------------------------------------------------------------------
% Build model with components created above.
% ---------------------------------------------------------------------------

arm.addBody(humerus);
arm.addBody(radius);
arm.addJoint(shoulder); % Now required in OpenSim4.0
arm.addJoint(elbow);
arm.addForce(biceps);
arm.addController(brain);

% ---------------------------------------------------------------------------
% Add a console reporter to print the muscle fibre force and elbow angle.
% ---------------------------------------------------------------------------

% We want to write our simulation results to the console.
reporter = ConsoleReporter();
reporter.set_report_time_interval(1.0);
reporter.addToReport(biceps.getOutput('fiber_force'));
elbow_coord = elbow.getCoordinate().getOutput('value');
reporter.addToReport(elbow_coord, 'elbow_angle');
arm.addComponent(reporter);

% ---------------------------------------------------------------------------
% Add display geometry. 
% ---------------------------------------------------------------------------

bodyGeometry = Ellipsoid(0.1, 0.5, 0.1);
bodyGeometry.setColor(Vec3(0.5)); % Gray
humerusCenter = PhysicalOffsetFrame();
humerusCenter.setName('humerusCenter');
humerusCenter.setParentFrame(humerus);
humerusCenter.setOffsetTransform(Transform(Vec3(0)));
humerus.addComponent(humerusCenter);
humerusCenter.attachGeometry(bodyGeometry.clone());

radiusCenter = PhysicalOffsetFrame();
radiusCenter.setName('radiusCenter');
radiusCenter.setParentFrame(radius);
radiusCenter.setOffsetTransform(Transform(Vec3(0)));
radius.addComponent(radiusCenter);
radiusCenter.attachGeometry(bodyGeometry.clone());

% ---------------------------------------------------------------------------
% Configure the model.
% ---------------------------------------------------------------------------

state = arm.initSystem();
% Fix the shoulder at its default angle and begin with the elbow flexed.
shoulder.getCoordinate().setLocked(state, true);
elbow.getCoordinate().setValue(state, 0.5 * pi);
arm.equilibrateMuscles(state);

% ---------------------------------------------------------------------------
% Configure the visualizer
% ---------------------------------------------------------------------------

viz = arm.updVisualizer().updSimbodyVisualizer();
viz.setBackgroundColor(Vec3(0)); % white
viz.setGroundHeight(-2)

% ---------------------------------------------------------------------------
% Simulate.
% ---------------------------------------------------------------------------

manager = Manager(arm);
state.setTime(0);
manager.initialize(state);
state = manager.integrate(5.0);

Results

The three segments of code (C++, MATLAB, Python) produce the following animation:

OpenSim Double Pendulum Muscle

and prints the following information to the console:

[reporter]
              | /forceset/bice|               |
          time| ps|fiber_force|    elbow_angle|
--------------| --------------| --------------|
           0.0|     0.59048448|      1.5707963|
           1.0|      24.574034|     0.91820573|
           2.0|      21.418144|      1.4289945|
           3.0|      17.584893|      1.5105765|
           4.0|      17.688588|      1.5090021|
           5.0|      17.590774|      1.5067387| 
Clone this wiki locally