首页 > 其他分享 >OCS2::ocs2_centroidal_model_质心动量模型

OCS2::ocs2_centroidal_model_质心动量模型

时间:2024-12-19 17:47:01浏览次数:4  
标签:info const auto template centroidal model data ocs2

1. ModelHelperFunctions.cpp

1.1 updateCentroidalDynamics() : 质心动力学更新

template <typename SCALAR_T>
void updateCentroidalDynamics(PinocchioInterfaceTpl<SCALAR_T>& interface, const CentroidalModelInfoTpl<SCALAR_T>& info,
                              const Eigen::Matrix<SCALAR_T, Eigen::Dynamic, 1>& q) {
  using vector3_t = Eigen::Matrix<SCALAR_T, 3, 1>;
  using matrix3_t = Eigen::Matrix<SCALAR_T, 3, 3>;
  using matrix6_t = Eigen::Matrix<SCALAR_T, 6, 6>;

  const auto& model = interface.getModel();
  auto& data = interface.getData();

  switch (info.centroidalModelType) {
    case CentroidalModelType::FullCentroidalDynamics: {
      pinocchio::computeCentroidalMap(model, data, q);
      pinocchio::updateFramePlacements(model, data);
      break;
    }
    case CentroidalModelType::SingleRigidBodyDynamics: {
        //从广义坐标 q 中提取的欧拉角
      const vector3_t eulerAnglesZyx = q.template segment<3>(3);
      // 将欧拉角导数映射到全局角速度的映射矩阵
      const matrix3_t mappingZyx = getMappingFromEulerAnglesZyxDerivativeToGlobalAngularVelocity(eulerAnglesZyx);
      //基坐标系到世界坐标系的旋转矩阵
      const matrix3_t rotationBaseToWorld = getRotationMatrixFromZyxEulerAngles(eulerAnglesZyx);
      //质心相对于基坐标系的位置信息,变换到世界坐标系
      const vector3_t comToBasePositionInWorld = rotationBaseToWorld * info.comToBasePositionNominal;
      //质心位置的反对称矩阵,用于计算惯性耦合项
      const matrix3_t skewSymmetricMap = skewSymmetricMatrix(comToBasePositionInWorld);
      //用于计算角动量相关的中间矩阵
      const matrix3_t mat1 = rotationBaseToWorld * info.centroidalInertiaNominal;
      const matrix3_t mat2 = rotationBaseToWorld.transpose() * mappingZyx;
      //刚体动力学下的质心动量映射矩阵,6x6 矩阵
      matrix6_t Ab = matrix6_t::Zero();
      //template显性的指定矩阵块大小
      //topLeftCorner左上角3*3块,diagonal:提取对角线元素,array:将对角线视为数组逐元素操作
      Ab.template topLeftCorner<3, 3>().diagonal().array() = info.robotMass;
      //noalias():优化矩阵赋值操作
      Ab.template topRightCorner<3, 3>().noalias() = info.robotMass * skewSymmetricMap * mappingZyx;
      Ab.template bottomRightCorner<3, 3>().noalias() = mat1 * mat2;
      //Ag前3行是线动量部分,后3行是角动量部分
      data.Ag = Eigen::Matrix<SCALAR_T, -1, -1>::Zero(6, info.generalizedCoordinatesNum);
      //左侧6列赋值为Ab
      data.Ag.template leftCols<6>() = Ab;
      data.com[0] = q.template head<3>() - comToBasePositionInWorld;
      pinocchio::forwardKinematics(model, data, q);
      pinocchio::updateFramePlacements(model, data);
      break;
    }
    default: {
      throw std::runtime_error("The chosen centroidal model type is not supported.");
      break;
    }
  }
}
  • 将欧拉角导数映射到全局角速度的映射矩阵:
    https://blog.csdn.net/subtitle_/article/details/131915276
    旋转顺序Z -> Y -> X,对应角度\(\alpha\),\(\beta\),\(\gamma\),

  • Ab(data.Ag)矩阵的公式:
    参考文献:D. E. Orin, A. Goswami, and S. Lee, “Centroidal dynamics of a humanoid robot,”

1.2 updateCentroidalDynamicsDerivatives() : 更新质心动力学导数

