1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Velocity twist transformation matrix.
33  *
34  * Authors:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 
39 #include <assert.h>
40 #include <sstream>
41 
42 #include <visp3/core/vpException.h>
43 #include <visp3/core/vpVelocityTwistMatrix.h>
44 
45 /*!
46   \file vpVelocityTwistMatrix.cpp
47 
48   \brief Definition of the vpVelocityTwistMatrix. Class that consider the
49   particular case of twist transformation matrix that allows to
50   transform a velocity skew from one frame to an other.
51 */
52 
53 /*!
54   Copy operator that allow to set a velocity twist matrix from an other one.
55 
56   \param V : Velocity twist matrix to copy.
57 */
operator =(const vpVelocityTwistMatrix & V)58 vpVelocityTwistMatrix &vpVelocityTwistMatrix::operator=(const vpVelocityTwistMatrix &V)
59 {
60   for (int i = 0; i < 6; i++) {
61     for (int j = 0; j < 6; j++) {
62       rowPtrs[i][j] = V.rowPtrs[i][j];
63     }
64   }
65 
66   return *this;
67 }
68 
69 /*!
70   Initialize a 6x6 velocity twist matrix as identity.
71 */
eye()72 void vpVelocityTwistMatrix::eye()
73 {
74   for (unsigned int i = 0; i < 6; i++)
75     for (unsigned int j = 0; j < 6; j++)
76       if (i == j)
77         (*this)[i][j] = 1.0;
78       else
79         (*this)[i][j] = 0.0;
80 }
81 
82 /*!
83   Initialize a velocity twist transformation matrix as identity.
84 */
vpVelocityTwistMatrix()85 vpVelocityTwistMatrix::vpVelocityTwistMatrix() : vpArray2D<double>(6, 6) { eye(); }
86 
87 /*!
88   Initialize a velocity twist transformation matrix from another velocity
89   twist matrix.
90 
91   \param V : Velocity twist matrix used as initializer.
92 */
vpVelocityTwistMatrix(const vpVelocityTwistMatrix & V)93 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpVelocityTwistMatrix &V) : vpArray2D<double>(6, 6) { *this = V; }
94 
95 /*!
96 
97   Initialize a velocity twist transformation matrix from an homogeneous matrix
98   \f$M\f$ with \f[ {\bf M} = \left[\begin{array}{cc} {\bf R} & {\bf t}
99   \\ {\bf 0}_{1\times 3} & 1 \end{array} \right] \f]
100 
101   \param M : Homogeneous matrix \f$\bf M\f$ used to initialize the velocity
102   twist transformation matrix. \param full : Boolean used to indicate which
103   matrix should be filled.
104   - When set to true, use the complete velocity skew transformation :
105   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
106   \\
107   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
108   - When set to false, use the block diagonal velocity skew transformation:
109   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3} \\
110   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
111 
112 */
vpVelocityTwistMatrix(const vpHomogeneousMatrix & M,bool full)113 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpHomogeneousMatrix &M, bool full) : vpArray2D<double>(6, 6)
114 {
115   if (full)
116     buildFrom(M);
117   else
118     buildFrom(M.getRotationMatrix());
119 }
120 
121 /*!
122 
123   Initialize a velocity twist transformation matrix from a translation vector
124   \e t and a rotation vector with \f$\theta u \f$ parametrization.
125 
126   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
127   \\
128   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
129 
130   \param t : Translation vector.
131   \param thetau : \f$\theta u\f$ rotation vector used to initialize rotation
132   vector \f$R\f$ .
133 
134 */
vpVelocityTwistMatrix(const vpTranslationVector & t,const vpThetaUVector & thetau)135 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpTranslationVector &t, const vpThetaUVector &thetau)
136   : vpArray2D<double>(6, 6)
137 {
138   buildFrom(t, thetau);
139 }
140 
141 /*!
142 
143   Initialize a velocity twist transformation matrix from a rotation vector
144   with \f$\theta u \f$ parametrization.
145 
146   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3}\\
147   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
148 
149   \param thetau : \f$\theta u\f$ rotation vector used to initialize rotation
150   vector \f$R\f$ .
151 
152 */
vpVelocityTwistMatrix(const vpThetaUVector & thetau)153 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpThetaUVector &thetau) : vpArray2D<double>(6, 6)
154 {
155   buildFrom(thetau);
156 }
157 
158 /*!
159 
160   Initialize a velocity twist transformation matrix from a translation vector
161   \e t and a rotation matrix \e R.
162 
163   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
164   \\
165   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
166 
167   \param t : Translation vector.
168   \param R : Rotation matrix.
169 
170 */
vpVelocityTwistMatrix(const vpTranslationVector & t,const vpRotationMatrix & R)171 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpTranslationVector &t, const vpRotationMatrix &R)
172   : vpArray2D<double>(6, 6)
173 {
174   buildFrom(t, R);
175 }
176 
177 /*!
178 
179   Initialize a velocity twist transformation matrix from a rotation matrix \e
180   R.
181 
182   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3} \\
183   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
184 
185   \param R : Rotation matrix.
186 
187 */
vpVelocityTwistMatrix(const vpRotationMatrix & R)188 vpVelocityTwistMatrix::vpVelocityTwistMatrix(const vpRotationMatrix &R) : vpArray2D<double>(6, 6) { buildFrom(R); }
189 
190 /*!
191 
192   Initialize a velocity twist transformation matrix from a translation vector
193   \f${\bf t}=(t_x, t_y, t_z)^T\f$ and a rotation vector with \f$\theta {\bf
194   u}=(\theta u_x, \theta u_y, \theta u_z)^T \f$ parametrization.
195 
196   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
197   \\
198   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
199 
200   \param tx,ty,tz : Translation vector in meters.
201 
202   \param tux,tuy,tuz : \f$\theta {\bf u}\f$ rotation vector expressed in
203   radians used to initialize \f$R\f$.
204 */
vpVelocityTwistMatrix(double tx,double ty,double tz,double tux,double tuy,double tuz)205 vpVelocityTwistMatrix::vpVelocityTwistMatrix(double tx, double ty, double tz, double tux, double tuy, double tuz)
206   : vpArray2D<double>(6, 6)
207 {
208   vpTranslationVector t(tx, ty, tz);
209   vpThetaUVector tu(tux, tuy, tuz);
210   buildFrom(t, tu);
211 }
212 
213 /*!
214 
215   Operator that allows to multiply a velocity twist transformation matrix by
216   an other velocity twist transformation matrix.
217 
218 */
operator *(const vpVelocityTwistMatrix & V) const219 vpVelocityTwistMatrix vpVelocityTwistMatrix::operator*(const vpVelocityTwistMatrix &V) const
220 {
221   vpVelocityTwistMatrix p;
222 
223   for (unsigned int i = 0; i < 6; i++) {
224     for (unsigned int j = 0; j < 6; j++) {
225       double s = 0;
226       for (int k = 0; k < 6; k++)
227         s += rowPtrs[i][k] * V.rowPtrs[k][j];
228       p[i][j] = s;
229     }
230   }
231   return p;
232 }
233 
234 /*!
235   Operator that allows to multiply a velocity twist transformation matrix by a
236 matrix.
237 
238   As shown in the example below, this operator can be used to compute the
239 corresponding camera velocity skew from the joint velocities knowing the robot
240 jacobian.
241 
242   \code
243 #include <visp3/core/vpColVector.h>
244 #include <visp3/core/vpConfig.h>
245 #include <visp3/core/vpVelocityTwistMatrix.h>
246 #include <visp3/robot/vpSimulatorCamera.h>
247 
248 int main()
249 {
250   vpSimulatorCamera robot;
251 
252   vpColVector q_vel(6); // Joint velocity on the 6 joints
253   // ... q_vel need here to be initialized
254 
255   vpColVector c_v(6); // Velocity in the camera frame: vx,vy,vz,wx,wy,wz
256 
257   vpVelocityTwistMatrix cVe;  // Velocity skew transformation from camera frame to end-effector
258   robot.get_cVe(cVe);
259 
260   vpMatrix eJe;       // Robot jacobian
261   robot.get_eJe(eJe);
262 
263   // Compute the velocity in the camera frame
264   c_v = cVe * eJe * q_vel;
265 
266   return 0;
267 }
268   \endcode
269 
270   \exception vpException::dimensionError If M is not a 6 rows dimension
271 matrix.
272 */
operator *(const vpMatrix & M) const273 vpMatrix vpVelocityTwistMatrix::operator*(const vpMatrix &M) const
274 {
275   if (6 != M.getRows()) {
276     throw(vpException(vpException::dimensionError, "Cannot multiply a (6x6) velocity twist matrix by a (%dx%d) matrix",
277                       M.getRows(), M.getCols()));
278   }
279 
280   vpMatrix p(6, M.getCols());
281   for (unsigned int i = 0; i < 6; i++) {
282     for (unsigned int j = 0; j < M.getCols(); j++) {
283       double s = 0;
284       for (unsigned int k = 0; k < 6; k++)
285         s += rowPtrs[i][k] * M[k][j];
286       p[i][j] = s;
287     }
288   }
289   return p;
290 }
291 
292 /*!
293 
294   Operator that allows to multiply a twist transformation matrix by a
295   6-dimension column vector.
296 
297   \param v : Velocity skew vector.
298 
299   \exception vpException::dimensionError If v is not a 6 dimension column
300   vector.
301 
302 */
operator *(const vpColVector & v) const303 vpColVector vpVelocityTwistMatrix::operator*(const vpColVector &v) const
304 {
305   vpColVector c(6);
306 
307   if (6 != v.getRows()) {
308     throw(vpException(vpException::dimensionError,
309                       "Cannot multiply a (6x6) velocity twist matrix by a "
310                       "(%d) column vector",
311                       v.getRows()));
312   }
313 
314   c = 0.0;
315 
316   for (unsigned int i = 0; i < 6; i++) {
317     for (unsigned int j = 0; j < 6; j++) {
318       {
319         c[i] += rowPtrs[i][j] * v[j];
320       }
321     }
322   }
323 
324   return c;
325 }
326 
327 /*!
328 
329   Build a velocity twist transformation block diagonal matrix from a rotation
330   matrix R.
331 
332   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3} \\
333   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
334 
335   \param R : Rotation matrix.
336 
337 */
buildFrom(const vpRotationMatrix & R)338 vpVelocityTwistMatrix vpVelocityTwistMatrix::buildFrom(const vpRotationMatrix &R)
339 {
340   for (unsigned int i = 0; i < 3; i++) {
341     for (unsigned int j = 0; j < 3; j++) {
342       (*this)[i][j] = R[i][j];
343       (*this)[i + 3][j + 3] = R[i][j];
344       (*this)[i][j + 3] = 0;
345     }
346   }
347   return (*this);
348 }
349 
350 /*!
351 
352   Build a velocity twist transformation matrix from a translation vector
353   \e t and a rotation matrix \e R.
354 
355   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
356   \\
357   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
358 
359   \param t : Translation vector.
360 
361   \param R : Rotation matrix.
362 
363 */
buildFrom(const vpTranslationVector & t,const vpRotationMatrix & R)364 vpVelocityTwistMatrix vpVelocityTwistMatrix::buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
365 {
366   vpMatrix skewaR = t.skew(t) * R;
367 
368   for (unsigned int i = 0; i < 3; i++) {
369     for (unsigned int j = 0; j < 3; j++) {
370       (*this)[i][j] = R[i][j];
371       (*this)[i + 3][j + 3] = R[i][j];
372       (*this)[i][j + 3] = skewaR[i][j];
373     }
374   }
375 
376   return (*this);
377 }
378 
379 /*!
380 
381   Initialize a velocity twist transformation matrix from a translation vector
382   \e t and a rotation vector with \f$\theta u \f$ parametrization.
383 
384   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
385   \\
386   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
387 
388   \param t : Translation vector.
389 
390   \param thetau : \f$\theta {\bf u}\f$ rotation vector used to create rotation
391   matrix \f${\bf R}\f$.
392 
393 */
buildFrom(const vpTranslationVector & t,const vpThetaUVector & thetau)394 vpVelocityTwistMatrix vpVelocityTwistMatrix::buildFrom(const vpTranslationVector &t, const vpThetaUVector &thetau)
395 {
396   buildFrom(t, vpRotationMatrix(thetau));
397   return (*this);
398 }
399 
400 /*!
401 
402   Initialize a velocity twist transformation matrix from a rotation vector
403   with \f$\theta u \f$ parametrization.
404 
405   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3} \\
406   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
407 
408   \param thetau : \f$\theta {\bf u}\f$ rotation vector used to create rotation
409   matrix \f${\bf R}\f$.
410 
411 */
buildFrom(const vpThetaUVector & thetau)412 vpVelocityTwistMatrix vpVelocityTwistMatrix::buildFrom(const vpThetaUVector &thetau)
413 {
414   buildFrom(vpRotationMatrix(thetau));
415   return (*this);
416 }
417 
418 /*!
419 
420   Initialize a velocity twist transformation matrix from an homogeneous matrix
421   \f$M\f$ with \f[ {\bf M} = \left[\begin{array}{cc} {\bf R} & {\bf t}
422   \\ {\bf 0}_{1\times 3} & 1 \end{array} \right] \f]
423 
424   \param M : Homogeneous matrix \f$M\f$ used to initialize the velocity twist
425   transformation matrix.
426   \param full : Boolean used to indicate which matrix should be filled.
427   - When set to true, use the complete velocity skew transformation :
428   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & [{\bf t}]_\times \; {\bf R}
429   \\
430   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
431   - When set to false, use the block diagonal velocity skew transformation:
432   \f[ {\bf V} = \left[\begin{array}{cc} {\bf R} & {\bf 0}_{3\times 3} \\
433   {\bf 0}_{3\times 3} & {\bf R} \end{array} \right] \f]
434 
435 */
buildFrom(const vpHomogeneousMatrix & M,bool full)436 vpVelocityTwistMatrix vpVelocityTwistMatrix::buildFrom(const vpHomogeneousMatrix &M, bool full)
437 {
438   if (full)
439     buildFrom(M.getTranslationVector(), M.getRotationMatrix());
440   else
441     buildFrom(M.getRotationMatrix());
442 
443   return (*this);
444 }
445 
446 //! Invert the velocity twist matrix.
inverse() const447 vpVelocityTwistMatrix vpVelocityTwistMatrix::inverse() const
448 {
449   vpVelocityTwistMatrix Wi;
450   vpRotationMatrix R;
451   extract(R);
452   vpTranslationVector T;
453   extract(T);
454   vpTranslationVector RtT;
455   RtT = -(R.t() * T);
456 
457   Wi.buildFrom(RtT, R.t());
458 
459   return Wi;
460 }
461 
462 //! Invert the velocity twist matrix.
inverse(vpVelocityTwistMatrix & V) const463 void vpVelocityTwistMatrix::inverse(vpVelocityTwistMatrix &V) const { V = inverse(); }
464 
465 //! Extract the rotation matrix from the velocity twist matrix.
extract(vpRotationMatrix & R) const466 void vpVelocityTwistMatrix::extract(vpRotationMatrix &R) const
467 {
468   for (unsigned int i = 0; i < 3; i++)
469     for (unsigned int j = 0; j < 3; j++)
470       R[i][j] = (*this)[i][j];
471 }
472 
473 //! Extract the translation vector from the velocity twist matrix.
extract(vpTranslationVector & tv) const474 void vpVelocityTwistMatrix::extract(vpTranslationVector &tv) const
475 {
476   vpRotationMatrix R;
477   extract(R);
478   vpMatrix skTR(3, 3);
479   for (unsigned int i = 0; i < 3; i++)
480     for (unsigned int j = 0; j < 3; j++)
481       skTR[i][j] = (*this)[i][j + 3];
482 
483   vpMatrix skT = skTR * R.t();
484   tv[0] = skT[2][1];
485   tv[1] = skT[0][2];
486   tv[2] = skT[1][0];
487 }
488 
489 /*!
490 
491   Pretty print a velocity twist matrix. The data are tabulated.
492   The common widths before and after the decimal point
493   are set with respect to the parameter maxlen.
494 
495   \param s Stream used for the printing.
496 
497   \param length The suggested width of each matrix element.
498   The actual width grows in order to accomodate the whole integral part,
499   and shrinks if the whole extent is not needed for all the numbers.
500   \param intro The introduction which is printed before the matrix.
501   Can be set to zero (or omitted), in which case
502   the introduction is not printed.
503 
504   \return Returns the common total width for all matrix elements
505 
506   \sa std::ostream &operator<<(std::ostream &s, const vpArray2D<Type> &A)
507 */
print(std::ostream & s,unsigned int length,char const * intro) const508 int vpVelocityTwistMatrix::print(std::ostream &s, unsigned int length, char const *intro) const
509 {
510   typedef std::string::size_type size_type;
511 
512   unsigned int m = getRows();
513   unsigned int n = getCols();
514 
515   std::vector<std::string> values(m * n);
516   std::ostringstream oss;
517   std::ostringstream ossFixed;
518   std::ios_base::fmtflags original_flags = oss.flags();
519 
520   // ossFixed <<std::fixed;
521   ossFixed.setf(std::ios::fixed, std::ios::floatfield);
522 
523   size_type maxBefore = 0; // the length of the integral part
524   size_type maxAfter = 0;  // number of decimals plus
525   // one place for the decimal point
526   for (unsigned int i = 0; i < m; ++i) {
527     for (unsigned int j = 0; j < n; ++j) {
528       oss.str("");
529       oss << (*this)[i][j];
530       if (oss.str().find("e") != std::string::npos) {
531         ossFixed.str("");
532         ossFixed << (*this)[i][j];
533         oss.str(ossFixed.str());
534       }
535 
536       values[i * n + j] = oss.str();
537       size_type thislen = values[i * n + j].size();
538       size_type p = values[i * n + j].find('.');
539 
540       if (p == std::string::npos) {
541         maxBefore = vpMath::maximum(maxBefore, thislen);
542         // maxAfter remains the same
543       } else {
544         maxBefore = vpMath::maximum(maxBefore, p);
545         maxAfter = vpMath::maximum(maxAfter, thislen - p - 1);
546       }
547     }
548   }
549 
550   size_type totalLength = length;
551   // increase totalLength according to maxBefore
552   totalLength = vpMath::maximum(totalLength, maxBefore);
553   // decrease maxAfter according to totalLength
554   maxAfter = (std::min)(maxAfter, totalLength - maxBefore);
555   if (maxAfter == 1)
556     maxAfter = 0;
557 
558   // the following line is useful for debugging
559   // std::cerr <<totalLength <<" " <<maxBefore <<" " <<maxAfter <<"\n";
560 
561   if (intro)
562     s << intro;
563   s << "[" << m << "," << n << "]=\n";
564 
565   for (unsigned int i = 0; i < m; i++) {
566     s << "  ";
567     for (unsigned int j = 0; j < n; j++) {
568       size_type p = values[i * n + j].find('.');
569       s.setf(std::ios::right, std::ios::adjustfield);
570       s.width((std::streamsize)maxBefore);
571       s << values[i * n + j].substr(0, p).c_str();
572 
573       if (maxAfter > 0) {
574         s.setf(std::ios::left, std::ios::adjustfield);
575         if (p != std::string::npos) {
576           s.width((std::streamsize)maxAfter);
577           s << values[i * n + j].substr(p, maxAfter).c_str();
578         } else {
579           assert(maxAfter > 1);
580           s.width((std::streamsize)maxAfter);
581           s << ".0";
582         }
583       }
584 
585       s << ' ';
586     }
587     s << std::endl;
588   }
589 
590   s.flags(original_flags); // restore s to standard state
591 
592   return (int)(maxBefore + maxAfter);
593 }
594 
595 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
596 
597 /*!
598   \deprecated You should rather use eye().
599 
600   Set the velocity twist transformation matrix to identity.
601 
602 */
setIdentity()603 void vpVelocityTwistMatrix::setIdentity() { eye(); }
604 
605 #endif // #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
606