25 #include <SimoxUtility/algorithm/string/string_tools.h>
41 #define RAWFORCE "_rawforcevectors"
42 #define OFFSETFORCE "_forceswithoffsetvectors"
43 #define FILTEREDFORCE "_filteredforcesvectors"
44 #define RAWTORQUE "_rawtorquevectors"
45 #define OFFSETTORQUE "_torqueswithoffsetvectors"
46 #define FORCETORQUEVECTORS "_forceTorqueVectors"
47 #define POD_SUFFIX "_pod"
58 this->topicName = topicName;
64 if (topicName.empty())
66 usingTopic(getProperty<std::string>(
"ForceTorqueTopicName").getValue());
83 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
86 auto sensorRobotNodeSplit =
87 armarx::Split(getProperty<std::string>(
"SensorRobotNodeMapping").getValue(),
",");
88 for (
auto& elem : sensorRobotNodeSplit)
92 if (
split.size() >= 2)
94 sensorRobotNodeMapping.emplace(
105 robot = getProxy<RobotStateComponentInterfacePrx>(
106 getProperty<std::string>(
"RobotStateComponentName").getValue());
109 debugDrawer = getTopic<DebugDrawerInterfacePrx>(
"DebugDrawerUpdates");
110 if (getProperty<bool>(
"VisualizeForce").getValue())
115 1000 / getProperty<int>(
"VisualizeForceUpdateFrequency").getValue(),
117 "visualizerFunction");
118 visualizerTask->start();
122 &ForceTorqueObserver::updateRobot,
123 1000 / getProperty<int>(
"RobotUpdateFrequency").getValue(),
127 updateRobotTask->start();
137 float maxTorque = getProperty<float>(
"MaxExpectedTorqueValue");
138 float torqueVisuDeadZone = getProperty<float>(
"TorqueVisuDeadZone");
139 float arrowLength = getProperty<float>(
"MaxForceArrowLength").getValue();
140 float forceFactor = getProperty<float>(
"ForceVisualizerFactor").getValue();
142 auto batchPrx = debugDrawer->ice_batchOneway();
144 std::unique_lock lock(dataMutex);
146 std::set<std::string> frameAlreadyReported;
147 for (
auto& channel : channels)
157 if (frameAlreadyReported.count(
value->frame) > 0 ||
159 !localRobot->hasRobotNode(
value->frame)))
163 frameAlreadyReported.insert(
value->frame);
164 auto force =
value->toGlobal(localRobot);
166 << channel.first <<
" : " << force->toEigen()
167 <<
" original frame: " <<
value->frame;
169 float forceMag = force->toEigen().norm() * forceFactor;
171 new Vector3(localRobot->getRobotNode(
value->frame)->getGlobalPose());
172 forceMag =
std::min(1.0f, forceMag);
173 batchPrx->setArrowVisu(
"Forces",
174 "Force" + channel.first,
177 DrawColor{forceMag, 1.0f - forceMag, 0.0f, 0.5f},
178 std::max(arrowLength * forceMag, 10.f),
181 field = DatafieldRefPtr::dynamicCast(
187 Eigen::Vector3f dirXglobal =
188 FramedDirection(Eigen::Vector3f::UnitX(), torque->frame, torque->agent)
189 .toGlobalEigen(localRobot);
190 Eigen::Vector3f dirYglobal =
191 FramedDirection(Eigen::Vector3f::UnitY(), torque->frame, torque->agent)
192 .toGlobalEigen(localRobot);
193 Eigen::Vector3f dirZglobal =
194 FramedDirection(Eigen::Vector3f::UnitZ(), torque->frame, torque->agent)
195 .toGlobalEigen(localRobot);
197 if (fabs(torque->x) > torqueVisuDeadZone)
199 batchPrx->setCircleArrowVisu(
"Torques",
200 "TorqueX" + channel.first,
204 torque->x / maxTorque,
205 3 *
std::max(1.0f, torque->x / maxTorque),
206 DrawColor{1.0f, 0.0f, 0.0f, 0.5f});
210 batchPrx->removeCircleVisu(
"Torques",
"TorqueX" + channel.first);
212 if (fabs(torque->y) > torqueVisuDeadZone)
214 batchPrx->setCircleArrowVisu(
"Torques",
215 "TorqueY" + channel.first,
219 torque->y / maxTorque,
220 3 *
std::max(1.0f, torque->y / maxTorque),
221 DrawColor{0.0f, 1.0f, 0.0f, 0.5f});
225 batchPrx->removeCircleVisu(
"Torques",
"TorqueY" + channel.first);
227 if (fabs(torque->z) > torqueVisuDeadZone)
229 batchPrx->setCircleArrowVisu(
"Torques",
230 "TorqueZ" + channel.first,
234 torque->z / maxTorque,
235 3 *
std::max(1.0f, torque->z / maxTorque),
236 DrawColor{0.0f, 0.0f, 1.0f, 0.5f});
240 batchPrx->removeCircleVisu(
"Torques",
"TorqueZ" + channel.first);
254 batchPrx->ice_flushBatchRequests();
265 ForceTorqueObserver::updateRobot()
267 std::unique_lock lock(dataMutex);
272 ForceTorqueObserver::offerValue(
const std::string& nodeName,
273 const std::string& type,
274 const FramedDirectionBasePtr&
value,
286 ARMARX_INFO <<
"Creating force/torque fields for node " << nodeName <<
" with id "
287 <<
id->getIdentifierStr();
293 type +
" vectors on specific parts of the robot.");
298 "3D vector for " + type +
" of " + nodeName);
304 std::string pod_channelName =
id->channelName +
POD_SUFFIX;
309 values[
id->datafieldName +
"_x"] =
new Variant(vec->x);
310 values[
id->datafieldName +
"_y"] =
new Variant(vec->y);
311 values[
id->datafieldName +
"_z"] =
new Variant(vec->z);
312 values[
id->datafieldName +
"_frame"] =
new Variant(vec->frame);
321 id->datafieldName +
" on " + nodeName +
" as plain old data (pod)");
324 pod_channelName, id->datafieldName +
"_x", Variant(vec->x), type +
" on X axis");
326 pod_channelName, id->datafieldName +
"_y", Variant(vec->y), type +
" on Y axis");
328 pod_channelName, id->datafieldName +
"_z", Variant(vec->z), type +
" on Z axis");
330 id->datafieldName +
"_frame",
332 "Frame of " +
value->frame);
338 const FramedDirectionBasePtr& forces,
339 const FramedDirectionBasePtr& torques,
340 const Ice::Current&
c)
342 std::unique_lock lock(dataMutex);
344 auto offerForceAndTorqueValue = [=,
this](std::string
const& sensorNodeName,
345 std::string
const& frame,
346 std::string channelName,
347 const FramedDirectionBasePtr& forces,
348 const FramedDirectionBasePtr& torques)
356 if (channelName.empty())
358 id = getForceDatafieldId(sensorNodeName, frame);
365 offerValue(sensorNodeName, id->datafieldName, forces,
id);
370 if (channelName.empty())
372 id = getTorqueDatafieldId(sensorNodeName, frame);
379 offerValue(sensorNodeName, id->datafieldName, torques,
id);
382 updateChannel(id->channelName);
385 catch (std::exception&)
387 ARMARX_ERROR <<
"Reporting force torque for " << sensorNodeName <<
" failed! ";
399 realTorques->changeFrame(
localRobot, forces->frame);
402 offerForceAndTorqueValue(sensorNodeName, forces->frame,
"", realForces, realTorques);
404 auto sensorMappingRange = sensorRobotNodeMapping.equal_range(sensorNodeName);
405 for (
auto iter = sensorMappingRange.first; iter != sensorMappingRange.second; ++iter)
407 auto& sensorName = iter->first;
408 auto& robotNodeName = iter->second.first;
409 auto& channelName = iter->second.second;
411 FramedDirectionPtr torquesCopy = FramedDirectionPtr::dynamicCast(realTorques->clone());
412 forcesCopy->changeFrame(
localRobot, robotNodeName);
413 torquesCopy->changeFrame(
localRobot, robotNodeName);
415 offerForceAndTorqueValue(
416 sensorName, robotNodeName, channelName, forcesCopy, torquesCopy);
422 const DatafieldRefBasePtr& forceTorqueDatafieldRef,
435 throw UserException(
"No sensor for node '" + nodeName +
"'available: channel " +
441 throw UserException(
"No sensor for node '" + nodeName +
"'available: datafield " +
445 return new DatafieldRef(
this, id->channelName, id->datafieldName);
455 throw UserException(
"No sensor for node '" + nodeName +
"'available: channel " +
461 throw UserException(
"No sensor for node '" + nodeName +
"'available: datafield " +
465 return new DatafieldRef(
this, id->channelName, id->datafieldName);
471 std::string channelName;
473 if (frame == nodeName)
475 channelName = nodeName;
479 channelName = nodeName +
"_" + frame;
482 std::string datafieldName =
"forces";
490 std::string channelName;
492 if (frame == nodeName)
494 channelName = nodeName;
498 channelName = nodeName +
"_" + frame;
501 std::string datafieldName =
"torques";
511 visualizerTask->stop();
515 updateRobotTask->stop();