data.dFdq.setZero(6, info.generalizedCoordinatesNum);
data.dFdq.template middleCols<3>(3) = getCentroidalMomentumZyxGradient(interface, info, q, v);
pinocchio::computeJointJacobians(model, data, q);
pinocchio::updateFramePlacements(model, data);
template <typename SCALAR_T>
Eigen::Matrix<SCALAR_T, 6, 3> getCentroidalMomentumZyxGradient(const PinocchioInterfaceTpl<SCALAR_T>& interface,
                                                               const CentroidalModelInfoTpl<SCALAR_T>& info,
                                                               const Eigen::Matrix<SCALAR_T, Eigen::Dynamic, 1>& q,
                                                               const Eigen::Matrix<SCALAR_T, Eigen::Dynamic, 1>& v) {
  using matrix_t = Eigen::Matrix<SCALAR_T, Eigen::Dynamic, Eigen::Dynamic>;
  using vector3_t = Eigen::Matrix<SCALAR_T, 3, 1>;
  using matrix3_t = Eigen::Matrix<SCALAR_T, 3, 3>;

  const auto& data = interface.getData();
  const auto m = info.robotMass;
  const vector3_t eulerAngles = q.template segment<3>(3);
  const vector3_t eulerAnglesDerivatives = v.template segment<3>(3);
  //从欧拉角导数到全局角速度的映射矩阵
  const auto T = getMappingFromEulerAnglesZyxDerivativeToGlobalAngularVelocity(eulerAngles);
  //从基座到世界坐标系的旋转矩阵
  const auto R = getRotationMatrixFromZyxEulerAngles(eulerAngles);
  matrix3_t Ibaseframe, Iworldframe;
  vector3_t rbaseframe, rworldframe;

  switch (info.centroidalModelType) {
    case CentroidalModelType::FullCentroidalDynamics: {
      Iworldframe = data.Ig.inertia().matrix();
      Ibaseframe.noalias() = R.transpose() * (Iworldframe * R);
      rworldframe = q.template head<3>() - data.com[0];
      rbaseframe.noalias() = R.transpose() * rworldframe;
      break;
    }
    case CentroidalModelType::SingleRigidBodyDynamics: {
      Ibaseframe = info.centroidalInertiaNominal;  //归一化的基座惯性张量
      Iworldframe.noalias() = R * (Ibaseframe * R.transpose()); //世界坐标惯性张量
      rbaseframe = info.comToBasePositionNominal; //质心位置
      rworldframe.noalias() = R * rbaseframe;   //世界坐标质心位置
      break;
    }
    default: {
      throw std::runtime_error("The chosen centroidal model type is not supported.");
    }
  }

  const auto S = skewSymmetricMatrix(rworldframe); //r_com 反对称矩阵
  const auto dT = getMappingZyxGradient(eulerAngles); //映射矩阵 T 的梯度
  const auto dR = getRotationMatrixZyxGradient(eulerAngles);// 旋转矩阵R的梯度

  std::array<matrix3_t, 3> dS;
  for (size_t i = 0; i < 3; i++) {
    const vector3_t dr = dR[i] * rbaseframe;
    dS[i] = skewSymmetricMatrix(dr); //世界坐标质心位置关于欧拉角的梯度
  }

  matrix_t dhdq = matrix_t::Zero(6, 3);
  for (size_t i = 0; i < 3; i++) {
    const vector3_t T_eulerAnglesDev = T * eulerAnglesDerivatives; 
    const vector3_t dT_eulerAnglesDev = dT[i] * eulerAnglesDerivatives; 
    const matrix3_t dR_I_Rtrans = dR[i] * Ibaseframe * R.transpose();

    dhdq.template block<3, 1>(0, i).noalias() = m * (S * dT_eulerAnglesDev);
    dhdq.template block<3, 1>(0, i).noalias() += m * (dS[i] * T_eulerAnglesDev);

    dhdq.template block<3, 1>(3, i).noalias() = (dR_I_Rtrans + dR_I_Rtrans.transpose()) * T_eulerAnglesDev;
    dhdq.template block<3, 1>(3, i).noalias() += Iworldframe * dT_eulerAnglesDev;
  }

  if (info.centroidalModelType == CentroidalModelType::FullCentroidalDynamics) {
    const auto jointVelocities = v.tail(info.actuatedDofNum);
    const vector3_t comLinearVelocityInWorldFrame = (1.0 / m) * (data.Ag.topRightCorner(3, info.actuatedDofNum) * jointVelocities);
    const vector3_t comAngularVelocityInWorldFrame =
        Iworldframe.inverse() * (data.Ag.bottomRightCorner(3, info.actuatedDofNum) * jointVelocities);
    const vector3_t linearMomentumInBaseFrame = m * (R.transpose() * comLinearVelocityInWorldFrame);
    const vector3_t angularMomentumInBaseFrame = Ibaseframe * (R.transpose() * comAngularVelocityInWorldFrame);
    for (size_t i = 0; i < 3; i++) {
      dhdq.template block<3, 1>(0, i).noalias() += dR[i] * linearMomentumInBaseFrame;
      dhdq.template block<3, 1>(3, i).noalias() += dR[i] * angularMomentumInBaseFrame;
    }
  }

  return dhdq;
}
  • 其中dh/dq的公式为:


