NaN when calculating the SVD of a matrix with Eigne

Issue #69 duplicate
Fabian Gerlinghaus created an issue

Dear Samir, dear Gerald, dear anyone who might know,

in most cases my program works fine, but sometimes it crashes right after starting. I tracked the problem as far as I could. At first I thought it might be the SVD itself, but it appears that the problem starts earlier. I exit the program immediately if any element of data_->Lambda_omega_body_ is a NaN (see code attached).

The previous cout of data shows, that all the values used to calculate data_->Lambda_omega_inv_body_ which is used for the SVD are already NaN (see console output of the program). The first matrix to become NaN is data_->Trans_matrix_.matrix(). It's calculated by TAO.

Any ideas on how to fix the problem?

Thanks a lot, Fabian

CODE:

  bool CKUKAOrientationTask::computeModel()
  {
#ifdef DEBUG
    assert(has_been_init_);
    assert(S_NULL!=dynamics_);
#endif
    if(data_->has_been_init_)
    {
      bool flag = true;
      const scl::SGcModel* gcm = data_->gc_model_;

      // Calculate Body Transformation and Jacobian
      dynamics_->calculateTransformationMatrix(data_->link_id_body_,data_->Trans_matrix_);
      Eigen::Vector3d pos = data_->Trans_matrix_ * data_->pos_in_parent_;
      flag = flag && dynamics_->calculateJacobian(data_->link_id_body_,pos,data_->Jacobian_body_);



      // Split into J_v and J_omega
      data_->J_omega_body_ = data_->Jacobian_body_.block(3,0,3,data_->robot_->dof_); //angluar velocity Jacobian of Body


      // Find #DOF
      scl::sUInt dof = data_->robot_->dof_;

      std::cout << "\nBEGINNING\n";
      std::cout << "\ndata_->Trans_matrix_:\n";
      std::cout << data_->Trans_matrix_.matrix() << std::endl;
      std::cout << "\ndata_->pos_in_parent_:\n";
      std::cout << data_->pos_in_parent_ << std::endl;

      std::cout << "\ndata_->link_id_body_:\n";
      std::cout << data_->link_id_body_ << std::endl;
      std::cout << "\npos:\n";
      std::cout << pos << std::endl;

      std::cout << "\ndata_->J_omega_body_:\n";
      std::cout << data_->J_omega_body_ << std::endl;
      std::cout << "\ngcm->Ainv_:\n";
      std::cout << gcm->Ainv_ << std::endl;
      std::cout << "\ndata_->J_omega_body_.transpose():\n";
      std::cout << data_->J_omega_body_.transpose() << std::endl;

      //Lambda = (J * Ainv * J')^-1
      data_->Lambda_omega_inv_body_ = data_->J_omega_body_ * gcm->Ainv_ * data_->J_omega_body_.transpose(); // Lambda_omega for Body



      if(!lambda_inv_singular_)
      {
        //The general inverse function works very well for op-point controllers.
        //3x3 matrix inversion behaves quite well. Even near singularities where
        //singular values go down to ~0.001. If the model is coarse, use a n-k rank
        //approximation with the SVD for a k rank loss in a singularity.
        qr_.compute(data_->Lambda_omega_inv_body_);
        qr_.setThreshold(1e-25);

        if(qr_.isInvertible())
        { data_->Lambda_omega_body_ = qr_.inverse(); }
        else
        {
          std::cout<<"\nCKUKAOrientationTask::computeModel() : Warning. Lambda_omega_inv_body_ is rank deficient. Using svd. Rank = "<<qr_.rank() << std::endl;
          std::cout << std::endl << std::endl << data_->Lambda_omega_inv_body_ << std::endl;
//          std::cout << "Threshold= " << qr_.threshold() << std::endl;

          lambda_inv_singular_ = true;
        }
      }

      if(lambda_inv_singular_)
      {
        //Use a Jacobi svd. No preconditioner is required coz lambda inv is square.
        //NOTE : This is slower and generally performs worse than the simple inversion
        //for small (3x3) matrices that are usually used in op-space controllers.
        svd_.compute(data_->Lambda_omega_inv_body_,
            Eigen::ComputeFullU | Eigen::ComputeFullV | Eigen::ColPivHouseholderQRPreconditioner);
//        svd_.compute(data_->Lambda_omega_inv_body_,
//                    Eigen::ComputeFullU | Eigen::ComputeFullV | Eigen::FullPivHouseholderQRPreconditioner);



#ifdef DEBUG
        std::cout<<"\n Singular values : "<<svd_.singularValues().transpose();
#endif

        //NOTE : A threshold of .005 works quite well for most robots.
        //Experimentally determined: Take the robot to a singularity
        //and observe the response as you allow the min singular values
        //to decrease. Stop when the robot starts to go unstable.
        //NOTE : This also strongly depends on how good your model is
        //and how fast you update it. A bad model will require higher
        //thresholds and will result in coarse motions. A better model
        //will allow much lower thresholds and will result in smooth
        //motions.
        if(svd_.singularValues()(0) > 0.005)
        { singular_values_(0,0) = 1.0/svd_.singularValues()(0);  }
        else { singular_values_(0,0) = 0.0; }
        if(svd_.singularValues()(1) > 0.005)
        { singular_values_(1,1) = 1.0/svd_.singularValues()(1);  }
        else { singular_values_(1,1) = 0.0; }
        if(svd_.singularValues()(2) > 0.005)
        { singular_values_(2,2) = 1.0/svd_.singularValues()(2);  }
        else { singular_values_(2,2) = 0.0; }

        data_->Lambda_omega_body_ = svd_.matrixU() * singular_values_ * svd_.matrixV().transpose();

        std::cout<<"\nComputing the SVD:" << std::endl;
        std::cout << std::endl << std::endl << data_->Lambda_omega_body_ << std::endl << std::endl;


        for (int i=0; i<3; i++) {
            for (int j=0; j<3; j++) {
                if ( isnan(data_->Lambda_omega_body_(i,j)) ) {
                    data_->Lambda_omega_body_(i,j) = 0.0;

                    std::cout << "\nNOT A NUMBER!!!\n";
//                  exit(0);
                }
            }
        }

        std::cout<<"\nComputing the SVD:" << std::endl;
        std::cout << std::endl << std::endl << data_->Lambda_omega_body_ << std::endl << std::endl;

        for (int i=0; i<3; i++) {
            for (int j=0; j<3; j++) {
                if ( isnan(data_->Lambda_omega_body_(i,j)) ) {
                    data_->Lambda_omega_body_(i,j) = 0.0;
                    exit(0);
                }
            }
        }

        //Turn off the svd after 20 iterations
        //Don't worry, the qr will pop back to svd if it is still singular
        static scl::sInt svd_ctr = 0; svd_ctr++;
        std::cout << "Counter=" << svd_ctr << "\n";
        if(20>=svd_ctr)
        { svd_ctr = 0; lambda_inv_singular_ = false;  }
      }



      //Compute the Jacobian dynamically consistent generalized inverse :
      //J_dyn_inv = Ainv * J' * Lambda
      data_->jacobian_dyn_inv_ = gcm->Ainv_ * data_->J_omega_body_.transpose() * data_->Lambda_omega_body_;


      // Set up the null space
      // N = I-J'*J_dyn_inv'
      data_->null_space_ = Eigen::MatrixXd::Identity(dof, dof) - data_->J_omega_body_.transpose() * data_->jacobian_dyn_inv_.transpose();


      // We do not use the centrifugal/coriolis forces. They can cause instabilities.
      data_->mu_.setZero(data_->dof_task_,1);

      // J' * J_dyn_inv' * g(q)
      //data_->p_ =  data_->jacobian_dyn_inv_.transpose() * gcm->g_;
      data_->p_.setZero(data_->dof_task_,1);



      return flag;

    }
    else
    { return false; }
  }

CONSOLE OUTPUT:

CTaskOpPos::computeModel() : Warning. Lambda_inv is rank deficient. Using svd. Rank = 0
BEGINNING

data_->Trans_matrix_:
nan nan nan nan
nan nan nan nan
nan nan nan nan
  0   0   0   1

data_->pos_in_parent_:
0
1
0

data_->link_id_body_:
0xa45a228

pos:
nan
nan
nan

data_->J_omega_body_:
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan

gcm->Ainv_:
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan
nan nan nan nan nan nan nan

data_->J_omega_body_.transpose():
nan nan nan
nan nan nan
nan nan nan
nan nan nan
nan nan nan
nan nan nan
nan nan nan

CKUKAOrientationTask::computeModel() : Warning. Lambda_omega_inv_body_ is rank deficient. Using svd. Rank = 0


nan nan nan
nan nan nan
nan nan nan

Computing the SVD:


nan nan nan
nan nan nan
nan nan nan


NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

NOT A NUMBER!!!

Computing the SVD:


0 0 0
0 0 0
0 0 0

Counter=1
#!

