btMultiBody.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /*
  2. * PURPOSE:
  3. * Class representing an articulated rigid body. Stores the body's
  4. * current state, allows forces and torques to be set, handles
  5. * timestepping and implements Featherstone's algorithm.
  6. *
  7. * COPYRIGHT:
  8. * Copyright (C) Stephen Thompson, <stephen@solarflare.org.uk>, 2011-2013
  9. * Portions written By Erwin Coumans: replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
  10. This software is provided 'as-is', without any express or implied warranty.
  11. In no event will the authors be held liable for any damages arising from the use of this software.
  12. Permission is granted to anyone to use this software for any purpose,
  13. including commercial applications, and to alter it and redistribute it freely,
  14. subject to the following restrictions:
  15. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  16. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  17. 3. This notice may not be removed or altered from any source distribution.
  18. */
  19. #include "btMultiBody.h"
  20. #include "btMultiBodyLink.h"
  21. #include "btMultiBodyLinkCollider.h"
  22. // #define INCLUDE_GYRO_TERM
  23. namespace {
  24. const btScalar SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2)
  25. const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds
  26. }
  27. //
  28. // Various spatial helper functions
  29. //
  30. namespace {
  31. void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
  32. const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
  33. const btVector3 &top_in, // top part of input vector
  34. const btVector3 &bottom_in, // bottom part of input vector
  35. btVector3 &top_out, // top part of output vector
  36. btVector3 &bottom_out) // bottom part of output vector
  37. {
  38. top_out = rotation_matrix * top_in;
  39. bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in;
  40. }
  41. void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix,
  42. const btVector3 &displacement,
  43. const btVector3 &top_in,
  44. const btVector3 &bottom_in,
  45. btVector3 &top_out,
  46. btVector3 &bottom_out)
  47. {
  48. top_out = rotation_matrix.transpose() * top_in;
  49. bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in));
  50. }
  51. btScalar SpatialDotProduct(const btVector3 &a_top,
  52. const btVector3 &a_bottom,
  53. const btVector3 &b_top,
  54. const btVector3 &b_bottom)
  55. {
  56. return a_bottom.dot(b_top) + a_top.dot(b_bottom);
  57. }
  58. }
  59. //
  60. // Implementation of class btMultiBody
  61. //
  62. btMultiBody::btMultiBody(int n_links,
  63. btScalar mass,
  64. const btVector3 &inertia,
  65. bool fixed_base_,
  66. bool can_sleep_)
  67. : base_quat(0, 0, 0, 1),
  68. base_mass(mass),
  69. base_inertia(inertia),
  70. fixed_base(fixed_base_),
  71. awake(true),
  72. can_sleep(can_sleep_),
  73. sleep_timer(0),
  74. m_baseCollider(0),
  75. m_linearDamping(0.04f),
  76. m_angularDamping(0.04f),
  77. m_useGyroTerm(true),
  78. m_maxAppliedImpulse(1000.f),
  79. m_hasSelfCollision(true)
  80. {
  81. links.resize(n_links);
  82. vector_buf.resize(2*n_links);
  83. matrix_buf.resize(n_links + 1);
  84. m_real_buf.resize(6 + 2*n_links);
  85. base_pos.setValue(0, 0, 0);
  86. base_force.setValue(0, 0, 0);
  87. base_torque.setValue(0, 0, 0);
  88. }
  89. btMultiBody::~btMultiBody()
  90. {
  91. }
  92. void btMultiBody::setupPrismatic(int i,
  93. btScalar mass,
  94. const btVector3 &inertia,
  95. int parent,
  96. const btQuaternion &rot_parent_to_this,
  97. const btVector3 &joint_axis,
  98. const btVector3 &r_vector_when_q_zero,
  99. bool disableParentCollision)
  100. {
  101. links[i].mass = mass;
  102. links[i].inertia = inertia;
  103. links[i].parent = parent;
  104. links[i].zero_rot_parent_to_this = rot_parent_to_this;
  105. links[i].axis_top.setValue(0,0,0);
  106. links[i].axis_bottom = joint_axis;
  107. links[i].e_vector = r_vector_when_q_zero;
  108. links[i].is_revolute = false;
  109. links[i].cached_rot_parent_to_this = rot_parent_to_this;
  110. if (disableParentCollision)
  111. links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
  112. links[i].updateCache();
  113. }
  114. void btMultiBody::setupRevolute(int i,
  115. btScalar mass,
  116. const btVector3 &inertia,
  117. int parent,
  118. const btQuaternion &zero_rot_parent_to_this,
  119. const btVector3 &joint_axis,
  120. const btVector3 &parent_axis_position,
  121. const btVector3 &my_axis_position,
  122. bool disableParentCollision)
  123. {
  124. links[i].mass = mass;
  125. links[i].inertia = inertia;
  126. links[i].parent = parent;
  127. links[i].zero_rot_parent_to_this = zero_rot_parent_to_this;
  128. links[i].axis_top = joint_axis;
  129. links[i].axis_bottom = joint_axis.cross(my_axis_position);
  130. links[i].d_vector = my_axis_position;
  131. links[i].e_vector = parent_axis_position;
  132. links[i].is_revolute = true;
  133. if (disableParentCollision)
  134. links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
  135. links[i].updateCache();
  136. }
  137. int btMultiBody::getParent(int i) const
  138. {
  139. return links[i].parent;
  140. }
  141. btScalar btMultiBody::getLinkMass(int i) const
  142. {
  143. return links[i].mass;
  144. }
  145. const btVector3 & btMultiBody::getLinkInertia(int i) const
  146. {
  147. return links[i].inertia;
  148. }
  149. btScalar btMultiBody::getJointPos(int i) const
  150. {
  151. return links[i].joint_pos;
  152. }
  153. btScalar btMultiBody::getJointVel(int i) const
  154. {
  155. return m_real_buf[6 + i];
  156. }
  157. void btMultiBody::setJointPos(int i, btScalar q)
  158. {
  159. links[i].joint_pos = q;
  160. links[i].updateCache();
  161. }
  162. void btMultiBody::setJointVel(int i, btScalar qdot)
  163. {
  164. m_real_buf[6 + i] = qdot;
  165. }
  166. const btVector3 & btMultiBody::getRVector(int i) const
  167. {
  168. return links[i].cached_r_vector;
  169. }
  170. const btQuaternion & btMultiBody::getParentToLocalRot(int i) const
  171. {
  172. return links[i].cached_rot_parent_to_this;
  173. }
  174. btVector3 btMultiBody::localPosToWorld(int i, const btVector3 &local_pos) const
  175. {
  176. btVector3 result = local_pos;
  177. while (i != -1) {
  178. // 'result' is in frame i. transform it to frame parent(i)
  179. result += getRVector(i);
  180. result = quatRotate(getParentToLocalRot(i).inverse(),result);
  181. i = getParent(i);
  182. }
  183. // 'result' is now in the base frame. transform it to world frame
  184. result = quatRotate(getWorldToBaseRot().inverse() ,result);
  185. result += getBasePos();
  186. return result;
  187. }
  188. btVector3 btMultiBody::worldPosToLocal(int i, const btVector3 &world_pos) const
  189. {
  190. if (i == -1) {
  191. // world to base
  192. return quatRotate(getWorldToBaseRot(),(world_pos - getBasePos()));
  193. } else {
  194. // find position in parent frame, then transform to current frame
  195. return quatRotate(getParentToLocalRot(i),worldPosToLocal(getParent(i), world_pos)) - getRVector(i);
  196. }
  197. }
  198. btVector3 btMultiBody::localDirToWorld(int i, const btVector3 &local_dir) const
  199. {
  200. btVector3 result = local_dir;
  201. while (i != -1) {
  202. result = quatRotate(getParentToLocalRot(i).inverse() , result);
  203. i = getParent(i);
  204. }
  205. result = quatRotate(getWorldToBaseRot().inverse() , result);
  206. return result;
  207. }
  208. btVector3 btMultiBody::worldDirToLocal(int i, const btVector3 &world_dir) const
  209. {
  210. if (i == -1) {
  211. return quatRotate(getWorldToBaseRot(), world_dir);
  212. } else {
  213. return quatRotate(getParentToLocalRot(i) ,worldDirToLocal(getParent(i), world_dir));
  214. }
  215. }
  216. void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const
  217. {
  218. int num_links = getNumLinks();
  219. // Calculates the velocities of each link (and the base) in its local frame
  220. omega[0] = quatRotate(base_quat ,getBaseOmega());
  221. vel[0] = quatRotate(base_quat ,getBaseVel());
  222. for (int i = 0; i < num_links; ++i) {
  223. const int parent = links[i].parent;
  224. // transform parent vel into this frame, store in omega[i+1], vel[i+1]
  225. SpatialTransform(btMatrix3x3(links[i].cached_rot_parent_to_this), links[i].cached_r_vector,
  226. omega[parent+1], vel[parent+1],
  227. omega[i+1], vel[i+1]);
  228. // now add qidot * shat_i
  229. omega[i+1] += getJointVel(i) * links[i].axis_top;
  230. vel[i+1] += getJointVel(i) * links[i].axis_bottom;
  231. }
  232. }
  233. btScalar btMultiBody::getKineticEnergy() const
  234. {
  235. int num_links = getNumLinks();
  236. // TODO: would be better not to allocate memory here
  237. btAlignedObjectArray<btVector3> omega;omega.resize(num_links+1);
  238. btAlignedObjectArray<btVector3> vel;vel.resize(num_links+1);
  239. compTreeLinkVelocities(&omega[0], &vel[0]);
  240. // we will do the factor of 0.5 at the end
  241. btScalar result = base_mass * vel[0].dot(vel[0]);
  242. result += omega[0].dot(base_inertia * omega[0]);
  243. for (int i = 0; i < num_links; ++i) {
  244. result += links[i].mass * vel[i+1].dot(vel[i+1]);
  245. result += omega[i+1].dot(links[i].inertia * omega[i+1]);
  246. }
  247. return 0.5f * result;
  248. }
  249. btVector3 btMultiBody::getAngularMomentum() const
  250. {
  251. int num_links = getNumLinks();
  252. // TODO: would be better not to allocate memory here
  253. btAlignedObjectArray<btVector3> omega;omega.resize(num_links+1);
  254. btAlignedObjectArray<btVector3> vel;vel.resize(num_links+1);
  255. btAlignedObjectArray<btQuaternion> rot_from_world;rot_from_world.resize(num_links+1);
  256. compTreeLinkVelocities(&omega[0], &vel[0]);
  257. rot_from_world[0] = base_quat;
  258. btVector3 result = quatRotate(rot_from_world[0].inverse() , (base_inertia * omega[0]));
  259. for (int i = 0; i < num_links; ++i) {
  260. rot_from_world[i+1] = links[i].cached_rot_parent_to_this * rot_from_world[links[i].parent+1];
  261. result += (quatRotate(rot_from_world[i+1].inverse() , (links[i].inertia * omega[i+1])));
  262. }
  263. return result;
  264. }
  265. void btMultiBody::clearForcesAndTorques()
  266. {
  267. base_force.setValue(0, 0, 0);
  268. base_torque.setValue(0, 0, 0);
  269. for (int i = 0; i < getNumLinks(); ++i) {
  270. links[i].applied_force.setValue(0, 0, 0);
  271. links[i].applied_torque.setValue(0, 0, 0);
  272. links[i].joint_torque = 0;
  273. }
  274. }
  275. void btMultiBody::clearVelocities()
  276. {
  277. for (int i = 0; i < 6 + getNumLinks(); ++i)
  278. {
  279. m_real_buf[i] = 0.f;
  280. }
  281. }
  282. void btMultiBody::addLinkForce(int i, const btVector3 &f)
  283. {
  284. links[i].applied_force += f;
  285. }
  286. void btMultiBody::addLinkTorque(int i, const btVector3 &t)
  287. {
  288. links[i].applied_torque += t;
  289. }
  290. void btMultiBody::addJointTorque(int i, btScalar Q)
  291. {
  292. links[i].joint_torque += Q;
  293. }
  294. const btVector3 & btMultiBody::getLinkForce(int i) const
  295. {
  296. return links[i].applied_force;
  297. }
  298. const btVector3 & btMultiBody::getLinkTorque(int i) const
  299. {
  300. return links[i].applied_torque;
  301. }
  302. btScalar btMultiBody::getJointTorque(int i) const
  303. {
  304. return links[i].joint_torque;
  305. }
  306. inline btMatrix3x3 vecMulVecTranspose(const btVector3& v0, const btVector3& v1Transposed)
  307. {
  308. btVector3 row0 = btVector3(
  309. v0.x() * v1Transposed.x(),
  310. v0.x() * v1Transposed.y(),
  311. v0.x() * v1Transposed.z());
  312. btVector3 row1 = btVector3(
  313. v0.y() * v1Transposed.x(),
  314. v0.y() * v1Transposed.y(),
  315. v0.y() * v1Transposed.z());
  316. btVector3 row2 = btVector3(
  317. v0.z() * v1Transposed.x(),
  318. v0.z() * v1Transposed.y(),
  319. v0.z() * v1Transposed.z());
  320. btMatrix3x3 m(row0[0],row0[1],row0[2],
  321. row1[0],row1[1],row1[2],
  322. row2[0],row2[1],row2[2]);
  323. return m;
  324. }
  325. void btMultiBody::stepVelocities(btScalar dt,
  326. btAlignedObjectArray<btScalar> &scratch_r,
  327. btAlignedObjectArray<btVector3> &scratch_v,
  328. btAlignedObjectArray<btMatrix3x3> &scratch_m)
  329. {
  330. // Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot)
  331. // and the base linear & angular accelerations.
  332. // We apply damping forces in this routine as well as any external forces specified by the
  333. // caller (via addBaseForce etc).
  334. // output should point to an array of 6 + num_links reals.
  335. // Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame),
  336. // num_links joint acceleration values.
  337. int num_links = getNumLinks();
  338. const btScalar DAMPING_K1_LINEAR = m_linearDamping;
  339. const btScalar DAMPING_K2_LINEAR = m_linearDamping;
  340. const btScalar DAMPING_K1_ANGULAR = m_angularDamping;
  341. const btScalar DAMPING_K2_ANGULAR= m_angularDamping;
  342. btVector3 base_vel = getBaseVel();
  343. btVector3 base_omega = getBaseOmega();
  344. // Temporary matrices/vectors -- use scratch space from caller
  345. // so that we don't have to keep reallocating every frame
  346. scratch_r.resize(2*num_links + 6);
  347. scratch_v.resize(8*num_links + 6);
  348. scratch_m.resize(4*num_links + 4);
  349. btScalar * r_ptr = &scratch_r[0];
  350. btScalar * output = &scratch_r[num_links]; // "output" holds the q_double_dot results
  351. btVector3 * v_ptr = &scratch_v[0];
  352. // vhat_i (top = angular, bottom = linear part)
  353. btVector3 * vel_top_angular = v_ptr; v_ptr += num_links + 1;
  354. btVector3 * vel_bottom_linear = v_ptr; v_ptr += num_links + 1;
  355. // zhat_i^A
  356. btVector3 * zero_acc_top_angular = v_ptr; v_ptr += num_links + 1;
  357. btVector3 * zero_acc_bottom_linear = v_ptr; v_ptr += num_links + 1;
  358. // chat_i (note NOT defined for the base)
  359. btVector3 * coriolis_top_angular = v_ptr; v_ptr += num_links;
  360. btVector3 * coriolis_bottom_linear = v_ptr; v_ptr += num_links;
  361. // top left, top right and bottom left blocks of Ihat_i^A.
  362. // bottom right block = transpose of top left block and is not stored.
  363. // Note: the top right and bottom left blocks are always symmetric matrices, but we don't make use of this fact currently.
  364. btMatrix3x3 * inertia_top_left = &scratch_m[num_links + 1];
  365. btMatrix3x3 * inertia_top_right = &scratch_m[2*num_links + 2];
  366. btMatrix3x3 * inertia_bottom_left = &scratch_m[3*num_links + 3];
  367. // Cached 3x3 rotation matrices from parent frame to this frame.
  368. btMatrix3x3 * rot_from_parent = &matrix_buf[0];
  369. btMatrix3x3 * rot_from_world = &scratch_m[0];
  370. // hhat_i, ahat_i
  371. // hhat is NOT stored for the base (but ahat is)
  372. btVector3 * h_top = num_links > 0 ? &vector_buf[0] : 0;
  373. btVector3 * h_bottom = num_links > 0 ? &vector_buf[num_links] : 0;
  374. btVector3 * accel_top = v_ptr; v_ptr += num_links + 1;
  375. btVector3 * accel_bottom = v_ptr; v_ptr += num_links + 1;
  376. // Y_i, D_i
  377. btScalar * Y = r_ptr; r_ptr += num_links;
  378. btScalar * D = num_links > 0 ? &m_real_buf[6 + num_links] : 0;
  379. // ptr to the joint accel part of the output
  380. btScalar * joint_accel = output + 6;
  381. // Start of the algorithm proper.
  382. // First 'upward' loop.
  383. // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
  384. rot_from_parent[0] = btMatrix3x3(base_quat);
  385. vel_top_angular[0] = rot_from_parent[0] * base_omega;
  386. vel_bottom_linear[0] = rot_from_parent[0] * base_vel;
  387. if (fixed_base) {
  388. zero_acc_top_angular[0] = zero_acc_bottom_linear[0] = btVector3(0,0,0);
  389. } else {
  390. zero_acc_top_angular[0] = - (rot_from_parent[0] * (base_force
  391. - base_mass*(DAMPING_K1_LINEAR+DAMPING_K2_LINEAR*base_vel.norm())*base_vel));
  392. zero_acc_bottom_linear[0] =
  393. - (rot_from_parent[0] * base_torque);
  394. if (m_useGyroTerm)
  395. zero_acc_bottom_linear[0]+=vel_top_angular[0].cross( base_inertia * vel_top_angular[0] );
  396. zero_acc_bottom_linear[0] += base_inertia * vel_top_angular[0] * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR*vel_top_angular[0].norm());
  397. }
  398. inertia_top_left[0] = btMatrix3x3(0,0,0,0,0,0,0,0,0);//::Zero();
  399. inertia_top_right[0].setValue(base_mass, 0, 0,
  400. 0, base_mass, 0,
  401. 0, 0, base_mass);
  402. inertia_bottom_left[0].setValue(base_inertia[0], 0, 0,
  403. 0, base_inertia[1], 0,
  404. 0, 0, base_inertia[2]);
  405. rot_from_world[0] = rot_from_parent[0];
  406. for (int i = 0; i < num_links; ++i) {
  407. const int parent = links[i].parent;
  408. rot_from_parent[i+1] = btMatrix3x3(links[i].cached_rot_parent_to_this);
  409. rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1];
  410. // vhat_i = i_xhat_p(i) * vhat_p(i)
  411. SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
  412. vel_top_angular[parent+1], vel_bottom_linear[parent+1],
  413. vel_top_angular[i+1], vel_bottom_linear[i+1]);
  414. // we can now calculate chat_i
  415. // remember vhat_i is really vhat_p(i) (but in current frame) at this point
  416. coriolis_bottom_linear[i] = vel_top_angular[i+1].cross(vel_top_angular[i+1].cross(links[i].cached_r_vector))
  417. + 2 * vel_top_angular[i+1].cross(links[i].axis_bottom) * getJointVel(i);
  418. if (links[i].is_revolute) {
  419. coriolis_top_angular[i] = vel_top_angular[i+1].cross(links[i].axis_top) * getJointVel(i);
  420. coriolis_bottom_linear[i] += (getJointVel(i) * getJointVel(i)) * links[i].axis_top.cross(links[i].axis_bottom);
  421. } else {
  422. coriolis_top_angular[i] = btVector3(0,0,0);
  423. }
  424. // now set vhat_i to its true value by doing
  425. // vhat_i += qidot * shat_i
  426. vel_top_angular[i+1] += getJointVel(i) * links[i].axis_top;
  427. vel_bottom_linear[i+1] += getJointVel(i) * links[i].axis_bottom;
  428. // calculate zhat_i^A
  429. zero_acc_top_angular[i+1] = - (rot_from_world[i+1] * (links[i].applied_force));
  430. zero_acc_top_angular[i+1] += links[i].mass * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR*vel_bottom_linear[i+1].norm()) * vel_bottom_linear[i+1];
  431. zero_acc_bottom_linear[i+1] =
  432. - (rot_from_world[i+1] * links[i].applied_torque);
  433. if (m_useGyroTerm)
  434. {
  435. zero_acc_bottom_linear[i+1] += vel_top_angular[i+1].cross( links[i].inertia * vel_top_angular[i+1] );
  436. }
  437. zero_acc_bottom_linear[i+1] += links[i].inertia * vel_top_angular[i+1] * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR*vel_top_angular[i+1].norm());
  438. // calculate Ihat_i^A
  439. inertia_top_left[i+1] = btMatrix3x3(0,0,0,0,0,0,0,0,0);//::Zero();
  440. inertia_top_right[i+1].setValue(links[i].mass, 0, 0,
  441. 0, links[i].mass, 0,
  442. 0, 0, links[i].mass);
  443. inertia_bottom_left[i+1].setValue(links[i].inertia[0], 0, 0,
  444. 0, links[i].inertia[1], 0,
  445. 0, 0, links[i].inertia[2]);
  446. }
  447. // 'Downward' loop.
  448. // (part of TreeForwardDynamics in Mirtich.)
  449. for (int i = num_links - 1; i >= 0; --i) {
  450. h_top[i] = inertia_top_left[i+1] * links[i].axis_top + inertia_top_right[i+1] * links[i].axis_bottom;
  451. h_bottom[i] = inertia_bottom_left[i+1] * links[i].axis_top + inertia_top_left[i+1].transpose() * links[i].axis_bottom;
  452. btScalar val = SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, h_top[i], h_bottom[i]);
  453. D[i] = val;
  454. Y[i] = links[i].joint_torque
  455. - SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, zero_acc_top_angular[i+1], zero_acc_bottom_linear[i+1])
  456. - SpatialDotProduct(h_top[i], h_bottom[i], coriolis_top_angular[i], coriolis_bottom_linear[i]);
  457. const int parent = links[i].parent;
  458. // Ip += pXi * (Ii - hi hi' / Di) * iXp
  459. const btScalar one_over_di = 1.0f / D[i];
  460. const btMatrix3x3 TL = inertia_top_left[i+1] - vecMulVecTranspose(one_over_di * h_top[i] , h_bottom[i]);
  461. const btMatrix3x3 TR = inertia_top_right[i+1] - vecMulVecTranspose(one_over_di * h_top[i] , h_top[i]);
  462. const btMatrix3x3 BL = inertia_bottom_left[i+1]- vecMulVecTranspose(one_over_di * h_bottom[i] , h_bottom[i]);
  463. btMatrix3x3 r_cross;
  464. r_cross.setValue(
  465. 0, -links[i].cached_r_vector[2], links[i].cached_r_vector[1],
  466. links[i].cached_r_vector[2], 0, -links[i].cached_r_vector[0],
  467. -links[i].cached_r_vector[1], links[i].cached_r_vector[0], 0);
  468. inertia_top_left[parent+1] += rot_from_parent[i+1].transpose() * ( TL - TR * r_cross ) * rot_from_parent[i+1];
  469. inertia_top_right[parent+1] += rot_from_parent[i+1].transpose() * TR * rot_from_parent[i+1];
  470. inertia_bottom_left[parent+1] += rot_from_parent[i+1].transpose() *
  471. (r_cross * (TL - TR * r_cross) + BL - TL.transpose() * r_cross) * rot_from_parent[i+1];
  472. // Zp += pXi * (Zi + Ii*ci + hi*Yi/Di)
  473. btVector3 in_top, in_bottom, out_top, out_bottom;
  474. const btScalar Y_over_D = Y[i] * one_over_di;
  475. in_top = zero_acc_top_angular[i+1]
  476. + inertia_top_left[i+1] * coriolis_top_angular[i]
  477. + inertia_top_right[i+1] * coriolis_bottom_linear[i]
  478. + Y_over_D * h_top[i];
  479. in_bottom = zero_acc_bottom_linear[i+1]
  480. + inertia_bottom_left[i+1] * coriolis_top_angular[i]
  481. + inertia_top_left[i+1].transpose() * coriolis_bottom_linear[i]
  482. + Y_over_D * h_bottom[i];
  483. InverseSpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
  484. in_top, in_bottom, out_top, out_bottom);
  485. zero_acc_top_angular[parent+1] += out_top;
  486. zero_acc_bottom_linear[parent+1] += out_bottom;
  487. }
  488. // Second 'upward' loop
  489. // (part of TreeForwardDynamics in Mirtich)
  490. if (fixed_base)
  491. {
  492. accel_top[0] = accel_bottom[0] = btVector3(0,0,0);
  493. }
  494. else
  495. {
  496. if (num_links > 0)
  497. {
  498. //Matrix<btScalar, 6, 6> Imatrix;
  499. //Imatrix.block<3,3>(0,0) = inertia_top_left[0];
  500. //Imatrix.block<3,3>(3,0) = inertia_bottom_left[0];
  501. //Imatrix.block<3,3>(0,3) = inertia_top_right[0];
  502. //Imatrix.block<3,3>(3,3) = inertia_top_left[0].transpose();
  503. //cached_imatrix_lu.reset(new Eigen::LU<Matrix<btScalar, 6, 6> >(Imatrix)); // TODO: Avoid memory allocation here?
  504. cached_inertia_top_left = inertia_top_left[0];
  505. cached_inertia_top_right = inertia_top_right[0];
  506. cached_inertia_lower_left = inertia_bottom_left[0];
  507. cached_inertia_lower_right= inertia_top_left[0].transpose();
  508. }
  509. btVector3 rhs_top (zero_acc_top_angular[0][0], zero_acc_top_angular[0][1], zero_acc_top_angular[0][2]);
  510. btVector3 rhs_bot (zero_acc_bottom_linear[0][0], zero_acc_bottom_linear[0][1], zero_acc_bottom_linear[0][2]);
  511. float result[6];
  512. solveImatrix(rhs_top, rhs_bot, result);
  513. // printf("result=%f,%f,%f,%f,%f,%f\n",result[0],result[0],result[0],result[0],result[0],result[0]);
  514. for (int i = 0; i < 3; ++i) {
  515. accel_top[0][i] = -result[i];
  516. accel_bottom[0][i] = -result[i+3];
  517. }
  518. }
  519. // now do the loop over the links
  520. for (int i = 0; i < num_links; ++i) {
  521. const int parent = links[i].parent;
  522. SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
  523. accel_top[parent+1], accel_bottom[parent+1],
  524. accel_top[i+1], accel_bottom[i+1]);
  525. joint_accel[i] = (Y[i] - SpatialDotProduct(h_top[i], h_bottom[i], accel_top[i+1], accel_bottom[i+1])) / D[i];
  526. accel_top[i+1] += coriolis_top_angular[i] + joint_accel[i] * links[i].axis_top;
  527. accel_bottom[i+1] += coriolis_bottom_linear[i] + joint_accel[i] * links[i].axis_bottom;
  528. }
  529. // transform base accelerations back to the world frame.
  530. btVector3 omegadot_out = rot_from_parent[0].transpose() * accel_top[0];
  531. output[0] = omegadot_out[0];
  532. output[1] = omegadot_out[1];
  533. output[2] = omegadot_out[2];
  534. btVector3 vdot_out = rot_from_parent[0].transpose() * accel_bottom[0];
  535. output[3] = vdot_out[0];
  536. output[4] = vdot_out[1];
  537. output[5] = vdot_out[2];
  538. // Final step: add the accelerations (times dt) to the velocities.
  539. applyDeltaVee(output, dt);
  540. }
  541. void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, float result[6]) const
  542. {
  543. int num_links = getNumLinks();
  544. ///solve I * x = rhs, so the result = invI * rhs
  545. if (num_links == 0)
  546. {
  547. // in the case of 0 links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
  548. result[0] = rhs_bot[0] / base_inertia[0];
  549. result[1] = rhs_bot[1] / base_inertia[1];
  550. result[2] = rhs_bot[2] / base_inertia[2];
  551. result[3] = rhs_top[0] / base_mass;
  552. result[4] = rhs_top[1] / base_mass;
  553. result[5] = rhs_top[2] / base_mass;
  554. } else
  555. {
  556. /// Special routine for calculating the inverse of a spatial inertia matrix
  557. ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
  558. btMatrix3x3 Binv = cached_inertia_top_right.inverse()*-1.f;
  559. btMatrix3x3 tmp = cached_inertia_lower_right * Binv;
  560. btMatrix3x3 invIupper_right = (tmp * cached_inertia_top_left + cached_inertia_lower_left).inverse();
  561. tmp = invIupper_right * cached_inertia_lower_right;
  562. btMatrix3x3 invI_upper_left = (tmp * Binv);
  563. btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
  564. tmp = cached_inertia_top_left * invI_upper_left;
  565. tmp[0][0]-= 1.0;
  566. tmp[1][1]-= 1.0;
  567. tmp[2][2]-= 1.0;
  568. btMatrix3x3 invI_lower_left = (Binv * tmp);
  569. //multiply result = invI * rhs
  570. {
  571. btVector3 vtop = invI_upper_left*rhs_top;
  572. btVector3 tmp;
  573. tmp = invIupper_right * rhs_bot;
  574. vtop += tmp;
  575. btVector3 vbot = invI_lower_left*rhs_top;
  576. tmp = invI_lower_right * rhs_bot;
  577. vbot += tmp;
  578. result[0] = vtop[0];
  579. result[1] = vtop[1];
  580. result[2] = vtop[2];
  581. result[3] = vbot[0];
  582. result[4] = vbot[1];
  583. result[5] = vbot[2];
  584. }
  585. }
  586. }
  587. void btMultiBody::calcAccelerationDeltas(const btScalar *force, btScalar *output,
  588. btAlignedObjectArray<btScalar> &scratch_r, btAlignedObjectArray<btVector3> &scratch_v) const
  589. {
  590. // Temporary matrices/vectors -- use scratch space from caller
  591. // so that we don't have to keep reallocating every frame
  592. int num_links = getNumLinks();
  593. scratch_r.resize(num_links);
  594. scratch_v.resize(4*num_links + 4);
  595. btScalar * r_ptr = num_links == 0 ? 0 : &scratch_r[0];
  596. btVector3 * v_ptr = &scratch_v[0];
  597. // zhat_i^A (scratch space)
  598. btVector3 * zero_acc_top_angular = v_ptr; v_ptr += num_links + 1;
  599. btVector3 * zero_acc_bottom_linear = v_ptr; v_ptr += num_links + 1;
  600. // rot_from_parent (cached from calcAccelerations)
  601. const btMatrix3x3 * rot_from_parent = &matrix_buf[0];
  602. // hhat (cached), accel (scratch)
  603. const btVector3 * h_top = num_links > 0 ? &vector_buf[0] : 0;
  604. const btVector3 * h_bottom = num_links > 0 ? &vector_buf[num_links] : 0;
  605. btVector3 * accel_top = v_ptr; v_ptr += num_links + 1;
  606. btVector3 * accel_bottom = v_ptr; v_ptr += num_links + 1;
  607. // Y_i (scratch), D_i (cached)
  608. btScalar * Y = r_ptr; r_ptr += num_links;
  609. const btScalar * D = num_links > 0 ? &m_real_buf[6 + num_links] : 0;
  610. btAssert(num_links == 0 || r_ptr - &scratch_r[0] == scratch_r.size());
  611. btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
  612. // First 'upward' loop.
  613. // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
  614. btVector3 input_force(force[3],force[4],force[5]);
  615. btVector3 input_torque(force[0],force[1],force[2]);
  616. // Fill in zero_acc
  617. // -- set to force/torque on the base, zero otherwise
  618. if (fixed_base)
  619. {
  620. zero_acc_top_angular[0] = zero_acc_bottom_linear[0] = btVector3(0,0,0);
  621. } else
  622. {
  623. zero_acc_top_angular[0] = - (rot_from_parent[0] * input_force);
  624. zero_acc_bottom_linear[0] = - (rot_from_parent[0] * input_torque);
  625. }
  626. for (int i = 0; i < num_links; ++i)
  627. {
  628. zero_acc_top_angular[i+1] = zero_acc_bottom_linear[i+1] = btVector3(0,0,0);
  629. }
  630. // 'Downward' loop.
  631. for (int i = num_links - 1; i >= 0; --i)
  632. {
  633. Y[i] = - SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, zero_acc_top_angular[i+1], zero_acc_bottom_linear[i+1]);
  634. Y[i] += force[6 + i]; // add joint torque
  635. const int parent = links[i].parent;
  636. // Zp += pXi * (Zi + hi*Yi/Di)
  637. btVector3 in_top, in_bottom, out_top, out_bottom;
  638. const btScalar Y_over_D = Y[i] / D[i];
  639. in_top = zero_acc_top_angular[i+1] + Y_over_D * h_top[i];
  640. in_bottom = zero_acc_bottom_linear[i+1] + Y_over_D * h_bottom[i];
  641. InverseSpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
  642. in_top, in_bottom, out_top, out_bottom);
  643. zero_acc_top_angular[parent+1] += out_top;
  644. zero_acc_bottom_linear[parent+1] += out_bottom;
  645. }
  646. // ptr to the joint accel part of the output
  647. btScalar * joint_accel = output + 6;
  648. // Second 'upward' loop
  649. if (fixed_base)
  650. {
  651. accel_top[0] = accel_bottom[0] = btVector3(0,0,0);
  652. } else
  653. {
  654. btVector3 rhs_top (zero_acc_top_angular[0][0], zero_acc_top_angular[0][1], zero_acc_top_angular[0][2]);
  655. btVector3 rhs_bot (zero_acc_bottom_linear[0][0], zero_acc_bottom_linear[0][1], zero_acc_bottom_linear[0][2]);
  656. float result[6];
  657. solveImatrix(rhs_top,rhs_bot, result);
  658. // printf("result=%f,%f,%f,%f,%f,%f\n",result[0],result[0],result[0],result[0],result[0],result[0]);
  659. for (int i = 0; i < 3; ++i) {
  660. accel_top[0][i] = -result[i];
  661. accel_bottom[0][i] = -result[i+3];
  662. }
  663. }
  664. // now do the loop over the links
  665. for (int i = 0; i < num_links; ++i) {
  666. const int parent = links[i].parent;
  667. SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
  668. accel_top[parent+1], accel_bottom[parent+1],
  669. accel_top[i+1], accel_bottom[i+1]);
  670. joint_accel[i] = (Y[i] - SpatialDotProduct(h_top[i], h_bottom[i], accel_top[i+1], accel_bottom[i+1])) / D[i];
  671. accel_top[i+1] += joint_accel[i] * links[i].axis_top;
  672. accel_bottom[i+1] += joint_accel[i] * links[i].axis_bottom;
  673. }
  674. // transform base accelerations back to the world frame.
  675. btVector3 omegadot_out;
  676. omegadot_out = rot_from_parent[0].transpose() * accel_top[0];
  677. output[0] = omegadot_out[0];
  678. output[1] = omegadot_out[1];
  679. output[2] = omegadot_out[2];
  680. btVector3 vdot_out;
  681. vdot_out = rot_from_parent[0].transpose() * accel_bottom[0];
  682. output[3] = vdot_out[0];
  683. output[4] = vdot_out[1];
  684. output[5] = vdot_out[2];
  685. }
  686. void btMultiBody::stepPositions(btScalar dt)
  687. {
  688. int num_links = getNumLinks();
  689. // step position by adding dt * velocity
  690. btVector3 v = getBaseVel();
  691. base_pos += dt * v;
  692. // "exponential map" method for the rotation
  693. btVector3 base_omega = getBaseOmega();
  694. const btScalar omega_norm = base_omega.norm();
  695. const btScalar omega_times_dt = omega_norm * dt;
  696. const btScalar SMALL_ROTATION_ANGLE = 0.02f; // Theoretically this should be ~ pow(FLT_EPSILON,0.25) which is ~ 0.0156
  697. if (fabs(omega_times_dt) < SMALL_ROTATION_ANGLE)
  698. {
  699. const btScalar xsq = omega_times_dt * omega_times_dt; // |omega|^2 * dt^2
  700. const btScalar sin_term = dt * (xsq / 48.0f - 0.5f); // -sin(0.5*dt*|omega|) / |omega|
  701. const btScalar cos_term = 1.0f - xsq / 8.0f; // cos(0.5*dt*|omega|)
  702. base_quat = base_quat * btQuaternion(sin_term * base_omega[0],sin_term * base_omega[1],sin_term * base_omega[2],cos_term);
  703. } else
  704. {
  705. base_quat = base_quat * btQuaternion(base_omega / omega_norm,-omega_times_dt);
  706. }
  707. // Make sure the quaternion represents a valid rotation.
  708. // (Not strictly necessary, but helps prevent any round-off errors from building up.)
  709. base_quat.normalize();
  710. // Finally we can update joint_pos for each of the links
  711. for (int i = 0; i < num_links; ++i)
  712. {
  713. float jointVel = getJointVel(i);
  714. links[i].joint_pos += dt * jointVel;
  715. links[i].updateCache();
  716. }
  717. }
  718. void btMultiBody::fillContactJacobian(int link,
  719. const btVector3 &contact_point,
  720. const btVector3 &normal,
  721. btScalar *jac,
  722. btAlignedObjectArray<btScalar> &scratch_r,
  723. btAlignedObjectArray<btVector3> &scratch_v,
  724. btAlignedObjectArray<btMatrix3x3> &scratch_m) const
  725. {
  726. // temporary space
  727. int num_links = getNumLinks();
  728. scratch_v.resize(2*num_links + 2);
  729. scratch_m.resize(num_links + 1);
  730. btVector3 * v_ptr = &scratch_v[0];
  731. btVector3 * p_minus_com = v_ptr; v_ptr += num_links + 1;
  732. btVector3 * n_local = v_ptr; v_ptr += num_links + 1;
  733. btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
  734. scratch_r.resize(num_links);
  735. btScalar * results = num_links > 0 ? &scratch_r[0] : 0;
  736. btMatrix3x3 * rot_from_world = &scratch_m[0];
  737. const btVector3 p_minus_com_world = contact_point - base_pos;
  738. rot_from_world[0] = btMatrix3x3(base_quat);
  739. p_minus_com[0] = rot_from_world[0] * p_minus_com_world;
  740. n_local[0] = rot_from_world[0] * normal;
  741. // omega coeffients first.
  742. btVector3 omega_coeffs;
  743. omega_coeffs = p_minus_com_world.cross(normal);
  744. jac[0] = omega_coeffs[0];
  745. jac[1] = omega_coeffs[1];
  746. jac[2] = omega_coeffs[2];
  747. // then v coefficients
  748. jac[3] = normal[0];
  749. jac[4] = normal[1];
  750. jac[5] = normal[2];
  751. // Set remaining jac values to zero for now.
  752. for (int i = 6; i < 6 + num_links; ++i) {
  753. jac[i] = 0;
  754. }
  755. // Qdot coefficients, if necessary.
  756. if (num_links > 0 && link > -1) {
  757. // TODO: speed this up -- don't calculate for links we don't need.
  758. // (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions,
  759. // which is resulting in repeated work being done...)
  760. // calculate required normals & positions in the local frames.
  761. for (int i = 0; i < num_links; ++i) {
  762. // transform to local frame
  763. const int parent = links[i].parent;
  764. const btMatrix3x3 mtx(links[i].cached_rot_parent_to_this);
  765. rot_from_world[i+1] = mtx * rot_from_world[parent+1];
  766. n_local[i+1] = mtx * n_local[parent+1];
  767. p_minus_com[i+1] = mtx * p_minus_com[parent+1] - links[i].cached_r_vector;
  768. // calculate the jacobian entry
  769. if (links[i].is_revolute) {
  770. results[i] = n_local[i+1].dot( links[i].axis_top.cross(p_minus_com[i+1]) + links[i].axis_bottom );
  771. } else {
  772. results[i] = n_local[i+1].dot( links[i].axis_bottom );
  773. }
  774. }
  775. // Now copy through to output.
  776. while (link != -1) {
  777. jac[6 + link] = results[link];
  778. link = links[link].parent;
  779. }
  780. }
  781. }
  782. void btMultiBody::wakeUp()
  783. {
  784. awake = true;
  785. }
  786. void btMultiBody::goToSleep()
  787. {
  788. awake = false;
  789. }
  790. void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep)
  791. {
  792. int num_links = getNumLinks();
  793. extern bool gDisableDeactivation;
  794. if (!can_sleep || gDisableDeactivation)
  795. {
  796. awake = true;
  797. sleep_timer = 0;
  798. return;
  799. }
  800. // motion is computed as omega^2 + v^2 + (sum of squares of joint velocities)
  801. btScalar motion = 0;
  802. for (int i = 0; i < 6 + num_links; ++i) {
  803. motion += m_real_buf[i] * m_real_buf[i];
  804. }
  805. if (motion < SLEEP_EPSILON) {
  806. sleep_timer += timestep;
  807. if (sleep_timer > SLEEP_TIMEOUT) {
  808. goToSleep();
  809. }
  810. } else {
  811. sleep_timer = 0;
  812. if (!awake)
  813. wakeUp();
  814. }
  815. }