1.3 质心(CoM)到特定接触点的平移雅可比矩阵

template <typename SCALAR_T>
Eigen::Matrix<SCALAR_T, 3, Eigen::Dynamic> getTranslationalJacobianComToContactPointInWorldFrame(
    const PinocchioInterfaceTpl<SCALAR_T>& interface, const CentroidalModelInfoTpl<SCALAR_T>& info, size_t contactIndex) {
  const auto& model = interface.getModel();
  auto data = interface.getData();
  Eigen::Matrix<SCALAR_T, 6, Eigen::Dynamic> jacobianWorldToContactPointInWorldFrame;
  jacobianWorldToContactPointInWorldFrame.setZero(6, info.generalizedCoordinatesNum);
  pinocchio::getFrameJacobian(model, data, info.endEffectorFrameIndices[contactIndex], pinocchio::LOCAL_WORLD_ALIGNED,
                              jacobianWorldToContactPointInWorldFrame);
  Eigen::Matrix<SCALAR_T, 3, Eigen::Dynamic> J_com = getCentroidalMomentumMatrix(interface).template topRows<3>() / info.robotMass;
  return (jacobianWorldToContactPointInWorldFrame.template topRows<3>() - J_com);
}

1.4 动量的变化率,也就是一阶导

/**********************动量的变化率,也就是一阶导,这里就是求的h_{com}的导数*********************************************************/
template <typename SCALAR_T>
Eigen::Matrix<SCALAR_T, 6, 1> getNormalizedCentroidalMomentumRate(const PinocchioInterfaceTpl<SCALAR_T>& interface,
                                                                  const CentroidalModelInfoTpl<SCALAR_T>& info,
                                                                  const Eigen::Matrix<SCALAR_T, Eigen::Dynamic, 1>& input) {
  const Eigen::Matrix<SCALAR_T, 3, 1> gravityVector(SCALAR_T(0.0), SCALAR_T(0.0), SCALAR_T(-9.81));
  Eigen::Matrix<SCALAR_T, 6, 1> centroidalMomentumRate;
  centroidalMomentumRate << info.robotMass * gravityVector, Eigen::Matrix<SCALAR_T, 3, 1>::Zero();

  for (size_t i = 0; i < info.numThreeDofContacts; i++) {
    const auto contactForceInWorldFrame = centroidal_model::getContactForces(input, i, info); //获取接触力
    const auto positionComToContactPointInWorldFrame = getPositionComToContactPointInWorldFrame(interface, info, i); //r_f
    centroidalMomentumRate.template head<3>() += contactForceInWorldFrame;
    centroidalMomentumRate.template tail<3>().noalias() += positionComToContactPointInWorldFrame.cross(contactForceInWorldFrame);
  }  // end of i loop

  for (size_t i = info.numThreeDofContacts; i < info.numThreeDofContacts + info.numSixDofContacts; i++) {
    const auto contactForceInWorldFrame = centroidal_model::getContactForces(input, i, info);
    const auto contactTorqueInWorldFrame = centroidal_model::getContactTorques(input, i, info);
    const auto positionComToContactPointInWorldFrame = getPositionComToContactPointInWorldFrame(interface, info, i);
    centroidalMomentumRate.template head<3>() += contactForceInWorldFrame;
    centroidalMomentumRate.template tail<3>().noalias() +=
        positionComToContactPointInWorldFrame.cross(contactForceInWorldFrame) + contactTorqueInWorldFrame;
  }  // end of i loop

  // normalize by the total mass
  centroidalMomentumRate /= info.robotMass;

  return centroidalMomentumRate;
}

2. CentroidalModelPinocchioMapping.cpp

