ColAvoid.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package ...
17 * @author Jianfeng Gao ( jianfeng dot gao at kit dot edu )
18 * @date 2025
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "ColAvoid.h"
24
25#include <SimoxUtility/color/Color.h>
26#include <VirtualRobot/MathTools.h>
27#include <VirtualRobot/RobotNodeSet.h>
28
29#include <simox/control/environment/collision.h>
30#include <simox/control/geodesics/util.h>
31#include <simox/control/robot/NodeInterface.h>
32#include <simox/control/utils/primitive.h>
33
35#include <ArmarXCore/core/PackagePath.h> // for GUI
39
43
45#include <armarx/control/common/control_law/aron/CollisionPrimitives.aron.generated.h>
47
49{
50 template <typename NJointControllerType, typename CollisionCtrlCfg>
53 const NJointControllerConfigPtr& config,
54 const VirtualRobot::RobotPtr& robot) :
55 NJointControllerType{robotUnit, config, robot}
56 {
57 auto cfg = ConfigPtrT::dynamicCast(config);
59 userCfgWithColl_ = CollisionCtrlCfg::FromAron(cfg->config);
60
61 std::map<std::string, std::vector<size_t>> velCtrlIndices;
62 for (auto& arm : this->limb)
63 {
64 velCtrlIndices.emplace(arm.first, arm.second->rtStatus.jointIDVelocityMode);
65 }
66 coll = std::make_shared<CollAvoidBase>(
67 this->rtGetRobot(), userCfgWithColl_.coll, velCtrlIndices);
68 collReady_.store(true);
69 // const std::string rootNodeName = "root";
70 // rootNode = this->rtGetRobot()->getRobotNode(rootNodeName);
71 }
73 template <typename NJointControllerType, typename CollisionCtrlCfg>
74 void
76 {
77 arm->controller.run(arm->rtConfig, arm->rtStatus);
79 if (collReady_.load())
80 {
82 // const std::string rootNodeName = "root";
83 // // coll->collLimb.at(arm->kinematicChainName)->rts.globalPose = rootNode->getGlobalPose();
84 // coll->collLimb.at(arm->kinematicChainName).rts.globalPose =
85 // this->rtGetRobot()->getGlobalPose();
86 coll->rtLimbControllerRun(arm->kinematicChainName,
87 arm->rtConfig.torqueLimit,
88 arm->rtConfig.velocityLimit,
89 arm->rtStatus);
90 // /// experimental implementation of admittance interface
91 // arm->rtStatus.inertia = coll->collLimb.at(arm->kinematicChainName).rts.inertia;
92 }
94 // if (collReady.load())
95 // {
96 // this->limbRTSetTarget(
97 // arm,
98 // arm->rtStatus.nDoFTorque,
99 // arm->rtStatus.nDoFVelocity,
100 // coll->collLimb.at(arm->kinematicChainName).rts.desiredJointTorques,
101 // arm->rtStatus.desiredJointVelocity);
102 // }
103 // else
104 // {
105 // this->limbRTSetTarget(arm,
106 // arm->rtStatus.nDoFTorque,
107 // arm->rtStatus.nDoFVelocity,
108 // arm->rtStatus.desiredJointTorque,
109 // arm->rtStatus.desiredJointVelocity);
110 // }
111 this->limbRTSetTarget(arm,
112 arm->rtStatus.nDoFTorque,
113 arm->rtStatus.nDoFVelocity,
114 arm->rtStatus.desiredJointTorque,
115 arm->rtStatus.desiredJointVelocity);
116 }
117
118 template <typename NJointControllerType, typename CollisionCtrlCfg>
119 void
121 const IceUtil::Time& /*sensorValuesTimestamp*/,
122 const IceUtil::Time& timeSinceLastIteration)
123 {
124 double deltaT = timeSinceLastIteration.toSecondsDouble();
125 // globalPose = rtGetRobot()->getRobotNode("root")->getGlobalPose();
126
127 if (collReady_.load())
128 {
130 coll->updateRtConfigFromUser();
131 coll->updateRtCollisionObjects();
132 coll->rtCollisionChecking();
133 }
134 for (auto& pair : this->limb)
135 {
136 this->limbRTUpdateStatus(pair.second, deltaT);
137 }
138
139 this->rtRunCoordinator(deltaT);
140
141 for (auto& pair : this->limb)
142 {
143 limbRT(pair.second);
144 }
145 if (this->hands)
146 {
147 this->hands->updateRTStatus(deltaT);
148 }
149 }
150
151 template <typename NJointControllerType, typename CollisionCtrlCfg>
152 void
154 const ::armarx::aron::data::dto::DictPtr& dto,
155 const Ice::Current& /*iceCurrent*/)
156 {
158 auto cfg = common::control_law::arondto::ObjectCollisionAvoidanceConfigDict::FromAron(dto);
159 coll->setUserCfg(cfg);
160 }
161
162 template <typename NJointControllerType, typename CollisionCtrlCfg>
163 void
165 {
166 size_t numCollisionObjects = 0;
167 for (const auto& pair : collisionObjects)
168 {
169 numCollisionObjects += pair.second.size();
170 }
171
172 std::vector<hpp::fcl::CollisionObject> allCollisionObjects;
173 allCollisionObjects.reserve(numCollisionObjects);
174 for (const auto& pair : collisionObjects)
175 {
176 allCollisionObjects.insert(
177 allCollisionObjects.end(), pair.second.begin(), pair.second.end());
178 }
179
180 coll->updateUserCollisionObjects(allCollisionObjects);
181 }
182
183 template <typename NJointControllerType, typename CollisionCtrlCfg>
184 void
186 const Ice::Current& /*iceCurrent*/)
187 {
188 coll->deleteUserCollisionObjects();
189 }
190
191 template <typename NJointControllerType, typename CollisionCtrlCfg>
192 void
194 const std::string& primitiveSourceName,
195 const ::armarx::aron::data::dto::DictPtr& dtoScene,
196 const Ice::Current& /*iceCurrent*/)
197 {
198 ARMARX_INFO_S << "updateCollisionObjects";
199 auto scene = common::control_law::arondto::CollisionScene::FromAron(dtoScene);
200 auto boxes = scene.boxes;
201 auto spheres = scene.spheres;
202 auto cylinders = scene.cylinders;
203 auto capsules = scene.capsules;
204 auto ellipsoids = scene.ellipsoids;
205
206 if (collisionObjects.count(primitiveSourceName) == 0)
207 {
208 collisionObjects.emplace(primitiveSourceName, std::vector<hpp::fcl::CollisionObject>());
209 }
210 std::vector<hpp::fcl::CollisionObject>& collisionObjectsOfSource =
211 collisionObjects[primitiveSourceName];
212 collisionObjectsOfSource.clear();
213 collisionObjectsOfSource.reserve(boxes.size() + spheres.size() + cylinders.size() +
214 capsules.size() + ellipsoids.size());
215
216 for (const auto& box : boxes)
217 {
218 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
219 simox::control::utils::primitive::Box{
220 .lengthX = box.lengthX, .lengthY = box.lengthY, .lengthZ = box.lengthZ},
221 Eigen::Isometry3d{box.transformation}));
222 }
223
224 for (const auto& sphere : spheres)
225 {
226 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
227 simox::control::utils::primitive::Sphere{.radius = sphere.radius},
228 Eigen::Isometry3d{sphere.transformation}));
229 }
230
231 for (const auto& cylinder : cylinders)
232 {
233 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
234 simox::control::utils::primitive::Cylinder{.radius = cylinder.radius,
235 .lengthY = cylinder.lengthY},
236 Eigen::Isometry3d{cylinder.transformation}));
237 }
238
239 for (const auto& capsule : capsules)
240 {
241 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
242 simox::control::utils::primitive::Capsule{.radius = capsule.radius,
243 .lengthY = capsule.lengthY},
244 Eigen::Isometry3d{capsule.transformation}));
245 }
246
247 for (const auto& ellipsoid : ellipsoids)
248 {
249 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
250 simox::control::utils::primitive::Ellipsoid{.lengthX = ellipsoid.lengthX,
251 .lengthY = ellipsoid.lengthY,
252 .lengthZ = ellipsoid.lengthZ},
253 Eigen::Isometry3d{ellipsoid.transformation}));
254 }
255
257 }
258
259 template <typename NJointControllerType, typename CollisionCtrlCfg>
262 const Ice::Current& /*iceCurrent*/)
263 {
264 if (not collReady_.load())
265 {
266 return nullptr;
267 }
268
270 return coll->userCfg.toAronDTO();
271 }
272
273 template <typename NJointControllerType, typename CollisionCtrlCfg>
274 void
276 const ::armarx::aron::data::dto::DictPtr& dto,
277 const Ice::Current& /*iceCurrent*/)
278 {
279 NJointControllerType::updateConfig(dto);
280 userCfgWithColl_ = CollisionCtrlCfg::FromAron(dto);
282 coll->setUserCfg(userCfgWithColl_.coll);
283 }
284
285 template <typename NJointControllerType, typename CollisionCtrlCfg>
288 const Ice::Current& /*iceCurrent*/)
289 {
290 // for (auto& pair : this->limb)
291 // {
292 // this->userConfig.limbs.at(pair.first) =
293 // pair.second->bufferConfigRtToUser.getUpToDateReadBuffer();
294 // }
295 NJointControllerType::getConfig();
296 userCfgWithColl_.limbs = this->userConfig.limbs;
297 userCfgWithColl_.hands = this->userConfig.hands;
298 return userCfgWithColl_.toAronDTO();
299 }
300
301 template <typename NJointControllerType, typename CollisionCtrlCfg>
302 void
304 const SensorAndControl& sc,
305 const DebugDrawerInterfacePrx& drawer,
306 const DebugObserverInterfacePrx& debugObs)
307 {
308 NJointControllerType::onPublish(sc, drawer, debugObs);
309 if (coll)
310 {
311 for (auto& pair : coll->collLimb)
312 {
313 collLimbPublish(pair.second, debugObs);
314 }
315 }
316 }
317
318 template <typename NJointControllerType, typename CollisionCtrlCfg>
319 void
322 const DebugObserverInterfacePrx& debugObs)
323 {
324 // double limbTimeMeasure = IceUtil::Time::now().toMicroSecondsDouble();
325
326 StringVariantBaseMap datafields;
327 auto rtStatus = arm.bufferRTtoPublish.getUpToDateReadBuffer();
328 auto recoveryState = arm.bufferRecoveryStateSelfColl.getUpToDateReadBuffer();
329
330 datafields["collDistanceThreshold"] = new Variant(recoveryState.collDistanceThreshold);
331 datafields["collDistanceThresholdInit"] =
332 new Variant(recoveryState.collDistanceThresholdInit);
333
334 datafields["trackingError"] = new Variant(rtStatus.trackingError);
335 common::debugEigenVec(datafields, "desiredJointTorques", rtStatus.desiredJointTorques);
336 common::debugEigenVec(datafields, "selfCollisionTorque", rtStatus.selfCollisionJointTorque);
337 common::debugEigenVec(datafields, "jointLimitTorque", rtStatus.jointLimitJointTorque);
338
339 datafields["selfColAdmInterface.active"] =
340 new Variant(static_cast<float>(rtStatus.selfColAdmInterface.active));
342 datafields, "selfColAdmInterface.jointVel", rtStatus.selfColAdmInterface.jointVel);
343 datafields["selfColAdmInterface.nDoFVel"] =
344 new Variant(static_cast<float>(rtStatus.selfColAdmInterface.nDoFVel));
345
346
347 datafields["jointLimAdmInterface.active"] =
348 new Variant(static_cast<float>(rtStatus.jointLimAdmInterface.active));
350 datafields, "jointLimAdmInterface.jointVel", rtStatus.jointLimAdmInterface.jointVel);
351 datafields["jointLimAdmInterface.nDoFVel"] =
352 new Variant(static_cast<float>(rtStatus.jointLimAdmInterface.nDoFVel));
353
355 datafields, "projectedImpedanceTorque", rtStatus.projImpedanceJointTorque);
356 // common::debugEigenVec(datafields, "projectedJointLimitTorque", rtStatus.projJointLimTorque);
357 // common::debugEigenVec(datafields, "projectedForceImpedance", rtStatus.projForceImpedance);
358 // common::debugEigenVec(
359 // datafields, "projectedSelfCollisionTorque", rtStatus.projSelfCollTorque);
360
361 const Eigen::VectorXf selfCollNullspace = rtStatus.selfCollNullSpace.diagonal();
362 const Eigen::VectorXf jointLimNullspace = rtStatus.jointLimNullSpace.diagonal();
363 common::debugEigenVec(datafields, "selfCollNullspaceDiagonal", selfCollNullspace);
364 common::debugEigenVec(datafields, "jointLimNullspaceDiagonal", jointLimNullspace);
365
366 // if (rtData.enableJointLimitAvoidance)
367 // {
368 // for (size_t i = 0; i < rtStatus.jointLimitData.size(); ++i)
369 // {
370 // if (not rtStatus.jointLimitData[i].isLimitless)
371 // {
372 // datafields["n_des(q)_" + std::to_string(i) + "_" +
373 // rtStatus.jointLimitData[i].jointName] =
374 // new Variant(rtStatus.jointLimitData[i].desiredNSjointLim);
375 // datafields["q_damping" + std::to_string(i) + "_" +
376 // rtStatus.jointLimitData[i].jointName] =
377 // new Variant(rtStatus.jointLimitData[i].totalDamping);
378 // datafields["q_repTorque" + std::to_string(i) + "_" +
379 // rtStatus.jointLimitData[i].jointName] =
380 // new Variant(rtStatus.jointLimitData[i].repulsiveTorque);
381 // }
382 // }
383 // }
384
385 datafields["collisionPairsNum"] = new Variant(rtStatus.collisionPairsNum);
386 datafields["activeCollPairsNum"] = new Variant(rtStatus.activeCollPairsNum);
387
388 datafields["collisionPairTime"] = new Variant(rtStatus.collisionPairTime);
389 datafields["collisionTorqueTime"] = new Variant(rtStatus.collisionTorqueTime);
390 datafields["jointLimitTorqueTime"] = new Variant(rtStatus.jointLimitTorqueTime);
391 datafields["selfCollNullspaceTime"] = new Variant(rtStatus.selfCollNullspaceTime);
392 datafields["jointLimitNullspaceTime"] = new Variant(rtStatus.jointLimitNullspaceTime);
393
394 datafields["impForceRatio"] = new Variant(rtStatus.impForceRatio);
395 datafields["impTorqueRatio"] = new Variant(rtStatus.impTorqueRatio);
396
397 for (unsigned int i = 0; i < rtStatus.activeCollPairsNum; ++i)
398 {
399 //size_t index = rtStatus.distanceIndexPairs[i].second;
400 datafields[std::to_string(i) + "_minDistance"] =
401 new Variant(rtStatus.collDataVec[i].minDistance);
402 datafields[std::to_string(i) + "_repForce"] =
403 new Variant(rtStatus.collDataVec[i].repulsiveForce);
404 datafields[std::to_string(i) + "_dampingForce"] = new Variant(
405 -1.0f * rtStatus.collDataVec[i].damping * rtStatus.collDataVec[i].distanceVelocity);
406 datafields[std::to_string(i) + "_n_des(d)"] =
407 new Variant(rtStatus.collDataVec[i].desiredNSColl);
409 datafields, std::to_string(i) + "_point", rtStatus.collDataVec[i].point1);
411 datafields, std::to_string(i) + "_dir", rtStatus.collDataVec[i].direction);
412 }
413
414
415 // /// prepare test case config
416 // const float tolerance = 1e-9f;
417 // if (rtData.testConfig == 1)
418 // {
419 // if (rtStatus.evalData[0].nodeName == "ArmL8_Wri2")
420 // {
421 // // set distance
422 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_dist"] =
423 // new Variant(rtStatus.evalData[0].minDistance);
424 // // set f_rep, damping, desired NS space
425
426
427 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_repF"] =
428 // new Variant(rtStatus.evalData[0].repulsiveForce);
429 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_projMass"] =
430 // new Variant(rtStatus.evalData[0].projectedMass);
431 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_locStiffness"] =
432 // new Variant(rtStatus.evalData[0].localStiffness);
433 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_dampFactor"] =
434 // new Variant(rtStatus.evalData[0].damping);
435 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_distVel"] =
436 // new Variant(rtStatus.evalData[0].distanceVelocity);
437 // if (fabs(rtStatus.evalData[0].damping + 1.0f) < tolerance)
438 // {
439 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_dampForce"] =
440 // new Variant(0.0);
441 // }
442 // else
443 // {
444 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_dampForce"] =
445 // new Variant(-1.0 * rtStatus.evalData[0].damping *
446 // rtStatus.evalData[0].distanceVelocity);
447 // }
448
449 // datafields["ArmL8_Wri2_" + rtStatus.evalData[0].otherName + "_n_des(d)"] =
450 // new Variant(rtStatus.evalData[0].desiredNSColl);
451 // }
452 // if (rtStatus.evalData[1].nodeName == "ArmL8_Wri2")
453 // {
454 // // set distance
455 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_dist"] =
456 // new Variant(rtStatus.evalData[1].minDistance);
457 // // set f_rep, damping, desired NS space
458
459 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_repF"] =
460 // new Variant(rtStatus.evalData[1].repulsiveForce);
461 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_projMass"] =
462 // new Variant(rtStatus.evalData[1].projectedMass);
463 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_locStiffness"] =
464 // new Variant(rtStatus.evalData[1].localStiffness);
465 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_dampFactor"] =
466 // new Variant(rtStatus.evalData[1].damping);
467 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_distVel"] =
468 // new Variant(rtStatus.evalData[1].distanceVelocity);
469 // if (fabs(rtStatus.evalData[1].damping + 1.0f) < tolerance)
470 // {
471 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_dampForce"] =
472 // new Variant(0.0);
473 // }
474 // else
475 // {
476 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_dampForce"] =
477 // new Variant(-1.0 * rtStatus.evalData[1].damping *
478 // rtStatus.evalData[1].distanceVelocity);
479 // }
480
481 // datafields["ArmL8_Wri2_" + rtStatus.evalData[1].otherName + "_n_des(d)"] =
482 // new Variant(rtStatus.evalData[1].desiredNSColl);
483 // }
484 // if (rtStatus.evalData[2].nodeName == "ArmL7_Wri1")
485 // {
486 // // set distance
487 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_dist"] =
488 // new Variant(rtStatus.evalData[2].minDistance);
489 // // set f_rep, damping, desired NS space
490
491 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_repF"] =
492 // new Variant(rtStatus.evalData[2].repulsiveForce);
493
494 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_projMass"] =
495 // new Variant(rtStatus.evalData[2].projectedMass);
496 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_locStiffness"] =
497 // new Variant(rtStatus.evalData[2].localStiffness);
498 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_dampFactor"] =
499 // new Variant(rtStatus.evalData[2].damping);
500 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_distVel"] =
501 // new Variant(rtStatus.evalData[2].distanceVelocity);
502 // if (fabs(rtStatus.evalData[2].damping + 1.0f) < tolerance)
503 // {
504 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_dampForce"] =
505 // new Variant(0.0);
506 // }
507 // else
508 // {
509 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_dampForce"] =
510 // new Variant(-1.0 * rtStatus.evalData[2].damping *
511 // rtStatus.evalData[2].distanceVelocity);
512 // }
513
514
515 // datafields["ArmL7_Wri1_" + rtStatus.evalData[2].otherName + "_n_des(d)"] =
516 // new Variant(rtStatus.evalData[2].desiredNSColl);
517 // }
518 // if (rtStatus.evalData[3].nodeName == "ArmL8_Wri2")
519 // {
520 // // set distance
521 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_dist"] =
522 // new Variant(rtStatus.evalData[3].minDistance);
523 // // set f_rep, damping, desired NS space
524
525 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_repF"] =
526 // new Variant(rtStatus.evalData[3].repulsiveForce);
527
528 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_projMass"] =
529 // new Variant(rtStatus.evalData[3].projectedMass);
530 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_locStiffness"] =
531 // new Variant(rtStatus.evalData[3].localStiffness);
532 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_dampFactor"] =
533 // new Variant(rtStatus.evalData[3].damping);
534 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_distVel"] =
535 // new Variant(rtStatus.evalData[3].distanceVelocity);
536 // if (fabs(rtStatus.evalData[3].damping + 1.0f) < tolerance)
537 // {
538 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_dampForce"] =
539 // new Variant(0.0);
540 // }
541 // else
542 // {
543 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_dampForce"] =
544 // new Variant(-1.0 * rtStatus.evalData[3].damping *
545 // rtStatus.evalData[3].distanceVelocity);
546 // }
547
548
549 // datafields["ArmL8_Wri2_" + rtStatus.evalData[3].otherName + "_n_des(d)"] =
550 // new Variant(rtStatus.evalData[3].desiredNSColl);
551 // }
552
553 // if (rtStatus.evalData[4].nodeName == "ArmL8_Wri2")
554 // {
555 // // set distance
556 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_dist"] =
557 // new Variant(rtStatus.evalData[4].minDistance);
558 // // set f_rep, damping, desired NS space
559
560 // // values have been calculated
561 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_repF"] =
562 // new Variant(rtStatus.evalData[4].repulsiveForce);
563
564 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_projMass"] =
565 // new Variant(rtStatus.evalData[4].projectedMass);
566 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_locStiffness"] =
567 // new Variant(rtStatus.evalData[4].localStiffness);
568 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_dampFactor"] =
569 // new Variant(rtStatus.evalData[4].damping);
570 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_distVel"] =
571 // new Variant(rtStatus.evalData[4].distanceVelocity);
572 // if (fabs(rtStatus.evalData[4].damping + 1.0f) < tolerance)
573 // {
574 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_dampForce"] =
575 // new Variant(0.0);
576 // }
577 // else
578 // {
579 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_dampForce"] =
580 // new Variant(-1.0 * rtStatus.evalData[4].damping *
581 // rtStatus.evalData[4].distanceVelocity);
582 // }
583
584
585 // datafields["ArmL8_Wri2_" + rtStatus.evalData[4].otherName + "_n_des(d)"] =
586 // new Variant(rtStatus.evalData[4].desiredNSColl);
587 // }
588 // if (rtStatus.evalData[5].nodeName == "ArmL8_Wri2")
589 // {
590 // // set distance
591 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_dist"] =
592 // new Variant(rtStatus.evalData[5].minDistance);
593
594 // // values have been calculated
595 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_repF"] =
596 // new Variant(rtStatus.evalData[5].repulsiveForce);
597
598 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_projMass"] =
599 // new Variant(rtStatus.evalData[5].projectedMass);
600 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_locStiffness"] =
601 // new Variant(rtStatus.evalData[5].localStiffness);
602 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_dampFactor"] =
603 // new Variant(rtStatus.evalData[5].damping);
604 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_distVel"] =
605 // new Variant(rtStatus.evalData[5].distanceVelocity);
606 // if (fabs(rtStatus.evalData[5].damping + 1.0f) < tolerance)
607 // {
608 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_dampForce"] =
609 // new Variant(0.0);
610 // }
611 // else
612 // {
613 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_dampForce"] =
614 // new Variant(-1.0 * rtStatus.evalData[5].damping *
615 // rtStatus.evalData[5].distanceVelocity);
616 // }
617
618
619 // datafields["ArmL8_Wri2_" + rtStatus.evalData[5].otherName + "_n_des(d)"] =
620 // new Variant(rtStatus.evalData[5].desiredNSColl);
621 // }
622 // if (rtStatus.evalData[6].nodeName == "ArmL5_Elb1")
623 // {
624 // // set distance
625 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_dist"] =
626 // new Variant(rtStatus.evalData[6].minDistance);
627
628 // // values have been calculated
629 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_repF"] =
630 // new Variant(rtStatus.evalData[6].repulsiveForce);
631
632 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_projMass"] =
633 // new Variant(rtStatus.evalData[6].projectedMass);
634 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_locStiffness"] =
635 // new Variant(rtStatus.evalData[6].localStiffness);
636 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_dampFactor"] =
637 // new Variant(rtStatus.evalData[6].damping);
638 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_distVel"] =
639 // new Variant(rtStatus.evalData[6].distanceVelocity);
640 // if (fabs(rtStatus.evalData[6].damping + 1.0f) < tolerance)
641 // {
642 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_dampForce"] =
643 // new Variant(0.0);
644 // }
645 // else
646 // {
647 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_dampForce"] =
648 // new Variant(-1.0 * rtStatus.evalData[6].damping *
649 // rtStatus.evalData[6].distanceVelocity);
650 // }
651
652
653 // datafields["ArmL5_Elb1_" + rtStatus.evalData[6].otherName + "_n_des(d)"] =
654 // new Variant(rtStatus.evalData[6].desiredNSColl);
655 // }
656 // }
657
658
659 //double selfCollDebugTime = IceUtil::Time::now().toMicroSecondsDouble() - timeMeasure;
660 //datafields["selfCollDebugTime"] = new Variant(selfCollDebugTime);
661
662 // debug value assignment torso, neck joints
663 // datafields["torsoJointValue_float"] = new Variant(rtStatus.torsoJointValuef);
664 // datafields["neck1JointValue_float"] = new Variant(rtStatus.neck1JointValuef);
665 // datafields["neck2JointValue_float"] = new Variant(rtStatus.neck2JointValuef);
666
667 // datafields["torsoJointValue_double"] = new Variant(rtStatus.torsoJointValued);
668 // datafields["neck1JointValue_double"] = new Variant(rtStatus.neck1JointValued);
669 // datafields["neck2JointValue_double"] = new Variant(rtStatus.neck2JointValued);
670
671 // common::debugEigenVec(
672 // datafields, "set_ActuatedJointValues", rtStatus.setActuatedJointValues.cast<float>());
673 // common::debugEigenVec(
674 // datafields, "get_ActuatedJointValues", rtStatus.getActuatedJointValues.cast<float>());
675
676 // double limbTime = IceUtil::Time::now().toMicroSecondsDouble() - limbTimeMeasure;
677 // datafields["limbOnPublishTime"] = new Variant(limbTime);
678
679 debugObs->setDebugChannel("CollAvoid_ImpCtrl_" + arm.nodeSetName, datafields);
680 }
681
682 template <typename NJointControllerType, typename CollisionCtrlCfg>
683 void
685 viz::Layer& layer,
686 const std::vector<hpp::fcl::CollisionObject>& objects)
687 {
688 for (size_t i = 0; i < objects.size(); ++i)
689 {
690 auto object = objects.at(i);
691 const auto position = object.getTranslation().cast<float>() * 1000;
692 const Eigen::Matrix3f rotation = object.getRotation().cast<float>();
693
694 switch (object.getNodeType())
695 {
696 case hpp::fcl::NODE_TYPE::GEOM_BOX:
697 {
698 const hpp::fcl::Box* box =
699 std::static_pointer_cast<hpp::fcl::Box>(object.collisionGeometry()).get();
700 const viz::Box vizObject = viz::Box("box " + std::to_string(i))
701 .size(box->halfSide.cast<float>() * 1000 * 2)
702 .orientation(rotation)
703 .position(position)
704 .color(255, 0, 0, 128);
705 layer.add(vizObject);
706 break;
707 }
708 case hpp::fcl::NODE_TYPE::GEOM_SPHERE:
709 {
710 const hpp::fcl::Sphere* sphere =
711 std::static_pointer_cast<hpp::fcl::Sphere>(object.collisionGeometry())
712 .get();
713 const viz::Sphere vizObject =
714 viz::Sphere("sphere " + std::to_string(i))
715 .radius(static_cast<float>(sphere->radius) * 1000)
716 .orientation(rotation)
717 .position(position)
718 .color(0, 0, 255, 128);
719 layer.add(vizObject);
720 break;
721 }
722 case hpp::fcl::NODE_TYPE::GEOM_CYLINDER:
723 {
724 const hpp::fcl::Cylinder* cylinder =
725 std::static_pointer_cast<hpp::fcl::Cylinder>(object.collisionGeometry())
726 .get();
727 const viz::Cylinder vizObject =
728 viz::Cylinder("cylinder " + std::to_string(i))
729 .height(static_cast<float>(cylinder->halfLength) * 1000 * 2)
730 .radius(static_cast<float>(cylinder->radius) * 1000)
731 .orientation(rotation *
732 Eigen::AngleAxisf(M_PI / 2., Eigen::Vector3f::UnitX()))
733 .position(position)
734 .color(0, 255, 0, 128);
735 layer.add(vizObject);
736 break;
737 }
738 case hpp::fcl::NODE_TYPE::GEOM_CAPSULE:
739 {
740 const hpp::fcl::Capsule* capsule =
741 std::static_pointer_cast<hpp::fcl::Capsule>(object.collisionGeometry())
742 .get();
743 const auto _rotation =
744 rotation * Eigen::AngleAxisf(M_PI / 2., Eigen::Vector3f::UnitX());
745 Eigen::Vector3f offset;
746 offset << 0, static_cast<float>(capsule->halfLength) * 1000, 0;
747 offset = _rotation * offset;
748
749 const viz::Sphere cap1 = viz::Sphere("capsule_cap1 " + std::to_string(i))
750 .radius(static_cast<float>(capsule->radius) * 1000)
751 .position(position + offset)
752 .orientation(_rotation)
753 .color(255, 200, 0, 128);
754 const viz::Sphere cap2 = viz::Sphere("capsule_cap2 " + std::to_string(i))
755 .radius(static_cast<float>(capsule->radius) * 1000)
756 .position(position - offset)
757 .orientation(_rotation)
758 .color(255, 200, 0, 128);
759 const viz::Cylinder vizObject =
760 viz::Cylinder("capsule_mid " + std::to_string(i))
761 .height(static_cast<float>(capsule->halfLength) * 1000 * 2)
762 .radius(static_cast<float>(capsule->radius) * 1000)
763 .color(255, 200, 0, 128)
764 .orientation(_rotation)
765 .position(position);
766 layer.add(vizObject);
767 layer.add(cap1);
768 layer.add(cap2);
769 break;
770 }
771 case hpp::fcl::NODE_TYPE::GEOM_ELLIPSOID:
772 {
773 const hpp::fcl::Ellipsoid* ellipsoid =
774 std::static_pointer_cast<hpp::fcl::Ellipsoid>(object.collisionGeometry())
775 .get();
776 const viz::Ellipsoid vizObject =
777 viz::Ellipsoid("ellipsoid " + std::to_string(i))
778 // axis lengths seem to be radii instead of axis lengths
779 .axisLengths(ellipsoid->radii.cast<float>() * 1000)
780 .orientation(rotation)
781 .position(position)
782 .color(255, 0, 200, 128);
783 layer.add(vizObject);
784 break;
785 }
786 default:;
787 }
788 }
789 }
790
791 template <typename NJointControllerType, typename CollisionCtrlCfg>
792 void
794 viz::StagedCommit& stage) const
795 {
796 NJointControllerType::collectArviz(stage);
797
798 auto transformVector = [](const Eigen::Matrix4f& pose,
799 const Eigen::Vector3f& vec) -> Eigen::Vector3f
800 { return common::getOri(pose) * vec + common::getPos(pose); };
801
802 if (coll)
803 {
804 for (const auto& [_, arm] : coll->collLimb)
805 {
806 const auto& rtStatus = arm.bufferRTtoPublish.getUpToDateReadBuffer();
807
808 viz::Layer layer = this->scopedArviz->layer("ColStatus_" + arm.nodeSetName);
809
810 for (unsigned int i = 0; i < rtStatus.activeCollPairsNum; ++i)
811 {
812 // visualize impedance force
813 // layer.add(viz::Arrow("projImpForce_" + std::to_string(i))
814 // .fromTo(rtStatus.collDataVec[i].point * 1000.0,
815 // rtStatus.collDataVec[i].point * 1000.0 +
816 // rtStatus.collDataVec[i].projectedImpedanceForce *
817 // rtStatus.collDataVec[i].direction * 5.0)
818 // .color(simox::Color::purple()));
819
820 // layer.add(viz::Arrow("impForce_" + std::to_string(i))
821 // .fromTo(rtStatus.collDataVec[i].point * 1000.0,
822 // rtStatus.collDataVec[i].point * 1000.0 +
823 // rtStatus.forceImpedance.head<3>().dot(
824 // rtStatus.collDataVec[i].direction) *
825 // rtStatus.collDataVec[i].direction * 5.0)
826 // .color(simox::Color::yellow())); // project forceImp in dir of collision
827
828 layer.add(
829 viz::Arrow("Force_" + std::to_string(i))
830 .fromTo(transformVector(rtStatus.globalPose,
831 rtStatus.collDataVec[i].point1 * 1000.0F),
832 transformVector(rtStatus.globalPose,
833 rtStatus.collDataVec[i].point1 * 1000.0F +
834 rtStatus.collDataVec[i].direction * 50.0F *
835 rtStatus.collDataVec[i].repulsiveForce))
836 .color(simox::Color::blue())
837 .width(5.0f));
838 }
839
840 layer.add(viz::Pose("RootPose").pose(rtStatus.globalPose).scale(2));
841
842 // visualize impedance force
843 // layer.add(viz::Arrow("impForce")
844 // .fromTo(transformVector(rtStatus.globalPose,
845 // rtStatus.currentPose.block<3, 1>(0, 3)),
846 // transformVector(rtStatus.globalPose,
847 // rtStatus.currentPose.block<3, 1>(0, 3) +
848 // rtStatus.forceImpedance.head<3>() * 1000.0))
849 // .color(simox::Color::yellow()));
850 // layer.add(viz::Arrow("projImpForce")
851 // .fromTo(rtStatus.currentPose.block<3, 1>(0, 3),
852 // rtStatus.currentPose.block<3, 1>(0, 3) +
853 // rtStatus.projForceImpedance.head<3>() * 1000.0)
854 // .color(simox::Color::purple()));
855
856 stage.add(layer);
857 }
858
859 if (not coll->userCollisionObjects.empty())
860 {
861 viz::Layer layer = this->scopedArviz->layer("ColStatus_objectModels");
862 AddArvizObjects(layer, coll->userCollisionObjects);
863 stage.add(layer);
864 }
865 const bool enableRobotPrimitiveVis = true;
866 if (enableRobotPrimitiveVis)
867 {
868 // TODO uses rt collision robot
869 const auto& robotObjects =
870 coll->collisionRobot->getCollisionManager()->getObjects();
871 std::vector<hpp::fcl::CollisionObject> robotObjectsByValue;
872 robotObjectsByValue.reserve(robotObjects.size());
873 for (const auto* ptr : robotObjects)
874 {
875 robotObjectsByValue.push_back(*ptr);
876 }
877 viz::Layer layer = this->scopedArviz->layer("ColStatus_robotModel");
878 AddArvizObjects(layer, robotObjectsByValue);
879 stage.add(layer);
880 }
881 }
882 }
883
884 template <typename NJointControllerType, typename CollisionCtrlCfg>
885 void
887 {
888 // ARMARX_RT_LOGF_INFO("rt Preactivate controller "
889 // "NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController");
890 NJointControllerType::rtPreActivateController();
892 if (collReady_.load())
893 {
895 coll->rtPreActivate();
896 }
897 }
898
899 template <typename NJointControllerType, typename CollisionCtrlCfg>
900 void
902 {
903 NJointControllerType::rtPostDeactivateController();
904 if (collReady_.load())
905 {
907 coll->rtPostDeactivate();
908 }
909 // ARMARX_RT_LOGF_INFO("-- post deactivate: "
910 // "NJointTaskspaceCollisionAvoidanceMixedImpedanceVelocityController");
911 }
912
913 template <typename NJointControllerType, typename CollisionCtrlCfg>
916 const StringVariantBaseMap& values)
917 {
918 auto cfgName = values.at("config_box")->getString();
919 const armarx::PackagePath configPath(
920 "armarx_control",
921 "controller_config/" + std::string(NJointControllerType::ControlType::TypeName) +
922 "Col/" + cfgName + ".json");
923 ARMARX_INFO_S << "Loading config from " << configPath.toSystemPath();
924 ARMARX_CHECK(std::filesystem::exists(configPath.toSystemPath()));
925
926 auto cfgDTO = armarx::readFromJson<CollisionCtrlCfg>(configPath.toSystemPath());
927
929 return new ConfigurableNJointControllerConfig{cfgDTO.toAronDTO()};
930 }
931
932 /// ================================== TSMixImpVelCol ==================================
934 law::arondto::TSMixImpVelColConfigDict>;
935
938
940 const RobotUnitPtr& robotUnit,
941 const NJointControllerConfigPtr& config,
942 const VirtualRobot::RobotPtr& robot) :
943 // NJointTSMixImpVelController(robotUnit, config, robot),
944 NJointTSColController<NJointTSMixImpVelController, law::arondto::TSMixImpVelColConfigDict>(
945 robotUnit,
946 config,
947 robot)
948 {
949 }
950
951 std::string
952 NJointTSMixImpVelColController::getClassName(const Ice::Current& /*unused*/) const
953 {
954 return "TSMixImpVelCol";
955 }
956
957 /// ================================== TSImpCol ==================================
958
960
963
965 const NJointControllerConfigPtr& config,
966 const VirtualRobot::RobotPtr& robot) :
967 // NJointTSImpController(robotUnit, config, robot),
969 config,
970 robot)
971 {
972 }
973
974 std::string
975 NJointTSImpColController::getClassName(const Ice::Current& /*unused*/) const
976 {
977 return "TSImpCol";
978 }
979
980 /// ================================== TSVeloCol ==================================
981
983
986
988 const NJointControllerConfigPtr& config,
989 const VirtualRobot::RobotPtr& robot) :
990 // NJointTSVelController(robotUnit, config, robot),
992 config,
993 robot)
994 {
995 }
996
997 std::string
998 NJointTSVeloColController::getClassName(const Ice::Current& /*unused*/) const
999 {
1000 return "TSVeloCol";
1001 }
1002
1003
1004} // namespace armarx::control::njoint_controller::task_space
#define M_PI
Definition MathTools.h:17
const VirtualRobot::RobotPtr & rtGetRobot()
TODO make protected and use attorneys.
static std::filesystem::path toSystemPath(const data::PackagePath &pp)
const T & getUpToDateReadBuffer() const
The Variant class is described here: Variants.
Definition Variant.h:224
void collectArviz(viz::StagedCommit &stage) const override
Definition ColAvoid.cpp:793
NJointTSColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
Definition ColAvoid.cpp:51
std::map< std::string, std::vector< hpp::fcl::CollisionObject > > collisionObjects
Definition ColAvoid.h:100
static ConfigPtrT GenerateConfigFromVariants(const StringVariantBaseMap &values)
Definition ColAvoid.cpp:915
static void AddArvizObjects(viz::Layer &layer, const std::vector< hpp::fcl::CollisionObject > &objects)
Definition ColAvoid.cpp:684
void collLimbPublish(CollAvoidBase::NodeSetData &arm, const DebugObserverInterfacePrx &debugObs)
Definition ColAvoid.cpp:320
void updateCollisionAvoidanceConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
NJointController interface for collision avoidance.
Definition ColAvoid.cpp:153
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
Definition ColAvoid.cpp:120
typename NJointControllerType::ConfigPtrT ConfigPtrT
Definition ColAvoid.h:49
void onPublish(const SensorAndControl &sc, const DebugDrawerInterfacePrx &drawer, const DebugObserverInterfacePrx &) override
Definition ColAvoid.cpp:303
::armarx::aron::data::dto::DictPtr getConfig(const Ice::Current &iceCurrent) override
Definition ColAvoid.cpp:287
void updateCollisionObjects(const std::string &primitiveSourceName, const ::armarx::aron::data::dto::DictPtr &dtoScene, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
Definition ColAvoid.cpp:193
void rtPreActivateController() override
NJointControllerBase interface.
Definition ColAvoid.cpp:886
void updateConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent) override
Definition ColAvoid.cpp:275
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
Definition ColAvoid.cpp:975
NJointTSImpColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
Definition ColAvoid.cpp:964
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
Definition ColAvoid.cpp:952
NJointTSMixImpVelColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
Definition ColAvoid.cpp:939
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
Definition ColAvoid.cpp:998
NJointTSVeloColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
Definition ColAvoid.cpp:987
void limbRTSetTarget(ArmPtr &arm, const size_t nDoFTorque, const size_t nDoFVelocity, const Eigen::VectorXf &targetTorque, const Eigen::VectorXf &targetVelocity)
Definition Base.cpp:365
DerivedT & color(Color color)
Definition ElementOps.h:218
DerivedT & position(float x, float y, float z)
Definition ElementOps.h:136
DerivedT & orientation(Eigen::Quaternionf const &ori)
Definition ElementOps.h:152
DerivedT & scale(Eigen::Vector3f scale)
Definition ElementOps.h:254
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO_S
Definition Logging.h:200
armarx::aron::data::dto::Dict getCollisionAvoidanceConfig()
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
::IceInternal::Handle< Dict > DictPtr
void debugEigenVec(StringVariantBaseMap &datafields, const std::string &name, Eigen::VectorXf vec)
Definition utils.cpp:190
Eigen::Block< Eigen::Matrix4f, 3, 3 > getOri(Eigen::Matrix4f &matrix)
Definition utils.cpp:265
Eigen::Block< Eigen::Matrix4f, 3, 1 > getPos(Eigen::Matrix4f &matrix)
Definition utils.cpp:301
NJointControllerRegistration< NJointTSVeloColController > registrationControllerNJointTSVeloColController("TSVeloCol")
NJointControllerRegistration< NJointTSMixImpVelColController > registrationControllerNJointTSMixImpVelColController("TSMixImpVelCol")
NJointControllerRegistration< NJointTSImpColController > registrationControllerNJointTSImpColController("TSImpCol")
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
std::map< std::string, VariantBasePtr > StringVariantBaseMap
AronDTO readFromJson(const std::filesystem::path &filename)
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
Arrow & width(float w)
Definition Elements.h:211
Box & size(Eigen::Vector3f const &s)
Definition Elements.h:52
Cylinder & height(float h)
Definition Elements.h:84
Cylinder & radius(float r)
Definition Elements.h:76
Ellipsoid & axisLengths(const Eigen::Vector3f &axisLengths)
Definition Elements.h:156
void add(ElementT const &element)
Definition Layer.h:31
Sphere & radius(float r)
Definition Elements.h:138
A staged commit prepares multiple layers to be committed.
Definition Client.h:30
void add(Layer const &layer)
Stage a layer to be committed later via client.apply(*this)
Definition Client.h:36
#define ARMARX_TRACE
Definition trace.h:75