@@ -865,15 +865,7 @@ void mj_tendon(const mjModel* m, mjData* d) {
865865void mj_tendonDot (const mjModel * m , mjData * d , int id , mjtNum * Jdot ) {
866866 int nv = m -> nv ;
867867
868- // allocate stack arrays
869- mjtNum * jac1 , * jac2 , * jacdif , * tmp ;
870- mj_markStack (d );
871- jac1 = mjSTACKALLOC (d , 3 * nv , mjtNum );
872- jac2 = mjSTACKALLOC (d , 3 * nv , mjtNum );
873- jacdif = mjSTACKALLOC (d , 3 * nv , mjtNum );
874- tmp = mjSTACKALLOC (d , nv , mjtNum );
875-
876- // return if tendon id is invalid
868+ // tendon id is invalid: return
877869 if (id < 0 || id >= m -> ntendon ) {
878870 return ;
879871 }
@@ -887,6 +879,13 @@ void mj_tendonDot(const mjModel* m, mjData* d, int id, mjtNum* Jdot) {
887879 return ;
888880 }
889881
882+ // allocate stack arrays
883+ mj_markStack (d );
884+ mjtNum * jac1 = mjSTACKALLOC (d , 3 * nv , mjtNum );
885+ mjtNum * jac2 = mjSTACKALLOC (d , 3 * nv , mjtNum );
886+ mjtNum * jacdif = mjSTACKALLOC (d , 3 * nv , mjtNum );
887+ mjtNum * tmp = mjSTACKALLOC (d , nv , mjtNum );
888+
890889 // process spatial tendon
891890 mjtNum divisor = 1 ;
892891 int wraptype , j = 0 ;
@@ -1470,6 +1469,63 @@ void mj_transmission(const mjModel* m, mjData* d) {
14701469
14711470//-------------------------- inertia ---------------------------------------------------------------
14721471
1472+ // add tendon armature to qM
1473+ void mj_tendonArmature (const mjModel * m , mjData * d ) {
1474+ TM_START ;
1475+ int nv = m -> nv , ntendon = m -> ntendon , issparse = mj_isSparse (m );
1476+
1477+ for (int k = 0 ; k < ntendon ; k ++ ) {
1478+ mjtNum armature = m -> tendon_armature [k ];
1479+
1480+ if (!armature ) {
1481+ continue ;
1482+ }
1483+
1484+ // dense
1485+ if (!issparse ) {
1486+ mjtNum * ten_J = d -> ten_J + nv * k ;
1487+ for (int i = 0 ; i < m -> nv ; i ++ ) {
1488+ int Madr = m -> dof_Madr [i ];
1489+ for (int j = i ; j >= 0 ; j = m -> dof_parentid [j ]) {
1490+ d -> qM [Madr ++ ] += armature * ten_J [j ] * ten_J [i ];
1491+ }
1492+ }
1493+ }
1494+
1495+ // sparse
1496+ else {
1497+ // get sparse info for tendon k
1498+ int rowadr = d -> ten_J_rowadr [k ];
1499+ int rownnz = d -> ten_J_rownnz [k ];
1500+ const int * colind = d -> ten_J_colind + rowadr ;
1501+ mjtNum * ten_J = d -> ten_J + rowadr ;
1502+
1503+ // iterate forward on nonzero rows i
1504+ for (int adr_i = 0 ; adr_i < rownnz ; adr_i ++ ) {
1505+ int i = colind [adr_i ];
1506+ int Madr = m -> dof_Madr [i ];
1507+ int adr_j = rownnz - 1 ;
1508+
1509+ // iterate backward on ancestors of i, find matching column j
1510+ for (int j = i ; j >= 0 ; j = m -> dof_parentid [j ]) {
1511+ // reduce adr_j until column index is no bigger than j
1512+ while (colind [adr_j ] > j && adr_j >= 0 ) {
1513+ adr_j -- ;
1514+ }
1515+
1516+ // found match, update qM
1517+ if (colind [adr_j ] == j ) {
1518+ d -> qM [Madr ++ ] += armature * ten_J [adr_j ] * ten_J [adr_i ];
1519+ }
1520+ }
1521+ }
1522+ }
1523+ }
1524+ TM_END (mjTIMER_POS_INERTIA );
1525+ }
1526+
1527+
1528+
14731529// composite rigid body inertia algorithm
14741530void mj_crb (const mjModel * m , mjData * d ) {
14751531 TM_START ;
@@ -2321,3 +2377,53 @@ void mj_rnePostConstraint(const mjModel* m, mjData* d) {
23212377 mju_addTo (d -> cfrc_int + 6 * m -> body_parentid [j ], d -> cfrc_int + 6 * j , 6 );
23222378 }
23232379}
2380+
2381+
2382+
2383+ // add bias force due to tendon armature
2384+ void mj_tendonBias (const mjModel * m , mjData * d , mjtNum * qfrc ) {
2385+ int ntendon = m -> ntendon , nv = m -> nv , issparse = mj_isSparse (m );
2386+ mjtNum * ten_Jdot = NULL ;
2387+ mj_markStack (d );
2388+
2389+ // add bias term due to tendon armature
2390+ for (int i = 0 ; i < ntendon ; i ++ ) {
2391+ mjtNum armature = m -> tendon_armature [i ];
2392+
2393+ // no armature: skip
2394+ if (!armature ) {
2395+ continue ;
2396+ }
2397+
2398+ // allocate if required
2399+ if (!ten_Jdot ) {
2400+ ten_Jdot = mjSTACKALLOC (d , nv , mjtNum );
2401+ }
2402+
2403+ // get dense d/dt(tendon Jacobian) for tendon i
2404+ mj_tendonDot (m , d , i , ten_Jdot );
2405+
2406+ // add bias term: qfrc += ten_J * armature * dot(ten_Jdot, qvel)
2407+ mjtNum coef = armature * mju_dot (ten_Jdot , d -> qvel , nv );
2408+
2409+ if (coef ) {
2410+ // dense
2411+ if (!issparse ) {
2412+ mju_addToScl (qfrc , d -> ten_J + nv * i , coef , nv );
2413+ }
2414+
2415+ // sparse
2416+ else {
2417+ int nnz = d -> ten_J_rownnz [i ];
2418+ int adr = d -> ten_J_rowadr [i ];
2419+ const int * colind = d -> ten_J_colind + adr ;
2420+ const mjtNum * ten_J = d -> ten_J + adr ;
2421+ for (int j = 0 ; j < nnz ; j ++ ) {
2422+ qfrc [colind [j ]] += coef * ten_J [j ];
2423+ }
2424+ }
2425+ }
2426+ }
2427+
2428+ mj_freeStack (d );
2429+ }
0 commit comments