2.1 getPinocchioJointVelocity 获取浮动基座速度

/********************获取浮动基座速度**********************************************************/
template <typename SCALAR>
auto CentroidalModelPinocchioMappingTpl<SCALAR>::getPinocchioJointVelocity(const vector_t& state, const vector_t& input) const -> vector_t {
  const auto& model = pinocchioInterfacePtr_->getModel();
  const auto& data = pinocchioInterfacePtr_->getData();
  const auto& info = centroidalModelInfo_;
  assert(info.stateDim == state.rows());
  assert(info.inputDim == input.rows());

  const auto& A = getCentroidalMomentumMatrix(*pinocchioInterfacePtr_);
  const Eigen::Matrix<SCALAR, 6, 6> Ab = A.template leftCols<6>(); //取左侧6列关于浮动基座的部分
  const auto Ab_inv = computeFloatingBaseCentroidalMomentumMatrixInverse(Ab);

  const auto jointVelocities = centroidal_model::getJointVelocities(input, info).head(info.actuatedDofNum);

  Eigen::Matrix<SCALAR, 6, 1> momentum = info.robotMass * centroidal_model::getNormalizedMomentum(state, info);
  if (info.centroidalModelType == CentroidalModelType::FullCentroidalDynamics) {
    momentum.noalias() -= A.rightCols(info.actuatedDofNum) * jointVelocities;
  }

  vector_t vPinocchio(info.generalizedCoordinatesNum);
  vPinocchio.template head<6>().noalias() = Ab_inv * momentum;
  vPinocchio.tail(info.actuatedDofNum) = jointVelocities;

  return vPinocchio;
}
  • computeFloatingBaseCentroidalMomentumMatrixInverse():

2.2 getOcs2Jacobian 动力学公式内的关节速度和浮动速度对状态和输入的偏导

/****主要动力学公式内的关节速度和浮动速度对状态和输入的偏导**************************************************************************/
template <typename SCALAR>
auto CentroidalModelPinocchioMappingTpl<SCALAR>::getOcs2Jacobian(const vector_t& state, const matrix_t& Jq, const matrix_t& Jv) const
    -> std::pair<matrix_t, matrix_t> {
  const auto& model = pinocchioInterfacePtr_->getModel();
  const auto& data = pinocchioInterfacePtr_->getData();
  const auto& info = centroidalModelInfo_;
  assert(info.stateDim == state.rows());

  // Partial derivatives of joint velocities
  //关节角速度对输入的偏导
  matrix_t jointVelocitiesDerivativeInput = matrix_t::Zero(info.actuatedDofNum, info.inputDim);
  jointVelocitiesDerivativeInput.rightCols(info.actuatedDofNum).setIdentity();

  // Partial derivatives of the floating base variables
  //浮动基座速度对状态和输入的偏导
  // TODO: move getFloatingBaseCentroidalMomentumMatrixInverse(Ab) to PreComputation
  matrix_t floatingBaseVelocitiesDerivativeState = matrix_t::Zero(6, info.stateDim);
  matrix_t floatingBaseVelocitiesDerivativeInput = matrix_t::Zero(6, info.inputDim);
  const auto& A = getCentroidalMomentumMatrix(*pinocchioInterfacePtr_);
  const Eigen::Matrix<SCALAR, 6, 6> Ab = A.template leftCols<6>();
  const auto Ab_inv = computeFloatingBaseCentroidalMomentumMatrixInverse(Ab);
  floatingBaseVelocitiesDerivativeState.leftCols(6) = info.robotMass * Ab_inv;

  using matrix6x_t = Eigen::Matrix<SCALAR, 6, Eigen::Dynamic>;
  matrix6x_t dhdq(6, info.generalizedCoordinatesNum);
  switch (info.centroidalModelType) {
    case CentroidalModelType::FullCentroidalDynamics: {
      pinocchio::translateForceSet(data.dHdq, data.com[0], dhdq.const_cast_derived());
      for (size_t k = 0; k < model.nv; ++k) {
        dhdq.template block<3, 1>(pinocchio::Force::ANGULAR, k) +=
            data.hg.linear().cross(data.dFda.template block<3, 1>(pinocchio::Force::LINEAR, k)) / data.Ig.mass();
      }
      dhdq.middleCols(3, 3) = data.dFdq.middleCols(3, 3);
      const auto Aj = A.rightCols(info.actuatedDofNum);
      floatingBaseVelocitiesDerivativeState.rightCols(info.generalizedCoordinatesNum).noalias() = -Ab_inv * dhdq;
      floatingBaseVelocitiesDerivativeInput.rightCols(info.actuatedDofNum).noalias() = -Ab_inv * Aj;
      break;
    }
    case CentroidalModelType::SingleRigidBodyDynamics: {
      dhdq = data.dFdq;
      floatingBaseVelocitiesDerivativeState.middleCols(6, 6).noalias() = -Ab_inv * dhdq.leftCols(6);
      break;
    }
    default: {
      throw std::runtime_error("The chosen centroidal model type is not supported.");
    }
  }

  matrix_t dvdx = matrix_t::Zero(info.generalizedCoordinatesNum, info.stateDim);
  dvdx.template topRows<6>() = floatingBaseVelocitiesDerivativeState;
  matrix_t dvdu = matrix_t::Zero(info.generalizedCoordinatesNum, info.inputDim);
  dvdu << floatingBaseVelocitiesDerivativeInput, jointVelocitiesDerivativeInput;
  matrix_t dfdx = matrix_t::Zero(Jq.rows(), centroidalModelInfo_.stateDim);
  dfdx.middleCols(6, info.generalizedCoordinatesNum) = Jq;
  dfdx.noalias() += Jv * dvdx;
  const matrix_t dfdu = Jv * dvdu;
  return {dfdx, dfdu};
}

