Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
Body & ground = cat.getGroundBody();

// Anterior body to the ground via a CustomJoint
// `````````````````````````````````````````````
using OpenSim::CustomJoint;
// Rotation is defined via YZX Euler angles, named yaw, pitch, and
// roll respectively.
Vec3 locGAInGround(0);
Vec3 orientGAInGround(0);
Vec3
locGAInAnterior(0);
Vec3 orientGAInAnterior(0);

// To pass to the CustomJoint (farther down), define a SpatialTransform.
// The SpatialTransfrom has 6 transform axes. The first 3 are rotations,
// defined about the axes of our choosing. The remaining 3 are translations,
// which we choose to be along the X, Y, and Z directions of the ground's
// frame.
using OpenSim::Array;
OpenSim::SpatialTransform groundAnteriorST;
groundAnteriorST.updTransformAxis(0).setCoordinateNames(
        Array<std::string>("yaw", 1));
groundAnteriorST.updTransformAxis(0).setAxis(Vec3(0, 1, 0));
groundAnteriorST.updTransformAxis(1).setCoordinateNames(
        Array<std::string>("pitch", 1));
groundAnteriorST.updTransformAxis(1).setAxis(Vec3(0, 0, 1));
groundAnteriorST.updTransformAxis(2).setCoordinateNames(
        Array<std::string>("roll", 1));
groundAnteriorST.updTransformAxis(2).setAxis(Vec3(1, 0, 0));
groundAnteriorST.updTransformAxis(3).setCoordinateNames(
        Array<std::string>("tx", 1));
groundAnteriorST.updTransformAxis(3).setAxis(Vec3(1, 0, 0));
groundAnteriorST.updTransformAxis(4).setCoordinateNames(
        Array<std::string>("ty", 1));
groundAnteriorST.updTransformAxis(4).setAxis(Vec3(0, 1, 0));
groundAnteriorST.updTransformAxis(5).setCoordinateNames(
        Array<std::string>("tz", 1));
groundAnteriorST.updTransformAxis(5).setAxis(Vec3(0, 0, 1));

Vec3 locGAInGround(0);
Vec3 orientGAInGround(0);
Vec3 locGAInAnterior(0);
Vec3 orientGAInAnterior(0);

CustomJoint * groundAnterior = new CustomJoint("ground_anterior",
        ground, locGAInGround, orientGAInGround,
        *anteriorBody, locGAInAnterior, orientGAInAnterior,
        groundAnteriorST);

// Edit the Coordinate's created by the CustomJoint. The 6 coordinates
// correspond to the TransformAxis's we set above.
using OpenSim::CoordinateSet;
using SimTK::convertDegreesToRadians;
using SimTK::Pi;
CoordinateSet & groundAnteriorCS = groundAnterior->upd_CoordinateSet();
// yaw
// As is, the range only affects how one can vary this coordinate in the
// GUI. The range is not a joint limit, and does not affect dynamics.
double groundAnteriorCS0range[2] = {-Pi, Pi};
groundAnteriorCS[0].setRange(groundAnteriorCS0range);
groundAnteriorCS[0].setDefaultValue(0);
groundAnteriorCS[0].setDefaultLocked(false);
// pitch
double groundAnteriorCS1range[2] = {-Pi, Pi};
groundAnteriorCS[1].setRange(groundAnteriorCS1range);
groundAnteriorCS[1].setDefaultValue(convertDegreesToRadians(-15));
groundAnteriorCS[1].setDefaultLocked(false);
// roll
double groundAnteriorCS2range[2] = {-Pi, Pi};
groundAnteriorCS[2].setRange(groundAnteriorCS2range);
groundAnteriorCS[2].setDefaultValue(0);
groundAnteriorCS[2].setDefaultLocked(false);
// tx
double groundAnteriorCS3range[2] = {-1, 1};
groundAnteriorCS[3].setRange(groundAnteriorCS3range);
groundAnteriorCS[3].setDefaultValue(0);
groundAnteriorCS[3].setDefaultLocked(false);
// ty
double groundAnteriorCS4range[2] = {-1, 5};
groundAnteriorCS[4].setRange(groundAnteriorCS4range);
groundAnteriorCS[4].setDefaultValue(0);
groundAnteriorCS[4].setDefaultLocked(false);
// tz
double groundAnteriorCS5range[2] = {-1, 1};
groundAnteriorCS[5].setRange(groundAnteriorCS5range);
groundAnteriorCS[5].setDefaultValue(0);
groundAnteriorCS[5].setDefaultLocked(false); 
Code Block
// Anterior to posterior body via a CustomJoint
// ````````````````````````````````````````````
// Rotation is defined via ZYX Euler angles.
Vec3
locAPInAnterior(0);
Vec3 orientAPInAnterior(0);
Vec3 locAPInPosterior(0);
Vec3 orientAPInPosterior(0);

