39 #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;
63 if (topicName.empty())
65 usingTopic(getProperty<std::string>(
"ForceTorqueTopicName").getValue());
82 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
85 auto sensorRobotNodeSplit =
armarx::Split(getProperty<std::string>(
"SensorRobotNodeMapping").getValue(),
",");
86 for (
auto& elem : sensorRobotNodeSplit)
88 simox::alg::trim(elem);
90 if (
split.size() >= 2)
92 sensorRobotNodeMapping.emplace(
93 simox::alg::trim_copy(
split.at(0)),
94 std::make_pair(simox::alg::trim_copy(
split.at(1)),
95 split.size() >= 3 ? simox::alg::trim_copy(
split.at(2)) :
""));
102 robot = getProxy<RobotStateComponentInterfacePrx>(getProperty<std::string>(
"RobotStateComponentName").getValue());
104 debugDrawer = getTopic<DebugDrawerInterfacePrx>(
"DebugDrawerUpdates");
105 if (getProperty<bool>(
"VisualizeForce").getValue())
108 visualizerTask->start();
110 updateRobotTask =
new PeriodicTask<ForceTorqueObserver>(
this, &ForceTorqueObserver::updateRobot, 1000 / getProperty<int>(
"RobotUpdateFrequency").getValue(),
false,
"updateRobot",
false);
111 updateRobotTask->start();
121 float maxTorque = getProperty<float>(
"MaxExpectedTorqueValue");
122 float torqueVisuDeadZone = getProperty<float>(
"TorqueVisuDeadZone");
123 float arrowLength = getProperty<float>(
"MaxForceArrowLength").getValue();
124 float forceFactor = getProperty<float>(
"ForceVisualizerFactor").getValue();
126 auto batchPrx = debugDrawer->ice_batchOneway();
128 std::unique_lock lock(dataMutex);
130 std::set<std::string> frameAlreadyReported;
131 for (
auto& channel : channels)
144 frameAlreadyReported.insert(
value->frame);
145 auto force =
value->toGlobal(localRobot);
148 float forceMag = force->toEigen().norm() * forceFactor;
150 forceMag =
std::min(1.0f, forceMag);
151 batchPrx->setArrowVisu(
"Forces",
152 "Force" + channel.first,
155 DrawColor {forceMag, 1.0f - forceMag, 0.0f, 0.5f},
156 std::max(arrowLength * forceMag, 10.f),
159 field = DatafieldRefPtr::dynamicCast(
getTorqueDatafield(channel.first, Ice::emptyCurrent));
164 Eigen::Vector3f dirXglobal =
FramedDirection(Eigen::Vector3f::UnitX(), torque->frame, torque->agent).toGlobalEigen(localRobot);
165 Eigen::Vector3f dirYglobal =
FramedDirection(Eigen::Vector3f::UnitY(), torque->frame, torque->agent).toGlobalEigen(localRobot);
166 Eigen::Vector3f dirZglobal =
FramedDirection(Eigen::Vector3f::UnitZ(), torque->frame, torque->agent).toGlobalEigen(localRobot);
168 if (fabs(torque->x) > torqueVisuDeadZone)
170 batchPrx->setCircleArrowVisu(
"Torques",
171 "TorqueX" + channel.first,
175 torque->x / maxTorque,
176 3 *
std::max(1.0f, torque->x / maxTorque),
177 DrawColor {1.0f, 0.0f, 0.0f, 0.5f}
182 batchPrx->removeCircleVisu(
"Torques",
183 "TorqueX" + channel.first);
185 if (fabs(torque->y) > torqueVisuDeadZone)
187 batchPrx->setCircleArrowVisu(
"Torques",
188 "TorqueY" + channel.first,
192 torque->y / maxTorque,
193 3 *
std::max(1.0f, torque->y / maxTorque),
194 DrawColor {0.0f, 1.0f, 0.0f, 0.5f}
199 batchPrx->removeCircleVisu(
"Torques",
200 "TorqueY" + channel.first);
203 if (fabs(torque->z) > torqueVisuDeadZone)
205 batchPrx->setCircleArrowVisu(
"Torques",
206 "TorqueZ" + channel.first,
210 torque->z / maxTorque,
211 3 *
std::max(1.0f, torque->z / maxTorque),
212 DrawColor {0.0f, 0.0f, 1.0f, 0.5f}
217 batchPrx->removeCircleVisu(
"Torques",
218 "TorqueZ" + channel.first);
235 batchPrx->ice_flushBatchRequests();
245 void ForceTorqueObserver::updateRobot()
247 std::unique_lock lock(dataMutex);
252 void ForceTorqueObserver::offerValue(
const std::string& nodeName,
const std::string& type,
const FramedDirectionBasePtr&
value,
const DataFieldIdentifierPtr&
id)
265 ARMARX_INFO <<
"Creating force/torque fields for node " << nodeName <<
" with id " <<
id->getIdentifierStr();
270 offerChannel(id->channelName, type +
" vectors on specific parts of the robot.");
278 std::string pod_channelName =
id->channelName +
POD_SUFFIX;
283 values[
id->datafieldName +
"_x" ] =
new Variant(vec->x);
284 values[
id->datafieldName +
"_y" ] =
new Variant(vec->y);
285 values[
id->datafieldName +
"_z" ] =
new Variant(vec->z);
286 values[
id->datafieldName +
"_frame"] =
new Variant(vec->frame);
294 offerChannel(pod_channelName, id->datafieldName +
" on " + nodeName +
" as plain old data (pod)");
309 std::unique_lock lock(dataMutex);
311 auto offerForceAndTorqueValue = [ =, this ](std::string
const & sensorNodeName, std::string
const & frame, std::string channelName,
const FramedDirectionBasePtr & forces,
const FramedDirectionBasePtr & torques)
319 if (channelName.empty())
321 id = getForceDatafieldId(sensorNodeName, frame);
328 offerValue(sensorNodeName, id->datafieldName, forces,
id);
333 if (channelName.empty())
335 id = getTorqueDatafieldId(sensorNodeName, frame);
342 offerValue(sensorNodeName, id->datafieldName, torques,
id);
345 updateChannel(id->channelName);
348 catch (std::exception&)
350 ARMARX_ERROR <<
"Reporting force torque for " << sensorNodeName <<
" failed! ";
363 realTorques->changeFrame(localRobot, forces->frame);
366 offerForceAndTorqueValue(sensorNodeName, forces->frame,
"", realForces, realTorques);
368 auto sensorMappingRange = sensorRobotNodeMapping.equal_range(sensorNodeName);
369 for (
auto iter = sensorMappingRange.first; iter != sensorMappingRange.second; ++iter)
371 auto& sensorName = iter->first;
372 auto& robotNodeName = iter->second.first;
373 auto& channelName = iter->second.second;
375 FramedDirectionPtr torquesCopy = FramedDirectionPtr::dynamicCast(realTorques->clone());
376 forcesCopy->changeFrame(localRobot, robotNodeName);
377 torquesCopy->changeFrame(localRobot, robotNodeName);
379 offerForceAndTorqueValue(sensorName, robotNodeName, channelName, forcesCopy, torquesCopy);
395 throw UserException(
"No sensor for node '" + nodeName +
"'available: channel " + id->channelName);
400 throw UserException(
"No sensor for node '" + nodeName +
"'available: datafield " + id->datafieldName);
403 return new DatafieldRef(
this, id->channelName, id->datafieldName);
413 throw UserException(
"No sensor for node '" + nodeName +
"'available: channel " + id->channelName);
418 throw UserException(
"No sensor for node '" + nodeName +
"'available: datafield " + id->datafieldName);
421 return new DatafieldRef(
this, id->channelName, id->datafieldName);
426 std::string channelName;
428 if (frame == nodeName)
430 channelName = nodeName;
434 channelName = nodeName +
"_" + frame;
437 std::string datafieldName =
"forces";
444 std::string channelName;
446 if (frame == nodeName)
448 channelName = nodeName;
452 channelName = nodeName +
"_" + frame;
455 std::string datafieldName =
"torques";
464 visualizerTask->stop();
468 updateRobotTask->stop();