Versions Compared

Key

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

...

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
 /**
 * Finds a control input history that achieves certain desired features
 * of a cat's flipping maneuver, as determined by the objective function.
 * The control of the system is performed via a PrescribedController that
 * uses a spline for all actuators.
 *
 * Parameters are ordered by actuator, then by spline point index for a
 * given actuator. Parameters are nondimensionalized by the min or max
 * control values for the associated actuator.
 * */
class FlippinFelinesOptimizerSystem : public SimTK::OptimizerSystem {
public:

    FlippinFelinesOptimizerSystem(OpenSim::FlippinFelinesOptimizerTool & tool) :
        _tool(tool),
        _duration(1.0),
        _objectiveCalls(0),
        _objectiveFcnValueBestYet(SimTK::Infinity),
    {
        // Parse inputs & prepare output
        // --------------------------------------------------------------------
	    // ********** PART C.1 **********

        // Add a controller to the model to control its actuators
        // --------------------------------------------------------------------
        // ********** PART C.2 **********

		// Set parameter limits/bounds for the optimization.
        // --------------------------------------------------------------------
        // ********** PART C.3 **********

    }

    SimTK::Vector initialParameters()
    {
        // ********** PART C.4 **********
    }
   	// ...

    /**
     * Defines desired features for the cat model's flip. Each call to this
     * function updates the model's control, runs a forward dynamic simulation
     * with this control, computes the objective value resulting from the
     * simulation, and saves the results to output.
     * */
    int objectiveFunc(const SimTK::Vector & parameters, bool new_parameters,
            SimTK::Real & f) const
    {
        // ...
        // Unpack parameters into the model (i.e., update spline points)
        // --------------------------------------------------------------------
        // ********** PART C.5 **********

		// Run a forward dynamic simulation
        // --------------------------------------------------------------------
        // ********** PART C.6 **********

        // Construct the objective function, term by term
        // --------------------------------------------------------------------
        // ********** PART C.7 **********

        // Update the log and outputs with the objective function value
        // --------------------------------------------------------------------
        // ********** PART C.8 **********

    }
    // Miscellaneous functions (used, but uninteresting)
    // ------------------------------------------------------------------------
    // ********** PART C.109 **********

private:

    // Objective function terms
    // ------------------------------------------------------------------------
    // ********** PART C.7 **********

	// Member variables
    // ------------------------------------------------------------------------
	// ********** PART C.910 **********

};

TODO why you would look at the member variables sectionThroughout, we'll be making use of member variables we've defined. To see their declarations, see part C.10.

C.1: Parse inputs and prepare output

C.2: Add a controller to the model to control its actuators

C.3: Set parameter limits/bounds for the optimization

C.4: Initial parameters

C.5: Unpack parameters into the model

C.6: Run a forward dynamic simulation

C.7: The objective function

C.8: Update the log and outputs

C.9: Member variables

...

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Parse inputs
// --------------------------------------------------------------------
_name = _tool.get_results_directory();
_cat = OpenSim::Model(_tool.get_model_filename());

// Disable coordinate limit forces?
if (!_tool.get_use_coordinate_limit_forces())
{
    SimTK::State& initState = _cat.initSystem();
    // Loop over all forces in model.
    using OpenSim::CoordinateLimitForce;
    for (int iFor = 0; iFor < _cat.getForceSet().getSize(); iFor++)
    {
        CoordinateLimitForce * LF = dynamic_cast<CoordinateLimitForce *> (&_cat.updForceSet().get(iFor));
        if (LF)
        { // If it is a coordinate limit force, disable it.
            _cat.updForceSet().get(iFor).setDisabled(initState, true);
        }
    }
}

_numOptimSplinePoints = _tool.get_num_optim_spline_points();

// Prepare output
// --------------------------------------------------------------------

// Create a results directory for all the output files.
#if defined(_WIN32)
    _mkdir(_name.c_str());
#else
    mkdir(_name.c_str(), 0777);
#endif

