GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/planner/rbprm-node.cc Lines: 139 173 80.3 %
Date: 2024-02-02 12:21:48 Branches: 228 562 40.6 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2017 CNRS
3
// Authors: Fernbach Pierre
4
//
5
// This file is part of hpp-core
6
// hpp-core is free software: you can redistribute it
7
// and/or modify it under the terms of the GNU Lesser General Public
8
// License as published by the Free Software Foundation, either version
9
// 3 of the License, or (at your option) any later version.
10
//
11
// hpp-core is distributed in the hope that it will be
12
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
// General Lesser Public License for more details.  You should have
15
// received a copy of the GNU Lesser General Public License along with
16
// hpp-core  If not, see
17
// <http://www.gnu.org/licenses/>.
18
19
#include <hpp/fcl/collision_data.h>
20
21
#include <hpp/core/collision-validation-report.hh>
22
#include <hpp/pinocchio/configuration.hh>
23
#include <hpp/rbprm/planner/rbprm-node.hh>
24
#include <hpp/rbprm/rbprm-device.hh>
25
#include <hpp/util/debug.hh>
26
#include <hpp/util/timer.hh>
27
28
#include "hpp/rbprm/utils/algorithms.h"
29
namespace hpp {
30
namespace core {
31
32
typedef centroidal_dynamics::MatrixXX MatrixXX;
33
typedef centroidal_dynamics::Matrix6X Matrix6X;
34
typedef centroidal_dynamics::Vector3 Vector3;
35
typedef centroidal_dynamics::Matrix3 Matrix3;
36
typedef centroidal_dynamics::Matrix63 Matrix63;
37
typedef centroidal_dynamics::Vector6 Vector6;
38
typedef centroidal_dynamics::VectorX VectorX;
39
40
43378
Eigen::Quaterniond RbprmNode::getQuaternion() {
41
86756
  ConfigurationPtr_t q = configuration();
42


43378
  Eigen::Quaterniond quat((*q)[6], (*q)[3], (*q)[4], (*q)[5]);
43
86756
  return quat;
44
}
45
46
43580
bool computeIntersectionSurface(
47
    const core::CollisionValidationReportPtr_t report, geom::T_Point& inter,
48
    geom::Point& pn, pinocchio::DeviceData& deviceData) {
49
87160
  core::CollisionObjectConstPtr_t obj_rom = report->object1;
50
87160
  core::CollisionObjectConstPtr_t obj_env = report->object2;
51
  // hppDout(notice,"~~ compute intersection between : "<<obj_rom->name() << "
52
  // and "<<obj_env->name()); convert the two objects  :
53
87160
  geom::BVHModelOBConst_Ptr_t model_rom = geom::GetModel(obj_rom, deviceData);
54
87160
  geom::BVHModelOBConst_Ptr_t model_env = geom::GetModel(obj_env, deviceData);
55
56
  hppStartBenchmark(COMPUTE_INTERSECTION);
57

130740
  geom::T_Point plane = geom::intersectPolygonePlane(model_rom, model_env, pn);
58
  // plane contains a list of points : the intersections between model_rom and
59
  // the infinite plane defined by model_env. but they may not be contained
60
  // inside the shape defined by model_env
61
  hppStopBenchmark(COMPUTE_INTERSECTION);
62
  hppDisplayBenchmark(COMPUTE_INTERSECTION);
63
43580
  if (plane.size() > 0)
64

87160
    inter = geom::compute3DIntersection(
65
        plane,
66
87160
        geom::convertBVH(
67
43580
            model_env));  // hull contain only points inside the model_env shape
68
  else
69
    return false;
70
43580
  if (inter.size() == 0)
71
    return false;
72
  else
73
43580
    return true;
74
}
75
76
bool centerOfRomIntersection(const core::CollisionValidationReportPtr_t report,
77
                             geom::Point& pn, geom::Point& center,
78
                             pinocchio::DeviceData& deviceData) {
79
  geom::T_Point hull;
80
  bool success = computeIntersectionSurface(report, hull, pn, deviceData);
81
  if (!success) return false;
82
  // compute center point of the hull
83
  center = geom::center(hull.begin(), hull.end());
84
85
  hppDout(notice, "Center : " << center.transpose());
86
  hppDout(notice, "Normal : " << pn.transpose());
87
  return true;
88
}
89
90
/**
91
 * @brief approximateContactPoint Compute the approximation of the contact
92
 * Point. Current implementation : closest point of the reference config inside
93
 * the contact surface.
94
 * @param report the collision report
95
 * @param pn output the normal of the contact
96
 * @param result output the contact point
97
 * @param config configuration of the robot (only the root's configuration is
98
 * used here)
99
 * @param device
100
 * @return bool success
101
 */
102
43378
bool approximateContactPoint(const std::string romName,
103
                             const core::CollisionValidationReportPtr_t report,
104
                             geom::Point& pn, geom::Point& result,
105
                             core::ConfigurationPtr_t config,
106
                             pinocchio::RbPrmDevicePtr_t device) {
107
86756
  geom::T_Point hull;
108
86756
  pinocchio::DeviceSync deviceSync(device);
109
  hppDout(notice, "Approximate contact point for rom " << romName);
110

43378
  bool success = computeIntersectionSurface(report, hull, pn, deviceSync.d());
111
  // hppDout(notice,"Number of points in the intersection : "<<hull.size());
112
43378
  if (success) {
113

43378
    fcl::Vec3f reference = device->getEffectorReference(romName);
114

43378
    if (reference.norm() != 0) {
115
      // hppDout(notice,"Reference position for rom"<<romName<<" =
116
      // "<<reference.transpose());
117
43378
      fcl::Transform3f tRoot;
118
43378
      tRoot.setTranslation(
119


43378
          fcl::Vec3f((*config)[0], (*config)[1], (*config)[2]));
120

43378
      fcl::Quaternion3f quat((*config)[6], (*config)[3], (*config)[4],
121

86756
                             (*config)[5]);
122

43378
      tRoot.setRotation(quat.matrix());
123

43378
      reference = (tRoot * reference).getTranslation();
124
43378
      geom::Point refPoint(reference);
125
      // hppDout(notice,"Reference after root transform =
126
      // "<<refPoint.transpose());
127



43378
      geom::projectPointInsidePlan(hull, refPoint, pn, hull.front(), result);
128
      hppDout(notice,
129
              "Approximate contact point found : " << result.transpose());
130
43378
      return true;
131
    } else {
132
      hppDout(notice,
133
              "No reference end effector position defined, use center of "
134
              "intersection as approximation");
135
      result = geom::center(hull.begin(), hull.end());
136
      return true;
137
    }
138
  } else {
139
    hppDout(notice, "Error in the approximation of the ocntact point");
140
    return false;
141
  }
142
}
143
144
43378
void computeNodeMatrixForOnePoint(
145
    const geom::Point pn, const geom::Point center, const double sizeFootX,
146
    const double sizeFootY, const bool rectangularContact, const double mu,
147
    const Eigen::Quaterniond quat, size_t& indexRom, MatrixXX& V,
148
    Matrix6X& IP_hat) {
149

43378
  Vector3 ti1, ti2;
150
  // hppDout(notice,"normal for this contact : "<<getNormal());
151
  hppDout(notice, "mu used in computeNodeMatrix : " << mu);
152
  // compute tangent vector :
153
  // tProj is the the direction of the head of the robot projected in plan (x,y)
154

43378
  Vector3 tProj = quat * Vector3(1, 0, 0);
155
43378
  tProj[2] = 0;
156
43378
  tProj.normalize();
157
43378
  ti1 = pn.cross(tProj);
158


43378
  if (ti1.dot(ti1) < 0.001) ti1 = pn.cross(Vector3(1, 0, 0));
159


43378
  if (ti1.dot(ti1) < 0.001) ti1 = pn.cross(Vector3(0, 1, 0));
160
43378
  ti2 = pn.cross(ti1);
161
162
  // hppDout(info,"t"<<indexRom<<"1 : "<<ti1.transpose());
163
  // hppDout(info,"t"<<indexRom<<"2 : "<<ti2.transpose());
164
165
  // fill V with generating ray ([ n_i + \mu t_{i1} & n_i - \mu t_{i1} & n_i +
166
  // \mu t_{i2} & n_i - \mu t_{i2}]
167

86756
  MatrixXX Vi = MatrixXX::Zero(3, 4);
168


43378
  Vi.col(0) = (pn + mu * ti1);
169


43378
  Vi.col(1) = (pn - mu * ti1);
170


43378
  Vi.col(2) = (pn + mu * ti2);
171


43378
  Vi.col(3) = (pn - mu * ti2);
172

216890
  for (size_t i = 0; i < 4; i++) Vi.col(i).normalize();
173
174
43378
  if (rectangularContact) {
175
43378
    Vector3 pContact;
176

43378
    Vector3 shiftX, shiftY;
177

43378
    shiftX = sizeFootX * ti2;
178

43378
    shiftY = sizeFootY * ti1;
179
180
    // hppDout(notice,"shift x = "<<shiftX.transpose());
181
    // hppDout(notice,"shift y = "<<shiftY.transpose());
182
183
    hppDout(notice, "Center of rom collision :  ["
184
                        << center[0] << " , " << center[1] << " , " << center[2]
185
                        << "]");
186
216890
    for (size_t i = 0; i < 4; ++i) {
187
      // make a rectangle around center :
188
173512
      pContact = center;
189
173512
      if (i < 2)
190
86756
        pContact += shiftX;
191
      else
192
86756
        pContact -= shiftX;
193
173512
      if (i % 2 == 0)
194
86756
        pContact += shiftY;
195
      else
196
86756
        pContact -= shiftY;
197
198
      // fill IP_hat with position : [I_3  pi_hat] ^T
199

173512
      IP_hat.block<3, 3>(0, 3 * (indexRom + i)) = MatrixXX::Identity(3, 3);
200
173512
      IP_hat.block<3, 3>(3, 3 * (indexRom + i)) =
201

347024
          centroidal_dynamics::crossMatrix(pContact);
202
203
      hppDout(notice, "position of rom collision :  [" << pContact[0] << " , "
204
                                                       << pContact[1] << " , "
205
                                                       << pContact[2] << "]");
206
      // ssContacts<<"["<<pContact[0]<<" , "<<pContact[1]<<" ,
207
      // "<<pContact[2]<<"],"; hppDout(info,"p"<<(indexRom+i)<<"^T =
208
      // "<<pContact.transpose()); hppDout(info,"IP_hat at iter "<<indexRom<< "
209
      // = \n"<<IP_hat);
210
211
      // hppDout(notice,"V"<<indexRom<<" = \n"<<Vi);
212

173512
      V.block<3, 4>(3 * (indexRom + i), 4 * (indexRom + i)) = Vi;
213
      // hppDout(info,"V at iter "<<indexRom<<" : \n"<<V);
214
    }
215
43378
    indexRom += 4;
216
  } else {
217
    // fill IP_hat with position : [I_3  pi_hat] ^T
218
    IP_hat.block<3, 3>(0, 3 * indexRom) = MatrixXX::Identity(3, 3);
219
    IP_hat.block<3, 3>(3, 3 * indexRom) =
220
        centroidal_dynamics::crossMatrix(center);
221
222
    // hppDout(notice,"Center of rom collision :  ["<<center[0]<<" ,
223
    // "<<center[1]<<" , "<<center[2]<<"]");
224
    hppDout(info, "p" << indexRom << "^T = " << center.transpose());
225
    // hppDout(info,"IP_hat at iter "<<indexRom<< " = \n"<<IP_hat);
226
227
    // hppDout(notice,"V"<<indexRom<<" = \n"<<Vi);
228
    V.block<3, 4>(3 * indexRom, 4 * indexRom) = Vi;
229
    // hppDout(info,"V at iter "<<indexRom<<" : \n"<<V);
230
    indexRom++;
231
  }
232
43378
}
233
234
13520
void RbprmNode::fillNodeMatrices(ValidationReportPtr_t report,
235
                                 bool rectangularContact, double sizeFootX,
236
                                 double sizeFootY, double m, double mu,
237
                                 pinocchio::RbPrmDevicePtr_t device) {
238
13520
  assert(device && "Error in dynamic cast of problem device to rbprmDevice");
239
  hppStartBenchmark(FILL_NODE_MATRICE);
240
241
  core::RbprmValidationReportPtr_t rbReport =
242
13520
      dynamic_pointer_cast<core::RbprmValidationReport>(report);
243
  // checks : (use assert ? )
244
13520
  if (!rbReport) {
245
    hppDout(error, "~~ Validation Report cannot be cast");
246
    return;
247
  }
248
13520
  collisionReport(rbReport);
249
250
13520
  if (rbReport->trunkInCollision) {
251
    hppDout(error,
252
            "~~ ComputeGIWC : trunk is in collision");  // shouldn't happen
253
  }
254
13520
  if (!rbReport->romsValid) {
255
    hppDout(error,
256
            "~~ ComputeGIWC : roms filter not respected");  // shouldn't happen
257
  }
258
259
  hppDout(notice, "Robot mass used to compute matrices : " << m);
260
13520
  assert(m > 0. && " Robot mass during computation of dynamic matrices is 0.");
261
  // FIX ME : position of contact is in center of the collision surface
262
  size_type numContactpoints =
263
13520
      (rbReport->ROMReports.size() +
264
13520
       3 * rectangularContact * rbReport->ROMReports.size());
265
13520
  setNumberOfContacts(numContactpoints);
266
  hppDout(notice, "number of contact points = " << numContactpoints);
267

27040
  MatrixXX V = MatrixXX::Zero(3 * numContactpoints, 4 * numContactpoints);
268

27040
  Matrix6X IP_hat = Matrix6X::Zero(6, 3 * numContactpoints);
269
  // get the 2 object in contact for each ROM :
270
  hppDout(info,
271
          "~~ Number of roms in collision : " << rbReport->ROMReports.size());
272
13520
  size_t indexRom = 0;
273
13520
  std::ostringstream ssContact;
274
13520
  ssContact << "[";
275
  bool pointExist;
276
56898
  for (auto& it : rbReport->ROMReports) {
277
    hppDout(info, "~~ for rom : " << it.first);
278

43378
    geom::Point pn, contactPoint;
279

86756
    pointExist = approximateContactPoint(it.first, it.second, pn, contactPoint,
280
86756
                                         configuration(), device);
281



43378
    ssContact << "[" << contactPoint[0] << " , " << contactPoint[1] << " , "
282

43378
              << contactPoint[2] << "],";
283
284
43378
    if (!pointExist) {
285
      hppDout(error,
286
              "Unable to compute the approximation of the contact point");
287
      // save infos needed for LP problem in node structure
288
      // FIXME : Or retry with another obstacle ???
289
      setV(V);
290
      setIPHat(IP_hat);
291
292
      // compute other LP values : (constant for each nodes)
293
      setG(IP_hat * V);
294
      Vector3 c(3);
295
      c << (*configuration())[0], (*configuration())[1], (*configuration())[2];
296
      Matrix63 H = Matrix63::Zero(6, 3);
297
      H.block<3, 3>(0, 0) = Matrix3::Identity(3, 3);
298
      H.block<3, 3>(3, 0) = centroidal_dynamics::crossMatrix(c);
299
      setH(m * H);
300
      Vector6 h = Vector6::Zero(6);
301
      Vector3 g;
302
      g << 0, 0,
303
          -9.81;  // FIXME : retrieve it from somewhere ? instead of hardcoded
304
      h.head(3) = -g;
305
      h.tail(3) = c.cross(-g);
306
      seth(m * h);
307
    }
308
309

43378
    computeNodeMatrixForOnePoint(pn, contactPoint, sizeFootX, sizeFootY,
310
86756
                                 rectangularContact, mu, getQuaternion(),
311
                                 indexRom, V, IP_hat);
312
313
  }  // for each ROMS
314
315
  // save infos needed for LP problem in node structure
316

13520
  setV(V);
317

13520
  setIPHat(IP_hat);
318
319
  // compute other LP values : (constant for each nodes)
320

13520
  setG(IP_hat * V);
321
13520
  Vector3 c(3);
322




13520
  c << (*configuration())[0], (*configuration())[1], (*configuration())[2];
323

13520
  Matrix63 H = Matrix63::Zero(6, 3);
324

13520
  H.block<3, 3>(0, 0) = Matrix3::Identity(3, 3);
325


13520
  H.block<3, 3>(3, 0) = centroidal_dynamics::crossMatrix(c);
326

13520
  setH(m * H);
327

13520
  Vector6 h = Vector6::Zero(6);
328
13520
  Vector3 g;
329

13520
  g << 0, 0,
330
13520
      -9.81;  // FIXME : retrieve it from somewhere ? instead of hardcoded
331

13520
  h.head(3) = -g;
332


13520
  h.tail(3) = c.cross(-g);
333

13520
  seth(m * h);
334
335
  // debug output :
336
  /*hppDout(info,"G = \n"<<getG());
337
    hppDout(info,"c^T = "<<c.transpose());
338
    hppDout(info,"m = "<<m);
339
    hppDout(info,"h^T = "<<geth().transpose());
340
    hppDout(info,"H = \n"<<getH());
341
*/
342
  hppDout(notice, "list of all centers = " << ssContact.str() << "]");
343
344
  hppStopBenchmark(FILL_NODE_MATRICE);
345
  hppDisplayBenchmark(FILL_NODE_MATRICE);
346
}
347
348
548
void RbprmNode::chooseBestContactSurface(ValidationReportPtr_t report,
349
                                         pinocchio::RbPrmDevicePtr_t device) {
350
548
  assert(device && "Error in dynamic cast of problem device to rbprmDevice");
351
  core::RbprmValidationReportPtr_t rbReport =
352
548
      dynamic_pointer_cast<core::RbprmValidationReport>(report);
353

2652
  for (auto it : rbReport->ROMReports) {
354
    core::AllCollisionsValidationReportPtr_t romReports =
355
2104
        dynamic_pointer_cast<core::AllCollisionsValidationReport>(it.second);
356
2104
    if (!romReports) {
357
      hppDout(
358
          warning,
359
          "For rom : "
360
              << it.first
361
              << " unable to cast in a AllCollisionsValidationReport, did you "
362
                 "correctly call "
363
                 "computeAllContacts(true) before generating the report ? ");
364
      return;
365
    }
366
2104
    if (romReports->collisionReports.size() > 1) {
367
      // for each rom , for each different environnement surface in collision
368
      // with the rom: 1) compute the projection of the reference position
369
      // inside the intersection of the rom and the environnement surface 2)
370
      // find the surface with the minimal distance between the reference and
371
      // the projection 3) modify the report such that this surface is at the
372
      // top of the list
373
374

101
      fcl::Vec3f reference = device->getEffectorReference(it.first);
375
      hppDout(notice,
376
              "Reference position for rom" << it.first << " = " << reference);
377
202
      core::ConfigurationPtr_t q = configuration();
378
101
      fcl::Transform3f tRoot;
379


101
      tRoot.setTranslation(fcl::Vec3f((*q)[0], (*q)[1], (*q)[2]));
380


101
      fcl::Quaternion3f quat((*q)[6], (*q)[3], (*q)[4], (*q)[5]);
381
      // fcl::Matrix3f rot = quat.matrix();
382

101
      tRoot.setRotation(quat.matrix());
383

101
      reference = (tRoot * reference).getTranslation();
384
101
      geom::Point refPoint(reference);
385
      hppDout(notice, "Reference after root transform = " << reference);
386

101
      geom::Point normal, proj;
387
101
      double minDistance = std::numeric_limits<double>::max();
388
      double distance;
389
      CollisionValidationReportPtr_t bestReport(
390
202
          romReports->collisionReports.front());
391
      bool successInter;
392
202
      geom::T_Point intersection;
393
      hppDout(notice, "Number of possible surfaces for rom : "
394
                          << romReports->collisionReports.size());
395
303
      for (auto& itAff : romReports->collisionReports) {
396
404
        pinocchio::DeviceSync deviceSync(device);
397

202
        successInter = computeIntersectionSurface(itAff, intersection, normal,
398
                                                  deviceSync.d());
399
202
        if (successInter) {
400



404
          distance = geom::projectPointInsidePlan(
401
202
              intersection, refPoint, normal, intersection.front(), proj);
402
          hppDout(notice, "Distance found : " << distance);
403
202
          if (distance < minDistance) {
404
150
            minDistance = distance;
405
150
            bestReport = itAff;
406
          }
407
        }
408
      }
409
      // 3)
410
101
      romReports->object1 = bestReport->object1;
411
101
      romReports->object2 = bestReport->object2;
412
101
      romReports->result = bestReport->result;
413
    }
414
  }  // end for all rom
415
}
416
417
}  // namespace core
418
}  // namespace hpp