コード例 #1
0
Model* constructPendulumWithMarkers()
{
    Model* pendulum = new Model();
    pendulum->setName("pendulum");
    Body* ball =
        new Body("ball", 1.0, SimTK::Vec3(0), SimTK::Inertia::sphere(0.05));
    pendulum->addBody(ball);

    // PinJoint hinge is 1m above ground origin and 1m above the ball in the ball
    // reference frame such that the ball center is at the origin with the hinge
    // angle is zero
    PinJoint* hinge = new PinJoint("hinge", pendulum->getGround(),
        SimTK::Vec3(0, 1.0, 0), SimTK::Vec3(0),
        *ball, SimTK::Vec3(0, 1.0, 0), SimTK::Vec3(0));
    hinge->updCoordinate().setName("theta");
    pendulum->addJoint(hinge);

    // Add Markers
    Marker*m0 = new Marker();
    m0->setName("m0");
    m0->setParentFrame(*ball);
    m0->set_location(SimTK::Vec3(0));
    pendulum->addMarker(m0);
    
    // Shifted Right 1cm
    Marker*mR = new Marker();
    mR->setName("mR");
    mR->setParentFrame(*ball);
    mR->set_location(SimTK::Vec3(0.01, 0, 0));
    pendulum->addMarker(mR);
    
    // Shifted Left 2cm
    Marker*mL = new Marker();
    mL->setName("mL");
    mL->setParentFrame(*ball);
    mL->set_location(SimTK::Vec3(-0.02, 0, 0));
    pendulum->addMarker(mL);

    return pendulum;
}
コード例 #2
0
//=============================================================================
// Simbody Model building.
//=============================================================================
//_____________________________________________________________________________
void PinJoint::addToSystem(SimTK::MultibodySystem& system) const
{
	const SimTK::Vec3& orientation = getProperty_orientation().getValue();
	const SimTK::Vec3& location = getProperty_location().getValue();

	// CHILD TRANSFORM
	Rotation rotation(BodyRotationSequence, orientation[0],XAxis, orientation[1],YAxis, orientation[2],ZAxis);
	SimTK::Transform childTransform(rotation, location);

	const SimTK::Vec3& orientationInParent = getProperty_orientation_in_parent().getValue();
	const SimTK::Vec3& locationInParent = getProperty_location_in_parent().getValue();

	// PARENT TRANSFORM
	Rotation parentRotation(BodyRotationSequence, orientationInParent[0],XAxis, orientationInParent[1],YAxis, orientationInParent[2],ZAxis);
	SimTK::Transform parentTransform(parentRotation, locationInParent);

	PinJoint* mutableThis = const_cast<PinJoint*>(this);
	mutableThis->createMobilizedBody(parentTransform, childTransform);

    // TODO: Joints require super class to be called last.
    Super::addToSystem(system);
}
コード例 #3
0
Model* constructLegWithOrientationFrames()
{
    std::unique_ptr<Model> leg{ new Model() };
    leg->setName("leg");
    Body* thigh =
        new Body("thigh", 5.0, SimTK::Vec3(0),
                 SimTK::Inertia::cylinderAlongY(0.1, 0.5) );
    leg->addBody(thigh);
    Body* shank =
        new Body("shank", 2.0, SimTK::Vec3(0),
                 SimTK::Inertia::cylinderAlongY(0.04, 0.4) );
    leg->addBody(shank);
    Body* foot =
        new Body("foot", 1.0, SimTK::Vec3(0),
            SimTK::Inertia::cylinderAlongY(0.02, 0.1));
    leg->addBody(foot);


    // PinJoint hip is 1m above ground origin and 1m above the ball in the ball
    // reference frame such that the ball center is at the origin with the hinge
    // angle is zero
    PinJoint* hip = new PinJoint("hip", leg->getGround(),
        SimTK::Vec3(0, 1.0, 0), SimTK::Vec3(0),
        *thigh, SimTK::Vec3(0, 0.25, 0), SimTK::Vec3(0));
    hip->updCoordinate().setName("flex");
    leg->addJoint(hip);

    PinJoint* knee = new PinJoint("knee", *thigh,
        SimTK::Vec3(0, -0.25, 0), SimTK::Vec3(0),
        *shank, SimTK::Vec3(0, 0.2, 0), SimTK::Vec3(0));
    knee->updCoordinate().setName("flex");
    leg->addJoint(knee);

    PinJoint* ankle = new PinJoint("ankle", *shank,
        SimTK::Vec3(0, -0.2, 0), SimTK::Vec3(0),
        *foot, SimTK::Vec3(0, 0.1, 0), SimTK::Vec3(0));
    ankle->updCoordinate().setName("flex");
    leg->addJoint(ankle);

    // Add Orientation Sensor Frames
    SimTK::Transform offset(SimTK::Rotation(0.378, SimTK::YAxis) );
    thigh->addComponent(new PhysicalOffsetFrame("thigh_imu", *thigh, offset));
    shank->addComponent(new PhysicalOffsetFrame("shank_imu", *shank, offset));
    foot->addComponent(new PhysicalOffsetFrame("foot_imu", *foot, offset));

    return leg.release();
}
コード例 #4
0
/**
 * Run a simulation of block sliding with contact on by two muscles sliding with contact 
 */
