GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/sot/core/feature-pose.hxx Lines: 130 158 82.3 %
Date: 2023-03-13 12:09:37 Branches: 224 488 45.9 %

Line Branch Exec Source
1
/*
2
 * Copyright 2019
3
 * Joseph Mirabel
4
 *
5
 * LAAS-CNRS
6
 *
7
 */
8
9
/* --------------------------------------------------------------------- */
10
/* --- INCLUDE --------------------------------------------------------- */
11
/* --------------------------------------------------------------------- */
12
13
/* --- SOT --- */
14
#include <dynamic-graph/command-bind.h>
15
#include <dynamic-graph/command-getter.h>
16
#include <dynamic-graph/command-setter.h>
17
#include <dynamic-graph/command.h>
18
19
#include <Eigen/LU>
20
#include <boost/mpl/if.hpp>
21
#include <boost/type_traits/is_same.hpp>
22
#include <pinocchio/multibody/liegroup/liegroup.hpp>
23
#include <sot/core/debug.hh>
24
#include <sot/core/factory.hh>
25
#include <sot/core/feature-pose.hh>
26
27
namespace dynamicgraph {
28
namespace sot {
29
30
typedef pinocchio::CartesianProductOperation<
31
    pinocchio::VectorSpaceOperationTpl<3, double>,
32
    pinocchio::SpecialOrthogonalOperationTpl<3, double> >
33
    R3xSO3_t;
34
typedef pinocchio::SpecialEuclideanOperationTpl<3, double> SE3_t;
35
36
namespace internal {
37
template <Representation_t representation>
38
struct LG_t {
39
  typedef typename boost::mpl::if_c<representation == SE3Representation, SE3_t,
40
                                    R3xSO3_t>::type type;
41
};
42
}  // namespace internal
43
44
/* --------------------------------------------------------------------- */
45
/* --- CLASS ----------------------------------------------------------- */
46
/* --------------------------------------------------------------------- */
47
48
static const MatrixHomogeneous Id(MatrixHomogeneous::Identity());
49
50
template <Representation_t representation>
51
8
FeaturePose<representation>::FeaturePose(const std::string &pointName)
52
    : FeatureAbstract(pointName),
53
8
      oMja(NULL, CLASS_NAME + "(" + name + ")::input(matrixHomo)::oMja"),
54
8
      jaMfa(NULL, CLASS_NAME + "(" + name + ")::input(matrixHomo)::jaMfa"),
55
8
      oMjb(NULL, CLASS_NAME + "(" + name + ")::input(matrixHomo)::oMjb"),
56
8
      jbMfb(NULL, CLASS_NAME + "(" + name + ")::input(matrixHomo)::jbMfb"),
57
8
      jaJja(NULL, CLASS_NAME + "(" + name + ")::input(matrix)::jaJja"),
58
8
      jbJjb(NULL, CLASS_NAME + "(" + name + ")::input(matrix)::jbJjb"),
59
      faMfbDes(NULL,
60
8
               CLASS_NAME + "(" + name + ")::input(matrixHomo)::faMfbDes"),
61
      faNufafbDes(NULL,
62
8
                  CLASS_NAME + "(" + name + ")::input(vector)::faNufafbDes"),
63
      faMfb(
64
          boost::bind(&FeaturePose<representation>::computefaMfb, this, _1, _2),
65

8
          oMja << jaMfa << oMjb << jbMfb,
66
8
          CLASS_NAME + "(" + name + ")::output(matrixHomo)::faMfb"),
67
      q_faMfb(boost::bind(&FeaturePose<representation>::computeQfaMfb, this, _1,
68
                          _2),
69
8
              faMfb, CLASS_NAME + "(" + name + ")::output(vector7)::q_faMfb"),
70
      q_faMfbDes(boost::bind(&FeaturePose<representation>::computeQfaMfbDes,
71
                             this, _1, _2),
72
                 faMfbDes,
73


























16
                 CLASS_NAME + "(" + name + ")::output(vector7)::q_faMfbDes") {
74
8
  oMja.setConstant(Id);
75
8
  jaMfa.setConstant(Id);
76
8
  jbMfb.setConstant(Id);
77
8
  faMfbDes.setConstant(Id);
78

8
  faNufafbDes.setConstant(Vector::Zero(6));
79
80


8
  jacobianSOUT.addDependencies(q_faMfbDes << q_faMfb << jaJja << jbJjb);
81
82

8
  errorSOUT.addDependencies(q_faMfbDes << q_faMfb);
83
84



8
  signalRegistration(oMja << jaMfa << oMjb << jbMfb << jaJja << jbJjb);
85


8
  signalRegistration(faMfb << errordotSOUT << faMfbDes << faNufafbDes);
86
87

8
  errordotSOUT.setFunction(
88
      boost::bind(&FeaturePose<representation>::computeErrorDot, this, _1, _2));
89

8
  errordotSOUT.addDependencies(q_faMfbDes << q_faMfb << faNufafbDes);
90
91
  // Commands
92
  //
93
  {
94
    using namespace dynamicgraph::command;
95

8
    addCommand("keep",
96


16
               makeCommandVoid1(
97
                   *this, &FeaturePose<representation>::servoCurrentPosition,
98
                   docCommandVoid1(
99
                       "modify the desired position to servo at current pos.",
100
                       "time")));
101
  }
102
8
}
103
104
template <Representation_t representation>
105
8
FeaturePose<representation>::~FeaturePose() {}
106
107
/* --------------------------------------------------------------------- */
108
/* --------------------------------------------------------------------- */
109
/* --------------------------------------------------------------------- */
110
111
template <Representation_t representation>
112
3936
static inline void check(const FeaturePose<representation> &ft) {
113
  (void)ft;
114
3936
  assert(ft.oMja.isPlugged());
115
3936
  assert(ft.jaMfa.isPlugged());
116
3936
  assert(ft.oMjb.isPlugged());
117
3936
  assert(ft.jbMfb.isPlugged());
118
3936
  assert(ft.faMfbDes.isPlugged());
119
3936
  assert(ft.faNufafbDes.isPlugged());
120
3936
}
121
122
template <Representation_t representation>
123
8
unsigned int &FeaturePose<representation>::getDimension(unsigned int &dim,
124
                                                        int time) {
125
  sotDEBUG(25) << "# In {" << std::endl;
126
127
8
  const Flags &fl = selectionSIN.access(time);
128
129
8
  dim = 0;
130
56
  for (int i = 0; i < 6; ++i)
131

48
    if (fl(i)) dim++;
132
133
  sotDEBUG(25) << "# Out }" << std::endl;
134
8
  return dim;
135
}
136
137
640
void toVector(const MatrixHomogeneous &M, Vector7 &v) {
138

640
  v.head<3>() = M.translation();
139

640
  QuaternionMap(v.tail<4>().data()) = M.linear();
140
640
}
141
142
Vector7 toVector(const MatrixHomogeneous &M) {
143
  Vector7 ret;
144
  toVector(M, ret);
145
  return ret;
146
}
147
148
template <Representation_t representation>
149
64
Matrix &FeaturePose<representation>::computeJacobian(Matrix &J, int time) {
150
  typedef typename internal::LG_t<representation>::type LieGroup_t;
151
152
64
  check(*this);
153
154
64
  q_faMfb.recompute(time);
155
64
  q_faMfbDes.recompute(time);
156
157
64
  const unsigned int &dim = dimensionSOUT(time);
158
64
  const Flags &fl = selectionSIN(time);
159
160
64
  const Matrix &_jbJjb = jbJjb(time);
161
162
64
  const MatrixHomogeneous &_jbMfb =
163
128
      (jbMfb.isPlugged() ? jbMfb.accessCopy() : Id);
164
165
64
  const Matrix::Index cJ = _jbJjb.cols();
166
64
  J.resize(dim, cJ);
167
168
64
  MatrixTwist X;
169
64
  Eigen::Matrix<double, 6, 6, Eigen::RowMajor> Jminus;
170
171

64
  buildFrom(_jbMfb.inverse(Eigen::Affine), X);
172


128
  MatrixRotation faRfb = jaMfa.access(time).rotation().transpose() *
173


128
                         oMja.access(time).rotation().transpose() *
174


160
                         oMjb.access(time).rotation() * _jbMfb.rotation();
175
  if (boost::is_same<LieGroup_t, R3xSO3_t>::value)
176

32
    X.topRows<3>().applyOnTheLeft(faRfb);
177

128
  LieGroup_t().template dDifference<pinocchio::ARG1>(
178
64
      q_faMfbDes.accessCopy(), q_faMfb.accessCopy(), Jminus);
179
180
  // Contribution of b:
181
  // J = Jminus * X * jbJjb;
182
64
  unsigned int rJ = 0;
183
448
  for (unsigned int r = 0; r < 6; ++r)
184



384
    if (fl((int)r)) J.row(rJ++) = (Jminus * X).row(r) * _jbJjb;
185
186
64
  if (jaJja.isPlugged()) {
187
32
    const Matrix &_jaJja = jaJja(time);
188
32
    const MatrixHomogeneous &_jaMfa =
189
64
                                (jaMfa.isPlugged() ? jaMfa.accessCopy() : Id),
190
32
                            _faMfb = faMfb.accessCopy();
191
192

32
    buildFrom((_jaMfa * _faMfb).inverse(Eigen::Affine), X);
193
    if (boost::is_same<LieGroup_t, R3xSO3_t>::value)
194

16
      X.topRows<3>().applyOnTheLeft(faRfb);
195
196
    // J -= (Jminus * X) * jaJja(time);
197
32
    rJ = 0;
198
224
    for (unsigned int r = 0; r < 6; ++r)
199




192
      if (fl((int)r)) J.row(rJ++).noalias() -= (Jminus * X).row(r) * _jaJja;
200
  }
201
202
64
  return J;
203
}
204
205
template <Representation_t representation>
206
1184
MatrixHomogeneous &FeaturePose<representation>::computefaMfb(
207
    MatrixHomogeneous &res, int time) {
208
1184
  check(*this);
209
210


1184
  res = (oMja(time) * jaMfa(time)).inverse(Eigen::Affine) * oMjb(time) *
211
        jbMfb(time);
212
1184
  return res;
213
}
214
215
template <Representation_t representation>
216
1184
Vector7 &FeaturePose<representation>::computeQfaMfb(Vector7 &res, int time) {
217
1184
  check(*this);
218
219
1184
  toVector(faMfb(time), res);
220
1184
  return res;
221
}
222
223
template <Representation_t representation>
224
96
Vector7 &FeaturePose<representation>::computeQfaMfbDes(Vector7 &res, int time) {
225
96
  check(*this);
226
227
96
  toVector(faMfbDes(time), res);
228
96
  return res;
229
}
230
231
template <Representation_t representation>
232
1184
Vector &FeaturePose<representation>::computeError(Vector &error, int time) {
233
  typedef typename internal::LG_t<representation>::type LieGroup_t;
234
1184
  check(*this);
235
236
1184
  const Flags &fl = selectionSIN(time);
237
238
1184
  Eigen::Matrix<double, 6, 1> v;
239


1184
  LieGroup_t().difference(q_faMfbDes(time), q_faMfb(time), v);
240
241

1184
  error.resize(dimensionSOUT(time));
242
1184
  unsigned int cursor = 0;
243
8288
  for (unsigned int i = 0; i < 6; ++i)
244


7104
    if (fl((int)i)) error(cursor++) = v(i);
245
246
1184
  return error;
247
}
248
249
// This function is responsible of converting the input velocity expressed with
250
// SE(3) convention onto a velocity expressed with the convention of this
251
// feature (R^3xSO(3) or SE(3)), in the right frame.
252
template <>
253
56
Vector6d convertVelocity<SE3_t>(const MatrixHomogeneous &M,
254
                                const MatrixHomogeneous &Mdes,
255
                                const Vector &faNufafbDes) {
256
  (void)M;
257
56
  MatrixTwist X;
258

56
  buildFrom(Mdes.inverse(Eigen::Affine), X);
259

112
  return X * faNufafbDes;
260
}
261
template <>
262
56
Vector6d convertVelocity<R3xSO3_t>(const MatrixHomogeneous &M,
263
                                   const MatrixHomogeneous &Mdes,
264
                                   const Vector &faNufafbDes) {
265
56
  Vector6d nu;
266
56
  nu.head<3>() =
267


112
      faNufafbDes.head<3>() - M.translation().cross(faNufafbDes.tail<3>());
268


56
  nu.tail<3>() = Mdes.rotation().transpose() * faNufafbDes.tail<3>();
269
56
  return nu;
270
}
271
272
template <Representation_t representation>
273
224
Vector &FeaturePose<representation>::computeErrorDot(Vector &errordot,
274
                                                     int time) {
275
  typedef typename internal::LG_t<representation>::type LieGroup_t;
276
224
  check(*this);
277
278

224
  errordot.resize(dimensionSOUT(time));
279
224
  const Flags &fl = selectionSIN(time);
280
224
  if (!faNufafbDes.isPlugged()) {
281
    errordot.setZero();
282
    return errordot;
283
  }
284
285
224
  q_faMfb.recompute(time);
286
224
  q_faMfbDes.recompute(time);
287
224
  faNufafbDes.recompute(time);
288
289
224
  const MatrixHomogeneous &_faMfbDes = faMfbDes(time);
290
291
224
  Eigen::Matrix<double, 6, 6, Eigen::RowMajor> Jminus;
292
293

448
  LieGroup_t().template dDifference<pinocchio::ARG0>(
294
224
      q_faMfbDes.accessCopy(), q_faMfb.accessCopy(), Jminus);
295
224
  Vector6d nu = convertVelocity<LieGroup_t>(faMfb(time), _faMfbDes,
296

224
                                            faNufafbDes.accessCopy());
297
224
  unsigned int cursor = 0;
298
1568
  for (unsigned int i = 0; i < 6; ++i)
299



1344
    if (fl((int)i)) errordot(cursor++) = Jminus.row(i) * nu;
300
301
224
  return errordot;
302
}
303
304
/* Modify the value of the reference (sdes) so that it corresponds
305
 * to the current position. The effect on the servo is to maintain the
306
 * current position and correct any drift. */
307
template <Representation_t representation>
308
void FeaturePose<representation>::servoCurrentPosition(const int &time) {
309
  check(*this);
310
311
  const MatrixHomogeneous &_oMja = (oMja.isPlugged() ? oMja.access(time) : Id),
312
                          _jaMfa =
313
                              (jaMfa.isPlugged() ? jaMfa.access(time) : Id),
314
                          _oMjb = oMjb.access(time),
315
                          _jbMfb =
316
                              (jbMfb.isPlugged() ? jbMfb.access(time) : Id);
317
  faMfbDes = (_oMja * _jaMfa).inverse(Eigen::Affine) * _oMjb * _jbMfb;
318
}
319
320
static const char *featureNames[] = {"X ", "Y ", "Z ", "RX", "RY", "RZ"};
321
template <Representation_t representation>
322
void FeaturePose<representation>::display(std::ostream &os) const {
323
  os << CLASS_NAME << "<" << name << ">: (";
324
325
  try {
326
    const Flags &fl = selectionSIN.accessCopy();
327
    bool first = true;
328
    for (int i = 0; i < 6; ++i)
329
      if (fl(i)) {
330
        if (first) {
331
          first = false;
332
        } else {
333
          os << ",";
334
        }
335
        os << featureNames[i];
336
      }
337
    os << ") ";
338
  } catch (ExceptionAbstract e) {
339
    os << " selectSIN not set.";
340
  }
341
}
342
343
}  // namespace sot
344
}  // namespace dynamicgraph