Versions Compared

Key

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

...

For the display geometry to help at all, we must transform the geometry so that it aligns with how we defined the inertial properties of the bodies. Namely, we want the centroid of the cylinder to be located at the body's mass center , and for the

...

languagecpp

(+/-0.5

...

*

...

segmentalLength,

...

0,

...

0),

...

and

...

for the symmetry axis of the cylinder to be parallel to the X axis of the body's frame.

Code Block
languagecpp
SimTK::Rotation rot;
// Rotate the cylinder's symmetry (Y) axis to align with the body's X axis:
rot.setRotationFromAngleAboutZ(0.5 * Pi);
// Tranform combines rotation and translation:
anteriorDisplay->setTransform(
        SimTK::Transform(rot, Vec3(-0.5 * segmentalLength, 0, 0)));
anteriorDisplay->setScaleFactors(
        Vec3(segmentalDiam, segmentalLength, segmentalDiam));
anteriorBody->updDisplayer()->updGeometrySet().adoptAndAppend(anteriorDisplay);
anteriorBody->updDisplayer()->setShowAxes(true);

// Posterior body
// ``````````````
DisplayGeometry * posteriorDisplay = new DisplayGeometry("cylinder.vtp");
posteriorDisplay->setOpacity(0.5);
posteriorDisplay->setColor(Vec3(0.7, 0.7, 0.7));

posteriorDisplay->setTransform(
        SimTK::Transform(rot, Vec3(0.5 * segmentalLength, 0, 0)));
posteriorDisplay->setScaleFactors(
        Vec3(segmentalDiam, segmentalLength, segmentalDiam));
posteriorBody->updDisplayer()->updGeometrySet().adoptAndAppend(posteriorDisplay);
posteriorBody->updDisplayer()->setShowAxes(true);

A.4: Actuation

...

...

Since

...

the

...

coordinates

...

between

...

the

...

segments

...

are

...

angles,

...

the

...

actuators

...

are

...

effectively

...

torque

...

actuators.

...

The

...

reason

...

to

...

use

...

a

...

CoordinateActuator

...

instead

...

of

...

a

...

TorqueActuator

...

is

...

that

...

for

...

a

...

CoordinateActuator

...

we

...

needn't

...

specify

...

the

...

axis

...

of

...

the

...

actuation,

...

or

...

the

...

bodies

...

on

...

which

...

it

...

acts.

...

Code Block
languagecpp
using OpenSim::CoordinateActuator;
// hunch
CoordinateActuator * hunchAct = new CoordinateActuator("hunch");
hunchAct->setName("hunch_actuator");
hunchAct->setMinControl(-maxTorque);
hunchAct->setMaxControl(maxTorque);
cat.addForce(hunchAct);
// wag
CoordinateActuator * wagAct = new CoordinateActuator("wag");
wagAct->setName("wag_actuator");
wagAct->setMinControl(-maxTorque);
wagAct->setMaxControl(maxTorque);
cat.addForce(wagAct);

We're done making the first model! Print it (serialize) to a file.

Code Block
languagecpp
cat.print("flippinfelines_hunch_wag.osim");

B: Second model: adding legs for the variable-inertia mechanism of flipping

This model will be able to twist, and also has legs. Most of the set-up for

...

this model has already been done. Many of the objects and variables defined above are simply updated or renamed.

Code Block
languagecpp
// First model: exhibiting the counter-rotation mechanism of flipping
// ========================================================================
// ********** PART A   ********** 	

// Second model: adding legs for the variable-inertia mechanism of flipping
// ========================================================================
// ********** PART B ********** 	        	            	                
    
// Define leg bodies
// ------------------------------------------------------------------------
// ********** PART B.1 **********

// Define leg joints (i.e., between legs and two halves of cat)
// ------------------------------------------------------------------------
// ********** PART B.2 ********** 	                    
    
// Display geometry
// ------------------------------------------------------------------------
// ********** PART B.3 ********** 	            
    
// Actuation
// ------------------------------------------------------------------------
// ********** PART B.4 ********** 	            
    
// Enforce joint limits on the legs
// ------------------------------------------------------------------------
// ********** PART B.5 ********** 	            
Code Block
languagecpp
// 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

The twist

...

degree of freedom was defined already. Now, we just need to unlock it and add a corresponding actuator.

Code Block
languagecpp
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

...

  // kg

B.1: Define leg bodies

We model the legs as having the same shape as the anterior and posterior halves; just scaled down. We model the cat's 4 legs using just 2 bodies: one body for both front legs, and another for the back legs.

Code Block
languagecpp
// 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)

...

languagecpp

...

Note the definition of orientALegsInLegs. We 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, we position the leg's long (X) axis normal to the half of the cat.

Code Block
languagecpp
using OpenSim::PinJoint;
// Anterior leg
// ````````````
Vec3 locALegsInAnterior(-0.75 * segmentalLength, 0.5 * segmentalDiam, 0);
Vec3 orientALegsInAnterior(0);
Vec3 locALegsInLegs(0);
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);

The posterior leg joint is defined similarly.

Code Block
languagecpp
// Posterior leg
// `````````````
Vec3 locPLegsInPosterior(0.75 * segmentalLength, 0.5 * segmentalDiam, 0);
Vec3 orientPLegsInPosterior(0, Pi, 0);
Vec3 locPLegsInLegs(0);
Vec3 orientPLegsInLegs(0, 0, -0.5 * Pi);

PinJoint * posteriorToLegs = new PinJoint("posterior_legs",
        *posteriorBody, locPLegsInPosterior, orientPLegsInPosterior,
        *posteriorLegs, locPLegsInLegs, orientPLegsInLegs);
CoordinateSet & posteriorToLegsCS = posteriorToLegs->upd_CoordinateSet();
posteriorToLegsCS[0].setName("backLegs");
double posteriorToLegsCS0range[2] = {-0.5 * Pi, 0.5 * Pi};
posteriorToLegsCS[0].setRange(posteriorToLegsCS0range);
posteriorToLegsCS[0].setDefaultValue(-pitch);
posteriorToLegsCS[0].setDefaultLocked(false);

Now that we've defined the joints, we can add the bodies.

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

...

B.3: Display geometry

We give both legs the same display geometry. We needn't create two DisplayGeometry objects.

Code Block
languagecpp
// 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.5: Enforce joint limits on the legs

In playing around with models, it became evident that actually enforcing reasonable joint limits on the legs would be helpful. These objects apply a restorative force about the corresponding coordinate when the coordinate goes outside its range. The range for both of these coordinates is [-90 ,  90] degrees.

Code Block
languagecpp
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);
Code Block
languagecpp
cat.print("flippinfelines_hunch_wag_twist_legs.osim");

Let's put these cats to use!