PageRenderTime 133ms CodeModel.GetById 32ms RepoModel.GetById 6ms app.codeStats 0ms

/src/man/motion/bhwalk/Modules/MotionControl/Indykick/CartTableController.cpp

https://github.com/emamanto/nbites
C++ | 359 lines | 301 code | 44 blank | 14 comment | 29 complexity | 8773b463491e8f981364adf4261920af MD5 | raw file
  1. /*
  2. * @file CartTableController.cpp
  3. * This file implements the methods of the cart table zmp preview controller class.
  4. * @author Felix Wenk
  5. */
  6. #include "CartTableController.h"
  7. #include <algorithm>
  8. #include "Representations/Configuration/MassCalibration.h"
  9. #include "Representations/Sensing/OrientationData.h"
  10. #include "Representations/Sensing/RobotModel.h"
  11. #include "Tools/InverseKinematic.h"
  12. #include "Tools/Debugging/Debugging.h"
  13. #include "Tools/Streams/InStreams.h"
  14. #include "Tools/Debugging/DebugDrawings.h"
  15. #include "Tools/Debugging/Modify.h"
  16. template <int n>
  17. CartTableZMPPreviewController<n>::CartTableZMPPreviewController(const MassCalibration& theMassCalibration,
  18. const RobotDimensions& theRobotDimensions,
  19. const OrientationData& theOrientationData,
  20. const float motionCycleTime)
  21. : deltaT(motionCycleTime),
  22. comHeight(200.0f),
  23. zmpErrorSum(0.0f, 0.0f),
  24. theMassCalibration(theMassCalibration), theRobotDimensions(theRobotDimensions), theOrientationData(theOrientationData)
  25. {
  26. InTextFile stream("carttable-riccatisolution.cfg");
  27. stream >> P;
  28. stream >> R;
  29. /* COM height and motion cycle time used to calculate the Riccati equation
  30. * must match the actual motion cycle time and COM height. */
  31. float comHeightTest;
  32. stream >> comHeightTest;
  33. ASSERT(comHeightTest == comHeight);
  34. float motionCycleTimeTest;
  35. stream >> motionCycleTimeTest;
  36. ASSERT(motionCycleTimeTest == motionCycleTime);
  37. /* Assemble matrices. */
  38. const float zg = comHeight / 9.81e-3f;
  39. Matrix4x1f Bt;
  40. Bt.c[0][0] = sqr(deltaT) * deltaT / 6.0f - zg * deltaT;
  41. Bt.c[0][1] = sqr(deltaT) * deltaT / 6.0f;
  42. Bt.c[0][2] = sqr(deltaT) / 2.0f;
  43. Bt.c[0][3] = deltaT;
  44. const Matrix1x4f BtTrans = Bt.transpose();
  45. Matrix4x1f It;
  46. It[0][0] = 1.0f;
  47. It[0][1] = 0.0f;
  48. It[0][2] = 0.0f;
  49. It[0][3] = 0.0f;
  50. Matrix4x3f Ft;
  51. Ft[0][0] = 1.0f; Ft[1][0] = deltaT; Ft[2][0] = sqr(deltaT) / 2.0f - zg;
  52. Ft[0][1] = 1.0f; Ft[1][1] = deltaT; Ft[2][1] = sqr(deltaT) / 2.0f;
  53. Ft[0][2] = 0.0f; Ft[1][2] = 1.0f; Ft[2][2] = deltaT;
  54. Ft[0][3] = 0.0f; Ft[1][3] = 0.0f; Ft[2][3] = 1.0f;
  55. const Matrix4x4f At(It.c[0], Ft.c[0], Ft.c[1], Ft.c[2]);
  56. /* Calculate integral and state gain matrices. */
  57. const Matrix1x1f bpb = BtTrans * P * Bt;
  58. const float denum = R + bpb[0][0];
  59. const Matrix1x4f gainBase = (BtTrans * P) / denum;
  60. const Matrix1x1f integralGainMatrix = gainBase * It;
  61. integralGain = integralGainMatrix[0][0];
  62. stateGain = gainBase * Ft;
  63. /* Calculate preview gain matrices */
  64. const Matrix4x4f Atc = At - Bt * gainBase * At;
  65. const Matrix4x4f AtcTranspose = Atc.transpose();
  66. Matrix4x1f Xt = AtcTranspose * P * (It * (-1.0f));
  67. previewGain[0] = 0.0f; // Index 0 contains no valid preview gain!
  68. previewGain[1] = -integralGain;
  69. for(int l = 2; l < n + frameDelay; ++l)
  70. {
  71. const Matrix1x1f previewGainMatrix = BtTrans / denum * Xt;
  72. previewGain[l] = previewGainMatrix[0][0];
  73. Xt = AtcTranspose * Xt;
  74. }
  75. }
  76. template <int n> void CartTableZMPPreviewController<n>::generateSupportLegAngles(const float yRotationFraction,
  77. const float xRotationFraction,
  78. const RingBuffer<Vector2f, n>& zmpReference,
  79. const Vector3<>& estimatedZmp,
  80. const Pose3D& kickFoot,
  81. const bool useSupportFootCoordinateSystem,
  82. JointData& myJointData,
  83. const Vector3<>& delayedComPositionInSupportFoot,
  84. const Vector3<>& delayedComVelocityInSupportFoot,
  85. const Vector3<>& delayedComAccelerationInSupportFoot,
  86. Vector2<>& demandedTorsoAngularVelocity)
  87. {
  88. calculateNextCom(zmpReference, estimatedZmp, delayedComPositionInSupportFoot, delayedComVelocityInSupportFoot, delayedComAccelerationInSupportFoot);
  89. generateLegAnglesForCenterOfMassOrientation(yRotationFraction, xRotationFraction, myJointData,
  90. kickFoot, useSupportFootCoordinateSystem, comPositionInSupportFoot, demandedTorsoAngularVelocity);
  91. }
  92. template <int n> void CartTableZMPPreviewController<n>::calculateNextCom(const RingBuffer<Vector2f, n>& zmpReference, const Vector3<>& estimatedZmp,
  93. const Vector3<>& delayedComPositionInSupportFoot,
  94. const Vector3<>& delayedComVelocityInSupportFoot,
  95. const Vector3<>& delayedComAccelerationInSupportFoot)
  96. {
  97. static const float zg = comHeight / 9.81e-3f;
  98. const bool bufferFull = zmpRefHistory.getNumberOfEntries() == frameDelay;
  99. zmpErrorSum.x = estimatedZmp.x - zmpReference[n - 1].x + 0.5f * zmpErrorSum.x;
  100. zmpErrorSum.y = estimatedZmp.x - zmpReference[n - 1].y + 0.5f * zmpErrorSum.y;
  101. float actionX = -integralGain * zmpErrorSum.x;
  102. actionX -= (stateGain[0][0] * comPositionInSupportFoot.x + stateGain[1][0] * comVelocityInSupportFoot.x + stateGain[2][0] * comAccelerationInSupportFoot.x);
  103. float actionY = -integralGain * zmpErrorSum.y;
  104. actionY -= (stateGain[0][0] * comPositionInSupportFoot.y + stateGain[1][0] * comVelocityInSupportFoot.y + stateGain[2][0] * comAccelerationInSupportFoot.y);
  105. for(int j = 1; j < n; ++j)
  106. {
  107. actionX -= previewGain[j] * zmpReference[n - 1 - j].x;
  108. actionY -= previewGain[j] * zmpReference[n - 1 - j].y;
  109. }
  110. comPositionInSupportFoot.x += comVelocityInSupportFoot.x * deltaT + comAccelerationInSupportFoot.x * sqr(deltaT) / 2.0f
  111. + actionX * sqr(deltaT) * deltaT / 6.0f;
  112. comPositionInSupportFoot.y += comVelocityInSupportFoot.y * deltaT + comAccelerationInSupportFoot.y * sqr(deltaT) / 2.0f
  113. + actionY * sqr(deltaT) * deltaT / 6.0f;
  114. comVelocityInSupportFoot.x += comAccelerationInSupportFoot.x * deltaT + actionX * sqr(deltaT) / 2.0f;
  115. comVelocityInSupportFoot.y += comAccelerationInSupportFoot.y * deltaT + actionY * sqr(deltaT) / 2.0f;
  116. comAccelerationInSupportFoot.x += actionX * deltaT;
  117. comAccelerationInSupportFoot.y += actionY * deltaT;
  118. if(bufferFull)
  119. plotModelError(estimatedZmp, delayedComPositionInSupportFoot, delayedComVelocityInSupportFoot, delayedComAccelerationInSupportFoot);
  120. zmpRefHistory.add(Vector2<>(zmpReference[n - 1].x, zmpReference[n - 1].y));
  121. modelZmpHistory.add(Vector2<>(comPositionInSupportFoot.x - zg * comAccelerationInSupportFoot.x,
  122. comPositionInSupportFoot.y - zg * comAccelerationInSupportFoot.y));
  123. modelComPositionHistory.add(comPositionInSupportFoot);
  124. modelComVelocitiesHistory.add(comVelocityInSupportFoot);
  125. modelComAccelerationsHistory.add(comAccelerationInSupportFoot);
  126. }
  127. template <int n> void CartTableZMPPreviewController<n>::generateLegAnglesForCenterOfMassOrientation(const float yRotationFraction,
  128. const float xRotationFraction,
  129. JointData& myJointData,
  130. const Pose3D& kickFoot2,
  131. const bool useSupportFootCoordinateSystem,
  132. const Vector3<>& desiredCom,
  133. Vector2<>& demandedTorsoAngularVelocity)
  134. {
  135. bool reachable;
  136. const bool left = supportFoot == MassCalibration::footLeft;
  137. const float ratio = left ? 1.0f : 0.0f;
  138. PLOT("module:IndykickEngine:carttable:kickfoot:rotation:x", toDegrees(kickFoot2.rotation.getXAngle()));
  139. PLOT("module:IndykickEngine:carttable:kickfoot:rotation:y", toDegrees(kickFoot2.rotation.getYAngle()));
  140. PLOT("module:IndykickEngine:carttable:kickfoot:rotation:z", toDegrees(kickFoot2.rotation.getZAngle()));
  141. Pose3D originInSupportFoot = supportFootInOrigin.invert();
  142. /* Calculate torso orientation error and remove that from kick foot orientation. TODO: Move to kick engine. */
  143. RotationMatrix kickFootOrientationCorrection(Vector3<>(1.0f, 0.0f, 0.0f), Vector3<>(0.0f, 1.0f, 0.0f), Vector3<>(0.0f, 0.0f, 1.0f));
  144. const float orientationBalanceTranslation = 7.0f;
  145. if(orientationBuffer.getNumberOfEntries() == frameDelay)
  146. {
  147. const Vector2<>& delayedTorsoOrientation = orientationBuffer[frameDelay - 1];
  148. const Vector2<> measuredTorsoOrientation(std::atan2(theOrientationData.rotation.c1.z, theOrientationData.rotation.c2.z),
  149. std::atan2(-theOrientationData.rotation.c0.z, theOrientationData.rotation.c2.z));
  150. Vector2<> torsoOrientationError = delayedTorsoOrientation - measuredTorsoOrientation;
  151. torsoOrientationError.x = normalize(torsoOrientationError.x);
  152. torsoOrientationError.y = normalize(torsoOrientationError.y);
  153. float kickFootZ = kickFoot2.translation.z;
  154. if(!useSupportFootCoordinateSystem)
  155. {
  156. Pose3D kickFootInSupportFoot(originInSupportFoot);
  157. kickFootInSupportFoot.conc(kickFoot2);
  158. kickFootZ = kickFootInSupportFoot.translation.z;
  159. }
  160. const float correctionFactor = std::min(kickFootZ / orientationBalanceTranslation, 1.0f);
  161. PLOT("module:IndykickEngine:carttable:measuredxzrotation", toDegrees(measuredTorsoOrientation.y));
  162. PLOT("module:IndykickEngine:carttable:demandedxzrotation", toDegrees(delayedTorsoOrientation.y));
  163. PLOT("module:IndykickEngine:carttable:orientationerror:y", toDegrees(torsoOrientationError.y));
  164. kickFootOrientationCorrection.rotateY(torsoOrientationError.y * correctionFactor);
  165. }
  166. const Pose3D kickFootPose(useSupportFootCoordinateSystem ? kickFootOrientationCorrection * kickFoot2.rotation : kickFoot2.rotation * kickFootOrientationCorrection, kickFoot2.translation);
  167. PLOT("module:IndykickEngine:carttable:correctedkickfoot:rotation:x", toDegrees(kickFootPose.rotation.getXAngle()));
  168. PLOT("module:IndykickEngine:carttable:correctedkickfoot:rotation:y", toDegrees(kickFootPose.rotation.getYAngle()));
  169. PLOT("module:IndykickEngine:carttable:correctedkickfoot:rotation:z", toDegrees(kickFootPose.rotation.getZAngle()));
  170. Pose3D kickFootInOrigin;
  171. if(useSupportFootCoordinateSystem)
  172. kickFootInOrigin = supportFootInOrigin;
  173. kickFootInOrigin.conc(kickFootPose);
  174. Pose3D *poseLeft = left ? &supportFootInOrigin : &kickFootInOrigin;
  175. Pose3D *poseRight = left ? &kickFootInOrigin : &supportFootInOrigin;
  176. reachable = InverseKinematic::calcLegJoints(*poseLeft, *poseRight, myJointData, theRobotDimensions, ratio);
  177. if(!reachable)
  178. {
  179. printf("Rotation X: %f\tRotation Y: %f\t Rotation Z: %f\n", toDegrees(originInSupportFoot.rotation.getXAngle()),
  180. toDegrees(originInSupportFoot.rotation.getYAngle()), toDegrees(originInSupportFoot.rotation.getZAngle()));
  181. OUTPUT(idText, text, "Cart table: Unreachable kick leg position.");
  182. }
  183. RobotModel myRobotModel(myJointData, theRobotDimensions, theMassCalibration);
  184. Vector3<> com = originInSupportFoot * myRobotModel.centerOfMass;
  185. const float y = yRotationFraction * com.y + (1.0f - yRotationFraction) * desiredCom.y;
  186. const float x = xRotationFraction * com.x + (1.0f - xRotationFraction) * desiredCom.x;
  187. for(int i = 0; i < 7; ++i)
  188. {
  189. const float deltaY = y - com.y;
  190. const float deltaX = x - com.x;
  191. originInSupportFoot.translation.x += deltaX;
  192. originInSupportFoot.translation.y += deltaY;
  193. supportFootInOrigin = originInSupportFoot.invert();
  194. if(useSupportFootCoordinateSystem)
  195. {
  196. kickFootInOrigin = supportFootInOrigin;
  197. kickFootInOrigin.conc(kickFootPose);
  198. }
  199. reachable = InverseKinematic::calcLegJoints(*poseLeft, *poseRight, myJointData, theRobotDimensions, ratio);
  200. if(!reachable)
  201. OUTPUT(idText, text, "Cart table: Unreachable kick leg position.");
  202. myRobotModel.setJointData(myJointData, theRobotDimensions, theMassCalibration);
  203. com = originInSupportFoot * myRobotModel.centerOfMass;
  204. }
  205. float z2 = std::sqrt(sqr(com.y) + sqr(com.z) - sqr(desiredCom.y));
  206. float angle = std::atan2(com.y, com.z) - std::atan2(desiredCom.y, z2);
  207. // while(abs(angle) > 0.0005f)
  208. for(int i = 0; (i < 10) && (std::abs(angle) > 0.0005f); ++i)
  209. {
  210. originInSupportFoot.rotation = RotationMatrix::fromRotationX(angle) * originInSupportFoot.rotation;
  211. supportFootInOrigin = originInSupportFoot.invert();
  212. if(useSupportFootCoordinateSystem)
  213. {
  214. kickFootInOrigin = supportFootInOrigin;
  215. kickFootInOrigin.conc(kickFootPose);
  216. }
  217. reachable = InverseKinematic::calcLegJoints(*poseLeft, *poseRight, myJointData, theRobotDimensions, ratio);
  218. if(!reachable)
  219. OUTPUT(idText, text, "Cart table: Unreachable kick leg position.");
  220. myRobotModel.setJointData(myJointData, theRobotDimensions, theMassCalibration);
  221. com = originInSupportFoot * myRobotModel.centerOfMass;
  222. z2 = std::sqrt(sqr(com.y) + sqr(com.z) - sqr(desiredCom.y));
  223. angle = std::atan2(com.y, com.z) - std::atan2(desiredCom.y, z2);
  224. }
  225. z2 = std::sqrt(sqr(com.x) + sqr(com.z) - sqr(desiredCom.x));
  226. angle = std::atan2(com.x, com.z) - std::atan2(desiredCom.x, z2);
  227. for(int i = 0; (i < 10) && (std::abs(angle) > 0.0005f); ++i)
  228. {
  229. originInSupportFoot.rotation = RotationMatrix::fromRotationY(-angle) * originInSupportFoot.rotation;
  230. supportFootInOrigin = originInSupportFoot.invert();
  231. if(useSupportFootCoordinateSystem)
  232. {
  233. kickFootInOrigin = supportFootInOrigin;
  234. kickFootInOrigin.conc(kickFootPose);
  235. }
  236. reachable = InverseKinematic::calcLegJoints(*poseLeft, *poseRight, myJointData, theRobotDimensions, ratio);
  237. if(!reachable)
  238. OUTPUT(idText, text, "Cart table: Unreachable kick leg position.");
  239. myRobotModel.setJointData(myJointData, theRobotDimensions, theMassCalibration);
  240. com = originInSupportFoot * myRobotModel.centerOfMass;
  241. z2 = std::sqrt(sqr(com.x) + sqr(com.z) - sqr(desiredCom.x));
  242. angle = std::atan2(com.x, com.z) - std::atan2(desiredCom.x, z2);
  243. }
  244. for(int i = 0; i < 7; ++i)
  245. {
  246. const Vector3<> deltaCom = desiredCom - com;
  247. originInSupportFoot.translation += deltaCom;
  248. supportFootInOrigin = originInSupportFoot.invert();
  249. if(useSupportFootCoordinateSystem)
  250. {
  251. kickFootInOrigin = supportFootInOrigin;
  252. kickFootInOrigin.conc(kickFootPose);
  253. }
  254. reachable = InverseKinematic::calcLegJoints(*poseLeft, *poseRight, myJointData, theRobotDimensions, ratio);
  255. if(!reachable)
  256. OUTPUT(idText, text, "Cart table: Unreachable kick leg position.");
  257. myRobotModel.setJointData(myJointData, theRobotDimensions, theMassCalibration);
  258. com = originInSupportFoot * myRobotModel.centerOfMass;
  259. }
  260. /* Save demanded torso orientation. */
  261. orientationBuffer.add(Vector2<>(std::atan2(originInSupportFoot.rotation.c1.z, originInSupportFoot.rotation.c2.z),
  262. std::atan2(-originInSupportFoot.rotation.c0.z, originInSupportFoot.rotation.c2.z)));
  263. /* Calculate demanded angular velocities of the torso. */
  264. const RotationMatrix rotationDelta = originInSupportFoot.rotation.invert() * lastTorsoRotation;
  265. const Vector3<> rotationDeltaPole = rotationDelta * Vector3<>(0.0f, 0.0f, 1.0f);
  266. demandedTorsoAngularVelocity.x = std::atan2(rotationDeltaPole.y, rotationDeltaPole.z) / 0.01f;
  267. demandedTorsoAngularVelocity.y = std::atan2(rotationDeltaPole.x, rotationDeltaPole.z) / 0.01f;
  268. lastTorsoRotation = originInSupportFoot.rotation;
  269. }
  270. template <int n> void CartTableZMPPreviewController<n>::reset(const bool leftSupport,
  271. const Vector3<>& comPositionInSupportFoot,
  272. const Vector3<>& comVelocityInSupportFoot,
  273. const Vector3<>& comAccelerationInSupportFoot,
  274. const RobotModel& initialRobotModel)
  275. {
  276. zmpErrorSum.x = 0.0f;
  277. zmpErrorSum.y = 0.0f;
  278. this->comPositionInSupportFoot = comPositionInSupportFoot;
  279. this->comVelocityInSupportFoot = Vector2<>(comVelocityInSupportFoot.x, comVelocityInSupportFoot.y);
  280. this->comAccelerationInSupportFoot = Vector2<>(comAccelerationInSupportFoot.x, comAccelerationInSupportFoot.y);
  281. supportFoot = leftSupport ? MassCalibration::footLeft : MassCalibration::footRight;
  282. supportFootInOrigin = initialRobotModel.limbs[supportFoot];
  283. lastTorsoRotation = supportFootInOrigin.rotation.invert();
  284. zmpRefHistory.init();
  285. maxComAcceleration = 0.0f;
  286. maxComVelocity = 0.0f;
  287. maxComPositionError = 0.0f;
  288. orientationBuffer.init();
  289. }
  290. template <int n> void CartTableZMPPreviewController<n>::plotModelError(const Vector3<>& estimatedZmp,
  291. const Vector3<>& delayedComPositionInSupportFoot,
  292. const Vector3<>& delayedComVelocityInSupportFoot,
  293. const Vector3<>& delayedComAccelerationInSupportFoot)
  294. {
  295. const Vector2<>& modelZmp = modelZmpHistory[frameDelay - 1];
  296. const Vector3<>& modelComPosition = modelComPositionHistory[frameDelay - 1];
  297. const Vector2<>& modelComVelocity = modelComVelocitiesHistory[frameDelay - 1];
  298. const Vector2<>& modelComAcceleration = modelComAccelerationsHistory[frameDelay - 1];
  299. if(modelComAcceleration.abs() > maxComAcceleration)
  300. maxComAcceleration = modelComAcceleration.abs();
  301. if(modelComVelocity.abs() > maxComVelocity)
  302. maxComVelocity = modelComVelocity.abs();
  303. const Vector2<> zmpError(estimatedZmp.x - modelZmp.x, estimatedZmp.y - modelZmp.y);
  304. const Vector2<> comPositionError = Vector2<>(delayedComPositionInSupportFoot.x - modelComPosition.x,
  305. delayedComPositionInSupportFoot.y - modelComPosition.y);
  306. const Vector2<> comVelocityError = Vector2<>(delayedComVelocityInSupportFoot.x, delayedComVelocityInSupportFoot.y) - modelComVelocity;
  307. const Vector2<> comAccelerationError = Vector2<>(delayedComAccelerationInSupportFoot.x, delayedComAccelerationInSupportFoot.y) - modelComAcceleration;
  308. if(comPositionError.abs() > maxComPositionError)
  309. maxComPositionError = comPositionError.abs();
  310. PLOT("module:IndykickEngine:carttable:zmpError", zmpError.abs());
  311. PLOT("module:IndykickEngine:carttable:comPositionError", comPositionError.abs());
  312. PLOT("module:IndykickEngine:carttable:comVelocityError", comVelocityError.abs());
  313. PLOT("module:IndykickEngine:carttable:comAccelerationError", comAccelerationError.abs());
  314. }
  315. template class CartTableZMPPreviewController<50>;