int main()
{

	try {
		// Create a new OpenSim model
		Model osimModel;
		osimModel.setName("osimModel");

		double Pi = SimTK::Pi;
		
		
		// Get the ground body
		OpenSim::Body& ground = osimModel.getGroundBody();
		ground.addDisplayGeometry("checkered_floor.vtp");

		// create linkage body
		double linkageMass = 0.001, linkageLength = 0.5, linkageDiameter = 0.06;
		
		Vec3 linkageDimensions(linkageDiameter, linkageLength, linkageDiameter);
		Vec3 linkageMassCenter(0,linkageLength/2,0);
		Inertia linkageInertia = Inertia::cylinderAlongY(linkageDiameter/2.0, linkageLength/2.0);

		OpenSim::Body* linkage1 = new OpenSim::Body("linkage1", linkageMass, linkageMassCenter, linkageMass*linkageInertia);

		// Graphical representation
		linkage1->addDisplayGeometry("cylinder.vtp");
		//This cylinder.vtp geometry is 1 meter tall, 1 meter diameter.  Scale and shift it to look pretty
		GeometrySet& geometry = linkage1->updDisplayer()->updGeometrySet();
		DisplayGeometry& thinCylinder = geometry[0];
		thinCylinder.setScaleFactors(linkageDimensions);
		thinCylinder.setTransform(Transform(Vec3(0.0,linkageLength/2.0,0.0)));
		linkage1->addDisplayGeometry("sphere.vtp");
		//This sphere.vtp is 1 meter in diameter.  Scale it.
		geometry[1].setScaleFactors(Vec3(0.1));
		
		// Creat a second linkage body
		OpenSim::Body* linkage2 = new OpenSim::Body(*linkage1);
		linkage2->setName("linkage2");

		// Creat a block to be the pelvis
		double blockMass = 20.0, blockSideLength = 0.2;
		Vec3 blockMassCenter(0);
		Inertia blockInertia = blockMass*Inertia::brick(blockSideLength, blockSideLength, blockSideLength);
		OpenSim::Body *block = new OpenSim::Body("block", blockMass, blockMassCenter, blockInertia);
		block->addDisplayGeometry("block.vtp");
		//This block.vtp is 0.1x0.1x0.1 meters.  scale its appearance
		block->updDisplayer()->updGeometrySet()[0].setScaleFactors(Vec3(2.0));

		// Create 1 degree-of-freedom pin joints between the bodies to creat a kinematic chain from ground through the block
		
		Vec3 orientationInGround(0), locationInGround(0), locationInParent(0.0, linkageLength, 0.0), orientationInChild(0), locationInChild(0);

		PinJoint *ankle = new PinJoint("ankle", ground, locationInGround, orientationInGround, *linkage1, 
			locationInChild, orientationInChild);

		PinJoint *knee = new PinJoint("knee", *linkage1, locationInParent, orientationInChild, *linkage2,
			locationInChild, orientationInChild);

		PinJoint *hip = new PinJoint("hip", *linkage2, locationInParent, orientationInChild, *block,
			locationInChild, orientationInChild);
		
		double range[2] = {-SimTK::Pi*2, SimTK::Pi*2};
		CoordinateSet& ankleCoordinateSet = ankle->upd_CoordinateSet();
		ankleCoordinateSet[0].setName("q1");
		ankleCoordinateSet[0].setRange(range);

		CoordinateSet& kneeCoordinateSet = knee->upd_CoordinateSet();
		kneeCoordinateSet[0].setName("q2");
		kneeCoordinateSet[0].setRange(range);

		CoordinateSet& hipCoordinateSet = hip->upd_CoordinateSet();
		hipCoordinateSet[0].setName("q3");
		hipCoordinateSet[0].setRange(range);

		// Add the bodies to the model
		osimModel.addBody(linkage1);
		osimModel.addBody(linkage2);
		osimModel.addBody(block);

		// Define contraints on the model
		//  Add a point on line constraint to limit the block to vertical motion

		Vec3 lineDirection(0,1,0), pointOnLine(0,0,0), pointOnBlock(0);
		PointOnLineConstraint *lineConstraint = new PointOnLineConstraint(ground, lineDirection, pointOnLine, *block, pointOnBlock);
		osimModel.addConstraint(lineConstraint);

		// Add PistonActuator between the first linkage and the block
		Vec3 pointOnBodies(0);
		PistonActuator *piston = new PistonActuator();
		piston->setName("piston");
		piston->setBodyA(linkage1);
		piston->setBodyB(block);
		piston->setPointA(pointOnBodies);
		piston->setPointB(pointOnBodies);
		piston->setOptimalForce(200.0);
		piston->setPointsAreGlobal(false);

		osimModel.addForce(piston);
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Added ControllableSpring between the first linkage and the second block
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		ControllableSpring *spring = new ControllableSpring;
		spring->setName("spring");
		spring->setBodyA(block);
		spring->setBodyB(linkage1);
		spring->setPointA(pointOnBodies);
		spring->setPointB(pointOnBodies);
		spring->setOptimalForce(2000.0);
		spring->setPointsAreGlobal(false);
		spring->setRestLength(0.8);

		osimModel.addForce(spring);

		// define the simulation times
		double t0(0.0), tf(15);

		// create a controller to control the piston and spring actuators
		// the prescribed controller sets the controls as functions of time
		PrescribedController *legController = new PrescribedController();
		// give the legController control over all (two) model actuators
		legController->setActuators(osimModel.updActuators());

		// specify some control nodes for spring stiffness control
		double t[] = {0.0, 4.0, 7.0,  10.0, 15.0};
        double x[] = {1.0, 1.0, 0.25,  0.25, 5.0};

		// specify the control function for each actuator
		legController->prescribeControlForActuator("piston", new Constant(0.1));
		legController->prescribeControlForActuator("spring", new PiecewiseLinearFunction(5, t, x));

		// add the controller to the model
		osimModel.addController(legController);		
		
		// define the acceration due to gravity
		osimModel.setGravity(Vec3(0, -9.80665, 0));

		// enable the model visualizer see the model in action, which can be
		// useful for debugging
		osimModel.setUseVisualizer(true);

		// Initialize system
		SimTK::State& si = osimModel.initSystem();
		
		// Pin joint initial states
		double q1_i = -Pi/4;
		double q2_i = - 2*q1_i;
		CoordinateSet &coordinates = osimModel.updCoordinateSet();
		coordinates[0].setValue(si, q1_i, true);
		coordinates[1].setValue(si,q2_i, true);

		// Setup integrator and manager
		SimTK::RungeKuttaMersonIntegrator integrator(osimModel.getMultibodySystem());
		integrator.setAccuracy(1.0e-3);

		ForceReporter *forces = new ForceReporter(&osimModel);	
		osimModel.updAnalysisSet().adoptAndAppend(forces);
		Manager manager(osimModel, integrator);
	
		//Examine the model
		osimModel.printDetailedInfo(si, std::cout);
		// Save the model
		osimModel.print("toyLeg.osim");
		// Print out the initial position and velocity states
		si.getQ().dump("Initial q's");
		si.getU().dump("Initial u's");
		std::cout << "Initial time: " << si.getTime() << std::endl;

		// Integrate
		manager.setInitialTime(t0);
		manager.setFinalTime(tf);
		std::cout<<"\n\nIntegrating from " << t0 << " to " << tf << std::endl;
		manager.integrate(si);

		// Save results
		osimModel.printControlStorage("SpringActuatedLeg_controls.sto");
		Storage statesDegrees(manager.getStateStorage());
		osimModel.updSimbodyEngine().convertRadiansToDegrees(statesDegrees);
		//statesDegrees.print("PistonActuatedLeg_states_degrees.mot");
		statesDegrees.print("SpringActuatedLeg_states_degrees.mot");

		forces->getForceStorage().print("actuator_forces.mot");
		
	}
    catch (const std::exception& ex)
    {
        std::cout << "Exception in toyLeg_example: " << ex.what() << std::endl;
        return 1;
    }

	std::cout << "Exiting" << std::endl;
	return 0;
}
コード例 #5
0
ファイル: modeling.cpp プロジェクト: chrisdembia/feliscatus
/**
 * Creates two cat models for flipping. The first is simply two segments
 * connected by a 2-degree-of-freedom (no twist) joint. It exhibits the
 * counter-rotation mechanism of flipping. The second adds actuate-able
 * legs to the first model, as well as unlocking the twist degree of
 * freedom between the model's two halves. This model exhibits the variable-
 * inertia mechanism of flipping.
 * */
