-
Notifications
You must be signed in to change notification settings - Fork 322
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.
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;
};
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)
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);
The three segments of code (C++, MATLAB, Python) produce the following animation:
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|