OpenSim::SpatialTransform anteriorPosteriorST;
anteriorPosteriorST.updTransformAxis(0).setCoordinateNames(
        Array<std::string>("hunch", 1));
anteriorPosteriorST.updTransformAxis(0).setAxis(Vec3(0, 0, 1));
anteriorPosteriorST.updTransformAxis(1).setCoordinateNames(
        Array<std::string>("wag", 1));
anteriorPosteriorST.updTransformAxis(1).setAxis(Vec3(0, 1, 0));
anteriorPosteriorST.updTransformAxis(2).setCoordinateNames(
        Array<std::string>("twist", 1));
anteriorPosteriorST.updTransformAxis(2).setAxis(Vec3(1, 0, 0));
// There is no translation between the segments, and so we do not name the
// remaining 3 TransformAxis's in the SpatialTransform.

Vec3 locAPInAnterior(0);
Vec3 orientAPInAnterior(0);
Vec3 locAPInPosterior(0);
Vec3 orientAPInPosterior(0);

CustomJoint * anteriorPosterior = new CustomJoint("anterior_posterior",
        *anteriorBody, locAPInAnterior, orientAPInAnterior,
        *posteriorBody, locAPInPosterior, orientAPInPosterior,
        anteriorPosteriorST);

// Set coordinate limits and default values from empirical data (i.e.,
// photos & video).
CoordinateSet & anteriorPosteriorCS = anteriorPosterior->upd_CoordinateSet();
// hunch: [-20, +90] degrees
double anteriorPosteriorCS0range[2] = {convertDegreesToRadians(-20),
                                       convertDegreesToRadians(90)};
anteriorPosteriorCS[0].setRange(anteriorPosteriorCS0range);
anteriorPosteriorCS[0].setDefaultValue(convertDegreesToRadians(30));
anteriorPosteriorCS[0].setDefaultLocked(false);
// wag: [-45, 45] degrees
double anteriorPosteriorCS1range[2] = {-0.25 * Pi, 0.25 * Pi};
anteriorPosteriorCS[1].setRange(anteriorPosteriorCS1range);
anteriorPosteriorCS[1].setDefaultValue(0);
anteriorPosteriorCS[1].setDefaultLocked(false);
// twist: [-80, 80] degrees
double anteriorPosteriorCS2range[2] = {convertDegreesToRadians(-80),
                                       convertDegreesToRadians(80)};
anteriorPosteriorCS[2].setRange(anteriorPosteriorCS2range);
anteriorPosteriorCS[2].setDefaultValue(0);
// This first model can't twist; we'll unlock this for the next model.
anteriorPosteriorCS[2].setDefaultLocked(true);

...

Code Block
// NOTE: Most of the set-up for this model has already been done. Many of
// ----  the variables defined above are simply updated or renamed below.

// This model will additionally be able to twist, and has legs.
cat.setName("Leland_hunch_wag_twist_legs");

// Allow twist.
anteriorPosteriorCS[2].setDefaultLocked(false);
CoordinateActuator * twistAct = new CoordinateActuator("twist");
twistAct->setName("twist_actuator");
twistAct->setMinControl(-maxTorque);
twistAct->setMaxControl(maxTorque);
cat.addForce(twistAct);

// Leg properties
// ------------------------------------------------------------------------
double legsLength = 0.125;                             // m
double legsDiam = 0.1 * legsLength;                    // m
// Sum of both legs (60% distance across the belly):
double legsWidth = 0.6 * segmentalDiam;                // m
double legsMass = 0.2;                                 // kg

B.1: Define leg bodies

Code Block
// Scale the segmental inertia.
Inertia legsInertia = (legsMass/segmentalMass) * segmentalInertia;