Comments (13)

  1. Samir Menon repo owner

    Where is the entire code? Did you set all your variables to zero in the init() function? If not, some of them might have garbage values.

    Also, call computeModel() a once in the init function to set up tao's state.

  2. Fabian Gerlinghaus reporter

    Ok, I'm initializing all the variables in the init functions. That wasn't it. I'm also calling robot_.computeDynamics(); in CFabianApp::setInitialStateForUIAndDynamics() so that wasn't it either.

    Here's my complete code. I would be very grateful for any hints.

    CFabianApp.cpp

    /* This file is part of scl, a control and simulation library
    for robots and biomechanical models.
    
    scl is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 3 of the License, or (at your option) any later version.
    
    Alternatively, you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.
    
    scl is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License and a copy of the GNU General Public License along with
    scl. If not, see <http://www.gnu.org/licenses/>.
    */
    /* \file CFabianApp.cpp
     *
     *  Created on: Sep 16, 2011
     *
     *  Copyright (C) 2011
     *
     *  Author: Samir Menon <smenon@stanford.edu>
     */
    
    
    #include "CFabianApp.hpp"
    #include "CKUKAOrientationTask.hpp"
    
    #include <scl/DataTypes.hpp>
    #include <scl/data_structs/SDatabase.hpp>
    
    #include <sutil/CSystemClock.hpp>
    
    #include <chai3d.h>
    
    #include <iostream>
    #include <stdexcept>
    
    #include <Eigen/Dense>
    
    #include <math.h>
    #include <signal.h>
    
    // My Shared Memory Class
    #include "SMIC.hpp"
    
    // My Matlab Logging Class
    #include "MatlabLogger.hpp"
    
    
    #ifndef PI
    #define PI          3.1415926535897932384626433832795
    #endif
    
    #ifndef RAD
    #define RAD(A)  ((A) * PI / 180.0 )
    #endif
    
    #ifndef DEG
    #define DEG(A)  ((A) * 180.0 / PI )
    #endif
    
    
    bool ok = true;
    
    static void sighandler(int sig) {
        ok = false;
    }
    
    using namespace chai3d;
    
    namespace scl_app
    {
    
      /** Default constructor. Sets stuff to zero.
       * Uses a task controller*/
      CFabianApp::CFabianApp() :
    //      ctrl_(S_NULL),
    //      name_com_task_(""),
    //      task_com_(S_NULL),
    //      task_ds_com_(S_NULL),
    //      ui_pt_com_(-1),
    //      has_been_init_com_task_(false),
    //      chai_com_pos_(S_NULL),
    //      chai_com_pos_des_(S_NULL),
          haptic_pos_(3),
          haptic_base_pos_(3),
          old_goal_pos(3),
          base_goal_pos(3),
          has_been_init_haptics_(false)
      { }
    
      scl::sBool CFabianApp::initMyController(const std::vector<std::string>& argv,
          scl::sUInt args_parsed)
      {
        // Set up signal handler
        signal(SIGINT,  sighandler);
    
        // RUN SIMULATION (true) OR CONTROL THE REAL ROBOT (false)
        run_simulation_only=true;
        use_haptic_interface=true;
    
        capture_token_opportunity_time_window.tv_nsec   = 80000; // 0.08ms
        capture_token_opportunity_time_window.tv_sec        = 0;
    
        TimeInMillisec = 0;
    
        if(use_haptic_interface) {
            //First set up the haptics
            int tmp_n_haptics_connected = haptics_.connectToDevices();
            if(0 >= tmp_n_haptics_connected)
            { throw(std::runtime_error("Could not connect to haptic devices"));  }
    
            if (haptics_.getNumDevicesConnected() == 1) {
                has_been_init_haptics_ = true;
                scaling_factor = 5.0;
                clutch_active_previous_cycle = false;
            }
        }
    
    
        //
        // INIT FOR RUNNING THE KUKA HARDWARE IN THE LOOP
        //
        if (!run_simulation_only) {
            // Tell KUKATorqueInterface that the controller is ready to run
            SharedMemory.StartControllerProcess();
    
            // Initialize all the arrays
            memset(MeasuredJointPosInRad, 0x0, NUMBER_OF_JOINTS * sizeof(float));
            memset(MeasuredJointVelocitiesInRadPerSec, 0x0, NUMBER_OF_JOINTS * sizeof(float));
            memset(MeasuredJointTorquesInNm, 0x0, NUMBER_OF_JOINTS * sizeof(float));
            memset(CommandedJointTorquesInNm, 0x0, NUMBER_OF_JOINTS * sizeof(float));
    
            memset(CommandedOperationalPoint, 0x0, 3 * sizeof(float));
            memset(MeasuredOperationalPoint, 0x0, 3 * sizeof(float));
    
            // Add variables which will be logged
            MatLog.addFloatArray(MeasuredJointPosInRad,                 NUMBER_OF_JOINTS,   "MeasuredJointPosInRad");
            MatLog.addFloatArray(MeasuredJointVelocitiesInRadPerSec,    NUMBER_OF_JOINTS,   "MeasuredJointVelocitiesInRadPerSec");
            MatLog.addFloatArray(MeasuredJointTorquesInNm,              NUMBER_OF_JOINTS,   "MeasuredJointTorquesInNm");
            MatLog.addFloatArray(CommandedJointTorquesInNm,             NUMBER_OF_JOINTS,   "CommandedJointTorquesInNm");
    
            MatLog.addFloatArray(CommandedOperationalPoint,             3,                  "CommandedOperationalPoint");
            MatLog.addFloatArray(MeasuredOperationalPoint,              3,                  "MeasuredOperationalPoint");
    
            MatLog.addInteger(&TimeInMillisec, "TimeInMillisec");
    
        }
        //
        // INIT FOR RUNNING THE SIMULATION ONLY
        //
        else {
            memset(CommandedOperationalPoint, 0x0, 3 * sizeof(float));
            memset(MeasuredOperationalPoint, 0x0, 3 * sizeof(float));
    
            MatLog.addFloatArray(CommandedOperationalPoint,             3,                  "CommandedOperationalPoint");
            MatLog.addFloatArray(MeasuredOperationalPoint,              3,                  "MeasuredOperationalPoint");
    
            MatLog.addInteger(&TimeInMillisec, "TimeInMillisec");
        }
    
    
        // Get the robot out of the singularity to avoid the NaN-problem in the SVD of the orientation task
        //Convert Arrays to Vectors
        Eigen::VectorXd JointPosInRadVector(7);
        Eigen::VectorXd JointVelocitiesInRadPerSecVector(7);
        for (int j=0; j<NUMBER_OF_JOINTS; j++) {
            JointPosInRadVector(j)              = 0.0;
            JointVelocitiesInRadPerSecVector(j) = 0.0;
        }
    
        JointPosInRadVector(1) = RAD(22.0);
        JointPosInRadVector(3) = RAD(44.0);
    
        robot_.setGeneralizedCoordinates(JointPosInRadVector);
        robot_.setGeneralizedVelocities(JointVelocitiesInRadPerSecVector);
    
    
    
        bool flag;
        try
        {
          //Ctr in array of args_parsed = (args_parsed - 1)
          //So ctr for un-parsed arg = (args_parsed - 1) + 1
          scl::sUInt args_ctr = args_parsed, ui_points_used=0;
    
          // Check that we haven't finished parsing everything
          while(args_ctr < argv.size())
          {
            /* NOTE : ADD MORE COMMAND LINE PARSING OPTIONS IF REQUIRED */
            // else if (argv[args_ctr] == "-p")
            // { }
            if(true)
            {
              std::cout<<"\n Possible example task options: -p (start paused) -l (log file), -com (com control task), -op (op point task)";
              args_ctr++;
            }
        }
    
          return true;
        }
        catch(std::exception &e)
        { std::cout<<"\nCExampleApp::initMyController() : "<<e.what(); }
        return false;
      }
    
      scl::sBool CFabianApp::registerCustomDynamicTypes()
      {
    //    return registerFabianTaskType();
          return registerKUKAOrientationTaskType();
      }
    
      void CFabianApp::setInitialStateForUIAndDynamics()
      {
        //Compute dynamics and servo once to initialize matrices.
        robot_.computeDynamics();
        robot_.computeNonControlOperations();
        robot_.computeServo();
        robot_.setGeneralizedCoordinatesToZero();
        robot_.setGeneralizedVelocitiesToZero();
        robot_.setGeneralizedAccelerationsToZero();
    
        //Update the operational point tasks (if any)
        std::vector<SUiCtrlPointData>::iterator it,ite;
        for(it = taskvec_ui_ctrl_point_.begin(), ite = taskvec_ui_ctrl_point_.end(); it!=ite; ++it )
        {
          assert(it->has_been_init_);
          assert(NULL!=it->chai_pos_des_);
          assert(NULL!=it->task_);
          it->task_->getPos(it->pos_);
    #ifdef DEBUG
          if( (3 != it->pos_.rows() && 1 != it->pos_.cols()) ||
              (1 != it->pos_.rows() && 3 != it->pos_.cols()) )
          { assert(false);  }
    #endif
          db_->s_gui_.ui_point_[it->ui_pt_] = it->pos_;
    
          base_goal_pos(0) = -0.099;
          base_goal_pos(1) = -0.099;
          base_goal_pos(2) = 0.20;
    
          Eigen::Vector3d& ui_point_ = db_->s_gui_.ui_point_[it->ui_pt_];
          for (int i=0; i<3; i++) {
              //SET THE INITIAL DESIRED OPERATIONAL POINT
              ui_point_(i) = base_goal_pos(i);
              old_goal_pos(i) = base_goal_pos(i);
    
              if(has_been_init_haptics_) {
                  haptic_pos_(i) = 0.0;
                  haptic_base_pos_(i) = base_goal_pos(i);
              }
          }
          it->chai_pos_des_->setLocalPos(ui_point_(0),ui_point_(1),ui_point_(2));
        }
      }
    
      void CFabianApp::stepMySimulation()
      {
          // As long as user does not press Control-C ok=truex
          if(ok) {
              std::vector<SUiCtrlPointData>::iterator it,ite;
    
              // SET LIMITS TO THE OPERATIONAL POINT COORDINATES
              for(it = taskvec_ui_ctrl_point_.begin(), ite = taskvec_ui_ctrl_point_.end(); it!=ite; ++it )
              {
                  if(has_been_init_haptics_)
                  {
                      //Update the position of the first few points using the haptics
                      bool flag = haptics_.getHapticDevicePosition(0, haptic_pos_);
                      assert(flag);
    
                      // Clutch is active
                      if (db_->s_gui_.ui_flag_[1])  {
                          if(!clutch_active_previous_cycle) {
                              //Reset the clutch origin to the current position of the commanded operational task point
                              bool flag = haptics_.getHapticDevicePosition(0, haptic_base_pos_);
                              assert(flag);
                              //Reset the operational point origin to the current operational point
                              base_goal_pos = db_->s_gui_.ui_point_[it->ui_pt_];
                          }
    
    
                          // Standard mapping for the simulation
                          if (run_simulation_only) {
                              //Overwrite the UI point witht he data from the haptic device
                              db_->s_gui_.ui_point_[it->ui_pt_] = base_goal_pos + 5 * (haptic_pos_ - haptic_base_pos_);
    
                          }
                          //Invert the perspective of the robot when controlling the real KUKA for more intuitive handling from my workplace perspective
                          else {
                              //Overwrite the UI point witht he data from the haptic device
                              (db_->s_gui_.ui_point_[it->ui_pt_])(0) = base_goal_pos(0) - 5 * (haptic_pos_(0) - haptic_base_pos_(0));
                              (db_->s_gui_.ui_point_[it->ui_pt_])(1) = base_goal_pos(1) - 5 * (haptic_pos_(1) - haptic_base_pos_(1));
                              (db_->s_gui_.ui_point_[it->ui_pt_])(2) = base_goal_pos(2) + 5 * (haptic_pos_(2) - haptic_base_pos_(2));
                          }
    
    
                          clutch_active_previous_cycle = true;
                      }
                      else { clutch_active_previous_cycle = false; }
    
    
    
                  }
    
    
                  // SET the origin of the transformed coordinate system roughly to the base of the robot
                  // This origin is used for creating a sphere that serves as a limit for the workspace with the goal of avoiding singularities
                  Eigen::Vector3d pos_des_transformed;
                  pos_des_transformed(0) = (db_->s_gui_.ui_point_[it->ui_pt_])(0) + 0.099;
                  pos_des_transformed(1) = (db_->s_gui_.ui_point_[it->ui_pt_])(1) + 0.099;
                  pos_des_transformed(2) = (db_->s_gui_.ui_point_[it->ui_pt_])(2) + 0.55;
    
                  //Robot must stay in between two bounding spheres with radius 0.4m<r<0.8m
                  double norm =  sqrt(  pow (pos_des_transformed(0), 2.0) +
                                        pow (pos_des_transformed(1), 2.0) +
                                        pow (pos_des_transformed(2), 2.0)       );
    
                  // Out of bounds: Set ui_point_pos back to the last viable position and deactivate clutch
                  if( norm<0.4 || norm>0.8 || pos_des_transformed(2) < 0) {
                      db_->s_gui_.ui_point_[it->ui_pt_] = old_goal_pos;
                      db_->s_gui_.ui_flag_[1]=false; // Deactivate the clutch when leaving workspace
                  }
                  // Within bounds: Always save the last viable ui_point_pos
                  else {    old_goal_pos = (db_->s_gui_.ui_point_[it->ui_pt_]); }
    
                  //Set the goal position for the operational point tasks
                  it->task_->setGoalPos(db_->s_gui_.ui_point_[it->ui_pt_]);
    
    
    
                  // UPDATE THE ARRAYS WHICH ARE BEING TRACKED BY THE LOGGER
                  scl::STaskOpPos* task_data = dynamic_cast<scl::STaskOpPos*> (it->task_->getTaskData());
                  for (int i=0; i<3; i++) {
                      CommandedOperationalPoint[i] = (db_->s_gui_.ui_point_[it->ui_pt_])(i);
                      MeasuredOperationalPoint[i] = (task_data->x_)(i);
                  }
    //            // Transform commanded OP vector to array for logging
    //            CommandedOperationalPoint[0] = (db_->s_gui_.ui_point_[it->ui_pt_])(0);
    //            CommandedOperationalPoint[1] = (db_->s_gui_.ui_point_[it->ui_pt_])(1);
    //            CommandedOperationalPoint[2] = (db_->s_gui_.ui_point_[it->ui_pt_])(2);
    //            // Transform actual measured OP vector to array for logging
    //            MeasuredOperationalPoint[0] = (task_data->x_)(0);
    //            MeasuredOperationalPoint[1] = (task_data->x_)(1);
    //            MeasuredOperationalPoint[2] = (task_data->x_)(2);
              }
    
    
    
              sutil::CSystemClock::tick(db_->sim_dt_);//Tick the clock.
    
              //
              // SIMULATION ONLY
              //
              if (run_simulation_only) {
    //            COM TASK DOES NOT DO ANYTHING ASK SAMIR WHAT IT's THERE FOR
    //            if(has_been_init_com_task_) //Update the com task (if any)
    //            { task_com_->setGoal(db_->s_gui_.ui_point_[ui_pt_com_]); }
    
                  //Update dynamics at a slower rate
                  if(ctrl_ctr_%2 == 0)
                  {
                      robot_.computeDynamics();
                      robot_.computeNonControlOperations();
                  }
    
                  //Update graphics and/or log at a slower rate
                  if(ctrl_ctr_%10 == 0)
                  {
                      //Set the positions of the ui points
                      for(it = taskvec_ui_ctrl_point_.begin(), ite = taskvec_ui_ctrl_point_.end(); it!=ite; ++it )
                      {
                          Eigen::Vector3d& tmp_ref = db_->s_gui_.ui_point_[it->ui_pt_];
                          it->chai_pos_des_->setLocalPos(tmp_ref(0),tmp_ref(1),tmp_ref(2));
    
                          it->task_->getPos(it->pos_);
                          Eigen::VectorXd& tmp_ref2 = it->pos_;
                          it->chai_pos_->setLocalPos(tmp_ref2(0),tmp_ref2(1),tmp_ref2(2));
                      }
    
                      //              if(has_been_init_com_task_)
                      //              {
                      //                  chai_com_pos_->setLocalPos(task_ds_com_->x_(0),task_ds_com_->x_(1),task_ds_com_->x_(2));
                      //                  Eigen::Vector3d& tmp_ref2 = db_->s_gui_.ui_point_[ui_pt_com_];
                      //                  chai_com_pos_des_->setLocalPos(tmp_ref2(0),tmp_ref2(1),tmp_ref2(2));
                      //              }
                  }
    
                  //Run the servo loop
                  robot_.computeServo();
                  //Integrate system
                  robot_.integrateDynamics();
    
                  TimeInMillisec = 1000 * sutil::CSystemClock::getSimTime();
    
                  ctrl_ctr_++;//Increment the counter for dynamics computed.
    
                  // LOG ONE SET OF DATA
                  //MatLog.logData();
              }
    
              //
              // CONTROL THE KUKA LBR (HARDWARE IN THE LOOP)
              //
              else {
                  // Process Synchronization
                  // The shared memory token is used to synchronize the kuka_torque_interface with the kuka_scl_controller.
                  // The token is made available from the kuka_torque_interface right after new sensor data was read from the robot and written into the shared memory.
                  // Then the kuka_scl_controller application starts calculating the new torques immediately.
                  SharedMemory.GrabToken();
    
                  // COM TASK DOES NOT DO ANYTHING ASK SAMIR WHAT IT's THERE FOR
    //            if(has_been_init_com_task_) //Update the com task (if any)
    //            { task_com_->setGoal(db_->s_gui_.ui_point_[ui_pt_com_]); }
    
                  // ASK SAMIR WHAT THIS STUFF DOES, TOO
                  robot_.computeDynamics();
                  robot_.computeNonControlOperations();
    
                  //Set the positions of the ui points
                  for(it = taskvec_ui_ctrl_point_.begin(), ite = taskvec_ui_ctrl_point_.end(); it!=ite; ++it )
                  {
                      Eigen::Vector3d& tmp_ref = db_->s_gui_.ui_point_[it->ui_pt_];
                      it->chai_pos_des_->setLocalPos(tmp_ref(0),tmp_ref(1),tmp_ref(2));
    
                      it->task_->getPos(it->pos_);
                      Eigen::VectorXd& tmp_ref2 = it->pos_;
                      it->chai_pos_->setLocalPos(tmp_ref2(0),tmp_ref2(1),tmp_ref2(2));
                  }
    
    //            if(has_been_init_com_task_)
    //            {
    //                chai_com_pos_->setLocalPos(task_ds_com_->x_(0),task_ds_com_->x_(1),task_ds_com_->x_(2));
    //                Eigen::Vector3d& tmp_ref2 = db_->s_gui_.ui_point_[ui_pt_com_];
    //                chai_com_pos_des_->setLocalPos(tmp_ref2(0),tmp_ref2(1),tmp_ref2(2));
    //            }
    
                  // Get the data from the real robot
                  SharedMemory.GetMeasuredJointPositions(MeasuredJointPosInRad);
                  SharedMemory.GetEstimatedJointVelocities(MeasuredJointVelocitiesInRadPerSec);
                  SharedMemory.GetMeasuredJointTorques(MeasuredJointTorquesInNm);
                  TimeInMillisec = SharedMemory.GetTimeInMillisec();
    
                  // Convert Arrays to Vectors
                  Eigen::VectorXd JointPosInRadVector(7);
                  Eigen::VectorXd JointVelocitiesInRadPerSecVector(7);
                  for (int j=0; j<NUMBER_OF_JOINTS; j++) {
                      JointPosInRadVector(j)                = (double) MeasuredJointPosInRad[j];
                      JointVelocitiesInRadPerSecVector(j)   = (double) MeasuredJointVelocitiesInRadPerSec[j];
                  }
    
                  // Write the sensor data into the data structure of SCL
                  robot_.setGeneralizedCoordinates(JointPosInRadVector);
                  robot_.setGeneralizedVelocities(JointVelocitiesInRadPerSecVector);
    
                  // Let SCl compute the torques for the robot
                  robot_.computeServo();
    
                  // Store the computed torques in an array
                  Eigen::VectorXd GeneralizedForcesCommanded(7);
                  GeneralizedForcesCommanded = robot_.getGeneralizedForcesCommanded();
                  for (int j=0; j<NUMBER_OF_JOINTS; j++) { CommandedJointTorquesInNm[j] = (float) GeneralizedForcesCommanded[j]; }
    
                  // Write the commanded torques to shared memory
                  SharedMemory.SetCommandedJointTorques(CommandedJointTorquesInNm);
                  // Tel kuka_torque_interface that kuka_scl_controller is done computing the torques
                  SharedMemory.FreeToken();
                  //Wait a little to give kuka_torque_interface time to recapture the token
                  nanosleep(&capture_token_opportunity_time_window,NULL);
    
                  // Log one set of data
                  if ( SharedMemory.LoggerRunning() ) { MatLog.logData(); }
              }
          }
    
          // Control-C was cought -> tell the TorqueInterface that the controller is no longer running and write the logfile
          else {
              SharedMemory.StopControllerProcess();
              SharedMemory.StopLogging();
    
              if(run_simulation_only)   { MatLog.writeLogFile("log/logfile_sim.mat"); } // Simulation Logfile
              else                      { MatLog.writeLogFile("log/logfile_hil.mat"); } // Hardware In the Loop Logfile
              exit(1);
          }
      }
    }
    

    CFabianApp.hpp

    /* This file is part of scl, a control and simulation library
    for robots and biomechanical models.
    
    scl is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 3 of the License, or (at your option) any later version.
    
    Alternatively, you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.
    
    scl is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License and a copy of the GNU General Public License along with
    scl. If not, see <http://www.gnu.org/licenses/>.
     */
    /* \file CFabianApp.hpp
     *
     *  Created on: Sep 16, 2011
     *
     *  Copyright (C) 2011
     *
     *  Author: Samir Menon <smenon@stanford.edu>
     */
    
    #ifndef CFABIANAPP_HPP_
    #define CFABIANAPP_HPP_
    
    #include <Eigen/Dense>
    
    #include <scl/robot/CRobotApp.hpp>
    
    #include <scl/control/task/CTaskController.hpp>
    #include <scl/control/task/tasks/CTaskOpPos.hpp>
    #include <scl/control/task/tasks/CTaskComPos.hpp>
    
    #include <scl/graphics/chai/data_structs/SChaiGraphics.hpp>
    #include <scl/haptics/chai/CChaiHaptics.hpp>
    
    // My Shared Memory Class
    #include "SMIC.hpp"
    
    // My Matlab Logging Class
    #include "MatlabLogger.hpp"
    
    namespace scl_app
    {
      class CFabianApp : public scl::CRobotApp
      {
      public:
        // ****************************************************
        //                 The main functions
        // ****************************************************
        /** Runs the task controller. */
        virtual void stepMySimulation();
    
        // ****************************************************
        //           The initialization functions
        // ****************************************************
        /** Default constructor. Sets stuff to zero. */
        CFabianApp();
    
        /** Default destructor. Does nothing. */
        virtual ~CFabianApp(){}
    
        /** Sets up the task controller. */
        virtual scl::sBool initMyController(const std::vector<std::string>& argv,
            scl::sUInt args_parsed);
    
        /** Register any custom dynamic types that you have. */
        virtual scl::sBool registerCustomDynamicTypes();
    
        /** Sets all the ui points to their current position and
         * run the dynamics once to flush the state. */
        void setInitialStateForUIAndDynamics();
    
    
        //Shared Memory Object
        SMIC SharedMemory;
    
        // Pointer to the logging object
        MatlabLogger MatLog;
    
        // All the variables which should be logged need to be public
        float                       MeasuredJointPosInRad[NUMBER_OF_JOINTS];                            // Measured
        float                       MeasuredJointVelocitiesInRadPerSec[NUMBER_OF_JOINTS];               // Measured
        float                       MeasuredJointTorquesInNm[NUMBER_OF_JOINTS];                         // Measured
        float                       CommandedJointTorquesInNm[NUMBER_OF_JOINTS];
    
        float                       CommandedOperationalPoint[3];
        float                       MeasuredOperationalPoint[3];
    
        int                         TimeInMillisec;
    
      private:
        // ****************************************************
        //                      The data
        // ****************************************************
    
        // CHOOSE WHETHER TO RUN HARDWARE IN THE LOOP (false) OR SIMULATION (true)
        bool run_simulation_only;
        bool use_haptic_interface;
    
        // Workspace Limitation - Save the last viable UI Point
        Eigen::VectorXd     old_goal_pos, base_goal_pos;
        double              scaling_factor;
        bool                clutch_active_previous_cycle;
        struct timespec capture_token_opportunity_time_window;
    
        //For controlling op points with haptics
        //The app will support dual-mode control, with the haptics controlling op points.
        scl::CChaiHaptics haptics_;
        scl::sUInt num_haptic_devices_to_use_; //These will directly control ui-points.
        bool has_been_init_haptics_;
        Eigen::VectorXd haptic_pos_;
        Eigen::VectorXd haptic_base_pos_;
      };
    
    }
    
    #endif /* CFABIANAPP_HPP_ */
    

    CKUKAOrientationTask.cpp

    /* Copyright (C) 2011  Samir Menon, Stanford University
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     */
    /*
     * CKUKAOrientationTask.cpp
     *
     *  Created on: Apr 12, 2011
     *      Author: samir
     */
    
    #include "CKUKAOrientationTask.hpp"
    
    #include <scl/Singletons.hpp>
    
    #include <sutil/CRegisteredDynamicTypes.hpp>
    
    #include <stdexcept>
    
    #include <math.h>
    
    namespace scl_app
    {
      CKUKAOrientationTask::CKUKAOrientationTask() :
                      scl::CTaskBase(),
                      data_(S_NULL),
                      link_dynamic_id_(S_NULL),
                      lambda_inv_singular_(false)
      {}
    
      CKUKAOrientationTask::~CKUKAOrientationTask()
      {}
    
      bool CKUKAOrientationTask::computeServo(const scl::SRobotSensorData* arg_sensors)
      {
        static int cntr = 0;
    #ifdef DEBUG
        assert(has_been_init_);
        assert(S_NULL!=dynamics_);
    #endif
        if(data_->has_been_init_)
        {
          // COMPUTE SERVO GENERALIZED FORCES
    
          // ***************** BODY ORIENTATION ****************
    
          //Step 1: Find current orientation
    
          Eigen::Matrix3d R_cur = data_->Trans_matrix_.rotation();
    
    
          //Step 2: Find desired orientation
          // Desired orientation, keeps Divebot horizontal, only adjusts z-angle
          Eigen::Matrix3d R_des;
          //R_des.setIdentity(3,3);
          double theta_z = 0.25*3.14;
          R_des(0,0) = cos(theta_z);
          R_des(0,1) = -sin(theta_z);
          R_des(0,2) = 0;
          R_des(1,0) = sin(theta_z);
          R_des(1,1) = cos(theta_z);
          R_des(1,2) = 0;
          R_des(2,0) = 0;
          R_des(2,1) = 0;
          R_des(2,2) = 1;
    
    
          //Step 3: Find angular error
    
          //Direction cosines (current):
          Eigen::Vector3d s1_cur = R_cur.col(0);
          Eigen::Vector3d s2_cur = R_cur.col(1);
          Eigen::Vector3d s3_cur = R_cur.col(2);
          //Direction cosines (desired):
          Eigen::Vector3d s1_des = R_des.col(0);
          Eigen::Vector3d s2_des = R_des.col(1);
          Eigen::Vector3d s3_des = R_des.col(2);
    
          Eigen::Vector3d delta_PHI;
          delta_PHI = -0.5 * ( s1_cur.cross(s1_des) + s2_cur.cross(s2_des) + s3_cur.cross(s3_des) );
    
    
          //Step 4: Find angular velocity
    
          Eigen::Vector3d omega;
          omega = data_->J_omega_body_ * arg_sensors->dq_;
    
    
          //Step 5: compute unit-mass moment(=acceleration), due to rotation
    
          Eigen::Vector3d M_star;
          M_star = - data_->kp_[0] * delta_PHI - data_->kv_[0] * omega;    //TODO: expand kp, kv
    
    
          //Step 6: Compute OP-space moment
    
          Eigen::VectorXd M;
          M = data_->Lambda_omega_body_ * M_star;
    
    
          //Step 7: Compute GC torque
    
          Eigen::VectorXd force_gc_orientation;
          data_->force_gc_ = data_->J_omega_body_.transpose() * M;
    
    
    
          if(cntr++ % 10000 == 0){
    
            //std::cout << arg_sensors->q_ << std::endl << std::endl;
            //std::cout << rightOP << std::endl << std::endl;
            //std::cout << x_body_cur << std::endl << std::endl << std::endl << std::endl;
            //std::cout << "force_gc_" << std::endl << data_->force_gc_ << std::endl << std::endl << std::endl; // Cross product does not work
            //std::cout << theta_z << std::endl << std::endl << std::endl;
            //std::cout << R_cur << std::endl << std::endl << std::endl;
            //std::cout << force_task << std::endl << std::endl << std::endl;
            //std::cout << data_->Lambda_v_inv_body_ << std::endl << std::endl << std::endl;
            //std::cout << data_->p_ << std::endl << std::endl << std::endl;
            //std::cout << R_des_left << std::endl << std::endl << std::endl;
          }
    
    
          return true;
        }
        else
        { return false; }
      }
    
    
      bool CKUKAOrientationTask::computeModel()
      {
    #ifdef DEBUG
        assert(has_been_init_);
        assert(S_NULL!=dynamics_);
    #endif
        if(data_->has_been_init_)
        {
          bool flag = true;
          const scl::SGcModel* gcm = data_->gc_model_;
    
          // Calculate Body Transformation and Jacobian
          dynamics_->calculateTransformationMatrix(data_->link_id_body_,data_->Trans_matrix_);
          Eigen::Vector3d pos = data_->Trans_matrix_ * data_->pos_in_parent_;
          flag = flag && dynamics_->calculateJacobian(data_->link_id_body_,pos,data_->Jacobian_body_);
    
    
    
          // Split into J_v and J_omega
          data_->J_omega_body_ = data_->Jacobian_body_.block(3,0,3,data_->robot_->dof_); //angluar velocity Jacobian of Body
    
    
          // Find #DOF
          scl::sUInt dof = data_->robot_->dof_;
    
          std::cout << "\nBEGINNING\n";
          std::cout << "\ndata_->Trans_matrix_:\n";
          std::cout << data_->Trans_matrix_.matrix() << std::endl;
          std::cout << "\ndata_->pos_in_parent_:\n";
          std::cout << data_->pos_in_parent_ << std::endl;
    
          std::cout << "\ndata_->link_id_body_:\n";
          std::cout << data_->link_id_body_ << std::endl;
          std::cout << "\npos:\n";
          std::cout << pos << std::endl;
    
          std::cout << "\ndata_->J_omega_body_:\n";
          std::cout << data_->J_omega_body_ << std::endl;
          std::cout << "\ngcm->Ainv_:\n";
          std::cout << gcm->Ainv_ << std::endl;
          std::cout << "\ndata_->J_omega_body_.transpose():\n";
          std::cout << data_->J_omega_body_.transpose() << std::endl;
    
          //Lambda = (J * Ainv * J')^-1
          data_->Lambda_omega_inv_body_ = data_->J_omega_body_ * gcm->Ainv_ * data_->J_omega_body_.transpose(); // Lambda_omega for Body
    
    
    
          if(!lambda_inv_singular_)
          {
            //The general inverse function works very well for op-point controllers.
            //3x3 matrix inversion behaves quite well. Even near singularities where
            //singular values go down to ~0.001. If the model is coarse, use a n-k rank
            //approximation with the SVD for a k rank loss in a singularity.
            qr_.compute(data_->Lambda_omega_inv_body_);
            qr_.setThreshold(1e-25);
    
            if(qr_.isInvertible())
            { data_->Lambda_omega_body_ = qr_.inverse(); }
            else
            {
              std::cout<<"\nCKUKAOrientationTask::computeModel() : Warning. Lambda_omega_inv_body_ is rank deficient. Using svd. Rank = "<<qr_.rank() << std::endl;
              std::cout << std::endl << std::endl << data_->Lambda_omega_inv_body_ << std::endl;
    //          std::cout << "Threshold= " << qr_.threshold() << std::endl;
    
              lambda_inv_singular_ = true;
            }
          }
    
          if(lambda_inv_singular_)
          {
            //Use a Jacobi svd. No preconditioner is required coz lambda inv is square.
            //NOTE : This is slower and generally performs worse than the simple inversion
            //for small (3x3) matrices that are usually used in op-space controllers.
            svd_.compute(data_->Lambda_omega_inv_body_,
                Eigen::ComputeFullU | Eigen::ComputeFullV | Eigen::ColPivHouseholderQRPreconditioner);
    //        svd_.compute(data_->Lambda_omega_inv_body_,
    //                    Eigen::ComputeFullU | Eigen::ComputeFullV | Eigen::FullPivHouseholderQRPreconditioner);
    
    
    
    #ifdef DEBUG
            std::cout<<"\n Singular values : "<<svd_.singularValues().transpose();
    #endif
    
            //NOTE : A threshold of .005 works quite well for most robots.
            //Experimentally determined: Take the robot to a singularity
            //and observe the response as you allow the min singular values
            //to decrease. Stop when the robot starts to go unstable.
            //NOTE : This also strongly depends on how good your model is
            //and how fast you update it. A bad model will require higher
            //thresholds and will result in coarse motions. A better model
            //will allow much lower thresholds and will result in smooth
            //motions.
            if(svd_.singularValues()(0) > 0.005)
            { singular_values_(0,0) = 1.0/svd_.singularValues()(0);  }
            else { singular_values_(0,0) = 0.0; }
            if(svd_.singularValues()(1) > 0.005)
            { singular_values_(1,1) = 1.0/svd_.singularValues()(1);  }
            else { singular_values_(1,1) = 0.0; }
            if(svd_.singularValues()(2) > 0.005)
            { singular_values_(2,2) = 1.0/svd_.singularValues()(2);  }
            else { singular_values_(2,2) = 0.0; }
    
            data_->Lambda_omega_body_ = svd_.matrixU() * singular_values_ * svd_.matrixV().transpose();
    
            std::cout<<"\nComputing the SVD:" << std::endl;
            std::cout << std::endl << std::endl << data_->Lambda_omega_body_ << std::endl << std::endl;
    
    
            for (int i=0; i<3; i++) {
                for (int j=0; j<3; j++) {
                    if ( isnan(data_->Lambda_omega_body_(i,j)) ) {
                        data_->Lambda_omega_body_(i,j) = 0.0;
    
                        std::cout << "\nNOT A NUMBER!!!\n";
    //                  exit(0);
                    }
                }
            }
    
            std::cout<<"\nComputing the SVD:" << std::endl;
            std::cout << std::endl << std::endl << data_->Lambda_omega_body_ << std::endl << std::endl;
    
            for (int i=0; i<3; i++) {
                for (int j=0; j<3; j++) {
                    if ( isnan(data_->Lambda_omega_body_(i,j)) ) {
                        data_->Lambda_omega_body_(i,j) = 0.0;
                        exit(0);
                    }
                }
            }
    
            //Turn off the svd after 20 iterations
            //Don't worry, the qr will pop back to svd if it is still singular
            static scl::sInt svd_ctr = 0; svd_ctr++;
            std::cout << "Counter=" << svd_ctr << "\n";
            if(20>=svd_ctr)
            { svd_ctr = 0; lambda_inv_singular_ = false;  }
          }
    
    
    
          //Compute the Jacobian dynamically consistent generalized inverse :
          //J_dyn_inv = Ainv * J' * Lambda
          data_->jacobian_dyn_inv_ = gcm->Ainv_ * data_->J_omega_body_.transpose() * data_->Lambda_omega_body_;
    
    
          // Set up the null space
          // N = I-J'*J_dyn_inv'
          data_->null_space_ = Eigen::MatrixXd::Identity(dof, dof) - data_->J_omega_body_.transpose() * data_->jacobian_dyn_inv_.transpose();
    
    
          // We do not use the centrifugal/coriolis forces. They can cause instabilities.
          data_->mu_.setZero(data_->dof_task_,1);
    
          // J' * J_dyn_inv' * g(q)
          //data_->p_ =  data_->jacobian_dyn_inv_.transpose() * gcm->g_;
          data_->p_.setZero(data_->dof_task_,1);
    
    
    
          return flag;
    
        }
        else
        { return false; }
      }
    
      scl::STaskBase* CKUKAOrientationTask::getTaskData()
      { return data_; }
    
      bool CKUKAOrientationTask::init(scl::STaskBase* arg_task_data,
          scl::CDynamicsBase* arg_dynamics)
      {
        try
        {
          if(S_NULL == arg_task_data)
          { throw(std::runtime_error("Passed a null task data structure"));  }
    
          if(false == arg_task_data->has_been_init_)
          { throw(std::runtime_error("Passed an uninitialized task data structure"));  }
    
          if(S_NULL == arg_dynamics)
          { throw(std::runtime_error("Passed a null dynamics object"));  }
    
          if(false == arg_dynamics->hasBeenInit())
          { throw(std::runtime_error("Passed an uninitialized dynamics object"));  }
    
          data_ = dynamic_cast<SKUKAOrientationTask*>(arg_task_data);
          dynamics_ = arg_dynamics;
    
          // Gerald: Custom for this task, in order to get the transformation matrix for Body
          // TODO Change Hardcoding
          // TODO Parse Cfg.xml file for parent link of the task
          data_->link_id_body_ = dynamics_->getIdForLink("end-effector");
          if(S_NULL == data_->link_id_body_)
          { throw(std::runtime_error("The link dynamic id for the BODY operational point's parent link is NULL. Probably due to un-initialized dynamics.")); }
    
    
          has_been_init_ = true;
        }
        catch(std::exception& e)
        {
          std::cerr<<"\nCKUKAOrientationTask::init() :"<<e.what();
          has_been_init_ = false;
        }
        return has_been_init_;
      }
    
      void CKUKAOrientationTask::reset()
      {
        data_ = S_NULL;
        dynamics_ = S_NULL;
        has_been_init_ = false;
      }
    
    
      /*******************************************
                Dynamic Type : CKUKAOrientationTask
    
       NOTE : To enable dynamic typing for tasks, you
       must define the types for the "CTaskName" computation
       object AND the "STaskName" data structure. THIS IS NECESSARY.
    
       Why? So that you have a quick and easy way to specify
       custom xml parameters in the *Cfg.xml file.
       *******************************************/
      scl::sBool registerKUKAOrientationTaskType()
      {
        bool flag;
        try
        {
          sutil::CDynamicType<std::string,scl_app::CKUKAOrientationTask> typeCKUKAOrientationTask(std::string("CKUKAOrientationTask"));
          flag = typeCKUKAOrientationTask.registerType();
          if(false == flag) {throw(std::runtime_error("Could not register type CKUKAOrientationTask"));}
    
          sutil::CDynamicType<std::string,scl_app::SKUKAOrientationTask> typeSKUKAOrientationTask(std::string("SKUKAOrientationTask"));
          flag = typeSKUKAOrientationTask.registerType();
          if(false == flag) {throw(std::runtime_error("Could not register type SKUKAOrientationTask"));}
    
    #ifdef DEBUG
          std::cout<<"\nregisterKUKAOrientationTaskType() : Registered my cool task with the database";
    #endif
        }
        catch (std::exception& e)
        {
          std::cout<<"\nregisterKUKAOrientationTaskType() : Error : "<<e.what();
          return false;
        }
        return true;
      }
    }
    

    CKUKAOrientationTask.hpp

    /* Copyright (C) 2011  Samir Menon, Stanford University
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */
    /*
     * CKUKAOrientationTask.hpp
     *
     *  Created on: Apr 12, 2011
     *      Author: Samir Menon
     */
    
    #ifndef CKUKAORIENTATIONTASK_HPP_
    #define CKUKAORIENTATIONTASK_HPP_
    
    #include <scl/control/task/CTaskBase.hpp>
    
    #include "SKUKAOrientationTask.hpp"
    
    namespace scl_app
    {
    
      /** Function to register task with the database and enable
       * dynamic typing. Call this function if you want your
       * task to be initialized by specifying stuff in a file. */
      scl::sBool registerKUKAOrientationTaskType();
    
      /** This is my cool new task. */
      class CKUKAOrientationTask : public scl::CTaskBase
      {
      public:
        /*******************************************
         * CTaskBase API : TODO : IMPLEMENT THESE!!
         *******************************************/
        /** Computes the gc forces that resist gc velocity */
        virtual bool computeServo(const scl::SRobotSensorData* arg_sensors);
    
        /** Does nothing. GC tasks don't require OSC models */
        virtual bool computeModel();
    
        /** Return this task controller's task data structure.*/
        virtual scl::STaskBase* getTaskData();
    
        /** Initializes the task object. Required to set output
         * gc force dofs. */
        virtual bool init(scl::STaskBase* arg_task_data,
            scl::CDynamicsBase* arg_dynamics);
    
        /** Resets the task by removing its data.
         * NOTE : Does not deallocate its data structure */
        virtual void reset();
    
      public:
        CKUKAOrientationTask();
        virtual ~CKUKAOrientationTask();
    
      protected:
        //This will be filled in from the file
        SKUKAOrientationTask* data_;
    
        /** True when the lambda_inv matrix turns singular. */
         scl::sBool lambda_inv_singular_;
    
         /** For inverting the operational space inertia matrix
          * near singularities. 3x3 for operational point tasks. */
         Eigen::JacobiSVD<Eigen::Matrix3d > svd_;
         Eigen::Matrix3d singular_values_;
    
    
         /** For inverting the lambda matrix (when it gets singular) */
         Eigen::ColPivHouseholderQR<Eigen::Matrix3d> qr_;
    
    
         //TODO : Add what you want.
         //myCoolDataType data2_;
    
    
    
    
        const void * link_dynamic_id_;
      };
    }
    
    #endif /* CKUKAOrientationTASK_HPP_ */
    

    SKUKAOrientationTask.hpp

    /* Copyright (C) 2011  Samir Menon, Stanford University
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */
    /*
     * SKUKAOrientationTask.hpp
     *
     *  Created on: Sep 1, 2011
     *      Author: Samir Menon
     */
    
    #ifndef SKUKAORIENTATIONTASK_HPP_
    #define SKUKAORIENTATIONTASK_HPP_
    
    #include <scl/control/task/data_structs/STaskBase.hpp>
    
    namespace scl_app
    {
    
    
      class SKUKAOrientationTask : public scl::STaskBase
      {
    
      public:
        // Data
    
        Eigen::MatrixXd J_omega_body_;       //Rotation Jacobian Body
    
        Eigen::MatrixXd Jacobian_body_;       //Basic Jacobian Body
    
        Eigen::Vector3d pos_in_parent_; //Position in the parent link's local frame (x,y,z)
        std::string link_name_;         //The parent link
        const scl::SRigidBody *link_ds_;     //The parent link's parsed data structure
    
        scl::sFloat spatial_resolution_;     //Meters
    
        const void *link_id_body_;   //Link ID of body
    
        Eigen::Affine3d Trans_matrix_; //Transformation matrix from ground to the body link
    
        Eigen::Matrix3d Lambda_omega_inv_body_;
        Eigen::Matrix3d Lambda_omega_body_;
    
    
        SKUKAOrientationTask();
        virtual ~SKUKAOrientationTask();
    
        /** Processes the task's non standard parameters, which the
         * init() function stores in the task_nonstd_params_.
         *
         * NOTE : This is a sample task and hence doesn't have any non
         * standard params. You may extend it to add yours if you like. */
        virtual bool initTaskParams();
      };
    
    } /* namespace scl */
    #endif /* SKUKAOrientationTASK_HPP_ */
    

    SKUKAOrientationTask.cpp

    /* This file is part of scl, a control and simulation library
    for robots and biomechanical models.
    
    scl is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 3 of the License, or (at your option) any later version.
    
    Alternatively, you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.
    
    scl is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License and a copy of the GNU General Public License along with
    scl. If not, see <http://www.gnu.org/licenses/>.
    */
    /* \file SPostureBodyOriTask.cpp
     *
     *  Created on: Jan 1, 2011
     *
     *  Copyright (C) 2011
     *
     *  Author: Samir Menon <smenon@stanford.edu>
     */
    
    
    
    // file copied from old rotation controller
    #include "SKUKAOrientationTask.hpp"
    
    #include <stdexcept>
    #include <iostream>
    
    namespace scl_app
    {
    
      //0.5cm spatial resolution
    #define SCL_COPPTTASK_SPATIAL_RESOLUTION 0.005
    #define SCL_COPPTTASK_TASK_DOF 3
    
      SKUKAOrientationTask::SKUKAOrientationTask() : STaskBase(),
          link_name_(""),
          link_ds_(S_NULL),
          spatial_resolution_(SCL_COPPTTASK_SPATIAL_RESOLUTION),
          link_id_body_(S_NULL)
      { }
    
      SKUKAOrientationTask::~SKUKAOrientationTask()
      { }
    
    
      bool SKUKAOrientationTask::initTaskParams()
      {
        try
        {
    
          /** Extract the extra params */
          std::string parent_link_name;
          Eigen::Vector3d pos_in_parent;
    
          bool contains_plink = false, contains_posinp = false;
    
          std::vector<scl::sString2>::const_iterator it,ite;
          for(it = task_nonstd_params_.begin(), ite = task_nonstd_params_.end();
              it!=ite;++it)
          {
            const scl::sString2& param = *it;
            if(param.data_[0] == std::string("parent_link"))
            {
              parent_link_name = param.data_[1];
              contains_plink = true;
            }
            else if(param.data_[0] == std::string("pos_in_parent"))
            {
              std::stringstream ss(param.data_[1]);
              ss>> pos_in_parent[0];
              ss>> pos_in_parent[1];
              ss>> pos_in_parent[2];
    
              contains_posinp = true;
            }
          }
    
          //Error checks
    
    
          /* Gerald: don't need parent link and pos in parent at this point for this task
          if(false == contains_plink)
          { throw(std::runtime_error("Task's nonstandard params do not contain a parent link name."));  }
    
          if(false == contains_posinp)
          { throw(std::runtime_error("Task's nonstandard params do not contain a pos in parent."));  }
    
          if(0>=parent_link_name.size())
          { throw(std::runtime_error("Parent link's name is too short."));  }
    
          link_name_ = parent_link_name;
    
          link_ds_ = dynamic_cast<const scl::SRobotLink *>(robot_->robot_br_rep_.at_const(link_name_));
          if(S_NULL == link_ds_)
          { throw(std::runtime_error("Could not find the parent link in the parsed robot data structure"));  }
    
          //Initalize the task data structure.
          pos_in_parent_ = pos_in_parent;
    
          */
    
          //Set variables to zero
    
          J_omega_body_.setZero(3,robot_->dof_);
          Jacobian_body_.setZero(6,robot_->dof_);
    
          Trans_matrix_.setIdentity();
    
          Lambda_omega_inv_body_.setZero(3,3);
          Lambda_omega_body_.setZero(3,3);
    
        }
        catch(std::exception& e)
        {
          std::cerr<<"\nSKUKAOrientationTask::init() : "<<e.what();
          return false;
        }
        return true;
      }
    }
    
  3. Fabian Gerlinghaus reporter

    Finally here's the complete output of the program from one of the times, when it fails. Interesting to notice, that all the variables hold valid numbers for a couple of iterations before NaNs start to appear.

    Shared Memory already created!
    
    Initialized clock and database. Start Time:0.000118
    Running scl task controller for input file: kuka_specs/KukaCfg.xml
    scl_registry::parseRobot() : Parsed : KukaBot
    scl_registry::parseGraphics() : Parsed : KukaBotStdView
    CChaiHaptics::connectToDevices() : Searched and connected to [1] devices
    Registered haptic device: 0
    Connected to haptic device: 0
     Possible example task options: -p (start paused) -l (log file), -com (com control task), -op (op point task)
     Possible example task options: -p (start paused) -l (log file), -com (com control task), -op (op point task)
    Starting simulation. Integration timestep: 0.0005
    
    *** Robot printables ***
    
    scl>> print <printable name>
    
    Printable information                              Printable name
    
    Printable: Robot:                                       KukaBotParsed
    Printable: KukaBot SRigidBody                            end-effector
    Printable: KukaBot SRigidBody                                  link_6
    Printable: KukaBot SRigidBody                                  link_5
    Printable: KukaBot SRigidBody                                  link_4
    Printable: KukaBot SRigidBody                                  link_3
    Printable: KukaBot SRigidBody                                  link_2
    Printable: KukaBot SRigidBody                                  link_1
    Printable: KukaBot SRigidBody                                    base
    Printable: Robot:                                             KukaBot
    Printable: Task Controller:                                       opc
    Printable: Task:                                 NullSpaceDampingTask
    Printable: Task:                                               GcTask
    Printable: Task:                               EndEffectorOrientation
    Printable: Task:                                  EndEffectorPosition
    Printable: UI-point                                               ui0
    Printable: UI-point                                               ui1
    Printable: UI-point                                               ui2
    Printable: UI-point                                               ui3
    Printable: UI-point                                               ui4
    Printable: UI-point                                               ui5
    Printable: UI-point                                               ui6
    Printable: UI-point                                               ui7
    Printable: UI-point                                               ui8
    Printable: UI-point                                               ui9
    Printable: UI-point                                              ui10
    Printable: UI-point                                              ui11
    
    
    BEGINNING
    
    data_->Trans_matrix_:
      0.927185          0   0.374602 -0.0842674
             0          1          0       -0.1
     -0.374602          0   0.927185   0.240684
             0          0          0          1
    
    data_->pos_in_parent_:
    0
    1
    0
    
    data_->link_id_body_:
    0x9129228
    
    pos:
    -0.0842674
    0.9
    0.240684
    
    data_->J_omega_body_:
              0           0   -0.374605           0    0.374603           0    0.374602
              0   -0.999998           0    0.999993           0   -0.999989           0
              1 2.20953e-06    0.927184 6.62857e-06    0.927184 1.10476e-05    0.927185
    
    gcm->Ainv_:
        9.51511 0.000411905   0.0618413    0.114256     -8.7195     0.42097   -0.147174
    0.000411905     1.18352  -0.0389225     2.23625  -0.0792861     1.53848    0.106893
      0.0618413  -0.0389225     3.43027  -0.0412501    -2.47944   0.0690744  -0.0454203
       0.114256     2.23625  -0.0412501     6.70086     2.93338     12.0791    -3.00967
        -8.7195  -0.0792861    -2.47944     2.93338     121.871     11.3207    -112.002
        0.42097     1.53848   0.0690744     12.0791     11.3207      124.46    -11.7609
      -0.147174    0.106893  -0.0454203    -3.00967    -112.002    -11.7609     3377.48
    
    data_->J_omega_body_.transpose():
              0           0           1
              0   -0.999998 2.20953e-06
      -0.374605           0    0.927184
              0    0.999993 6.62857e-06
       0.374603           0    0.927184
              0   -0.999989 1.10476e-05
       0.374602           0    0.927185
    
    scl>> 
    BEGINNING
    
    data_->Trans_matrix_:
           1        0        0     -0.1
           0        1        0     -0.1
           0        0        1 0.301995
           0        0        0        1
    
    data_->pos_in_parent_:
    0
    1
    0
    
    data_->link_id_body_:
    0x9129228
    
    pos:
    -0.1
    0.9
    0.301995
    
    data_->J_omega_body_:
              0           0           0           0           0           0           0
              0   -0.999998           0    0.999993           0   -0.999989           0
              1 2.20953e-06           1 6.62857e-06           1 1.10476e-05           1
    
    gcm->Ainv_:
      58.9163  0.620199  -58.8712   1.38802 -0.121656   1.12397 0.0767997
     0.620199   2.04174  -0.47263   4.56919 -0.400394   3.69979  0.252805
     -58.8712  -0.47263   117.794 -0.303378  -57.8852   1.93882  -1.03738
      1.38802   4.56919 -0.303378   12.7088    1.5716   17.4816  -2.65629
    -0.121656 -0.400394  -57.8852    1.5716   169.253   8.41725  -111.246
      1.12397   3.69979   1.93882   17.4816   8.41725   129.275  -11.4803
    0.0767997  0.252805  -1.03738  -2.65629  -111.246  -11.4803   3377.51
    
    data_->J_omega_body_.transpose():
              0           0           1
              0   -0.999998 2.20953e-06
              0           0           1
              0    0.999993 6.62857e-06
              0           0           1
              0   -0.999989 1.10476e-05
              0           0           1
    
    CKUKAOrientationTask::computeModel() : Warning. Lambda_omega_inv_body_ is rank deficient. Using svd. Rank = 2
    
    
              0           0           0
              0     107.321 -0.00111085
              0 -0.00111085     3265.31
    
    Computing the SVD:
    
    
                0  1.49167e-154  5.24706e-161
     2.68156e+154  9.43259e+147  3.31799e+141
      9.4326e+147 -2.68156e+154 -9.43259e+147
    
    
    Computing the SVD:
    
    
                0  1.49167e-154  5.24706e-161
     2.68156e+154  9.43259e+147  3.31799e+141
      9.4326e+147 -2.68156e+154 -9.43259e+147
    
    Counter=1
    
    BEGINNING
    
    data_->Trans_matrix_:
      0.734938   0.663146  -0.141764  -0.500279
    -0.0730155  -0.130438  -0.988749   0.362399
     -0.674187   0.737017 -0.0474396  -0.426256
             0          0          0          1
    
    data_->pos_in_parent_:
    0
    1
    0
    
    data_->link_id_body_:
    0x9129228
    
    pos:
    0.162867
    0.23196
    0.310761
    
    data_->J_omega_body_:
              0   -0.321739   -0.927006   -0.188743  -0.0566774   -0.203358   -0.141764
              0   -0.946826    0.315004   0.0770934    0.994388   0.0760046   -0.988749
              1 2.20953e-06    0.203531   -0.978982   0.0892419   -0.976128  -0.0474396
    
    gcm->Ainv_:
       0.930939  -0.0315523  -0.0934681     1.37798  -0.0721924    0.290922 -0.00913485
     -0.0315523     1.81835    -3.13631  -0.0541479     3.12147  -0.0511279    0.675357
     -0.0934681    -3.13631     7.95058   -0.140772    -5.30878    0.074136   -0.616924
        1.37798  -0.0541479   -0.140772     4.49057     -3.1956     4.47282    -3.02446
     -0.0721924     3.12147    -5.30878     -3.1956     113.125    -5.16548     106.712
       0.290922  -0.0511279    0.074136     4.47282    -5.16548     95.2348    -4.96783
    -0.00913485    0.675357   -0.616924    -3.02446     106.712    -4.96783     3369.03
    
    data_->J_omega_body_.transpose():
              0           0           1
      -0.321739   -0.946826 2.20953e-06
      -0.927006    0.315004    0.203531
      -0.188743   0.0770934   -0.978982
     -0.0566774    0.994388   0.0892419
      -0.203358   0.0760046   -0.976128
      -0.141764   -0.988749  -0.0474396
    
    BEGINNING
    
    data_->Trans_matrix_:
    -nan -nan -nan -nan
    -nan -nan -nan -nan
    -nan -nan -nan -nan
       0    0    0    1
    
    data_->pos_in_parent_:
    0
    1
    0
    
    data_->link_id_body_:
    0x9129228
    
    pos:
    -nan
    -nan
    -nan
    
    data_->J_omega_body_:
    -nan -nan -nan -nan -nan -nan -nan
    -nan -nan -nan -nan -nan -nan -nan
    -nan -nan -nan -nan -nan -nan -nan
    
    gcm->Ainv_:
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    nan nan nan nan nan nan nan
    
    data_->J_omega_body_.transpose():
    -nan -nan -nan
    -nan -nan -nan
    -nan -nan -nan
    -nan -nan -nan
    -nan -nan -nan
    -nan -nan -nan
    -nan -nan -nan
    
    CKUKAOrientationTask::computeModel() : Warning. Lambda_omega_inv_body_ is rank deficient. Using svd. Rank = 0
    
    
    nan nan nan
    nan nan nan
    nan nan nan
    
    Computing the SVD:
    
    
    nan nan nan
    nan nan nan
    nan nan nan
    
    
    NOT A NUMBER!!!
    
  4. geraldb

    I guess the problem is within dynamics_->calculateTransformationMatrix. Can you try to dig deeper into that function and see (cout or debug) what's going on in there when the error occurs?

    Have you experienced Eigen reporting rank deficiencies when the Lamba matrix actually is invertible?

  5. Fabian Gerlinghaus reporter

    Here's the implementation of calculateTransformationMatrix:

      sBool CTaoDynamics::calculateTransformationMatrix(
          const void* arg_link_id,
          Eigen::Affine3d& arg_T)
      {
        const taoDNode * link_addr;
        link_addr = static_cast<const taoDNode *>(arg_link_id);
        bool flag = model_->getGlobalFrame(link_addr,arg_T);
        return flag;
      }
    

    then one level deeper there's the implementation of getGlobalFrame:

      bool Model::getGlobalFrame(taoDNode const * node,
          Eigen::Affine3d & global_transform) const
      {
        if ( ! node) {
          return false;
        }
    
        deFrame const * tao_frame(node->frameGlobal());
        deQuaternion const & tao_quat(tao_frame->rotation());
        deVector3 const & tao_trans(tao_frame->translation());
    
    #ifndef WIN32
    #warning "TO DO: maybe the other way around..."
    #endif
        // beware: Eigen::Quaternion(w, x, y, z) asks for w first, (but stores it as xyzw)
        // whereas
        // deQuaternion(qx, qy, qz, qw) asks for w last and stores it as xyzw.
        //DE_MATH_API void deSetQ4S4(deFloat* res, const deFloat x, const deFloat y, const deFloat z, const deFloat w)
        //{ res[0] = x; res[1] = y; res[2] = z; res[3] = w; }
        global_transform = Eigen::Translation3d(tao_trans[0], tao_trans[1], tao_trans[2]);
        global_transform *= Eigen::Quaternion<double>(tao_quat[3], tao_quat[0], tao_quat[1], tao_quat[2]);
    
        return true;
      }
    

    Since I still don't have a debugger under 32 bit ;-) I'll just cout the hell out of stuff :-)

  6. Fabian Gerlinghaus reporter

    OK, I COUTed lots of stuff and tracked the first appearance of a NaN to tao_trans in Model::getGlobalFrame

    That one in turn is defined in TaoDeFrame.h:

    #ifndef _deFrame_h
    #define _deFrame_h
    /*!
     *  \brief      Transformation class using quaternion 
     *  \ingroup    deMath
     *
     *  This class consists of a quaternion for rotation and a vector for translation.
     *  \sa deVector3, deQuaternion, deTransform
     */
    class deFrame
    {
    public:
      /** Default ctor inits to identity. */
      inline deFrame() { identity(); }
    
      /** Construction from three floats ends up as pure translation. */
      inline deFrame(deFloat tx, deFloat ty, deFloat tz)
      { set(deQuaternion(), deVector3(tx, ty, tz)); }
    
      inline deFrame(deFrame const & orig): _q(orig._q), _v(orig._v) {}
    
        //! \return rotation part
        deQuaternion& rotation() { return _q; }
        //! \return rotation part
        const deQuaternion& rotation() const { return _q; }
        //! \return translation part
        deVector3& translation() { return _v;; }
        //! \return translation part
        const deVector3& translation() const { return _v; }
        //! this = identity matrix
        DE_MATH_API void identity();
        //! this = f
        DE_MATH_API void operator=(const deFrame & f);
    
      /**
         Combine two frame transformations: \c f2 gets rotated and
         translated by \c f1. For example, if you know the COM frame of a
         link relative to its local frame, and you want to know the global
         COM position given the global position of the local frame, you
         do:
         \code
         deFrame com_wrt_link, link_wrt_global;
         deFrame com;
         com.multiply(link_wrt_global, com_wrt_link);
         \endcode
    
         \note Do NOT invoke this method on one of the parameters, because
         the operation is not atomic. If you want to replace a frame by
         the result of this multiplication, use a temporary object.
    
         \code
         // old pseudo-code documentation for this method:
         this = f1 * f2 = [r1,p1][r2,p2] = [r1*r2, r1*p2 + p1]
         \endcode
    
         \code
         // BAD example: this will produce garbage
         deFrame foo, bar;
         foo.multiply(foo, bar); // foo gets partially modified half way through the operation
         \endcode
    
         \code
         // GOOD example: use a temporary object if you want to replace a frame
         deFrame foo, bar;
         foo.multiply(deFrame(foo), bar);
         \endcode
      */
        DE_MATH_API void multiply(const deFrame& f1, const deFrame& f2);
    
        //! this = f1^-1 * f2 
        //       = ~[r1,p1][r2,p2] = [~r1, -(~r1*p1)][r2,p2] = [~r1*r2, ~r1*p2 - (~r1*p1)]
        //       = [~r1*r2, ~r1*(p2-p1)]
        DE_MATH_API void inversedMultiply(const deFrame& f1, const deFrame& f2);
        //! this = f1 * f2^-1 
        //       = [r1,p1]~[r2,p2] = [r1,p1][~r2, -(~r2*p2)] = [r1*~r2, -r1*(~r2*p2) + p1]
        //       = [r1*~r2, -r1*~r2*p2 + p1]
        DE_MATH_API void multiplyInversed(const deFrame& f1, const deFrame& f2);
        //! this = f^-1
        //       =  ~[r,p] = [~r, -(~r*p)]
        DE_MATH_API void inverse(const deFrame& f);
        //! this = t
        DE_MATH_API void set(const deTransform& t);
        //! this = [q, v]
        DE_MATH_API void set(const deQuaternion& q, const deVector3& v);
    
    private:
        deQuaternion _q;
        deVector3 _v;
    };
    
    #endif // _deFrame_h
    

    Any idea where to go on from here?

  7. Fabian Gerlinghaus reporter

    In getGlobalFrame this line is used:

    deFrame const * tao_frame(node->frameGlobal());

    node is of type taoDNode and in taoDNode.h the method frameGlobal() is commented out: //virtual deFrame* frameGlobal() = 0;

    Suspicious?

  8. Fabian Gerlinghaus reporter

    I commented it in and then the compiler complains:

    /home/fabian/KUKA_Teleoperation/01_Drivers/scl-manips-group.git/src/scl/dynamics/tao/jspace/Model.cpp: In member function ‘bool jspace::Model::getGlobalFrame(const taoDNode*, Eigen::Affine3d&) const’:
    /home/fabian/KUKA_Teleoperation/01_Drivers/scl-manips-group.git/src/scl/dynamics/tao/jspace/Model.cpp:284:49: error: passing ‘const taoDNode’ as ‘this’ argument of ‘virtual deFrame* taoDNode::frameGlobal()’ discards qualifiers [-fpermissive]
    /home/fabian/KUKA_Teleoperation/01_Drivers/scl-manips-group.git/src/scl/dynamics/tao/jspace/Model.cpp: In member function ‘bool jspace::Model::computeJacobian(const taoDNode*, Eigen::MatrixXd&) const’:
    /home/fabian/KUKA_Teleoperation/01_Drivers/scl-manips-group.git/src/scl/dynamics/tao/jspace/Model.cpp:380:46: error: passing ‘const taoDNode’ as ‘this’ argument of ‘virtual deFrame* taoDNode::frameGlobal()’ discards qualifiers [-fpermissive]
    

    Any smart ideas?

  9. Samir Menon repo owner

    This bug's resolution is to stop using tao for Jacobians. Transition to scl dynamics.

  10. Log in to comment