bool SimulationModel::addSliderJoint(const unsigned int rbIndex1, const unsigned int rbIndex2, const Eigen::Vector3f &pos, const Eigen::Vector3f &axis)
{
    SliderJoint *joint = new SliderJoint();
    const bool res = joint->initConstraint(*this, rbIndex1, rbIndex2, pos, axis);
    if (res)
    {
        m_constraints.push_back(joint);
        m_groupsInitialized = false;
    }
    return res;
}
Example #2
0
/* ....................................................................... */
void
SliderServoMotor::operator()(ODEObject* object)
{

    SliderJoint*     slider = object->asSliderJoint() ;
    PS_ASSERT1( slider != NULL ) ;

    World*      world = object->getWorld() ;
    PS_ASSERT1( world != NULL ) ;


    PIDController*  pid = getPIDController() ;

    ooReal  vel = 0.0 ;

    if( pid ) {
        vel = pid->solve( m_position - slider->getPosition(), world->getCurrentStepSize() ) ;
    } else {
        vel = m_position - slider->getPosition() ;
    }



    if( m_max_vel >= 0.0 ) {

        vel = osg::clampTo( vel, -m_max_vel, m_max_vel ) ;
    }





    slider->setParam( dParamFMax, m_force ) ;
    slider->setParam( dParamVel, vel ) ;


    traverse(object) ;
}
Example #3
0
//=============================================================================
// Simbody Model building.
//=============================================================================
//_____________________________________________________________________________
void SliderJoint::addToSystem(SimTK::MultibodySystem& system) const
{
	const SimTK::Vec3& orientation = get_orientation();
	const SimTK::Vec3& location = get_location();

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

	const SimTK::Vec3& orientationInParent = get_orientation_in_parent();
	const SimTK::Vec3& locationInParent = get_location_in_parent();

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

	SliderJoint* mutableThis = const_cast<SliderJoint*>(this);

	mutableThis->createMobilizedBody(parentTransform, childTransform);

    // TODO: Joints require super class to be called last.
    Super::addToSystem(system);
}
void testMcKibbenActuator()
{

    double pressure = 5 * 10e5; // 5 bars
    double num_turns = 1.5;     // 1.5 turns
    double B = 277.1 * 10e-4;  // 277.1 mm

    using namespace SimTK;
    std::clock_t startTime = std::clock();

    double mass = 1;
    double ball_radius = 10e-6;

    Model *model = new Model;
    model->setGravity(Vec3(0));

    Ground& ground = model->updGround();

    McKibbenActuator *actuator = new McKibbenActuator("mckibben", num_turns, B);
    
    OpenSim::Body* ball = new OpenSim::Body("ball", mass ,Vec3(0),  mass*SimTK::Inertia::sphere(0.1));
    ball->scale(Vec3(ball_radius), false);

    actuator->addNewPathPoint("mck_ground", ground, Vec3(0));
    actuator->addNewPathPoint("mck_ball", *ball, Vec3(ball_radius));

    Vec3 locationInParent(0, ball_radius, 0), orientationInParent(0), locationInBody(0), orientationInBody(0);
    SliderJoint *ballToGround = new SliderJoint("ballToGround", ground, locationInParent, orientationInParent, *ball, locationInBody, orientationInBody);

    ballToGround->updCoordinate().setName("ball_d");
    ballToGround->updCoordinate().setPrescribedFunction(LinearFunction(20 * 10e-4, 0.5 * 264.1 * 10e-4));
    ballToGround->updCoordinate().set_prescribed(true);

    model->addBody(ball);
    model->addJoint(ballToGround);
    model->addForce(actuator);

    PrescribedController* controller =  new PrescribedController();
    controller->addActuator(*actuator);
    controller->prescribeControlForActuator("mckibben", new Constant(pressure));

    model->addController(controller);

    ForceReporter* reporter = new ForceReporter(model);
    model->addAnalysis(reporter);
    
    SimTK::State& si = model->initSystem();

    model->getMultibodySystem().realize(si, Stage::Position);

    double final_t = 10.0;
    double nsteps = 10;
    double dt = final_t / nsteps;

    RungeKuttaMersonIntegrator integrator(model->getMultibodySystem());
    integrator.setAccuracy(1e-7);
    Manager manager(*model, integrator);
    manager.setInitialTime(0.0);

    for (int i = 1; i <= nsteps; i++){
        manager.setFinalTime(dt*i);
        manager.integrate(si);
        model->getMultibodySystem().realize(si, Stage::Velocity);
        Vec3 pos;
        model->updSimbodyEngine().getPosition(si, *ball, Vec3(0), pos);

        double applied = actuator->computeActuation(si);;

        double theoretical = (pressure / (4* pow(num_turns,2) * SimTK::Pi)) * (3*pow(pos(0), 2) - pow(B, 2));

        ASSERT_EQUAL(applied, theoretical, 10.0);

        manager.setInitialTime(dt*i);
    }


    std::cout << " ******** Test McKibbenActuator time = ********" <<
        1.e3*(std::clock() - startTime) / CLOCKS_PER_SEC << "ms\n" << endl;
}
void testClutchedPathSpring()
{
    using namespace SimTK;

    // start timing
    std::clock_t startTime = std::clock();

    double mass = 1;
    double stiffness = 100;
    double dissipation = 0.3;
    double start_h = 0.5;
    //double ball_radius = 0.25;

    //double omega = sqrt(stiffness/mass);

    // Setup OpenSim model
    Model* model = new Model;
    model->setName("ClutchedPathSpringModel");
    model->setGravity(gravity_vec);

    //OpenSim bodies
    const Ground* ground = &model->getGround();
    
    // body that acts as the pulley that the path wraps over
    OpenSim::Body* pulleyBody =
        new OpenSim::Body("PulleyBody", mass ,Vec3(0),  mass*Inertia::brick(0.1, 0.1, 0.1));
    
    // body the path spring is connected to at both ends
    OpenSim::Body* block =
        new OpenSim::Body("block", mass ,Vec3(0),  mass*Inertia::brick(0.2, 0.1, 0.1));
    block->attachGeometry(new Brick(Vec3(0.2, 0.1, 0.1)));
    block->scale(Vec3(0.2, 0.1, 0.1), false);

    //double dh = mass*gravity_vec(1)/stiffness;
    
    WrapCylinder* pulley = new WrapCylinder();
    pulley->set_radius(0.1);
    pulley->set_length(0.05);

    // Add the wrap object to the body, which takes ownership of it
    pulleyBody->addWrapObject(pulley);

    // Add joints
    WeldJoint* weld = 
        new WeldJoint("weld", *ground, Vec3(0, 1.0, 0), Vec3(0), *pulleyBody, Vec3(0), Vec3(0));
    
    SliderJoint* slider =
        new SliderJoint("slider", *ground, Vec3(0), Vec3(0,0,Pi/2),*block, Vec3(0), Vec3(0,0,Pi/2));

    double positionRange[2] = {-10, 10};
    // Rename coordinates for a slider joint
    slider->updCoordinate().setName("block_h");
    slider->updCoordinate().setRange(positionRange);

    model->addBody(pulleyBody);
    model->addJoint(weld);

    model->addBody(block);
    model->addJoint(slider);

    ClutchedPathSpring* spring = 
        new ClutchedPathSpring("clutch_spring", stiffness, dissipation, 0.01);

    spring->updGeometryPath().appendNewPathPoint("origin", *block, Vec3(-0.1, 0.0 ,0.0));
    
    int N = 10;
    for(int i=1; i<N; ++i){
        double angle = i*Pi/N;
        double x = 0.1*cos(angle);
        double y = 0.1*sin(angle);
        spring->updGeometryPath().appendNewPathPoint("", *pulleyBody, Vec3(-x, y ,0.0));
    }

    spring->updGeometryPath().appendNewPathPoint("insertion", *block, Vec3(0.1, 0.0 ,0.0));

    // BUG in defining wrapping API requires that the Force containing the GeometryPath be
    // connected to the model before the wrap can be added
    model->addForce(spring);

    PrescribedController* controller = new PrescribedController();
    controller->addActuator(*spring);
    
    // Control greater than 1 or less than 0 should be treated as 1 and 0 respectively.
    double     timePts[4] = {0.0,  5.0, 6.0, 10.0};
    double clutchOnPts[4] = {1.5, -2.0, 0.5,  0.5};

    PiecewiseConstantFunction* controlfunc = 
        new PiecewiseConstantFunction(4, timePts, clutchOnPts);

    controller->prescribeControlForActuator("clutch_spring", controlfunc);
    model->addController(controller);

    model->print("ClutchedPathSpringModel.osim");

    //Test deserialization
    delete model;
    model = new Model("ClutchedPathSpringModel.osim");

    // Create the force reporter
    ForceReporter* reporter = new ForceReporter(model);
    model->addAnalysis(reporter);

    model->setUseVisualizer(false);
    SimTK::State& state = model->initSystem();

    CoordinateSet& coords = model->updCoordinateSet();
    coords[0].setValue(state, start_h);
    model->getMultibodySystem().realize(state, Stage::Position );

    //==========================================================================
    // Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(model->getMultibodySystem() );
    integrator.setAccuracy(integ_accuracy);
    Manager manager(*model,  integrator);
    manager.setWriteToStorage(true);

    manager.setInitialTime(0.0);

    double final_t = 4.99999;

    manager.setFinalTime(final_t);
    manager.integrate(state);

    // tension is dynamics dependent because controls must be computed
    model->getMultibodySystem().realize(state, Stage::Dynamics);

    spring = dynamic_cast<ClutchedPathSpring*>(
                &model->updForceSet().get("clutch_spring"));
    // Now check that the force reported by spring
    double model_force = spring->getTension(state);
    double stretch0 = spring->getStretch(state);

    // the tension should be half the weight of the block
    double analytical_force = -0.5*(gravity_vec(1))*mass;

    cout << "Tension is: " << model_force << " and should be: " << analytical_force << endl;

    // error if the block does not reach equilibrium since spring is clamped
    ASSERT_EQUAL(model_force, analytical_force, 10*integ_accuracy);

    // unclamp and continue integrating
    manager.setInitialTime(final_t);
    final_t = 5.99999;
    manager.setFinalTime(final_t);
    manager.integrate(state);

    // tension is dynamics dependent because controls must be computed
    model->getMultibodySystem().realize(state, Stage::Dynamics);

    // tension should go to zero quickly
    model_force = spring->getTension(state);

    cout << "Tension is: " << model_force << " and should be: 0.0" << endl;
    // is unclamped and block should be in free-fall
    ASSERT_EQUAL(model_force, 0.0, 10*integ_accuracy);

    // spring is reclamped at 7s so keep integrating
    manager.setInitialTime(final_t);
    final_t = 10.0;
    manager.setFinalTime(final_t);
    manager.integrate(state);

    // tension is dynamics dependent because controls must be computed
    model->getMultibodySystem().realize(state, Stage::Dynamics);

    // tension should build to support the block again
    model_force = spring->getTension(state);
    double stretch1 = spring->getStretch(state);

    cout << "Tension is: " << model_force << " and should be: "<< analytical_force << endl;

    // is unclamped and block should be in free-fall
    ASSERT_EQUAL(model_force, analytical_force, 10*integ_accuracy);

    cout << "Steady stretch at control = 1.0 is " << stretch0 << " m." << endl;
    cout << "Steady stretch at control = 0.5 is " << stretch1 << " m." << endl;

    ASSERT_EQUAL(2*stretch0, stretch1, 10*integ_accuracy);

    manager.getStateStorage().print("clutched_path_spring_states.sto");
    model->getControllerSet().printControlStorage("clutched_path_spring_controls.sto");

    // Save the forces
    reporter->getForceStorage().print("clutched_path_spring_forces.mot"); 

    model->disownAllComponents();

    cout << " ********** Test clutched spring time = ********** " << 
        1.e3*(std::clock()-startTime)/CLOCKS_PER_SEC << "ms\n" << endl;
}
Example #6
0
/*==============================================================================  
    Main test driver to be used on any muscle model (derived from Muscle) so new 
    cases should be easy to add currently, the test only verifies that the work 
    done by the muscle corresponds to the change in system energy.

    TODO: Test will fail wih prescribe motion until the work done by this 
    constraint is accounted for.
================================================================================
*/
void simulateMuscle(
        const Muscle &aMuscModel, 
        double startX, 
        double act0, 
        const Function *motion,  // prescribe motion of free end of muscle
        const Function *control, // prescribed excitation signal to the muscle
        double integrationAccuracy,
        int testType,
        double testTolerance,
        bool printResults)
{
    string prescribed = (motion == NULL) ? "." : " with Prescribed Motion.";

    cout << "\n******************************************************" << endl;
    cout << "Test " << aMuscModel.getConcreteClassName() 
         << " Model" << prescribed << endl;
    cout << "******************************************************" << endl;
    using SimTK::Vec3;

//==========================================================================
// 0. SIMULATION SETUP: Create the block and ground
//==========================================================================

    // Define the initial and final simulation times
    double initialTime = 0.0;
    double finalTime = 4.0;
    
    //Physical properties of the model
    double ballMass = 10;
    double ballRadius = 0.05;
    double anchorWidth = 0.1;

    // Create an OpenSim model
    Model model;

    double optimalFiberLength = aMuscModel.getOptimalFiberLength();
    double pennationAngle     = aMuscModel.getPennationAngleAtOptimalFiberLength();
    double tendonSlackLength  = aMuscModel.getTendonSlackLength();

    // Use a copy of the muscle model passed in to add path points later
    PathActuator *aMuscle = aMuscModel.clone();

    // Get a reference to the model's ground body
    Body& ground = model.getGroundBody();
    ground.addDisplayGeometry("box.vtp");
    ground.updDisplayer()
        ->setScaleFactors(Vec3(anchorWidth, anchorWidth, 2*anchorWidth));

    OpenSim::Body * ball = new OpenSim::Body("ball", 
                        ballMass , 
                        Vec3(0),  
                        ballMass*SimTK::Inertia::sphere(ballRadius));
    
    ball->addDisplayGeometry("sphere.vtp");
    ball->updDisplayer()->setScaleFactors(Vec3(2*ballRadius));
    // ball connected  to ground via a slider along X
    double xSinG = optimalFiberLength*cos(pennationAngle)+tendonSlackLength;

    SliderJoint* slider = new SliderJoint( "slider", 
                        ground, 
                        Vec3(anchorWidth/2+xSinG, 0, 0), 
                        Vec3(0), 
                        *ball, 
                        Vec3(0), 
                        Vec3(0));

    CoordinateSet& jointCoordinateSet = slider->upd_CoordinateSet();
        jointCoordinateSet[0].setName("tx");
        jointCoordinateSet[0].setDefaultValue(1.0);
        jointCoordinateSet[0].setRangeMin(0); 
        jointCoordinateSet[0].setRangeMax(1.0);
    
    if(motion != NULL){
        jointCoordinateSet[0].setPrescribedFunction(*motion);
        jointCoordinateSet[0].setDefaultIsPrescribed(true);
    }
    // add ball to model
    model.addBody(ball);
	model.addJoint(slider);


//==========================================================================
// 1. SIMULATION SETUP: Add the muscle
//==========================================================================

    //Attach the muscle
    const string &actuatorType = aMuscle->getConcreteClassName();
    aMuscle->setName("muscle");
    aMuscle->addNewPathPoint("muscle-box", ground, Vec3(anchorWidth/2,0,0));
    aMuscle->addNewPathPoint("muscle-ball", *ball, Vec3(-ballRadius,0,0));
    
    ActivationFiberLengthMuscle_Deprecated *aflMuscle 
        = dynamic_cast<ActivationFiberLengthMuscle_Deprecated *>(aMuscle);
    if(aflMuscle){
        // Define the default states for the muscle that has 
        //activation and fiber-length states
        aflMuscle->setDefaultActivation(act0);
        aflMuscle->setDefaultFiberLength(aflMuscle->getOptimalFiberLength());
    }else{
        ActivationFiberLengthMuscle *aflMuscle2 
            = dynamic_cast<ActivationFiberLengthMuscle *>(aMuscle);
        if(aflMuscle2){
            // Define the default states for the muscle 
            //that has activation and fiber-length states
            aflMuscle2->setDefaultActivation(act0);
            aflMuscle2->setDefaultFiberLength(aflMuscle2
                ->getOptimalFiberLength());
        }
    }

    model.addForce(aMuscle);

    // Create a prescribed controller that simply 
    //applies controls as function of time
    PrescribedController * muscleController = new PrescribedController();
    if(control != NULL){
        muscleController->setActuators(model.updActuators());
        // Set the indiviudal muscle control functions 
        //for the prescribed muscle controller
        muscleController->prescribeControlForActuator("muscle",control->clone());

        // Add the control set controller to the model
        model.addController(muscleController);
    }

    // Set names for muscles / joints.
    Array<string> muscNames;
    muscNames.append(aMuscle->getName());
    Array<string> jointNames;
    jointNames.append("slider");

//==========================================================================
// 2. SIMULATION SETUP: Instrument the test with probes
//==========================================================================

    Array<string> muscNamesTwice = muscNames;
    muscNamesTwice.append(muscNames.get(0));
    cout << "------------\nPROBES\n------------" << endl;
    int probeCounter = 1;

    // Add ActuatorPowerProbe to measure work done by the muscle 
    ActuatorPowerProbe* muscWorkProbe = new ActuatorPowerProbe(muscNames, false, 1);
    //muscWorkProbe->setName("ActuatorWork");
    muscWorkProbe->setOperation("integrate");
    SimTK::Vector ic1(1);
    ic1 = 9.0;      // some arbitary initial condition.
    muscWorkProbe->setInitialConditions(ic1);
    model.addProbe(muscWorkProbe);
	model.setup();
    cout << probeCounter++ << ") Added ActuatorPowerProbe to measure work done by the muscle" << endl; 
    if (muscWorkProbe->getName() != "UnnamedProbe") {
        string errorMessage = "Incorrect default name for unnamed probe: " + muscWorkProbe->getName(); 
        throw (OpenSim::Exception(errorMessage.c_str()));
    }

    // Add ActuatorPowerProbe to measure power generated by the muscle 
    ActuatorPowerProbe* muscPowerProbe = new ActuatorPowerProbe(*muscWorkProbe);	// use copy constructor
    muscPowerProbe->setName("ActuatorPower");
    muscPowerProbe->setOperation("value");
    model.addProbe(muscPowerProbe);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to measure power generated by the muscle" << endl; 

    // Add ActuatorPowerProbe to report the muscle power MINIMUM
    ActuatorPowerProbe* powerProbeMinimum = new ActuatorPowerProbe(*muscPowerProbe);			// use copy constructor
    powerProbeMinimum->setName("ActuatorPowerMinimum");
    powerProbeMinimum->setOperation("minimum");
    model.addProbe(powerProbeMinimum);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to report the muscle power MINIMUM" << endl;

    // Add ActuatorPowerProbe to report the muscle power ABSOLUTE MINIMUM
    ActuatorPowerProbe* powerProbeMinAbs = new ActuatorPowerProbe(*muscPowerProbe);			// use copy constructor
    powerProbeMinAbs->setName("ActuatorPowerMinAbs");
    powerProbeMinAbs->setOperation("minabs");
    model.addProbe(powerProbeMinAbs);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to report the muscle power MINABS" << endl;

    // Add ActuatorPowerProbe to report the muscle power MAXIMUM
    ActuatorPowerProbe* powerProbeMaximum = new ActuatorPowerProbe(*muscPowerProbe);			// use copy constructor
    powerProbeMaximum->setName("ActuatorPowerMaximum");
    powerProbeMaximum->setOperation("maximum");
    model.addProbe(powerProbeMaximum);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to report the muscle power MAXIMUM" << endl;

    // Add ActuatorPowerProbe to report the muscle power MAXABS
    ActuatorPowerProbe* powerProbeMaxAbs = new ActuatorPowerProbe(*muscPowerProbe);			// use copy constructor
    powerProbeMaxAbs->setName("ActuatorPowerMaxAbs");
    powerProbeMaxAbs->setOperation("maxabs");
    model.addProbe(powerProbeMaxAbs);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to report the muscle power MAXABS" << endl;


    // Add ActuatorPowerProbe to measure the square of the power generated by the muscle 
    ActuatorPowerProbe* muscPowerSquaredProbe = new ActuatorPowerProbe(*muscPowerProbe);	// use copy constructor
    muscPowerSquaredProbe->setName("ActuatorPowerSquared");
    muscPowerSquaredProbe->setExponent(2.0);
    model.addProbe(muscPowerSquaredProbe);
    cout << probeCounter++ << ") Added ActuatorPowerProbe to measure the square of the power generated by the muscle" << endl; 

    // Add JointInternalPowerProbe to measure work done by the joint 
    JointInternalPowerProbe* jointWorkProbe = new JointInternalPowerProbe(jointNames, false, 1);
    jointWorkProbe->setName("JointWork");
    jointWorkProbe->setOperation("integrate");
    jointWorkProbe->setInitialConditions(SimTK::Vector(1, 0.0));
    model.addProbe(jointWorkProbe);
    cout << probeCounter++ << ") Added JointPowerProbe to measure work done by the joint" << endl;

    // Add JointPowerProbe to measure power generated by the joint 
    JointInternalPowerProbe* jointPowerProbe = new JointInternalPowerProbe(*jointWorkProbe);	// use copy constructor
    jointPowerProbe->setName("JointPower");
    jointPowerProbe->setOperation("value");
    model.addProbe(jointPowerProbe);
    cout << probeCounter++ << ") Added JointPowerProbe to measure power generated by the joint" << endl;

    // Add ActuatorForceProbe to measure the impulse of the muscle force 
    ActuatorForceProbe* impulseProbe = new ActuatorForceProbe(muscNames, false, 1);
    impulseProbe->setName("ActuatorImpulse");
    impulseProbe->setOperation("integrate");
    impulseProbe->setInitialConditions(SimTK::Vector(1, 0.0));
    model.addProbe(impulseProbe);
    cout << probeCounter++ << ") Added ActuatorForceProbe to measure the impulse of the muscle force" << endl;

    // Add ActuatorForceProbe to report the muscle force 
    ActuatorForceProbe* forceProbe = new ActuatorForceProbe(*impulseProbe);			// use copy constructor
    forceProbe->setName("ActuatorForce");
    forceProbe->setOperation("value");
    model.addProbe(forceProbe);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the muscle force" << endl;

    // Add ActuatorForceProbe to report the square of the muscle force 
    ActuatorForceProbe* forceSquaredProbe = new ActuatorForceProbe(*forceProbe);			// use copy constructor
    forceSquaredProbe->setName("ActuatorForceSquared");
    forceSquaredProbe->setExponent(2.0);
    model.addProbe(forceSquaredProbe);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the square of the muscle force " << endl;

    // Add ActuatorForceProbe to report the square of the muscle force for the same muscle repeated twice
    ActuatorForceProbe* forceSquaredProbeTwice = new ActuatorForceProbe(*forceSquaredProbe);			// use copy constructor
    forceSquaredProbeTwice->setName("ActuatorForceSquared_RepeatedTwice");
    forceSquaredProbeTwice->setSumForcesTogether(true);
    forceSquaredProbeTwice->setActuatorNames(muscNamesTwice);
    model.addProbe(forceSquaredProbeTwice);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the square of the muscle force for the same muscle repeated twice" << endl;

    // Add ActuatorForceProbe to report the square of the muscle force for the same muscle repeated twice, SCALED BY 0.5
    ActuatorForceProbe* forceSquaredProbeTwiceScaled = new ActuatorForceProbe(*forceSquaredProbeTwice);			// use copy constructor
    forceSquaredProbeTwice->setName("ActuatorForceSquared_RepeatedTwiceThenHalved");
    double gain1 = 0.5;
    forceSquaredProbeTwiceScaled->setGain(gain1);
    model.addProbe(forceSquaredProbeTwiceScaled);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the square of the muscle force for the same muscle repeated twice, SCALED BY 0.5" << endl;

    // Add ActuatorForceProbe to report -3.5X the muscle force 
    double gain2 = -3.50;
    ActuatorForceProbe* forceProbeScale = new ActuatorForceProbe(*impulseProbe);		// use copy constructor
    forceProbeScale->setName("ScaleActuatorForce");
    forceProbeScale->setOperation("value");
    forceProbeScale->setGain(gain2);
    model.addProbe(forceProbeScale);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report -3.5X the muscle force" << endl;

    // Add ActuatorForceProbe to report the differentiated muscle force 
    ActuatorForceProbe* forceProbeDiff = new ActuatorForceProbe(*impulseProbe);		// use copy constructor
    forceProbeDiff->setName("DifferentiateActuatorForce");
    forceProbeDiff->setOperation("differentiate");
    model.addProbe(forceProbeDiff);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the differentiated muscle force" << endl;

    // Add SystemEnergyProbe to measure the system KE+PE
    SystemEnergyProbe* sysEnergyProbe = new SystemEnergyProbe(true, true);
    sysEnergyProbe->setName("SystemEnergy");
    sysEnergyProbe->setOperation("value");
    sysEnergyProbe->setComputeKineticEnergy(true);
    sysEnergyProbe->setComputePotentialEnergy(true);
    model.addProbe(sysEnergyProbe);
    cout << probeCounter++ << ") Added SystemEnergyProbe to measure the system KE+PE" << endl;

    // Add SystemEnergyProbe to measure system power (d/dt system KE+PE)
    SystemEnergyProbe* sysPowerProbe = new SystemEnergyProbe(*sysEnergyProbe);	// use copy constructor
    sysPowerProbe->setName("SystemPower");
    sysPowerProbe->setDisabled(false);
    sysPowerProbe->setOperation("differentiate");
    model.addProbe(sysPowerProbe);
    cout << probeCounter++ << ") Added SystemEnergyProbe to measure system power (d/dt system KE+PE)" << endl;

    // Add ActuatorForceProbe to report the muscle force value, twice -- REPORTED INDIVIDUALLY AS VECTORS
    ActuatorForceProbe* forceSquaredProbeTwiceReportedIndividually1 = new ActuatorForceProbe(*forceProbe);			// use copy constructor
    forceSquaredProbeTwiceReportedIndividually1->setName("MuscleForce_VALUE_VECTOR");
    forceSquaredProbeTwiceReportedIndividually1->setSumForcesTogether(false);    // report individually
    forceSquaredProbeTwiceReportedIndividually1->setActuatorNames(muscNamesTwice);
    //cout << forceSquaredProbeTwiceReportedIndividually1->getActuatorNames().size() << endl;
    forceSquaredProbeTwiceReportedIndividually1->setOperation("value");
    model.addProbe(forceSquaredProbeTwiceReportedIndividually1);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the muscle force value, twice - REPORTED INDIVIDUALLY" << endl;

    // Add ActuatorForceProbe to report the differentiated muscle force value, twice -- REPORTED INDIVIDUALLY AS VECTORS
    ActuatorForceProbe* forceSquaredProbeTwiceReportedIndividually2 = new ActuatorForceProbe(*forceSquaredProbeTwiceReportedIndividually1);			// use copy constructor
    forceSquaredProbeTwiceReportedIndividually2->setName("MuscleForce_DIFFERENTIATE_VECTOR");
    forceSquaredProbeTwiceReportedIndividually2->setSumForcesTogether(false);    // report individually
    forceSquaredProbeTwiceReportedIndividually2->setOperation("differentiate");
    model.addProbe(forceSquaredProbeTwiceReportedIndividually2);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the differentiated muscle force value, twice - REPORTED INDIVIDUALLY" << endl;

    // Add ActuatorForceProbe to report the integrated muscle force value, twice -- REPORTED INDIVIDUALLY AS VECTORS
    ActuatorForceProbe* forceSquaredProbeTwiceReportedIndividually3 = new ActuatorForceProbe(*forceSquaredProbeTwiceReportedIndividually1);			// use copy constructor
    forceSquaredProbeTwiceReportedIndividually3->setName("MuscleForce_INTEGRATE_VECTOR");
    forceSquaredProbeTwiceReportedIndividually3->setSumForcesTogether(false);    // report individually
    forceSquaredProbeTwiceReportedIndividually3->setOperation("integrate");
    SimTK::Vector initCondVec(2);
    initCondVec(0) = 0;
    initCondVec(1) = 10;
    forceSquaredProbeTwiceReportedIndividually3->setInitialConditions(initCondVec);
    model.addProbe(forceSquaredProbeTwiceReportedIndividually3);
    cout << probeCounter++ << ") Added ActuatorForceProbe to report the integrated muscle force value, twice - REPORTED INDIVIDUALLY" << endl;
    cout << "initCondVec = " << initCondVec << endl;

    /* Since all components are allocated on the stack don't have model 
       own them (and try to free)*/
//	model.disownAllComponents();
    model.setName("testProbesModel");
    cout << "Saving model... " << endl;
    model.print("testProbesModel.osim");
    cout << "Re-loading model... " << endl;
    Model reloadedModel = Model("testProbesModel.osim");

    /* Setup analyses and reporters. */
    ProbeReporter* probeReporter = new ProbeReporter(&model);
    model.addAnalysis(probeReporter);
    ForceReporter* forceReporter = new ForceReporter(&model);
    model.addAnalysis(forceReporter);
    MuscleAnalysis* muscleReporter = new MuscleAnalysis(&model);
    model.addAnalysis(muscleReporter);
    model.print("testProbesModel.osim");
    model.printBasicInfo(cout);
   


//==========================================================================
// 3. SIMULATION Initialization
//==========================================================================

    // Initialize the system and get the default state    
    SimTK::State& si = model.initSystem();
    SimTK::Vector testRealInitConditions = forceSquaredProbeTwiceReportedIndividually3->getProbeOutputs(si);

    model.getMultibodySystem().realize(si,SimTK::Stage::Dynamics);
    model.equilibrateMuscles(si);

    CoordinateSet& modelCoordinateSet = model.updCoordinateSet();

    // Define non-zero (defaults are 0) states for the free joint
    // set x-translation value
    modelCoordinateSet[0].setValue(si, startX, true); 

    //Copy the initial state
    SimTK::State initialState(si);

    // Check muscle is setup correctly 
    const PathActuator &muscle 
        = dynamic_cast<const PathActuator&>(model.updActuators().get("muscle"));
    double length = muscle.getLength(si);
    double trueLength = startX + xSinG - anchorWidth/2;
    
    ASSERT_EQUAL(length/trueLength, 1.0, testTolerance, __FILE__, __LINE__, 
        "testMuscles: path failed to initialize to correct length." );

    model.getMultibodySystem().realize(si, SimTK::Stage::Acceleration);

    double Emuscle0 = muscWorkProbe->getProbeOutputs(si)(0);
    //cout << "Muscle initial energy = " << Emuscle0 << endl;
    double Esys0 = model.getMultibodySystem().calcEnergy(si);
    Esys0 += (Emuscle0 + jointWorkProbe->getProbeOutputs(si)(0));
    double PEsys0 = model.getMultibodySystem().calcPotentialEnergy(si);
    //cout << "Total initial system energy = " << Esys0 << endl; 

//==========================================================================
// 4. SIMULATION Integration
//==========================================================================

    // Create the integrator
    SimTK::RungeKuttaMersonIntegrator integrator(model.getMultibodySystem());
    integrator.setAccuracy(integrationAccuracy);

    // Create the manager
    Manager manager(model, integrator);

    // Integrate from initial time to final time
    manager.setInitialTime(initialTime);
    manager.setFinalTime(finalTime);
    cout<<"\nIntegrating from " << initialTime<< " to " << finalTime << endl;

    // Start timing the simulation
    const clock_t start = clock();
    // simulate
    manager.integrate(si);

    // how long did it take?
    double comp_time = (double)(clock()-start)/CLOCKS_PER_SEC;



//==========================================================================
// 5. SIMULATION Reporting
//==========================================================================

    double realTimeMultiplier = ((finalTime-initialTime)/comp_time);
    printf("testMuscles: Realtime Multiplier: %f\n"
           "           :  simulation duration / clock duration\n"
           "              > 1 : faster than real time\n"
           "              = 1 : real time\n"
           "              < 1 : slower than real time\n",
            realTimeMultiplier );
    
    /*
    ASSERT(comp_time <= (finalTime-initialTime));
    printf("testMuscles: PASSED Realtime test\n"
           "             %s simulation time: %f with accuracy %f\n\n",
                         actuatorType.c_str(), comp_time , accuracy);
    */

    //An analysis only writes to a dir that exists, so create here.
    if(printResults == true){
        Storage states(manager.getStateStorage());
        states.print("testProbes_states.sto");
        probeReporter->getProbeStorage().print("testProbes_probes.sto");
        forceReporter->getForceStorage().print("testProbes_forces.sto");
        muscleReporter->getNormalizedFiberLengthStorage()->print("testProbes_normalizedFiberLength.sto");
        cout << "\nDone with printing results..." << endl;
    }

    double muscleWork = muscWorkProbe->getProbeOutputs(si)(0);
    cout << "Muscle work = " << muscleWork << endl;


    // Test the resetting of probes
    cout << "Resetting muscle work probe..." << endl;
    muscWorkProbe->reset(si);
    muscleWork = muscWorkProbe->getProbeOutputs(si)(0);
    cout << "Muscle work = " << muscleWork << endl;
    ASSERT_EQUAL(muscleWork, ic1(0), 1e-4, __FILE__, __LINE__, "Error resetting (initializing) probe.");





//==========================================================================
// 6. SIMULATION Tests
//==========================================================================
    model.getMultibodySystem().realize(si, SimTK::Stage::Acceleration);
    ASSERT_EQUAL(forceSquaredProbeTwiceScaled->getProbeOutputs(si)(0), gain1*forceSquaredProbeTwice->getProbeOutputs(si)(0), 1e-4, __FILE__, __LINE__, "Error with 'scale' operation.");
    ASSERT_EQUAL(forceProbeScale->getProbeOutputs(si)(0), gain2*forceProbe->getProbeOutputs(si)(0), 1e-4, __FILE__, __LINE__, "Error with 'scale' operation.");
    ASSERT_EQUAL(forceSquaredProbe->getProbeOutputs(si)(0), forceSquaredProbeTwiceScaled->getProbeOutputs(si)(0), 1e-4, __FILE__, __LINE__, "forceSquaredProbeTwiceScaled != forceSquaredProbe.");
    ASSERT_EQUAL(forceSquaredProbe->getProbeOutputs(si)(0), pow(forceProbe->getProbeOutputs(si)(0), 2), 1e-4, __FILE__, __LINE__, "Error with forceSquaredProbe probe.");
    ASSERT_EQUAL(forceSquaredProbeTwice->getProbeOutputs(si)(0), 2*pow(forceProbe->getProbeOutputs(si)(0), 2), 1e-4, __FILE__, __LINE__, "Error with forceSquaredProbeTwice probe.");
    for (int i=0; i<initCondVec.size(); ++i)  {
        stringstream myError;
        //myError << "Initial condition[" << i << "] for vector integration is not being correctly applied." << endl;
        //ASSERT_EQUAL(testRealInitConditions(i), initCondVec(i), 1e-4, __FILE__, __LINE__, myError.str());
        //if (testRealInitConditions(i) != initCondVec(i))
        //    cout << "WARNING: Initial condition[" << i << "] for vector integration is not being correctly applied.\nThis is actually an error, but I have made it into a warning for now so that the test passes..." << endl;
    }


}
Example #7
0
Joint* JointInteraction::xmlParseJoint(IrrXMLReader* xml, std::string& jointType)
{
	bool finished = false;
	Constraint* constraint = NULL;

	Joint* joint = JointFactory::create(xml->getAttributeValue("type"));
	jointType = xml->getAttributeValue("type");
	joint->setWorld(world);
	joint->setId(atoi(xml->getAttributeValue("id")));
	joint->setJointInteractionClass(this);
	if (xml->getAttributeValue("active"))
		joint->setActive(atoi(xml->getAttributeValue("active")));

	while (!finished && xml && xml->read())
	{
		switch (xml->getNodeType())
		{
			case EXN_ELEMENT:
				if (!strcmp("entities", xml->getNodeName()))
				{
					xmlParseEntities(xml, joint);
				} // else if
				else if (!strcmp("anchor", xml->getNodeName()))
				{
					if (!jointType.compare("ball") || !jointType.compare("Ball") || !jointType.compare("BALL"))
					{
						BallJoint* ball = dynamic_cast<BallJoint*>(joint);
						ball->setAnchor(atof(xml->getAttributeValue("xPos")), atof(xml->getAttributeValue("yPos")), atof(xml->getAttributeValue("zPos")));
					} // if
					else if (!jointType.compare("hinge") || !jointType.compare("Hinge") || !jointType.compare("HINGE"))
					{
						HingeJoint* hinge = dynamic_cast<HingeJoint*>(joint);
						hinge->setAnchor(atof(xml->getAttributeValue("xPos")), atof(xml->getAttributeValue("yPos")), atof(xml->getAttributeValue("zPos")));
					} // else if
					else if (!jointType.compare("universal") || !jointType.compare("Universal") || !jointType.compare("UNIVERSAL"))
					{
						UniversalJoint* universal = dynamic_cast<UniversalJoint*>(joint);
						universal->setAnchor(atof(xml->getAttributeValue("xPos")), atof(xml->getAttributeValue("yPos")), atof(xml->getAttributeValue("zPos")));
					} // else if
					else if (!jointType.compare("hinge2") || !jointType.compare("Hinge2") || !jointType.compare("HINGE2"))
					{
						Hinge2Joint* hinge2 = dynamic_cast<Hinge2Joint*>(joint);
						hinge2->setAnchor(atof(xml->getAttributeValue("xPos")), atof(xml->getAttributeValue("yPos")), atof(xml->getAttributeValue("zPos")));
					} // else if
					else
						printd(WARNING, "JointInteraction::loadJoints(): WARNING: JOINT-TYPE  %s NEEDS NO anchor ELEMENT!!!\n", jointType.c_str());
				} // else if
				else if (!strcmp("axis", xml->getNodeName()))
				{
					if (!jointType.compare("hinge") || !jointType.compare("Hinge") || !jointType.compare("HINGE"))
					{
						HingeJoint* hinge = dynamic_cast<HingeJoint*>(joint);
						hinge->setAxis(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
					} // if
					else if (!jointType.compare("slider") || !jointType.compare("Slider") || !jointType.compare("SLIDER"))
					{
						SliderJoint* slider = dynamic_cast<SliderJoint*>(joint);
						slider->setAxis(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
					} // else if
					else if (!jointType.compare("universal") || !jointType.compare("Universal") || !jointType.compare("UNIVERSAL")) {
						UniversalJoint* universal = dynamic_cast<UniversalJoint*>(joint);
						if (atoi(xml->getAttributeValue("index")) == 1)
							universal->setAxis1(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
						else if (atoi(xml->getAttributeValue("index")) == 2)
							universal->setAxis2(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
						else
							printd(WARNING, "JointInteraction::loadJoints(): WARNING: WRONG ATTRIBUTE FOUND IN axis ELEMENT of UniversalJoint!!!\n");
					} // else if
					else if (!jointType.compare("hinge2") || !jointType.compare("Hinge2") || !jointType.compare("HINGE2")) {
						Hinge2Joint* hinge2 = dynamic_cast<Hinge2Joint*>(joint);
						if (atoi(xml->getAttributeValue("index")) == 1)
							hinge2->setAxis1(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
						else if (atoi(xml->getAttributeValue("index")) == 2)
							hinge2->setAxis2(atof(xml->getAttributeValue("xDir")), atof(xml->getAttributeValue("yDir")), atof(xml->getAttributeValue("zDir")));
						else
							printd(WARNING, "JointInteraction::loadJoints(): WARNING: WRONG ATTRIBUTE FOUND IN axis ELEMENT of Hinge2Joint!!!\n");
					} // else if
					else
						printd(WARNING, "JointInteraction::loadJoints(): WARNING: JOINT-TYPE  %s NEEDS NO axis ELEMENT!!!\n", jointType.c_str());
				} // else if
				else if (!strcmp("angles", xml->getNodeName()))
				{
					if (!jointType.compare("hinge") || !jointType.compare("Hinge") || !jointType.compare("HINGE"))
					{
						HingeJoint* hinge = dynamic_cast<HingeJoint*>(joint);
						hinge->setAngles(atof(xml->getAttributeValue("min")), atof(xml->getAttributeValue("max")));
					} // if
					else
						printd(WARNING, "JointInteraction::loadJoints(): WARNING: JOINT-TYPE  %s HAS NO angles ELEMENT!!!\n", jointType.c_str());
				} // else if
				else if (!strcmp("positions", xml->getNodeName()))
				{
					SliderJoint* slider = dynamic_cast<SliderJoint*>(joint);
					slider->setPositions(atof(xml->getAttributeValue("min")), atof(xml->getAttributeValue("max")));
				} // else if
				else if (!strcmp("activateIF", xml->getNodeName()))
				{
					constraint = new Constraint(this);
					constraint->setActionType(Constraint::ACTIVATEIF);
					constraint->setOwner(joint);
					xmlParseConstraintAttributes(xml, constraint);
					joint->addConstraint(constraint);
					constraint = NULL;
				} // else if
				else if (!strcmp("deactivateIF", xml->getNodeName()))
				{
					constraint = new Constraint(this);
					constraint->setActionType(Constraint::DEACTIVATEIF);
					constraint->setOwner(joint);
					xmlParseConstraintAttributes(xml, constraint);
					joint->addConstraint(constraint);
					constraint = NULL;
				} // else if
				else if (!strcmp("activeIF", xml->getNodeName()))
				{
					constraint = new Constraint(this);
					constraint->setActionType(Constraint::ACTIVEIF);
					constraint->setOwner(joint);
					xmlParseConstraintAttributes(xml, constraint);
					joint->addConstraint(constraint);
					constraint = NULL;
				} // else if
				else if (!strcmp("inactiveIF", xml->getNodeName()))
				{
					constraint = new Constraint(this);
					constraint->setActionType(Constraint::INACTIVEIF);
					constraint->setOwner(joint);
					xmlParseConstraintAttributes(xml, constraint);
					joint->addConstraint(constraint);
					constraint = NULL;
				} // else if
				break;
			case EXN_ELEMENT_END:
				if (!strcmp("joint", xml->getNodeName()))
					finished = true;
				break;
			default:
				break;
		} // switch
	} // while
	assert(xml);
	return joint;
} // xmlParseJoint
void GazeboMechanismControl::UpdateChild()
{

  assert(joints_.size() == fake_state_->joint_states_.size());
  assert(joints_.size() == joints_damping_.size());

  //--------------------------------------------------
  //  Pushes out simulation state
  //--------------------------------------------------

  // Copies the state from the gazebo joints into the mechanism joints.
  for (unsigned int i = 0; i < joints_.size(); ++i)
  {
    if (!joints_[i])
      continue;

    fake_state_->joint_states_[i].applied_effort_ = fake_state_->joint_states_[i].commanded_effort_;

    switch(joints_[i]->GetType())
    {
    case Joint::HINGE: {
      HingeJoint *hj = (HingeJoint*)joints_[i];
      fake_state_->joint_states_[i].position_ = hj->GetAngle();
      fake_state_->joint_states_[i].velocity_ = hj->GetAngleRate();
      break;
    }
    case Joint::SLIDER: {
      SliderJoint *sj = (SliderJoint*)joints_[i];
      fake_state_->joint_states_[i].position_ = sj->GetPosition();
      fake_state_->joint_states_[i].velocity_ = sj->GetPositionRate();
      break;
    }
    default:
      abort();
    }
  }

  // Reverses the transmissions to propagate the joint position into the actuators.
  fake_state_->propagateStateBackwards();

  //--------------------------------------------------
  //  Runs Mechanism Control
  //--------------------------------------------------
  hw_.current_time_ = Simulator::Instance()->GetSimTime();
  try
  {
    mcn_.update();
  }
  catch (const char* c)
  {
    if (strcmp(c,"dividebyzero")==0)
      std::cout << "WARNING:pid controller reports divide by zero error" << std::endl;
    else
      std::cout << "unknown const char* exception: " << c << std::endl;
  }

  //--------------------------------------------------
  //  Takes in actuation commands
  //--------------------------------------------------

  // Reverses the transmissions to propagate the actuator commands into the joints.
  fake_state_->propagateEffortBackwards();

  // Copies the commands from the mechanism joints into the gazebo joints.
  for (unsigned int i = 0; i < joints_.size(); ++i)
  {
    if (!joints_[i])
      continue;

    double damping_force;
    double effort = fake_state_->joint_states_[i].commanded_effort_;
    switch (joints_[i]->GetType())
    {
    case Joint::HINGE:
      damping_force = joints_damping_[i] * ((HingeJoint*)joints_[i])->GetAngleRate();
      ((HingeJoint*)joints_[i])->SetTorque(effort - damping_force);
      break;
    case Joint::SLIDER:
      damping_force = joints_damping_[i] * ((SliderJoint*)joints_[i])->GetPositionRate();
      ((SliderJoint*)joints_[i])->SetSliderForce(effort - damping_force);
      break;
    default:
      abort();
    }
  }
}