// Serialize what we just deserialized, in the results directory, to keep
// everything in one organized place.
_tool.print(_name + "/" + _name + "_setup.xml");

// Create a log for the objective function value and the separate terms
// that go into it.
_optLog.open((_name + "/" + _name + "_log.txt").c_str(), std::ofstream::out);
_optLog << "Flippin Felines optimization log: " << _name << std::endl;
time_t rawtime; time(&rawtime);
_optLog << ctime(&rawtime);
_optLog << "Model file name: " << _tool.get_model_filename() << std::endl;

C.2: Add a controller to the model to control its actuators

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Compute the number of optimization parameters for the model.
_numActuators = _cat.getActuators().getSize();
int numParameters = _numActuators * _numOptimSplinePoints;
setNumParameters(numParameters);

// Size the vector of best-yet splines.
_splinesBestYet.resize(_numActuators);

// Add a PrescribedController to the model.
using OpenSim::PrescribedController;
PrescribedController * flipController = new PrescribedController();
flipController->setName("flip_controller");

// Set the PrescribedController to control all actuators.
flipController->setActuators(_cat.getActuators());

// Add the PrescribedController to the model.
_cat.addController(flipController);

// Create SimmSpline's for each actuator and push into vector.
double indexToTimeInSeconds =
    _duration / (double)(_numOptimSplinePoints - 1);
for (int i = 0; i < _numActuators; i++)
{
    // Create a spline function for the current actuator.
    _splines.push_back(new OpenSim::SimmSpline());
    // Name this spline with the name of the current actuator.
    _splines[i]->setName(_cat.getActuators().get(i).getName());
    // Add the correct number of points to this spline.
    for (int j = 0; j < _numOptimSplinePoints; j++)
    {
        // Scale the time points appropriately.
        double thisTime = (double)j * indexToTimeInSeconds;
        _splines[i]->addPoint(thisTime, 0.0);
    }
    // Tell the controller about this function.
    flipController->prescribeControlForActuator(i, _splines[i]);
} 

C.3: Set parameter limits/bounds for the optimization

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Set (nondimensional) parameter limits/bounds for the actuators.
SimTK::Vector lowerLimits(getNumParameters(), -1.0);
SimTK::Vector upperLimits(getNumParameters(), 1.0);
setParameterLimits(lowerLimits, upperLimits);

C.4: Initial parameters

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
SimTK::Vector initialParameters()
{
    SimTK::Vector initParams(getNumParameters(), 0.0);
    if (_tool.get_initial_parameters_filename() != "")
    { // A file is specified.
        // Deserialize the initial parameters XML file.
        OpenSim::FunctionSet initFcns(_tool.get_initial_parameters_filename());
        // Write a copy of the FunctionSet to the results directory.
        initFcns.print(_name + "/" + _name + "_initial_parameters.xml");
        OpenSim::Array<std::string> initNames;
        initFcns.getNames(initNames);
        
        // This loop is set up so that the initFcns do not need to be in the same
        // order as the optimization parameters. Also, the number of initFcns
        // specified by the initial parameters file can be greater than the
        // number of actuators in the model (assuming that the initial parameters
        // file AT LEAST contains the model's actuators).
        using OpenSim::SimmSpline;
        for (int iAct = 0; iAct < _numActuators; iAct++)
        {
            // Get index of the initFcn corresponding to the actuator.
            int iFcn = initFcns.getIndex(_cat.getActuators().get(iAct).getName());
            // Get access to the spline's methods.
            SimmSpline * fcn =
                dynamic_cast<SimmSpline *>(&initFcns.get(iFcn));
            for (int iPts = 0; iPts < _numOptimSplinePoints; iPts++)
            {
                // Find the right index in the optimization parameters.
                int paramIndex = iAct * _numOptimSplinePoints + iPts;
                // Transfer y value from input to initial parameters.
                initParams[paramIndex] = fcn->getY(iPts);
            }
        }
    }
    return initParams;
}

C.5: Unpack parameters into the model

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Increment the count of calls to this function.
_objectiveCalls++;

