25#include <SimoxUtility/color/Color.h>
26#include <VirtualRobot/MathTools.h>
27#include <VirtualRobot/RobotNodeSet.h>
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>
45#include <armarx/control/common/control_law/aron/CollisionPrimitives.aron.generated.h>
50 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
53 const NJointControllerConfigPtr& config,
55 NJointControllerType{
robotUnit, config, robot}
57 auto cfg = ConfigPtrT::dynamicCast(config);
59 userCfgWithColl_ = CollisionCtrlCfg::FromAron(cfg->config);
61 std::map<std::string, std::vector<size_t>> velCtrlIndices;
62 for (
auto& arm : this->
limb)
64 velCtrlIndices.emplace(arm.first, arm.second->rtStatus.jointIDVelocityMode);
66 coll = std::make_shared<CollAvoidBase>(
67 this->
rtGetRobot(), userCfgWithColl_.coll, velCtrlIndices);
68 collReady_.store(
true);
73 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
77 arm->controller.run(arm->rtConfig, arm->rtStatus);
79 if (collReady_.load())
86 coll->rtLimbControllerRun(arm->kinematicChainName,
87 arm->rtConfig.torqueLimit,
88 arm->rtConfig.velocityLimit,
112 arm->rtStatus.nDoFTorque,
113 arm->rtStatus.nDoFVelocity,
114 arm->rtStatus.desiredJointTorque,
115 arm->rtStatus.desiredJointVelocity);
118 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
121 const IceUtil::Time& ,
122 const IceUtil::Time& timeSinceLastIteration)
124 double deltaT = timeSinceLastIteration.toSecondsDouble();
127 if (collReady_.load())
130 coll->updateRtConfigFromUser();
131 coll->updateRtCollisionObjects();
132 coll->rtCollisionChecking();
134 for (
auto& pair : this->limb)
136 this->limbRTUpdateStatus(pair.second, deltaT);
139 this->rtRunCoordinator(deltaT);
141 for (
auto& pair : this->limb)
147 this->hands->updateRTStatus(deltaT);
151 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
154 const ::armarx::aron::data::dto::DictPtr& dto,
155 const Ice::Current& )
158 auto cfg = common::control_law::arondto::ObjectCollisionAvoidanceConfigDict::FromAron(dto);
159 coll->setUserCfg(cfg);
162 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
166 size_t numCollisionObjects = 0;
169 numCollisionObjects += pair.second.size();
172 std::vector<hpp::fcl::CollisionObject> allCollisionObjects;
173 allCollisionObjects.reserve(numCollisionObjects);
176 allCollisionObjects.insert(
177 allCollisionObjects.end(), pair.second.begin(), pair.second.end());
180 coll->updateUserCollisionObjects(allCollisionObjects);
183 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
186 const Ice::Current& )
188 coll->deleteUserCollisionObjects();
191 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
194 const std::string& primitiveSourceName,
195 const ::armarx::aron::data::dto::DictPtr& dtoScene,
196 const Ice::Current& )
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;
208 collisionObjects.emplace(primitiveSourceName, std::vector<hpp::fcl::CollisionObject>());
210 std::vector<hpp::fcl::CollisionObject>& collisionObjectsOfSource =
212 collisionObjectsOfSource.clear();
213 collisionObjectsOfSource.reserve(boxes.size() + spheres.size() + cylinders.size() +
214 capsules.size() + ellipsoids.size());
216 for (
const auto& box : boxes)
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}));
224 for (
const auto& sphere : spheres)
226 collisionObjectsOfSource.push_back(simox::control::environment::createCollisionObject(
227 simox::control::utils::primitive::Sphere{.radius = sphere.radius},
228 Eigen::Isometry3d{sphere.transformation}));
231 for (
const auto& cylinder : cylinders)
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}));
239 for (
const auto& capsule : capsules)
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}));
247 for (
const auto& ellipsoid : ellipsoids)
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}));
259 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
262 const Ice::Current& )
264 if (not collReady_.load())
270 return coll->userCfg.toAronDTO();
273 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
276 const ::armarx::aron::data::dto::DictPtr& dto,
277 const Ice::Current& )
279 NJointControllerType::updateConfig(dto);
280 userCfgWithColl_ = CollisionCtrlCfg::FromAron(dto);
282 coll->setUserCfg(userCfgWithColl_.coll);
285 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
288 const Ice::Current& )
295 NJointControllerType::getConfig();
296 userCfgWithColl_.limbs = this->userConfig.limbs;
297 userCfgWithColl_.hands = this->userConfig.hands;
298 return userCfgWithColl_.toAronDTO();
301 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
308 NJointControllerType::onPublish(sc, drawer, debugObs);
311 for (
auto& pair :
coll->collLimb)
318 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
330 datafields[
"collDistanceThreshold"] =
new Variant(recoveryState.collDistanceThreshold);
331 datafields[
"collDistanceThresholdInit"] =
332 new Variant(recoveryState.collDistanceThresholdInit);
334 datafields[
"trackingError"] =
new Variant(rtStatus.trackingError);
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));
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));
355 datafields,
"projectedImpedanceTorque", rtStatus.projImpedanceJointTorque);
361 const Eigen::VectorXf selfCollNullspace = rtStatus.selfCollNullSpace.diagonal();
362 const Eigen::VectorXf jointLimNullspace = rtStatus.jointLimNullSpace.diagonal();
385 datafields[
"collisionPairsNum"] =
new Variant(rtStatus.collisionPairsNum);
386 datafields[
"activeCollPairsNum"] =
new Variant(rtStatus.activeCollPairsNum);
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);
394 datafields[
"impForceRatio"] =
new Variant(rtStatus.impForceRatio);
395 datafields[
"impTorqueRatio"] =
new Variant(rtStatus.impTorqueRatio);
397 for (
unsigned int i = 0; i < rtStatus.activeCollPairsNum; ++i)
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);
679 debugObs->setDebugChannel(
"CollAvoid_ImpCtrl_" + arm.
nodeSetName, datafields);
682 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
686 const std::vector<hpp::fcl::CollisionObject>&
objects)
688 for (
size_t i = 0; i <
objects.size(); ++i)
691 const auto position =
object.getTranslation().cast<
float>() * 1000;
692 const Eigen::Matrix3f rotation =
object.getRotation().cast<
float>();
694 switch (
object.getNodeType())
696 case hpp::fcl::NODE_TYPE::GEOM_BOX:
698 const hpp::fcl::Box* box =
699 std::static_pointer_cast<hpp::fcl::Box>(
object.collisionGeometry()).get();
701 .
size(box->halfSide.cast<
float>() * 1000 * 2)
704 .
color(255, 0, 0, 128);
705 layer.
add(vizObject);
708 case hpp::fcl::NODE_TYPE::GEOM_SPHERE:
710 const hpp::fcl::Sphere* sphere =
711 std::static_pointer_cast<hpp::fcl::Sphere>(
object.collisionGeometry())
715 .
radius(
static_cast<float>(sphere->radius) * 1000)
718 .
color(0, 0, 255, 128);
719 layer.
add(vizObject);
722 case hpp::fcl::NODE_TYPE::GEOM_CYLINDER:
724 const hpp::fcl::Cylinder* cylinder =
725 std::static_pointer_cast<hpp::fcl::Cylinder>(
object.collisionGeometry())
729 .
height(
static_cast<float>(cylinder->halfLength) * 1000 * 2)
730 .
radius(
static_cast<float>(cylinder->radius) * 1000)
732 Eigen::AngleAxisf(
M_PI / 2., Eigen::Vector3f::UnitX()))
734 .
color(0, 255, 0, 128);
735 layer.
add(vizObject);
738 case hpp::fcl::NODE_TYPE::GEOM_CAPSULE:
740 const hpp::fcl::Capsule* capsule =
741 std::static_pointer_cast<hpp::fcl::Capsule>(
object.collisionGeometry())
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;
750 .
radius(
static_cast<float>(capsule->radius) * 1000)
753 .
color(255, 200, 0, 128);
755 .
radius(
static_cast<float>(capsule->radius) * 1000)
758 .
color(255, 200, 0, 128);
761 .
height(
static_cast<float>(capsule->halfLength) * 1000 * 2)
762 .
radius(
static_cast<float>(capsule->radius) * 1000)
763 .
color(255, 200, 0, 128)
766 layer.
add(vizObject);
771 case hpp::fcl::NODE_TYPE::GEOM_ELLIPSOID:
773 const hpp::fcl::Ellipsoid* ellipsoid =
774 std::static_pointer_cast<hpp::fcl::Ellipsoid>(
object.collisionGeometry())
779 .
axisLengths(ellipsoid->radii.cast<
float>() * 1000)
782 .
color(255, 0, 200, 128);
783 layer.
add(vizObject);
791 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
796 NJointControllerType::collectArviz(stage);
798 auto transformVector = [](
const Eigen::Matrix4f& pose,
799 const Eigen::Vector3f& vec) -> Eigen::Vector3f
804 for (
const auto& [_, arm] :
coll->collLimb)
806 const auto& rtStatus = arm.bufferRTtoPublish.getUpToDateReadBuffer();
808 viz::Layer layer = this->scopedArviz->layer(
"ColStatus_" + arm.nodeSetName);
810 for (
unsigned int i = 0; i < rtStatus.activeCollPairsNum; ++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())
859 if (not
coll->userCollisionObjects.empty())
861 viz::Layer layer = this->scopedArviz->layer(
"ColStatus_objectModels");
865 const bool enableRobotPrimitiveVis =
true;
866 if (enableRobotPrimitiveVis)
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)
875 robotObjectsByValue.push_back(*ptr);
877 viz::Layer layer = this->scopedArviz->layer(
"ColStatus_robotModel");
884 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
890 NJointControllerType::rtPreActivateController();
892 if (collReady_.load())
895 coll->rtPreActivate();
899 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
903 NJointControllerType::rtPostDeactivateController();
904 if (collReady_.load())
907 coll->rtPostDeactivate();
913 template <
typename NJo
intControllerType,
typename CollisionCtrlCfg>
918 auto cfgName = values.at(
"config_box")->getString();
921 "controller_config/" + std::string(NJointControllerType::ControlType::TypeName) +
922 "Col/" + cfgName +
".json");
929 return new ConfigurableNJointControllerConfig{cfgDTO.toAronDTO()};
934 law::arondto::TSMixImpVelColConfigDict>;
941 const NJointControllerConfigPtr& config,
954 return "TSMixImpVelCol";
965 const NJointControllerConfigPtr& config,
988 const NJointControllerConfigPtr& config,
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.
void collectArviz(viz::StagedCommit &stage) const override
void sendCollisionObjects()
NJointTSColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
std::map< std::string, std::vector< hpp::fcl::CollisionObject > > collisionObjects
static ConfigPtrT GenerateConfigFromVariants(const StringVariantBaseMap &values)
static void AddArvizObjects(viz::Layer &layer, const std::vector< hpp::fcl::CollisionObject > &objects)
void rtPostDeactivateController() override
void collLimbPublish(CollAvoidBase::NodeSetData &arm, const DebugObserverInterfacePrx &debugObs)
void updateCollisionAvoidanceConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
NJointController interface for collision avoidance.
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
typename NJointControllerType::ConfigPtrT ConfigPtrT
void onPublish(const SensorAndControl &sc, const DebugDrawerInterfacePrx &drawer, const DebugObserverInterfacePrx &) override
typename NJointControllerType::ArmPtr ArmPtr
::armarx::aron::data::dto::DictPtr getConfig(const Ice::Current &iceCurrent) override
void updateCollisionObjects(const std::string &primitiveSourceName, const ::armarx::aron::data::dto::DictPtr &dtoScene, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
void rtPreActivateController() override
NJointControllerBase interface.
void updateConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent) override
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
NJointTSImpColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
NJointTSMixImpVelColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
NJointTSVeloColController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
std::map< std::string, ArmPtr > limb
void limbRTSetTarget(ArmPtr &arm, const size_t nDoFTorque, const size_t nDoFVelocity, const Eigen::VectorXf &targetTorque, const Eigen::VectorXf &targetVelocity)
DerivedT & color(Color color)
DerivedT & position(float x, float y, float z)
DerivedT & orientation(Eigen::Quaternionf const &ori)
DerivedT & scale(Eigen::Vector3f scale)
#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.
armarx::aron::data::dto::Dict getCollisionAvoidanceConfig()
void deleteCollisionObjects()
std::shared_ptr< class Robot > RobotPtr
::IceInternal::Handle< Dict > DictPtr
void debugEigenVec(StringVariantBaseMap &datafields, const std::string &name, Eigen::VectorXf vec)
Eigen::Block< Eigen::Matrix4f, 3, 3 > getOri(Eigen::Matrix4f &matrix)
Eigen::Block< Eigen::Matrix4f, 3, 1 > getPos(Eigen::Matrix4f &matrix)
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
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
armarx::TripleBuffer< RecoveryState > bufferRecoveryStateSelfColl
armarx::TripleBuffer< RtStatus > bufferRTtoPublish
Box & size(Eigen::Vector3f const &s)
Cylinder & height(float h)
Cylinder & radius(float r)
Ellipsoid & axisLengths(const Eigen::Vector3f &axisLengths)
void add(ElementT const &element)
A staged commit prepares multiple layers to be committed.
void add(Layer const &layer)
Stage a layer to be committed later via client.apply(*this)