3 #include <SimoxUtility/math/convert/mat4f_to_quat.h>
4 #include <VirtualRobot/MathTools.h>
5 #include <VirtualRobot/Nodes/RobotNode.h>
6 #include <VirtualRobot/RobotNodeSet.h>
15 #include <simox/control/dynamics/RBDLModel.h>
16 #include <simox/control/robot/NodeInterface.h>
22 const simox::control::robot::NodeSetInterface* nodeSet) :
24 I(nodeSet ?
Eigen::MatrixXf::
Identity(nodeSet->getSize(), nodeSet->getSize()) :
Eigen::MatrixXf())
32 ARMARX_INFO <<
"Destruction of CollisionAvoidanceController";
38 CollisionAvoidanceController::calculateSelfCollisionTorque(
40 RtStatusForSafetyStrategy& rts,
41 const DistanceResults& collisionPairs,
42 const CollisionRobotIndices& collisionRobotIndices,
43 const Eigen::VectorXf& qvelFiltered)
const
60 rts.selfCollisionJointTorque.setZero();
61 rts.activeCollPairsNum = 0;
63 for (
auto&
data : rts.selfCollDataVec)
71 if (
static_cast<float>(collisionPair.minDistance) >
c.distanceThreshold)
76 if (collisionRobotIndices.count(collisionPair.node1) == 0 and
77 collisionRobotIndices.count(collisionPair.node2) == 0)
84 auto& selfCollDataVec = rts.selfCollDataVec[rts.activeCollPairsNum++];
86 selfCollDataVec.minDistance =
87 static_cast<float>(collisionPair.minDistance);
90 if (collisionRobotIndices.count(collisionPair.node1) > 0)
94 if (collisionRobotIndices.count(collisionPair.node2) > 0)
100 selfCollDataVec.node1 = collisionPair.node1;
101 selfCollDataVec.node2 = collisionPair.node2;
102 selfCollDataVec.point1 = collisionPair.point1->cast<
float>();
103 selfCollDataVec.point2 = collisionPair.point2->cast<
float>();
110 selfCollDataVec.node1 = collisionPair.node2;
111 selfCollDataVec.node2 = collisionPair.node1;
112 selfCollDataVec.point1 = collisionPair.point2->cast<
float>();
113 selfCollDataVec.point2 = collisionPair.point1->cast<
float>();
117 selfCollDataVec.direction = selfCollDataVec.point1 - selfCollDataVec.point2;
119 if (selfCollDataVec.minDistance < 0.0f)
121 selfCollDataVec.minDistance = 0.0f;
125 if (selfCollDataVec.point1.isApprox(selfCollDataVec.point2, 1e-8)
126 and collisionPair.normalVec != std::nullopt)
139 selfCollDataVec.direction = collisionPair.normalVec->cast<
float>();
142 selfCollDataVec.direction *= -1.0f;
147 selfCollDataVec.direction *= -1.0f;
151 selfCollDataVec.direction.normalize();
156 const auto* node = collisionRobotIndices.at(selfCollDataVec.node1);
158 localTransformation.translation() =
159 node->getGlobalPose().inverse() * selfCollDataVec.point1.cast<
double>();
160 const bool result = nodeSet->computeJacobian(
161 selfCollDataVec.jacobian,
163 simox::control::robot::JacobianParams{
165 .localTransformation = localTransformation});
171 selfCollDataVec.repulsiveForce =
172 c.maxRepulsiveForce / std::pow(
c.distanceThreshold, 2) *
173 std::pow(selfCollDataVec.minDistance -
c.distanceThreshold, 2);
174 selfCollDataVec.localStiffness =
175 -2.0 *
c.maxRepulsiveForce / std::pow(
c.distanceThreshold, 2) *
176 (selfCollDataVec.minDistance -
c.distanceThreshold);
179 selfCollDataVec.repulsiveForce =
180 std::clamp(selfCollDataVec.repulsiveForce, 0.0f,
c.maxRepulsiveForce);
186 selfCollDataVec.projectedJacT =
187 (selfCollDataVec.direction.transpose() * selfCollDataVec.jacobian.cast<
float>())
194 selfCollDataVec.distanceVelocity =
195 selfCollDataVec.projectedJacT.transpose() * qvelFiltered;
200 selfCollDataVec.projectedMass =
201 1 / (selfCollDataVec.projectedJacT.transpose() * rts.inertiaInverse *
202 selfCollDataVec.projectedJacT);
206 selfCollDataVec.damping =
207 2 *
std::sqrt(selfCollDataVec.localStiffness) *
208 std::sqrt(selfCollDataVec.projectedMass) *
c.dampingFactor;
212 rts.selfCollisionJointTorque +=
213 selfCollDataVec.projectedJacT *
214 (selfCollDataVec.repulsiveForce -
215 selfCollDataVec.damping * selfCollDataVec.distanceVelocity);
220 CollisionAvoidanceController::calculateJointLimitTorque(
const Config&
c,
221 RtStatusForSafetyStrategy& rts,
222 const Eigen::VectorXf& qpos,
223 const Eigen::VectorXf& qvelFiltered)
const
229 rts.jointLimitJointTorque.setZero();
237 for (
size_t i = 0; i < rts.jointLimitData.size(); ++i)
239 if (rts.jointLimitData[i].isLimitless)
244 auto& joint = rts.jointLimitData[i];
245 rts.jointInertia = rts.inertia(i, i);
246 if (qpos[i] < rts.jointLimitData[i].qposThresholdLow)
248 joint.repulsiveTorque =
249 c.maxRepulsiveTorque / std::pow(rts.jointLimitData[i].thresholdRange, 2) *
250 std::pow(rts.jointLimitData[i].qposThresholdLow - qpos[i], 2);
252 joint.repulsiveTorque =
253 std::clamp(joint.repulsiveTorque, 0.0f,
c.maxRepulsiveTorque);
255 rts.localStiffnessJointLim = 2 *
c.maxRepulsiveTorque /
256 std::pow(rts.jointLimitData[i].thresholdRange, 2) *
257 (rts.jointLimitData[i].qposThresholdLow - qpos[i]);
260 rts.dampingJointLim = 2 *
std::sqrt(rts.jointInertia) *
261 std::sqrt(rts.localStiffnessJointLim) *
c.dampingFactor;
264 joint.totalDamping = rts.dampingJointLim * qvelFiltered[i];
265 rts.jointLimitJointTorque(i) =
266 joint.repulsiveTorque - rts.dampingJointLim * qvelFiltered[i];
270 else if (qpos[i] > rts.jointLimitData[i].qposThresholdHigh)
272 joint.repulsiveTorque =
273 c.maxRepulsiveTorque / std::pow(rts.jointLimitData[i].thresholdRange, 2) *
274 std::pow(qpos[i] - rts.jointLimitData[i].qposThresholdHigh, 2);
277 joint.repulsiveTorque =
278 std::clamp(joint.repulsiveTorque, 0.0f,
c.maxRepulsiveTorque);
280 rts.localStiffnessJointLim = 2 *
c.maxRepulsiveTorque /
282 std::pow(rts.jointLimitData[i].thresholdRange, 2) *
283 (qpos[i] - rts.jointLimitData[i].qposThresholdHigh);
286 rts.dampingJointLim = 2 *
std::sqrt(rts.jointInertia) *
287 std::sqrt(rts.localStiffnessJointLim) *
c.dampingFactor;
289 joint.totalDamping = rts.dampingJointLim * qvelFiltered[i];
290 rts.jointLimitJointTorque(i) =
291 -(joint.repulsiveTorque + rts.dampingJointLim * qvelFiltered[i]);
298 CollisionAvoidanceController::calculateSelfCollisionNullspace(
const Config&
c,
299 RtStatusForSafetyStrategy& rts)
const
301 rts.selfCollNullSpace.setIdentity();
307 rts.k1 = rts.selfCollisionNullSpaceWeights(0);
308 rts.k2 = rts.selfCollisionNullSpaceWeights(1);
309 rts.k3 = rts.selfCollisionNullSpaceWeights(2);
310 rts.k4 = rts.selfCollisionNullSpaceWeights(3);
314 for (
unsigned int i = 0; i < rts.activeCollPairsNum; i++)
316 auto& active = rts.selfCollDataVec[i];
319 if (active.minDistance <
c.selfCollActivatorZ1)
322 rts.desiredNullSpace = 0.0f;
324 else if (
c.selfCollActivatorZ1 <= active.minDistance &&
325 active.minDistance <=
c.selfCollActivatorZ2)
328 rts.desiredNullSpace = rts.k1 * std::pow(active.minDistance, 3) +
329 rts.k2 * std::pow(active.minDistance, 2) +
330 rts.k3 * active.minDistance + rts.k4;
331 if (rts.desiredNullSpace > 1.0f)
334 <<
"desired null space value should not be higher than 1.0, was "
335 << rts.desiredNullSpace
336 <<
", in self-collision null space calulation, weights: " << rts.k1 <<
", "
337 << rts.k2 <<
", " << rts.k3 <<
", " << rts.k4;
343 rts.desiredNullSpace = 1.0f;
347 active.desiredNSColl = rts.desiredNullSpace;
348 rts.desiredNullSpace =
std::clamp(rts.desiredNullSpace, 0.0f, 1.0f);
351 rts.normalizedJacT = active.projectedJacT.normalized();
355 rts.tempNullSpaceMatrix = I - (rts.normalizedJacT * (1.0f - rts.desiredNullSpace) *
356 rts.normalizedJacT.transpose());
358 if (
c.onlyLimitCollDirection)
362 for (
int i = 0; i < rts.impedanceJointTorque.rows(); ++i)
364 if ((active.projectedJacT(i) < 0.0f and rts.impedanceJointTorque(i) < 0.0f) ||
365 (active.projectedJacT(i) > 0.0f and rts.impedanceJointTorque(i) > 0.0f))
368 rts.tempNullSpaceMatrix(i, i) = 1.0f;
374 rts.selfCollNullSpace *= rts.tempNullSpaceMatrix;
380 CollisionAvoidanceController::calculateJointLimitNullspace(
const Config&
c,
381 RtStatusForSafetyStrategy& rts,
382 const Eigen::VectorXf& qpos)
const
385 rts.jointLimNullSpace.setIdentity();
392 for (
size_t i = 0; i < rts.jointLimitData.size(); ++i)
394 auto& joint = rts.jointLimitData[i];
397 rts.k1Lo = joint.jointLimitNullSpaceWeightsLow(0);
398 rts.k2Lo = joint.jointLimitNullSpaceWeightsLow(1);
399 rts.k3Lo = joint.jointLimitNullSpaceWeightsLow(2);
400 rts.k4Lo = joint.jointLimitNullSpaceWeightsLow(3);
401 rts.k1Hi = joint.jointLimitNullSpaceWeightsHigh(0);
402 rts.k2Hi = joint.jointLimitNullSpaceWeightsHigh(1);
403 rts.k3Hi = joint.jointLimitNullSpaceWeightsHigh(2);
404 rts.k4Hi = joint.jointLimitNullSpaceWeightsHigh(3);
408 if (not joint.isLimitless)
411 if (qpos[i] < joint.qposZ1Low)
414 rts.desiredNullSpace = 0.0f;
416 else if (joint.qposZ1Low <= qpos[i] && qpos[i] <= joint.qposZ2Low)
419 rts.desiredNullSpace = rts.k1Lo * std::pow(qpos[i], 3) +
420 rts.k2Lo * std::pow(qpos[i], 2) + rts.k3Lo * qpos[i] +
422 if (rts.desiredNullSpace > 1.0f)
425 <<
"desired null space value should not be higher than 1.0, was "
426 << rts.desiredNullSpace
427 <<
", approaching lower joint limit, weights: " << rts.k1Lo <<
", "
428 << rts.k2Lo <<
", " << rts.k3Lo <<
", " << rts.k4Lo;
431 else if (joint.qposZ2High <= qpos[i] && qpos[i] <= joint.qposZ1High)
434 rts.desiredNullSpace = rts.k1Hi * std::pow(qpos[i], 3) +
435 rts.k2Hi * std::pow(qpos[i], 2) + rts.k3Hi * qpos[i] +
437 if (rts.desiredNullSpace > 1.0f)
440 <<
"desired null space value should not be higher than 1.0, was "
441 << rts.desiredNullSpace
442 <<
", approaching upper joint limit, weights: " << rts.k1Hi <<
", "
443 << rts.k2Hi <<
", " << rts.k3Hi <<
", " << rts.k4Hi;
446 else if (joint.qposZ1High < qpos[i])
449 rts.desiredNullSpace = 0.0f;
454 rts.desiredNullSpace = 1.0f;
458 joint.desiredNSjointLim = rts.desiredNullSpace;
459 rts.desiredNullSpace =
std::clamp(rts.desiredNullSpace, 0.0f, 1.0f);
463 rts.jointLimNullSpace(i, i) = 1.0f - (1.0f - rts.desiredNullSpace);
483 constraintMatrix << std::pow(z1, 3), std::pow(z1, 2), z1, 1, std::pow(z2, 3),
484 std::pow(z2, 2), z2, 1, 3 * std::pow(z1, 2), 2 * z1, 1, 0, 3 * std::pow(z2, 2), 2 * z2,
492 return constraintMatrix.colPivHouseholderQr().solve(b);
498 CollisionAvoidanceController::run(
504 const Eigen::VectorXf& qpos,
505 const Eigen::VectorXf& qvelFiltered,
511 dynamicsModel.getInertiaMatrix(qpos.cast<
double>(), rtStatus.
inertia);
518 if (
c.enableSelfCollisionAvoidance)
521 const double timeMeasure = IceUtil::Time::now().toMicroSecondsDouble();
522 calculateSelfCollisionTorque(
c,
525 collisionRobotIndices,
528 IceUtil::Time::now().toMicroSecondsDouble() - timeMeasure;
530 if (
c.enableJointLimitAvoidance)
533 const double timeMeasure = IceUtil::Time::now().toMicroSecondsDouble();
534 calculateJointLimitTorque(
c, rtStatus, qpos, qvelFiltered);
536 IceUtil::Time::now().toMicroSecondsDouble() - timeMeasure;
540 if (
c.enableSelfCollisionAvoidance)
543 const double timeMeasure = IceUtil::Time::now().toMicroSecondsDouble();
544 calculateSelfCollisionNullspace(
c, rtStatus);
546 IceUtil::Time::now().toMicroSecondsDouble() - timeMeasure;
548 if (
c.enableJointLimitAvoidance)
551 const double timeMeasure = IceUtil::Time::now().toMicroSecondsDouble();
552 calculateJointLimitNullspace(
c, rtStatus, qpos);
554 IceUtil::Time::now().toMicroSecondsDouble() - timeMeasure;
560 if (
c.filterSafetyValues)
641 else if (
c.enableSelfCollisionAvoidance and
c.enableJointLimitAvoidance)
645 if (
c.topPrioritySelfCollisionAvoidance)
671 else if (
c.topPriorityJointLimitAvoidance)
718 else if (
c.enableSelfCollisionAvoidance)
736 else if (
c.enableJointLimitAvoidance)
785 CollisionAvoidanceController::RtStatusForSafetyStrategy::reset(
787 const unsigned int nDoF,
788 const unsigned int maxCollisionPairs,
789 VirtualRobot::RobotNodeSetPtr& rns)
792 dirErrorImp.setZero();
793 totalForceImpedance = 0.0;
794 projForceImpedance.setZero();
795 projTotalForceImpedance = 0.0;
798 impedanceJointTorque.setZero(nDoF);
799 kdImpedanceTorque.setZero(nDoF);
800 selfCollisionJointTorque.setZero(nDoF);
801 jointLimitJointTorque.setZero(nDoF);
803 selfCollisionTorqueFiltered.setZero(nDoF);
804 jointLimitTorqueFiltered.setZero(nDoF);
807 projImpedanceJointTorque.setZero(nDoF);
808 projSelfCollJointTorque.setZero(nDoF);
809 projJointLimJointTorque.setZero(nDoF);
811 impForceRatio = 0.0f;
812 impTorqueRatio = 0.0f;
815 selfCollNullSpace.resize(nDoF, nDoF);
816 selfCollNullSpace.setZero();
817 jointLimNullSpace.resize(nDoF, nDoF);
818 jointLimNullSpace.setZero();
819 desiredNullSpace = 0.0;
821 selfCollNullSpaceFiltered.resize(nDoF, nDoF);
822 selfCollNullSpaceFiltered.setZero();
823 jointLimNullSpaceFiltered.resize(nDoF, nDoF);
824 jointLimNullSpaceFiltered.setZero();
832 selfCollisionNullSpaceWeights =
836 Eigen::Vector3d point1(0.0, 0.0, 0.0);
837 Eigen::Vector3d point2(0.0, 0.0, 0.0);
838 Eigen::Vector3d
norm(0.0, 0.0, 0.0);
840 selfCollDataVec.resize(maxCollisionPairs,
848 normalizedJacT.setZero(nDoF);
849 tempNullSpaceMatrix.resize(nDoF, nDoF);
850 tempNullSpaceMatrix.setZero();
853 CollisionAvoidanceController::RtStatusForSafetyStrategy::initJointLimtDataVec(
c, nDoF, rns);
856 inertia.resize(nDoF, nDoF);
858 inertiaInverse.resize(nDoF, nDoF);
859 inertiaInverse.setZero();
862 collisionPairTime = 0.0;
864 collisionTorqueTime = 0.0;
865 jointLimitTorqueTime = 0.0;
866 selfCollNullspaceTime = 0.0;
867 jointLimitNullspaceTime = 0.0;
870 collisionPairsNum = 0;
871 activeCollPairsNum = 0;
875 CollisionAvoidanceController::RtStatusForSafetyStrategy::initJointLimtDataVec(
877 const unsigned int nDoF,
878 VirtualRobot::RobotNodeSetPtr& rns)
883 localStiffnessJointLim = 0.0;
884 dampingJointLim = 0.0;
895 jointLimitData.resize(nDoF);
898 for (
size_t i = 0; i < nDoF; ++i)
900 jointLimitData[i].jointName = rns->getNode(i)->getName();
901 jointLimitData[i].isLimitless = rns->getNode(i)->isLimitless();
903 if (not jointLimitData[i].isLimitless)
905 jointLimitData[i].qLimLow = rns->getNode(i)->getJointLimitLow();
906 jointLimitData[i].qLimHigh = rns->getNode(i)->getJointLimitHigh();
911 for (
auto& joint : jointLimitData)
913 if (not joint.isLimitless)
916 float qRange = joint.qLimHigh - joint.qLimLow;
917 joint.thresholdRange =
c.jointRangeBufferZone * qRange;
918 joint.qposThresholdLow = joint.qLimLow + joint.thresholdRange;
919 joint.qposThresholdHigh = joint.qLimHigh - joint.thresholdRange;
920 float qposZ1 =
c.jointRangeBufferZoneZ1 * qRange;
921 float qposZ2 =
c.jointRangeBufferZoneZ2 * qRange;
922 joint.qposZ1Low = joint.qLimLow + qposZ1;
923 joint.qposZ2Low = joint.qLimLow + qposZ2;
924 joint.qposZ1High = joint.qLimHigh - qposZ1;
925 joint.qposZ2High = joint.qLimHigh - qposZ2;
926 joint.jointLimitNullSpaceWeightsLow =
928 joint.jointLimitNullSpaceWeightsHigh =
1004 if (cfg.topPrioritySelfCollisionAvoidance)
1008 (cfg.topPrioritySelfCollisionAvoidance == !cfg.topPriorityJointLimitAvoidance));
1010 if (cfg.topPriorityJointLimitAvoidance)
1014 (cfg.topPrioritySelfCollisionAvoidance == !cfg.topPriorityJointLimitAvoidance));