3. CentroidalModelRbdConversions.cpp

3.1 computeBaseKinematicsFromCentroidalModel 计算机体运动学

输入:状态state;输入input;关节角加速度jointAccelerations,
输出:基座位置basePose(从state获取);基座速度baseVelocity(getPinocchioJointVelocity获取);基座加速度
基座加速度公式:
\(A_b \ddot{q}_b = \dot{h}_{com} - \dot{A_b} \dot{q_b} - A_j \ddot{q_j}\)
\(\ddot{q_j}\)一般不考虑,等0

void CentroidalModelRbdConversions::computeBaseKinematicsFromCentroidalModel(const vector_t& state, const vector_t& input,
                                                                             const vector_t& jointAccelerations, Vector6& basePose,
                                                                             Vector6& baseVelocity, Vector6& baseAcceleration) {
  const auto& model = pinocchioInterface_.getModel();
  auto& data = pinocchioInterface_.getData();
  const auto& info = mapping_.getCentroidalModelInfo();
  const auto qPinocchio = mapping_.getPinocchioJointPosition(state);

  updateCentroidalDynamics(pinocchioInterface_, info, qPinocchio);

  // Base Pose in world frame
  basePose = qPinocchio.head<6>();
  const auto basePosition = basePose.head<3>();
  const auto baseOrientation = basePose.tail<3>();

  // Base Velocity in world frame
  const auto& A = getCentroidalMomentumMatrix(pinocchioInterface_); //获取动量矩阵Ab
  const Matrix6 Ab = A.template leftCols<6>();
  const auto Ab_inv = computeFloatingBaseCentroidalMomentumMatrixInverse(Ab);
  const auto Aj = A.rightCols(info.actuatedDofNum);

  const vector_t vPinocchio = mapping_.getPinocchioJointVelocity(state, input); //获取基座速度
  baseVelocity.head<3>() = vPinocchio.head<3>();
  const Vector3 derivativeEulerAnglesZyx = vPinocchio.segment<3>(3);
  baseVelocity.tail<3>() = getGlobalAngularVelocityFromEulerAnglesZyxDerivatives<scalar_t>(baseOrientation, derivativeEulerAnglesZyx);

  const auto Adot = pinocchio::dccrba(model, data, qPinocchio, vPinocchio); // 获取动量矩阵A的导数

  Vector6 centroidalMomentumRate = info.robotMass * getNormalizedCentroidalMomentumRate(pinocchioInterface_, info, input);
  centroidalMomentumRate.noalias() -= Adot * vPinocchio;
  centroidalMomentumRate.noalias() -= Aj * jointAccelerations.head(info.actuatedDofNum);
  const Vector6 qbaseDdot = Ab_inv * centroidalMomentumRate;

  // Base Acceleration in world frame
  baseAcceleration.head<3>() = qbaseDdot.head<3>();
  baseAcceleration.tail<3>() =
      getGlobalAngularAccelerationFromEulerAnglesZyxDerivatives<scalar_t>(baseOrientation, derivativeEulerAnglesZyx, qbaseDdot.tail<3>());
}