// Unpack parameters into the model (i.e., update spline points)
// --------------------------------------------------------------------
for (int iAct = 0; iAct < _numActuators; iAct++)
{
    // Max/min for all spline points for the i-th actuator.
    double minControl = _cat.getActuators().get(iAct).getMinControl();
    double maxControl = _cat.getActuators().get(iAct).getMaxControl();

    // Visit each point in this spline.
    for (int iPts = 0; iPts < _numOptimSplinePoints; iPts++)
    {
        int paramIndex = iAct * _numOptimSplinePoints + iPts;

        // Dimensionalize the control value.
        double dimControlValue;
        if  (parameters[paramIndex] < 0 && minControl < 0)
        { // parameter and minControl are both neg; must negate again.
            dimControlValue = -minControl * parameters[paramIndex];
        }
        else
        {
            dimControlValue = maxControl * parameters[paramIndex];
        }

        // Edit the spline with the dimensional control value.
        _splines[iAct]->setY(iPts, dimControlValue);
    }
}

C.6: Run a forward dynamic simulation

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
SimTK::State& initState = _cat.initSystem();

// Construct an integrator.
SimTK::RungeKuttaMersonIntegrator integrator(_cat.getMultibodySystem());
integrator.setAccuracy(1.0e-6);

// Construct a manager to run the integration.
OpenSim::Manager manager(_cat, integrator);
_cat.getMultibodySystem().realize(initState, SimTK::Stage::Acceleration);

// Integrate from initial time to final time
manager.setInitialTime(0.0);
manager.setFinalTime(_duration);
manager.integrate(initState);

C.7: The objective function

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Will be writing to a log while constructing the objective function.
if (_objectiveCalls % _outputPeriod == 0)
    _optLog << _objectiveCalls;

// Copy the model's state. We need a consistent state to access the
// model's configuration and related speeds.
SimTK::State aState = initState;
_cat.getMultibodySystem().realize(aState, SimTK::Stage::Acceleration);
const OpenSim::CoordinateSet& coordinates = _cat.getCoordinateSet();
double roll = coordinates.get("roll").getValue(aState);
double rollRate = coordinates.get("roll").getSpeedValue(aState);
double rollAccel = coordinates.get("roll").getAccelerationValue(aState);
double twist = coordinates.get("twist").getValue(aState);
double twistRate = coordinates.get("twist").getSpeedValue(aState);
double twistAccel = coordinates.get("twist").getAccelerationValue(aState);
double hunch = coordinates.get("hunch").getValue(aState);
double pitch = coordinates.get("pitch").getValue(aState);
double pitchRate = coordinates.get("pitch").getSpeedValue(aState);
double pitchAccel = coordinates.get("pitch").getAccelerationValue(aState);

// --------------------------------------------------------------------
f = 0;
f += anteriorLegsDownTerm(roll, rollRate, rollAccel);
f += posteriorLegsDownTerm(twist, twistRate, twistAccel);
f += sagittalSymmetryTerm(hunch, pitch, pitchRate, pitchAccel);
// --------------------------------------------------------------------
Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
/**
 * Helper function for writing data to the log.
 * */
double processObjTerm(std::string name, double weight, double term) const
{
    if (_objectiveCalls % _outputPeriod == 0)
        _optLog << " " << name << " " << weight * term;
    return weight * term;
}
/**
* The following functions must be 'const' because objectiveFunc() is const;
* cannot call member functions within a const member function unless those
* functions are also const.
*
* These functions are also defined inline (definition is inside the class
* definition) for efficiency: the compiler will 'paste' the function body
* into the place where the function is called.
* */
double anteriorLegsDownTerm(
        double roll, double rollRate, double rollAccel) const
{
    if (_tool.get_anterior_legs_down_weight() != 0.0)
    {
        return processObjTerm("anterior_legs_down", _tool.get_anterior_legs_down_weight(),
                pow(roll - SimTK::Pi, 2) + _relw * pow(rollRate, 2) + _relw * pow(rollAccel, 2));
    }
    return 0.0;
}
double posteriorLegsDownTerm(
        double twist, double twistRate, double twistAccel) const
{
    if (_tool.get_posterior_legs_down_weight() != 0.0)
    {
        return processObjTerm("posterior_legs_down", _tool.get_posterior_legs_down_weight(),
                pow(twist - 0.0, 2) + _relw * pow(twistRate, 2) + _relw * pow(twistAccel, 2));
    }
    return 0.0;
} 

