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