7#include <Eigen/Geometry>
9#include <SimoxUtility/algorithm/get_map_keys_values.h>
10#include <SimoxUtility/algorithm/string/string_tools.h>
11#include <SimoxUtility/math/pose.h>
12#include <SimoxUtility/math/rescale.h>
13#include <VirtualRobot/Nodes/Sensor.h>
14#include <VirtualRobot/XML/RobotIO.h>
19#include <ArmarXCore/interface/core/PackagePath.h>
36 descriptionSegment(descriptionSegment),
37 proprioceptionSegment(proprioceptionSegment),
38 localizationSegment(localizationSegment)
47 p.enabled, prefix +
"enabled",
"Enable or disable visualization of objects.");
48 defs->optional(p.frequencyHz, prefix +
"frequenzyHz",
"Frequency of visualization.");
49 defs->optional(p.framesEnabled,
50 prefix +
"framesEnabled",
51 "Enable or disable visualization of frames.");
52 defs->optional(p.forceTorque.enabled,
53 prefix +
"forceTorque.enabled",
54 "Enable or disable visualization of force torque sensors.");
55 defs->optional(p.forceTorque.forceScale,
56 prefix +
"forceTorque.forceScale",
57 "Scaling of force arrows.");
58 defs->optional(p.collisionModelEnabled,
59 prefix +
"collisionModelEnabled",
60 "Enable visualization of collision model.");
74 bool batchMode =
true;
95 const armarx::data::PackagePath xmlPath = robot.description.xml.serialize();
97 const auto* robotModel = getRobotModel(robot.description);
99 std::map<std::string, float> jointMap = robot.config.jointMap;
102 if (robotModel !=
nullptr)
104 for (
const auto& [jointName, jointValue] : robotModel->model->getJointValues())
106 if (jointMap.count(jointName) == 0)
108 jointMap[jointName] = jointValue;
115 .
file(xmlPath.package, xmlPath.package +
"/" + xmlPath.path)
117 .
pose(robot.config.globalPose);
129 layer.
add(robotVisu);
134 Visu::visualizeFrames(
135 viz::Layer& layerFrames,
136 const std::unordered_map<std::string, std::vector<Eigen::Isometry3f>>& frames)
138 for (
const auto& [robotName, robotFrames] : frames)
140 Eigen::Isometry3f pose = Eigen::Isometry3f::Identity();
143 for (
const auto& frame : robotFrames)
145 Eigen::Isometry3f
from = pose;
146 Eigen::Isometry3f to = pose * frame;
150 layerFrames.
add(viz::Arrow(robotName + std::to_string(++i))
151 .fromTo(
from.translation(), to.translation()));
157 Visu::visualizeFramesIndividual(
158 viz::Layer& layerFrames,
159 const std::unordered_map<std::string, std::vector<Eigen::Isometry3f>>& frames)
162 std::vector<std::string> FRAME_NAMES{
"map",
"odom",
"robot"};
164 for (
const auto& [robotName, robotFrames] : frames)
167 for (
const auto& frame : robotFrames)
170 viz::Pose(robotName + FRAME_NAMES.at(i++)).pose(frame.matrix()).scale(3));
178 CycleUtil cycle(
static_cast<int>(1000 / p.frequencyHz));
179 while (updateTask and not updateTask->isStopped())
190 catch (
const std::out_of_range& e)
192 ARMARX_WARNING <<
"Caught std::out_of_range while visualizing robots: \n"
195 catch (
const std::exception& e)
197 ARMARX_WARNING <<
"Caught exception while visualizing robots: \n" << e.what();
201 ARMARX_WARNING <<
"Caught unknown exception while visualizing robots.";
204 if (debugObserver.has_value())
206 debugObserver->sendDebugObserverBatch();
209 cycle.waitForCycleDuration();
225 descriptionSegment.getRobotDescriptionsLocking(
timestamp);
229 const auto globalPoses = localizationSegment.getRobotGlobalPosesLocking(
timestamp);
233 const auto frames = localizationSegment.getRobotFramePosesLocking(
timestamp);
238 proprioceptionSegment.getSensorValuesLocking(
timestamp,
239 debugObserver ? &*debugObserver :
nullptr);
254 <<
"\n- " << robotDescriptions.size() <<
" descriptions"
255 <<
"\n- " << globalPoses.size() <<
" global poses"
256 <<
"\n- " << sensorValues.size() <<
" joint positions";
261 ARMARX_DEBUG <<
"Visualize " << robots.size() <<
" robots ...";
262 std::vector<viz::Layer> layers;
265 viz::Layer& layer = layers.emplace_back(arviz.layer(
"Robots"));
266 visualizeRobots(layer, robots,
false);
269 if (p.collisionModelEnabled)
271 viz::Layer& layer = layers.emplace_back(arviz.layer(
"RobotsCol"));
272 visualizeRobots(layer, robots,
true);
278 viz::Layer& layer = layers.emplace_back(arviz.layer(
"Localization Frames"));
279 visualizeFrames(layer, frames);
285 viz::Layer& layer = layers.emplace_back(arviz.layer(
"Localization Frames Individual"));
286 visualizeFramesIndividual(layer, frames);
289 if (p.forceTorque.enabled)
291 viz::Layer& layerForceTorque = layers.emplace_back(arviz.layer(
"Force Torque"));
292 std::stringstream log;
294 for (
const armem::robot_state::Robot& robot : robots)
296 const std::string& robotName = robot.description.name;
298 auto itSensorValues = sensorValues.find(robotName);
299 if (itSensorValues == sensorValues.end())
301 log <<
"\nNo robot '" << robotName <<
"' in sensor values. Available are: ";
302 log << simox::alg::join(simox::alg::get_keys(sensorValues),
", ");
306 visualizeForceTorque(layerForceTorque, robot, itSensorValues->second);
309 if (not log.str().empty())
311 ARMARX_INFO <<
"While visualizing robot force torques: " << log.str();
320 arviz.commit(layers);
325 if (debugObserver.has_value())
327 const std::string p =
"Visu | ";
328 debugObserver->setDebugObserverDatafield(p +
"t Total (ms)",
329 tVisuTotal.toMilliSecondsDouble());
330 debugObserver->setDebugObserverDatafield(p +
"t 1 Get Data (ms)",
331 tVisuGetData.toMilliSecondsDouble());
332 debugObserver->setDebugObserverDatafield(p +
"t 1.1 Descriptions (ms)",
333 tRobotDescriptions.toMilliSecondsDouble());
334 debugObserver->setDebugObserverDatafield(p +
"t 1.2 Global Poses (ms)",
335 tGlobalPoses.toMilliSecondsDouble());
336 debugObserver->setDebugObserverDatafield(p +
"t 1.3 Frames (ms)",
337 tRobotFramePoses.toMilliSecondsDouble());
338 debugObserver->setDebugObserverDatafield(p +
"t 1.4 Sensor Values (ms)",
339 tSensorValues.toMilliSecondsDouble());
340 debugObserver->setDebugObserverDatafield(p +
"t 2 Build Layers (ms)",
341 tVisuBuildLayers.toMilliSecondsDouble());
342 debugObserver->setDebugObserverDatafield(p +
"t 3 Commit (ms)",
343 tVisuCommit.toMilliSecondsDouble());
348 Visu::getRobotModel(
const armem::robot_state::description::RobotDescription& robotDescription)
350 const std::string& robotName = robotDescription.
name;
352 RobotModel* robotModel =
nullptr;
353 if (
auto it = models.find(robotName); it != models.end())
355 robotModel = &it->second;
359 const std::filesystem::path robotPath = robotDescription.
xml.
toSystemPath();
360 ARMARX_INFO <<
"Loading robot model for '" << robotName <<
"' from " << robotPath
361 <<
" for visualization.";
362 auto [it2, _] = models.emplace(robotName, robotPath);
363 robotModel = &it2->second;
369 Visu::visualizeForceTorque(viz::Layer& layer,
370 const armem::robot_state::Robot& robot,
374 Visu::RobotModel* robotModel = getRobotModel(robot.
description);
376 if (robotModel ==
nullptr)
386 sensorValues.forceTorqueValuesMap;
388 for (
const auto& [side, ft] : forceTorques)
394 const std::string forceTorqueSensorName =
395 robotModel->nameHelper->getArm(side).getForceTorqueSensor();
397 const Eigen::Matrix4f forceTorqueSensorPose =
398 robotModel->model->getSensor(forceTorqueSensorName)->getGlobalPose();
400 const std::string xyz =
"XYZ";
402 const Eigen::Vector3f
from = simox::math::position(forceTorqueSensorPose);
403 for (
int i = 0; i < 3; ++i)
406 simox::Color((255 * Eigen::Matrix3i::Identity().col(i)).eval());
410 const float length = p.forceTorque.forceScale * ft.force(i);
412 std::min(simox::math::rescale(std::abs(length), 0.F, 100.F, 1.F, 10.F), 10.F);
414 const Eigen::Vector3f to =
415 from + length * simox::math::orientation(forceTorqueSensorPose).col(i);
417 std::stringstream key;
419 key << side <<
" Force " << xyz.at(i);
420 layer.
add(viz::Arrow(key.str()).fromTo(from, to).color(color).width(width));
427 Visu::RobotModel::RobotModel(
const std::filesystem::path& robotPath) :
429 VirtualRobot::RobotIO::loadRobot(robotPath, VirtualRobot::RobotIO::eStructure),
432 RobotNameHelper::Create(robotPath),
Brief description of class DebugObserverHelper.
void setTag(const LogTag &tag)
static std::filesystem::path toSystemPath(const data::PackagePath &pp)
static const std::string LocationLeft
static const std::string LocationRight
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="visu.")
void connect(const viz::Client &arviz, DebugObserverInterfacePrx debugObserver=nullptr)
Visu(const description::Segment &descriptionSegment, const proprioception::Segment &proprioceptionSegment, const localization::Segment &localizationSegment)
DerivedT & pose(Eigen::Matrix4f const &pose)
Robot & joints(std::map< std::string, float > const &values)
Robot & useCollisionModel()
Robot & file(std::string const &project, std::string const &filename)
#define ARMARX_CHECK_FITS_SIZE(number, size)
Check whether number is nonnegative (>= 0) and less than size.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define TIMING_START(name)
Helper macro to do timing tests.
#define TIMING_END_STREAM(name, os)
Prints duration.
std::vector< Robot > Robots
std::unordered_map< std::string, armarx::armem::robot_state::description::RobotDescription > RobotDescriptionMap
std::unordered_map< std::string, ForceTorqueValues > ForceTorqueValuesMap
std::unordered_map< std::string, SensorValues > SensorValuesMap
armem::robot_state::Robots combine(const description::RobotDescriptionMap &robotDescriptions, const localization::RobotPoseMap &globalPoses, const proprioception::SensorValuesMap &sensorValues, const armem::Time ×tamp)
armarx::core::time::DateTime Time
std::string toStringMilliSeconds(const Time &time, int decimals=3)
Returns time as e.g.
state::Type from(Eigen::Vector3f targetPosition)
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
SimpleRunningTask(Ts...) -> SimpleRunningTask< std::function< void(void)> >
description::RobotDescription description
void add(ElementT const &element)