// Anterior and posterior legs.
Body * anteriorLegs = new Body();
anteriorLegs->setName("anteriorLegs");
anteriorLegs->setMass(legsMass);
anteriorLegs->setMassCenter(Vec3(0.5 * legsLength, 0, 0));
anteriorLegs->setInertia(legsInertia);

Body * posteriorLegs = new Body();
posteriorLegs->setName("posteriorLegs");
posteriorLegs->setMass(legsMass);
posteriorLegs->setMassCenter(Vec3(0.5 * legsLength, 0, 0));
posteriorLegs->setInertia(legsInertia); 

B.2: Define leg joints (i.e., between legs and two halves of cat)

Code Block
using OpenSim::PinJoint;
// Anterior leg
// ````````````
Vec3 locALegsInAnterior(-0.75 * segmentalLength, 0.5 * segmentalDiam, 0);
Vec3 orientALegsInAnterior(0);
Vec3 locALegsInLegs(0);
// Rotate the leg about what will become the pin-joint axis (the leg's
// Z axis) so that it points straight out from the belly when leg angle
// is 0. In other words, position the leg's long (X) axis normal to the
// half of the cat.
Vec3 orientALegsInLegs(0, 0, -0.5 * Pi);

PinJoint * anteriorToLegs = new PinJoint("anterior_legs",
        *anteriorBody, locALegsInAnterior, orientALegsInAnterior,
        *anteriorLegs, locALegsInLegs, orientALegsInLegs);
CoordinateSet & anteriorToLegsCS = anteriorToLegs->upd_CoordinateSet();
anteriorToLegsCS[0].setName("frontLegs");
double anteriorToLegsCS0range[2] = {-0.5 * Pi, 0.5 * Pi};
anteriorToLegsCS[0].setRange(anteriorToLegsCS0range);
// So that the legs are directed strictly upwards initially:
double pitch = groundAnteriorCS[1].getDefaultValue();
anteriorToLegsCS[0].setDefaultValue(-pitch);
anteriorToLegsCS[0].setDefaultLocked(false);

...

Code Block
cat.addBody(anteriorLegs);
cat.addBody(posteriorLegs);

B.3: Display geometry

Code Block
// Both legs have the same display geometry.
// 'box.vtp' is in the Geometry folder of an OpenSim installation.
DisplayGeometry legsDisplay = DisplayGeometry("box.vtp");
legsDisplay.setOpacity(0.5);
legsDisplay.setColor(Vec3(0.7, 0.7, 0.7));
legsDisplay.setTransform(Transform(Vec3(0.3 * legsLength, 0, 0)));
legsDisplay.setScaleFactors(Vec3(legsLength, legsDiam, legsWidth));

anteriorLegs->updDisplayer()->updGeometrySet().cloneAndAppend(legsDisplay);
anteriorLegs->updDisplayer()->setShowAxes(true);

posteriorLegs->updDisplayer()->updGeometrySet().cloneAndAppend(legsDisplay);
posteriorLegs->updDisplayer()->setShowAxes(true); 

B.4: Actuation

Code Block
// front legs.
CoordinateActuator * frontLegsAct = new CoordinateActuator("frontLegs");
frontLegsAct->setName("frontLegs_actuator");
frontLegsAct->setMinControl(-maxTorque);
frontLegsAct->setMaxControl(maxTorque);
cat.addForce(frontLegsAct);

// back legs.
CoordinateActuator * backLegsAct = new CoordinateActuator("backLegs");
backLegsAct->setName("backLegs_actuator");
backLegsAct->setMinControl(-maxTorque);
backLegsAct->setMaxControl(maxTorque);
cat.addForce(backLegsAct);

B.5: Enforce joint limits on the legs

Code Block
using OpenSim::CoordinateLimitForce;

CoordinateLimitForce * frontLegsLimitForce = new CoordinateLimitForce(
            "frontLegs", 90, 1.0E2, -90, 1.0E2, 1.0E1, 2.0, false);
cat.addForce(frontLegsLimitForce);

CoordinateLimitForce * backLegsLimitForce = new CoordinateLimitForce(
            "backLegs", 90, 1.0E2, -90, 1.0E2, 1.0E1, 2.0, false);
cat.addForce(backLegsLimitForce);

...