coin-or / CppAD

A C++ Algorithmic Differentiation Package: Home Page
https://cppad.readthedocs.io
Other
446 stars 94 forks source link

CppAD::cg::CGException: what(): GreaterThanZero cannot be called for non-parameters #177

Closed IoannisDadiotis closed 1 year ago

IoannisDadiotis commented 1 year ago

Hi,

I am using CppAD in a robotics application for differentiating the robot forward kinematics. Sorry for not providing a compact piece of code to reproduce the issue for now, I will try to describe the problem. My overall application is using CppAD through a CPPAdInterface. The idea is that the user defines the function adFunction_ to be differentiated. Then the models are created, compiled with CppAD and saved through createModels.

In my case the adFunction_ is defined as the orientation of a robot frame, which is given as rotation matrix from the software used for kinematics (pinocchio in my case) but has to be converted to euler angles through the Eigen::MatrixBase< Derived >::eulerAngles. So my code looks like this:

ad_vector_t getOrientationCppAd(PinocchioInterfaceCppAd& pinocchioInterfaceCppAd,
                                                       const PinocchioStateInputMapping<ad_scalar_t>& mapping,
                                                       const ad_vector_t& state) {
  using ad_quaternion_t = Eigen::Quaternion<ad_scalar_t>;

  const auto& model = pinocchioInterfaceCppAd.getModel();
  auto& data = pinocchioInterfaceCppAd.getData();
  const ad_vector_t q = mapping.getPinocchioJointPosition(state);

  pinocchio::forwardKinematics(model, data, q);
  pinocchio::updateFramePlacements(model, data);

  ad_vector_t orientations(3 * endEffectorFrameIds_.size());
  for (int i = 0; i < endEffectorFrameIds_.size(); i++) {
    const size_t frameId = endEffectorFrameIds_[i];
    const auto euler = data.oMf[frameId].rotation().eulerAngles(0, 1, 2);
    orientations.segment<3>(3 * i) = euler;
  }
  return orientations;
}

, where getOrientationCppAd added as adFunction_ of a CppAdInterface object. The type declarations used can be found here.

I have noticed that when using the eulerAngles() function I get the following error during compiling with CppAD.

terminate called after throwing an instance of 'CppAD::cg::CGException'
what():  GreaterThanZero cannot be called for non-parameters

More in particular I have been trying to trace the problem inside eulerAngles function and it seems that the problem was found in this line when evaluating (!odd) inside the if statement. However this expression inside an if condition is also used in another line above which does not cause a problem during compilation.

Do you have an idea of what may be the issue?

bradbell commented 1 year ago

Are you able to run the same code without using CppADCodeGen; i.e, just using CppAD ?

IoannisDadiotis commented 1 year ago

Since I am quite new to CppAD and CppADCodeGen and I am only using it inside an existing open source library I am not sure how can I do this.

IoannisDadiotis commented 1 year ago

Just a guess for what can be a solution, based on previous issues I may have to replace the condition below if((odd && res[0]<SCALAR_T(0)) || ((!odd) && res[0]>SCALAR_T(0))) with a combination of CppAD::CondExpOp

bradbell commented 1 year ago

Yes, that should solve your problem, but it involves changing eigen's code ?

IoannisDadiotis commented 1 year ago

indeed, I have managed to work around by re implementing the eigen function I needed using CppAD::CondExpOp.

Please let me know if you are aware of a different way without modifying eigen's source code, otherwise the issue can be closed. thanks