@@ -16,6 +16,270 @@ namespace pinocchio
1616 template <typename Scalar, int Options>
1717 struct JointEllipsoidTpl ;
1818
19+ template <typename Scalar, int Options>
20+ struct JointMotionSubspaceEllipsoidTpl ;
21+
22+ template <typename Scalar, int Options>
23+ struct SE3GroupAction <JointMotionSubspaceEllipsoidTpl<Scalar, Options>>
24+ {
25+ typedef Eigen::Matrix<Scalar, 6 , 3 , Options> ReturnType;
26+ };
27+
28+ template <typename Scalar, int Options, typename MotionDerived>
29+ struct MotionAlgebraAction <JointMotionSubspaceEllipsoidTpl<Scalar, Options>, MotionDerived>
30+ {
31+ typedef Eigen::Matrix<Scalar, 6 , 3 , Options> ReturnType;
32+ };
33+
34+ template <typename Scalar, int Options, typename ForceDerived>
35+ struct ConstraintForceOp <JointMotionSubspaceEllipsoidTpl<Scalar, Options>, ForceDerived>
36+ {
37+ typedef Eigen::Matrix<Scalar, 3 , 1 , Options> ReturnType;
38+ };
39+
40+ template <typename Scalar, int Options, typename ForceSet>
41+ struct ConstraintForceSetOp <JointMotionSubspaceEllipsoidTpl<Scalar, Options>, ForceSet>
42+ {
43+ typedef Eigen::Matrix<Scalar, 3 , Eigen::Dynamic, Options> ReturnType;
44+ };
45+
46+ template <typename _Scalar, int _Options>
47+ struct traits <JointMotionSubspaceEllipsoidTpl<_Scalar, _Options>>
48+ {
49+ typedef _Scalar Scalar;
50+ enum
51+ {
52+ Options = _Options
53+ };
54+ enum
55+ {
56+ LINEAR = 0 ,
57+ ANGULAR = 3
58+ };
59+
60+ typedef MotionTpl<Scalar, Options> JointMotion;
61+ typedef Eigen::Matrix<Scalar, 3 , 1 , Options> JointForce;
62+ typedef Eigen::Matrix<Scalar, 6 , 3 , Options> DenseBase;
63+ typedef Eigen::Matrix<Scalar, 3 , 3 , Options> ReducedSquaredMatrix;
64+
65+ typedef DenseBase MatrixReturnType;
66+ typedef const DenseBase ConstMatrixReturnType;
67+
68+ typedef typename ReducedSquaredMatrix::IdentityReturnType StDiagonalMatrixSOperationReturnType;
69+ };
70+
71+
72+ template <typename _Scalar, int _Options>
73+ struct JointMotionSubspaceEllipsoidTpl
74+ : JointMotionSubspaceBase<JointMotionSubspaceEllipsoidTpl<_Scalar, _Options>>
75+ {
76+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
77+
78+ PINOCCHIO_CONSTRAINT_TYPEDEF_TPL (JointMotionSubspaceEllipsoidTpl)
79+ enum
80+ {
81+ NV = 3
82+ };
83+
84+ typedef Eigen::Matrix<Scalar, 6 , 3 , Options> Matrix63;
85+ Matrix63 S;
86+
87+ JointMotionSubspaceEllipsoidTpl ()
88+ {
89+ }
90+
91+ template <typename Vector3Like>
92+ JointMotion __mult__ (const Eigen::MatrixBase<Vector3Like> & v) const
93+ {
94+ // Compute first 6 rows from first 2 columns
95+ Eigen::Matrix<Scalar, 6 , 1 > result = S.template block <6 ,2 >(0 ,0 ) * v.template segment <2 >(0 );
96+
97+ // Add contribution from last column (only row 5 is non-zero: S(5,2) = 1)
98+ result[5 ] += v[2 ];
99+
100+ return JointMotion (result);
101+ }
102+
103+ template <typename S1, int O1>
104+ typename SE3GroupAction<JointMotionSubspaceEllipsoidTpl>::ReturnType
105+ se3Action (const SE3Tpl<S1, O1> & m) const
106+ {
107+ typedef typename SE3GroupAction<JointMotionSubspaceEllipsoidTpl>::ReturnType ReturnType;
108+ ReturnType res;
109+ // Apply SE3 action to first two columns
110+ motionSet::se3Action (m, S.template leftCols <2 >(), res.template leftCols <2 >());
111+
112+ res.template block <3 , 1 >(LINEAR, 2 ).noalias () = m.translation ().cross (m.rotation ().col (2 ));
113+ res.template block <3 , 1 >(ANGULAR, 2 ) = m.rotation ().col (2 );
114+
115+
116+ return res;
117+ }
118+
119+ template <typename S1, int O1>
120+ typename SE3GroupAction<JointMotionSubspaceEllipsoidTpl>::ReturnType
121+ se3ActionInverse (const SE3Tpl<S1, O1> & m) const
122+ {
123+ typedef typename SE3GroupAction<JointMotionSubspaceEllipsoidTpl>::ReturnType ReturnType;
124+ ReturnType res;
125+ // Apply inverse SE3 action to first two columns
126+ motionSet::se3ActionInverse (m, S.template leftCols <2 >(), res.template leftCols <2 >());
127+
128+ // Third column: inverse action on [0, 0, 0, 0, 0, 1]^T
129+ // angular part: R^T * e_z
130+ res.template block <3 , 1 >(ANGULAR, 2 ) = m.rotation ().transpose ().col (2 );
131+ // linear part: R^T * (t × e_z) = R^T * [-t_y, t_x, 0]^T
132+ typedef Eigen::Matrix<Scalar, 3 , 1 , Options> Vector3;
133+ const Vector3 t_cross_ez (-m.translation ()[1 ], m.translation ()[0 ], Scalar (0 ));
134+ res.template block <3 , 1 >(LINEAR, 2 ).noalias () = m.rotation ().transpose () * t_cross_ez;
135+
136+ return res;
137+ }
138+
139+ int nv_impl () const
140+ {
141+ return NV;
142+ }
143+
144+ struct TransposeConst : JointMotionSubspaceTransposeBase<JointMotionSubspaceEllipsoidTpl>
145+ {
146+ const JointMotionSubspaceEllipsoidTpl & ref;
147+ TransposeConst (const JointMotionSubspaceEllipsoidTpl & ref)
148+ : ref(ref)
149+ {
150+ }
151+
152+ template <typename ForceDerived>
153+ typename ConstraintForceOp<JointMotionSubspaceEllipsoidTpl, ForceDerived>::ReturnType
154+ operator *(const ForceDense<ForceDerived> & f) const
155+ {
156+ typedef typename ConstraintForceOp<JointMotionSubspaceEllipsoidTpl, ForceDerived>::ReturnType ReturnType;
157+ ReturnType res;
158+
159+ // First two rows: S[:, 0:2]^T * f
160+ res.template head <2 >().noalias () = ref.S .template leftCols <2 >().transpose () * f.toVector ();
161+
162+ // Third row: [0,0,0,0,0,1]^T · f = f.angular()[2]
163+ res[2 ] = f.angular ()[2 ];
164+
165+ return res;
166+ }
167+
168+ // / [CRBA] MatrixBase operator* (Constraint::Transpose S, ForceSet::Block)
169+ template <typename Derived>
170+ Eigen::Matrix<
171+ Scalar, 3 , Derived::ColsAtCompileTime,
172+ Options | Eigen::RowMajor,
173+ 3 , Derived::MaxColsAtCompileTime>
174+ operator *(const Eigen::MatrixBase<Derived> & F) const
175+ {
176+ EIGEN_STATIC_ASSERT (Derived::RowsAtCompileTime == 6 , THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE)
177+ typedef Eigen::Matrix<
178+ Scalar, 3 , Derived::ColsAtCompileTime,
179+ Options | Eigen::RowMajor,
180+ 3 , Derived::MaxColsAtCompileTime> ReturnType;
181+
182+ ReturnType res (3 , F.cols ());
183+
184+ // First two rows: S[:, 0:2]^T * F
185+ res.template topRows <2 >().noalias () = ref.S .template leftCols <2 >().transpose () * F.derived ();
186+
187+ // Third row: [0,0,0,0,0,1]^T · F = F.row(5)
188+ res.row (2 ) = F.row (5 );
189+
190+ return res;
191+ }
192+ }; // struct TransposeConst
193+
194+ TransposeConst transpose () const
195+ {
196+ return TransposeConst (*this );
197+ }
198+
199+ /* CRBA joint operators
200+ * - ForceSet::Block = ForceSet
201+ * - ForceSet operator* (Inertia Y,Constraint S)
202+ * - MatrixBase operator* (Constraint::Transpose S, ForceSet::Block)
203+ * - SE3::act(ForceSet::Block)
204+ */
205+ DenseBase matrix_impl () const
206+ {
207+ DenseBase res;
208+
209+ // Columns 0-1: copy the first two columns of S (6x2)
210+ res.template leftCols <2 >() = S.template leftCols <2 >();
211+
212+ // Column 2: sparse [0, 0, 0, 0, 0, 1]^T
213+ res.template block <5 , 1 >(0 , 2 ).setZero ();
214+ res (5 , 2 ) = Scalar (1 );
215+
216+ return res;
217+ }
218+
219+ template <typename MotionDerived>
220+ typename MotionAlgebraAction<JointMotionSubspaceEllipsoidTpl, MotionDerived>::ReturnType
221+ motionAction (const MotionDense<MotionDerived> & m) const
222+ {
223+ typedef
224+ typename MotionAlgebraAction<JointMotionSubspaceEllipsoidTpl, MotionDerived>::ReturnType
225+ ReturnType;
226+ ReturnType res;
227+
228+ // Motion action on first two columns
229+ motionSet::motionAction (m, S.template leftCols <2 >(), res.template leftCols <2 >());
230+
231+ // Motion action on third column [0, 0, 0, 0, 0, 1]^T
232+ // [v; w] × [0; e_z] = [v × e_z; w × e_z]
233+ const typename MotionDense<MotionDerived>::ConstLinearType & v_lin = m.linear ();
234+ const typename MotionDense<MotionDerived>::ConstAngularType & w = m.angular ();
235+
236+ // v × e_z = [v[1], -v[0], 0]
237+ res (LINEAR + 0 , 2 ) = v_lin[1 ];
238+ res (LINEAR + 1 , 2 ) = -v_lin[0 ];
239+ res (LINEAR + 2 , 2 ) = Scalar (0 );
240+
241+ // w × e_z = [w[1], -w[0], 0]
242+ res (ANGULAR + 0 , 2 ) = w[1 ];
243+ res (ANGULAR + 1 , 2 ) = -w[0 ];
244+ res (ANGULAR + 2 , 2 ) = Scalar (0 );
245+
246+ return res;
247+ }
248+
249+ bool isEqual (const JointMotionSubspaceEllipsoidTpl & other) const
250+ {
251+ return S == other.S ;
252+ }
253+
254+ }; // struct JointMotionSubspaceEllipsoidTpl
255+
256+ /* [CRBA] ForceSet operator* (Inertia Y, Constraint S) */
257+ template <typename S1, int O1, typename S2, int O2>
258+ Eigen::Matrix<S1, 6 , 3 , O1>
259+ operator *(const InertiaTpl<S1, O1> & Y, const JointMotionSubspaceEllipsoidTpl<S2, O2> & S)
260+ {
261+ // Y * S where Y is 6x6 inertia and S is 6x3 motion subspace
262+ // Returns 6x3 force set
263+ typedef InertiaTpl<S1, O1> Inertia;
264+ Eigen::Matrix<S1, 6 , 3 , O1> M;
265+ M.noalias () = Y.matrix () * S.matrix ();
266+ return M;
267+ }
268+
269+ /* [ABA] Y*S operator (Matrix6 Y, Constraint S) */
270+ template <typename Matrix6Like, typename S2, int O2>
271+ typename MatrixMatrixProduct<
272+ Matrix6Like,
273+ typename JointMotionSubspaceEllipsoidTpl<S2, O2>::DenseBase>::type
274+ operator *(
275+ const Eigen::MatrixBase<Matrix6Like> & Y,
276+ const JointMotionSubspaceEllipsoidTpl<S2, O2> & S)
277+ {
278+ EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE (Matrix6Like, 6 , 6 );
279+ return Y.derived () * S.matrix ();
280+ }
281+
282+
19283 template <typename _Scalar, int _Options>
20284 struct traits <JointEllipsoidTpl<_Scalar, _Options>>
21285 {
@@ -32,7 +296,9 @@ namespace pinocchio
32296 };
33297 typedef JointDataEllipsoidTpl<Scalar, Options> JointDataDerived;
34298 typedef JointModelEllipsoidTpl<Scalar, Options> JointModelDerived;
35- typedef JointMotionSubspaceTpl<3 , Scalar, Options, 3 > Constraint_t;
299+ // typedef JointMotionSubspaceTpl<3, Scalar, Options, 3> Constraint_t;
300+ typedef JointMotionSubspaceEllipsoidTpl<Scalar, Options> Constraint_t;
301+
36302 typedef SE3Tpl<Scalar, Options> Transformation_t;
37303
38304 typedef MotionTpl<Scalar, Options> Motion_t;
@@ -398,12 +664,13 @@ namespace pinocchio
398664 S_32 = dndotx_dqdot1 * radius_a * s1 - dndoty_dqdot1 * radius_b * c1 * s0
399665 + dndotz_dqdot1 * radius_c * c0 * c1;
400666
401- data.S .matrix () << S_11 , S_12 , Scalar (0 ),
402- S_21 , S_22 , Scalar (0 ),
403- S_31 , S_32 , Scalar (0 ),
404- c1 * c2, s2 , Scalar (0 ),
405- -c1 * s2, c2 , Scalar (0 ),
406- s1 , Scalar (0 ), Scalar (1 );
667+ // Write directly to the internal matrix S, not to matrix() which returns a copy
668+ data.S .S << S_11 , S_12 , Scalar (0 ),
669+ S_21 , S_22 , Scalar (0 ),
670+ S_31 , S_32 , Scalar (0 ),
671+ c1 * c2, s2 , Scalar (0 ),
672+ -c1 * s2, c2 , Scalar (0 ),
673+ s1 , Scalar (0 ), Scalar (1 );
407674 // clang-format on
408675 }
409676
0 commit comments