3.2 computeCentroidalStateFromRbdModel 将刚体模型rbdState转成质心模型state

输入rbdState:

  • 基座的位置、欧拉角
  • 关节角度
  • 基座的线速度、角速度
  • 关节速度
    输出state:
  • 归一化动量
  • 广义坐标(基座位置和关节角度)
/*******将刚体模型转换为质心模型****************/
vector_t CentroidalModelRbdConversions::computeCentroidalStateFromRbdModel(const vector_t& rbdState) {
  const auto& model = pinocchioInterface_.getModel();
  auto& data = pinocchioInterface_.getData();
  const auto& info = mapping_.getCentroidalModelInfo();

  vector_t qPinocchio(info.generalizedCoordinatesNum);
  qPinocchio.head<3>() = rbdState.segment<3>(3); //基座位置
  qPinocchio.segment<3>(3) = rbdState.head<3>(); //基座姿态
  qPinocchio.tail(info.actuatedDofNum) = rbdState.segment(6, info.actuatedDofNum);//关节角度

  vector_t vPinocchio(info.generalizedCoordinatesNum);
  vPinocchio.head<3>() = rbdState.segment<3>(info.generalizedCoordinatesNum + 3); //基座线速度
  vPinocchio.segment<3>(3) = getEulerAnglesZyxDerivativesFromGlobalAngularVelocity<scalar_t>(
      qPinocchio.segment<3>(3), rbdState.segment<3>(info.generalizedCoordinatesNum)); //基座欧拉角导数
  //关节速度
  vPinocchio.tail(info.actuatedDofNum) = rbdState.segment(info.generalizedCoordinatesNum + 6, info.actuatedDofNum);

  updateCentroidalDynamics(pinocchioInterface_, info, qPinocchio);
  const auto& A = getCentroidalMomentumMatrix(pinocchioInterface_); //获得动量矩阵

  vector_t state(info.stateDim);
  centroidal_model::getNormalizedMomentum(state, info).noalias() = A * vPinocchio / info.robotMass; //得到规划化后的动量
  centroidal_model::getGeneralizedCoordinates(state, info) = qPinocchio; //状态位置赋值

  return state;
}


3.3 computeRbdTorqueFromCentroidalModelPD 根据期望计算最终的控制力矩