int main(int argc, char *argv[])
{
    // First model: exhibiting the counter-rotation mechanism of flipping
    // ========================================================================

    // Properties
    // ------------------------------------------------------------------------
    double segmentalLength = 0.175;		                   // m
    double segmentalDiam = 0.15;			               // m
    double segmentalMass = 1;				               // kg
    double segmentalTransverseMomentOfInertia = 1;         // kg-m^2
    
    // Ratio of transverse to axial moment of inertia (Kane and Scher, 1969):
    double JIratio = 0.25;
    
    // For actuators:
	double maxTorque = 40.0;                               // N-m


    // Basics
    // ------------------------------------------------------------------------
    // Create the cat model.
    OpenSim::Model cat;

    // Name the cat after the founder of Stanford University.
    // This model will be able to hunch and wag (see the joints below).
    cat.setName("Leland_hunch_wag");

    // 'Turn off' gravity so it's easier to watch an animation of the flip.
    using SimTK::Vec3;
    cat.setGravity(Vec3(0, 0, 0));


    // Define anterior and posterior halves of the cat
    // ------------------------------------------------------------------------
    // Prepare inertia properties for the 2 primary segments of the cat.
    double segmentalAxialMomentOfInertia = JIratio * segmentalTransverseMomentOfInertia;
    double Ixx = segmentalAxialMomentOfInertia;
    double Iyy = segmentalTransverseMomentOfInertia;
    double Izz = segmentalTransverseMomentOfInertia;
    double Ixy = 0;
    double Ixz = 0;
    double Iyz = 0;
    using SimTK::Inertia;
    Inertia segmentalInertia = Inertia(Ixx, Iyy, Izz, Ixz, Ixz, Iyz);

    // Anterior half of cat.
    using OpenSim::Body;
    Body * anteriorBody = new Body();
    anteriorBody->setName("anteriorBody");
    anteriorBody->setMass(segmentalMass);
    // By choosing the following as the mass center, we choose the origin of
    // the anteriorBody frame to be at the body's positive-X extent. That is,
    // the anterior body sits to the -X direction from its origin.
    anteriorBody->setMassCenter(Vec3(-0.5 * segmentalLength, 0, 0));
    anteriorBody->setInertia(segmentalInertia);

    // Posterior half of cat (same mass properties as anterior half).
    Body * posteriorBody = new Body();
    posteriorBody->setName("posteriorBody");
    posteriorBody->setMass(segmentalMass);
    // Posterior body sits to the +X direction from its origin.
    posteriorBody->setMassCenter(Vec3(0.5 * segmentalLength, 0, 0));
    posteriorBody->setInertia(segmentalInertia);


    // Define joints between bodies (ground and two halves)
    // ------------------------------------------------------------------------
    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.

    // 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);

    // Anterior to posterior body via a CustomJoint
    // ````````````````````````````````````````````
	// Rotation is defined via ZYX Euler angles.

    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);


    // Add bodies to the model
    // ------------------------------------------------------------------------
    // ...now that we have connected the bodies via joints.
    cat.addBody(anteriorBody);
    cat.addBody(posteriorBody);


    // Display geometry
    // ------------------------------------------------------------------------
    using OpenSim::DisplayGeometry;
    // So that we can see what the cat's up to.
    // By default, the cylinder has a diameter of 1 meter, height of 1 meter,
    // its centroid is at (0, 0, 0) (its origin), and its axis of symmetry is
    // its Y axis.

    // Anterior body
    // `````````````
    // 'cylinder.vtp' is in the Geometry folder of an OpenSim installation.
    DisplayGeometry * anteriorDisplay = new DisplayGeometry("cylinder.vtp");
    anteriorDisplay->setOpacity(0.5);
    anteriorDisplay->setColor(Vec3(0.5, 0.5, 0.5));

    // We want the centroid to be at (-0.5 * segmentalLength, 0, 0), and for
    // its axis of symmetry to be its body's (i.e., the body it's helping us
    // to visualize) X axis.
    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);


    // 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.
    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);


    // Print the model
    // ------------------------------------------------------------------------
    cat.print("flippinfelines_hunch_wag.osim");
    
    
    

    // Second model: adding legs for the variable-inertia mechanism of flipping
    // ========================================================================
    // 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
    
    
    // Define leg bodies
    // ------------------------------------------------------------------------
    // 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);
    
    
    // Define leg joints (i.e., between legs and two halves of cat)
    // ------------------------------------------------------------------------
    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);

    // 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);
    
    
    // Add bodies to the model
    // ------------------------------------------------------------------------
    // ...now that we have connected the bodies via joints.
    cat.addBody(anteriorLegs);
    cat.addBody(posteriorLegs);
    
    
    // Display geometry
    // ------------------------------------------------------------------------
    // 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);
    

    // Actuation
    // ------------------------------------------------------------------------
    // 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);

    
    // Enforce joint limits on the legs
    // ------------------------------------------------------------------------
    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);
    
    
    // Print the model
    // ------------------------------------------------------------------------
    cat.print("flippinfelines_hunch_wag_twist_legs.osim");

    return EXIT_SUCCESS;
};
コード例 #6
0
void KaneScherFig2Modeling::addBaseJointsAndBodies()
{	
	// NOTE: Massless bodies are simply coordinate frames for rotation. We
    // ----  have attempted to be as faithful to Kane and Scher (1969) as
    //       possible. See their paper to understand the notation used.

	// BODY CONNECTIONS:  ground -> anterior -> K -> P -> B2 -> posterior
	//
	// JOINTS/COORDINATES:  custom (u_integ) -> pin (alpha) -> pin (theta) ->
	//						pin (beta) -> pin (v_integ)

	// Connecting the anterior body (A) to the ground via a custom joint (same
	// as in 'model_dembiasketch'). Rotation is defined via ZXY Euler angles,
	// named flip, u_integ (AKA. sprawl), and roll respectively. The important
	// translation is in Y, the direction of gravity.
	Body& ground = _cat.getGroundBody();
	
	SpatialTransform groundAnteriorST;
    groundAnteriorST.updTransformAxis(0).setCoordinateNames(
            Array<string>("anterior_flip", 1));
    groundAnteriorST.updTransformAxis(0).setAxis(Vec3(0, 0, 1));
    groundAnteriorST.updTransformAxis(1).setCoordinateNames(
            Array<string>("kane_u_integ", 1));
    groundAnteriorST.updTransformAxis(1).setAxis(Vec3(1, 0, 0));
    groundAnteriorST.updTransformAxis(2).setCoordinateNames(
            Array<string>("anterior_roll", 1));
    groundAnteriorST.updTransformAxis(2).setAxis(Vec3(0, 1, 0));
    groundAnteriorST.updTransformAxis(3).setCoordinateNames(
            Array<string>("anterior_tx", 1));
    groundAnteriorST.updTransformAxis(3).setAxis(Vec3(1, 0, 0));
    groundAnteriorST.updTransformAxis(4).setCoordinateNames(
            Array<string>("anterior_ty", 1));
    groundAnteriorST.updTransformAxis(4).setAxis(Vec3(0, 1, 0));
    groundAnteriorST.updTransformAxis(5).setCoordinateNames(
            Array<string>("anterior_tz", 1));
    groundAnteriorST.updTransformAxis(5).setAxis(Vec3(0, 0, 1));

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

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

    CoordinateSet & groundAnteriorCS = groundAnterior->upd_CoordinateSet();
    // flip
    double groundAnteriorCS0range[2] = {-Pi, Pi};
    groundAnteriorCS[0].setRange(groundAnteriorCS0range);
    groundAnteriorCS[0].setDefaultValue(0);
    groundAnteriorCS[0].setDefaultLocked(true);
    // u_integ (sprawl)
    double groundAnteriorCS1range[2] = {-Pi, Pi};
    groundAnteriorCS[1].setRange(groundAnteriorCS1range);
    groundAnteriorCS[1].setDefaultValue(0);
    groundAnteriorCS[1].setDefaultLocked(false);
    // roll
    double groundAnteriorCS2range[2] = {-3 * Pi, 3 * Pi};
    groundAnteriorCS[2].setRange(groundAnteriorCS2range);
    groundAnteriorCS[2].setDefaultValue(0);
    groundAnteriorCS[2].setDefaultLocked(true);
    // tx
    double groundAnteriorCS3range[2] = {-10, 10};
    groundAnteriorCS[3].setRange(groundAnteriorCS3range);
    groundAnteriorCS[3].setDefaultValue(0);
	groundAnteriorCS[3].setDefaultLocked(true);
    // ty
    double groundAnteriorCS4range[2] = {-1, 100};
    groundAnteriorCS[4].setRange(groundAnteriorCS4range);
    groundAnteriorCS[4].setDefaultValue(0);
	groundAnteriorCS[4].setDefaultLocked(false);
    // tz
    double groundAnteriorCS5range[2] = {-5, 5};
    groundAnteriorCS[5].setRange(groundAnteriorCS5range);
    groundAnteriorCS[5].setDefaultValue(0);
    groundAnteriorCS[5].setDefaultLocked(true);

    // Frame in which the X-axis points along ray K. K lies in the A1-A2
	// plane, so frame K is formed by rotation (by angle alpha) about A3.
    Body* frameK = newMasslessBody("K");
	Vec3 locationAKInAnterior(0);
	Vec3 orientationAKInAnterior(0);
	Vec3 locationAKinFrameK(0);
	Vec3 orientationAKinFrameK(0);
	PinJoint* anteriorFrameK = new PinJoint("anterior_K",
		*_anteriorBody, locationAKInAnterior, orientationAKInAnterior,
		*frameK, locationAKinFrameK, orientationAKinFrameK, false);
	CoordinateSet& anteriorFrameKCS = anteriorFrameK->upd_CoordinateSet();
	anteriorFrameKCS[0].setName("kane_alpha");
	//double anteriorFrameKCS0range[2] = {convertDegreesToRadians(35),
	//	convertDegreesToRadians(85)};
	double anteriorFrameKCS0range[2] = {-Pi, 0};
	anteriorFrameKCS[0].setRange(anteriorFrameKCS0range);
	//anteriorFrameKCS[0].setDefaultValue(convertDegreesToRadians(60));
	anteriorFrameKCS[0].setDefaultValue(0);
	anteriorFrameKCS[0].setDefaultLocked(true);

    // Defining the following axes:
    //		B1: X-axis of coordinate frame attached to the posterior body
    //		B2: normal to B1 and lying in the plane defined by B1 and ray K
    //		B3: mutually perpendicular to B1 and B2

	// Frame with Z-axis as B3 (named P in Kane and Scher), formed by rotation
	// about K by angle theta.
    Body* frameP = newMasslessBody("P");
	Vec3 locationKPInFrameK(0);
	Vec3 orientationKPInFrameK(0, 0.5 * Pi, 0);
	Vec3 locationKPInFrameP(0);
	Vec3 orientationKPInFrameP(0, -0.5 * Pi, 0);
	PinJoint* FrameKFrameP = new PinJoint("K_P",
		*frameK, locationKPInFrameK, orientationKPInFrameK,
		*frameP, locationKPInFrameP, orientationKPInFrameP, false);
	CoordinateSet& FrameKFramePCS = FrameKFrameP->upd_CoordinateSet();
	FrameKFramePCS[0].setName("kane_theta");
	double FrameKFramePCS0range[2] = {0, 2 * Pi};
	FrameKFramePCS[0].setRange(FrameKFramePCS0range);
	FrameKFramePCS[0].setDefaultValue(0);
	FrameKFramePCS[0].setDefaultLocked(false);

	// Frame with Y-axis as B2, formed by rotation about B3 by angle beta.
	Body* frameB2 = newMasslessBody("B2");
	Vec3 locationPB2InFrameB3(0);
	Vec3 orientationPB2InFrameB3(0);
	Vec3 locationPB2InFrameB2(0);
	Vec3 orientationPB2InFrameB2(0);
	PinJoint* FramePFrameB2 = new PinJoint("P_B2",
		*frameP, locationPB2InFrameB3, orientationPB2InFrameB3,
		*frameB2, locationPB2InFrameB2, orientationPB2InFrameB2, false);
	CoordinateSet& FramePFrameB2CS = FramePFrameB2->upd_CoordinateSet();
	FramePFrameB2CS[0].setName("kane_beta");
	//double FramePFrameB2CS0range[2] = {convertDegreesToRadians(60),
	//	convertDegreesToRadians(90)};
	double FramePFrameB2CS0range[2] = {0, Pi};
	FramePFrameB2CS[0].setRange(FramePFrameB2CS0range);
	//FramePFrameB2CS[0].setDefaultValue(convertDegreesToRadians(75));
	FramePFrameB2CS[0].setDefaultValue(0);
	FramePFrameB2CS[0].setDefaultLocked(true);

	// Connecting the posterior body (i.e., B1).
	Vec3 locationB2PostInFrameB2(0);
	Vec3 orientationB2PostInFrameB2(0, 0, -0.5 * Pi);
	Vec3 locationB2PostInPosterior(0);
	Vec3 orientationB2PostInPosterior(Pi, 0, 0.5 * Pi);
	PinJoint* FrameB2Posterior = new PinJoint("B2_posterior",
		*frameB2, locationB2PostInFrameB2, orientationB2PostInFrameB2,
		*_posteriorBody, locationB2PostInPosterior, orientationB2PostInPosterior, false);
	CoordinateSet& FrameB2PosteriorCS = FrameB2Posterior->upd_CoordinateSet();
	FrameB2PosteriorCS[0].setName("kane_v_integ");
	double FrameB2PosteriorCS0range[2] = {-Pi, Pi};
	FrameB2PosteriorCS[0].setRange(FrameB2PosteriorCS0range);
	FrameB2PosteriorCS[0].setDefaultValue(0);
	FrameB2PosteriorCS[0].setDefaultLocked(false);

	// TODO: add N, define gamma?

    // -- Add bodies.
    _cat.addBody(_anteriorBody);
	_cat.addBody(frameK);
	_cat.addBody(frameP);
	_cat.addBody(frameB2);
    _cat.addBody(_posteriorBody);
	//cat.addBody(frameN);

    // -- Add "no-twist" constraint. (TODO: is this right? don't we want to
    // constrain speeds?)
	CoordinateCouplerConstraint * twistConstr = new CoordinateCouplerConstraint();
    twistConstr->setName("twist");
    twistConstr->setIndependentCoordinateNames(Array<string>("kane_u_integ", 1));
    twistConstr->setDependentCoordinateName("kane_v_integ");
    Array<double> twistConstrFcnCoeff;
    twistConstrFcnCoeff.append(1);
    twistConstr->setFunction(new LinearFunction(twistConstrFcnCoeff));
	_cat.addConstraint(twistConstr);
}
コード例 #7
0
int main() {
    Model model;
    model.setName("bicep_curl");
#ifdef VISUALIZE
    model.setUseVisualizer(true);
#endif

    // Create two links, each with a mass of 1 kg, center of mass at the body's
    // origin, and moments and products of inertia of zero.
    OpenSim::Body* humerus = new OpenSim::Body("humerus", 1, Vec3(0), Inertia(0));
    OpenSim::Body* radius  = new OpenSim::Body("radius",  1, Vec3(0), Inertia(0));

    // 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, 1, 0), Vec3(0));
    PinJoint* elbow = new PinJoint("elbow",
            *humerus, Vec3(0), Vec3(0), *radius, Vec3(0, 1, 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.8, 0));
    biceps->addNewPathPoint("insertion", *radius,  Vec3(0, 0.7, 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, 0.5, 0)));
    humerus->addComponent(humerusCenter);
    humerusCenter->attachGeometry(bodyGeometry.clone());
    PhysicalOffsetFrame* radiusCenter = new PhysicalOffsetFrame(
        "radiusCenter", *radius, Transform(Vec3(0, 0.5, 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.
#ifdef VISUALIZE
    model.updMatterSubsystem().setShowDefaultGeometry(true);
    Visualizer& viz = model.updVisualizer().updSimbodyVisualizer();
    viz.setBackgroundType(viz.SolidColor);
    viz.setBackgroundColor(White);
#endif

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

    return 0;
};