double sagittalSymmetryTerm(
        double hunch, double pitch, double pitchRate, double pitchAccel) const
{
    if (_tool.get_sagittal_symmetry_weight() != 0.0)
    {
        return processObjTerm("sagittal_symmetry", _tool.get_sagittal_symmetry_weight(),
                pow(hunch + 2 * pitch, 2) + _relw * pow(pitchRate, 2) + _relw * pow(pitchAccel, 2));
    }
    return 0.0;
}

C.8: Update the log and outputs

We now return to objectiveFunc(), after we've finished assembling f.

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
_lastCallWasBestYet = _thisCallIsBestYet;
_thisCallIsBestYet = f <= _objectiveFcnValueBestYet;
if (_thisCallIsBestYet) _objectiveFcnValueBestYet = f;
if (_objectiveCalls % _outputPeriod == 0)
    _optLog << " objfcn " << f << " objfcn_best_yet " << _objectiveFcnValueBestYet << std::endl;
// If this is the best yet (i.e., smallest objective function value),
// save a copy of the splines.
if (_thisCallIsBestYet)
{
    for (unsigned int iFcn = 0; iFcn < _splinesBestYet.size(); iFcn++)
        _splinesBestYet[iFcn] = *_splines[iFcn];
}
// If this is worse, print out the best-yet splines and current model
// (NOTE: current model is NOT "best yet", but the idea is that it will
// be close). Also print out nondimensionalized splines so that they can
// be used directly as input for a subsequent optimization.
if (_lastCallWasBestYet && !_thisCallIsBestYet)
{
    printBestYetPrescribedControllerFunctionSet(
            _name + "_best_yet_parameters.xml");
    printBestYetPrescribedControllerFunctionSet(
            _name + "_best_yet_parameters_nomdim.xml", true);
    printModel(_name + "_best_yet.osim");
}
// Print out to the terminal/console every so often.
if (_objectiveCalls % _outputPeriod == 0)
    std::cout << "Objective call # " << _objectiveCalls << std::endl;
return 0;

C.9: Miscellaneous functions

Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
 

C.10: Member variables

// (NOTE: 'mutable' lets us modify the member variable inside const member
// functions, such as objectiveFunc() above). TODO
Code Block
languagecpp
titleFlippinFelinesOptimizerSystem.h
// Reference to the FlippinFelinesOptimizerTool.
OpenSim::FlippinFelinesOptimizerTool & _tool;

// Simulation runtime (seconds).
double _duration;

// Model containing the attributes described in this class' description
mutable OpenSim::Model _cat;

// Number of actuators in the model.
int _numActuators;

// Number of points used to define splines for actuator control.
int _numOptimSplinePoints;

// Vector of splines used in the PrescribedController.
std::vector<OpenSim::SimmSpline *> _splines;

// Vector of splines that gave the best objective value yet.
mutable std::vector<OpenSim::SimmSpline> _splinesBestYet;

// Number of calls to the objective function.
mutable int _objectiveCalls;

// Name of results directory.
std::string _name;

// Log for recording data during optimization
mutable std::ofstream _optLog;

// Period for how often objective terms are printed to the log.
static const int _outputPeriod = 100;

// Best (lowest) value of the objective function, for logging.
mutable double _objectiveFcnValueBestYet;

// To aid with conservative printing of best yet actuation:
mutable bool _lastCallWasBestYet;
mutable bool _thisCallIsBestYet; 

 

 

TODO MUTABLES

 

TODO talk about controls

...