/***根据期望计算最终控制的力矩*************************************************************************/
vector_t CentroidalModelRbdConversions::computeRbdTorqueFromCentroidalModelPD(const vector_t& desiredState, const vector_t& desiredInput,
                                                                              const vector_t& desiredJointAccelerations,
                                                                              const vector_t& measuredRbdState, const vector_t& pGains,
                                                                              const vector_t& dGains) {
  // handles
  const auto& info = mapping_.getCentroidalModelInfo();
  const auto& model = pinocchioInterface_.getModel();
  auto& data = pinocchioInterface_.getData();

  // desired
  Vector6 desiredBasePose, desiredBaseVelocity, desiredBaseAcceleration;
  //将质心模型的期望状态和输入转换为基座的期望位姿、速度、加速度
  computeBaseKinematicsFromCentroidalModel(desiredState, desiredInput, desiredJointAccelerations, desiredBasePose, desiredBaseVelocity,
                                           desiredBaseAcceleration);
  vector_t qDesired(info.generalizedCoordinatesNum), vDesired(info.generalizedCoordinatesNum), aDesired(info.generalizedCoordinatesNum);
  qDesired << desiredBasePose, centroidal_model::getJointAngles(desiredState, info);
  vDesired << desiredBaseVelocity, centroidal_model::getJointVelocities(desiredInput, info);
  aDesired << desiredBaseAcceleration, desiredJointAccelerations;
  
  //将世界坐标期望力转到末端坐标系的力和力矩
  pinocchio::container::aligned_vector<pinocchio::Force> fextDesired(model.njoints, pinocchio::Force::Zero());
  for (size_t i = 0; i < info.numThreeDofContacts; i++) {
    const auto frameIndex = info.endEffectorFrameIndices[i];
    const auto jointIndex = model.frames[frameIndex].parent;
    const Vector3 translationJointFrameToContactFrame = model.frames[frameIndex].placement.translation();
    const Matrix3 rotationWorldFrameToJointFrame = data.oMi[jointIndex].rotation().transpose();
    const Vector3 contactForce = rotationWorldFrameToJointFrame * centroidal_model::getContactForces(desiredInput, i, info);
    fextDesired[jointIndex].linear() = contactForce;
    fextDesired[jointIndex].angular() = translationJointFrameToContactFrame.cross(contactForce);
  }
  for (size_t i = info.numThreeDofContacts; i < info.numThreeDofContacts + info.numSixDofContacts; i++) {
    const auto frameIndex = info.endEffectorFrameIndices[i];
    const auto jointIndex = model.frames[frameIndex].parent;
    const Vector3 translationJointFrameToContactFrame = model.frames[frameIndex].placement.translation();
    const Matrix3 rotationWorldFrameToJointFrame = data.oMi[jointIndex].rotation().transpose();
    const Vector3 contactForce = rotationWorldFrameToJointFrame * centroidal_model::getContactForces(desiredInput, i, info);
    const Vector3 contactTorque = rotationWorldFrameToJointFrame * centroidal_model::getContactTorques(desiredInput, i, info);
    fextDesired[jointIndex].linear() = contactForce;
    fextDesired[jointIndex].angular() = translationJointFrameToContactFrame.cross(contactForce) + contactTorque;
  }

  // measured
  vector_t qMeasured(info.generalizedCoordinatesNum), vMeasured(info.generalizedCoordinatesNum);
  qMeasured.head<3>() = measuredRbdState.segment<3>(3);
  qMeasured.segment<3>(3) = measuredRbdState.head<3>();
  qMeasured.tail(info.actuatedDofNum) = measuredRbdState.segment(6, info.actuatedDofNum);
  vMeasured.head<3>() = measuredRbdState.segment<3>(info.generalizedCoordinatesNum + 3);
  vMeasured.segment<3>(3) = getEulerAnglesZyxDerivativesFromGlobalAngularVelocity<scalar_t>(
      qMeasured.segment<3>(3), measuredRbdState.segment<3>(info.generalizedCoordinatesNum));
  vMeasured.tail(info.actuatedDofNum) = measuredRbdState.segment(info.generalizedCoordinatesNum + 6, info.actuatedDofNum);

  // PD feedback augmentation
  const vector_t pdFeedback = pGains.cwiseProduct(qDesired - qMeasured) + dGains.cwiseProduct(vDesired - vMeasured);

  // feedforward plus PD on acceleration level
  const vector_t aAugmented = aDesired + pdFeedback;
  return pinocchio::rnea(model, data, qDesired, vDesired, aAugmented, fextDesired);
}
  1. 将质心模型的期望状态和输入转换为基座的期望位姿、速度、加速度
  2. 将世界坐标期望力转到末端坐标系的力和力矩
  3. PD控制器补偿到关节加速度
  4. 运动动力学公式计算各关节的控制力矩

4 PinocchioCentroidalDynamics.cpp

4.1 获取质心动力学的f值:

vector_t PinocchioCentroidalDynamics::getValue(scalar_t time, const vector_t& state, const vector_t& input) {
  const auto& interface = *pinocchioInterfacePtr_;
  const auto& info = mapping_.getCentroidalModelInfo();
  assert(info.stateDim == state.rows());

  vector_t f(info.stateDim);
  f << getNormalizedCentroidalMomentumRate(interface, info, input), mapping_.getPinocchioJointVelocity(state, input);

  return f;
}

4.2 computeNormalizedCentroidalMomentumRateGradients 计算质心动量导数对状态和输入的偏导


/*******计算质心动量导数对状态和输入的偏导**********************************************************************/
void PinocchioCentroidalDynamics::computeNormalizedCentroidalMomentumRateGradients(const vector_t& state, const vector_t& input) {
  const auto& interface = *pinocchioInterfacePtr_;
  const auto& info = mapping_.getCentroidalModelInfo();
  assert(info.stateDim == state.rows());
  assert(info.inputDim == input.rows());

  // compute partial derivatives of the center of robotMass acceleration and normalized angular momentum
  normalizedLinearMomentumRateDerivativeQ_.setZero(3, info.generalizedCoordinatesNum); //线动量率对状态的偏导
  normalizedAngularMomentumRateDerivativeQ_.setZero(3, info.generalizedCoordinatesNum);//角动量率对状态的偏导
  normalizedLinearMomentumRateDerivativeInput_.setZero(3, info.inputDim); //线动量率对输入的偏导
  normalizedAngularMomentumRateDerivativeInput_.setZero(3, info.inputDim);//角动量率对输入的偏导
  Matrix3 f_hat, p_hat;

  for (size_t i = 0; i < info.numThreeDofContacts; i++) {
    const Vector3 contactForceInWorldFrame = centroidal_model::getContactForces(input, i, info);
    f_hat = skewSymmetricMatrix(contactForceInWorldFrame) / info.robotMass;
    const auto J = getTranslationalJacobianComToContactPointInWorldFrame(interface, info, i);
    normalizedAngularMomentumRateDerivativeQ_.noalias() -= f_hat * J;
    normalizedLinearMomentumRateDerivativeInput_.block<3, 3>(0, 3 * i).diagonal().array() = 1.0 / info.robotMass;
    p_hat = skewSymmetricMatrix(getPositionComToContactPointInWorldFrame(interface, info, i)) / info.robotMass;
    normalizedAngularMomentumRateDerivativeInput_.block<3, 3>(0, 3 * i) = p_hat;
  }

  for (size_t i = info.numThreeDofContacts; i < info.numThreeDofContacts + info.numSixDofContacts; i++) {
    const size_t inputIdx = 3 * info.numThreeDofContacts + 6 * (i - info.numThreeDofContacts);
    const Vector3 contactForceInWorldFrame = centroidal_model::getContactForces(input, i, info);
    f_hat = skewSymmetricMatrix(contactForceInWorldFrame) / info.robotMass;
    const auto J = getTranslationalJacobianComToContactPointInWorldFrame(interface, info, i);
    normalizedAngularMomentumRateDerivativeQ_.noalias() -= f_hat * J;
    normalizedLinearMomentumRateDerivativeInput_.block<3, 3>(0, inputIdx).diagonal().array() = 1.0 / info.robotMass;
    p_hat = skewSymmetricMatrix(getPositionComToContactPointInWorldFrame(interface, info, i)) / info.robotMass;
    normalizedAngularMomentumRateDerivativeInput_.block<3, 3>(0, 3 * inputIdx) = p_hat;
    normalizedAngularMomentumRateDerivativeInput_.block<3, 3>(0, 3 * inputIdx + 3).diagonal().array() = 1.0 / info.robotMass;
  }
}

4.3 getLinearApproximation 线性化近似

/****线性近似,求df/dx,df/du*******************************************************************************/
VectorFunctionLinearApproximation PinocchioCentroidalDynamics::getLinearApproximation(scalar_t time, const vector_t& state,
                                                                                      const vector_t& input) {
  const auto& info = mapping_.getCentroidalModelInfo();
  assert(info.stateDim == state.rows());
  assert(info.inputDim == input.rows());

  auto dynamics = ocs2::VectorFunctionLinearApproximation::Zero(info.stateDim, info.stateDim, info.inputDim);
  dynamics.f = getValue(time, state, input); 

  // Partial derivatives of the normalized momentum rates
  computeNormalizedCentroidalMomentumRateGradients(state, input);

  matrix_t dfdq = matrix_t::Zero(info.stateDim, info.generalizedCoordinatesNum);  //对状态求偏导
  matrix_t dfdv = matrix_t::Zero(info.stateDim, info.generalizedCoordinatesNum);  //对输入求偏导
  //先将动量一阶导对状态的偏导赋值
  dfdq.topRows<6>() << normalizedLinearMomentumRateDerivativeQ_, normalizedAngularMomentumRateDerivativeQ_;
  
  dfdv.bottomRows(info.generalizedCoordinatesNum).setIdentity();
  
  //计算关节角速度和浮动基座速度对状态和输入的偏导
  std::tie(dynamics.dfdx, dynamics.dfdu) = mapping_.getOcs2Jacobian(state, dfdq, dfdv);

  // Add partial derivative of f with respect to u since part of f depends explicitly on the inputs (contact forces + torques)
  //将动量一阶导对输入的偏导加入矩阵中
  dynamics.dfdu.topRows<3>() += normalizedLinearMomentumRateDerivativeInput_;
  dynamics.dfdu.middleRows(3, 3) += normalizedAngularMomentumRateDerivativeInput_;

  return dynamics;
}

标签:info,const,auto,template,centroidal,model,data,ocs2
From: https://www.cnblogs.com/penuel/p/18605204

相关文章