Visu.cpp
Go to the documentation of this file.
1 #include "Visu.h"
2 
3 #include <algorithm>
4 #include <exception>
5 #include <string>
6 
7 #include <Eigen/Geometry>
8 
9 #include <SimoxUtility/algorithm/get_map_keys_values.h>
10 #include <SimoxUtility/math/pose.h>
11 #include <SimoxUtility/math/rescale.h>
12 #include <VirtualRobot/XML/RobotIO.h>
13 
17 #include <ArmarXCore/interface/core/PackagePath.h>
18 
25 
26 #include "combine.h"
27 
29 {
30 
31  Visu::Visu(const description::Segment& descriptionSegment,
32  const proprioception::Segment& proprioceptionSegment,
33  const localization::Segment& localizationSegment) :
34  descriptionSegment(descriptionSegment),
35  proprioceptionSegment(proprioceptionSegment),
36  localizationSegment(localizationSegment)
37  {
38  Logging::setTag("Visu");
39  }
40 
41  void
42  Visu::defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix)
43  {
44  defs->optional(
45  p.enabled, prefix + "enabled", "Enable or disable visualization of objects.");
46  defs->optional(p.frequencyHz, prefix + "frequenzyHz", "Frequency of visualization.");
47  defs->optional(p.framesEnabled,
48  prefix + "framesEnabled",
49  "Enable or disable visualization of frames.");
50  defs->optional(p.forceTorque.enabled,
51  prefix + "forceTorque.enabled",
52  "Enable or disable visualization of force torque sensors.");
53  defs->optional(p.forceTorque.forceScale,
54  prefix + "forceTorque.forceScale",
55  "Scaling of force arrows.");
56  }
57 
58  void
60  {
61  }
62 
63  void
65  {
66  this->arviz = arviz;
67  if (debugObserver)
68  {
69  bool batchMode = true;
70  this->debugObserver = DebugObserverHelper("RobotStateMemory", debugObserver, batchMode);
71  }
72 
73  if (updateTask)
74  {
75  updateTask->stop();
76  updateTask->join();
77  updateTask = nullptr;
78  }
79  updateTask = new SimpleRunningTask<>([this]() { this->visualizeRun(); });
80  updateTask->start();
81  }
82 
83  void
84  Visu::visualizeRobots(viz::Layer& layer, const robot::Robots& robots)
85  {
86  for (const robot::Robot& robot : robots)
87  {
88  const armarx::data::PackagePath xmlPath = robot.description.xml.serialize();
89 
90  // clang-format off
91  viz::Robot robotVisu = viz::Robot(robot.description.name)
92  .file(xmlPath.package, xmlPath.package + "/" + xmlPath.path)
93  .joints(robot.config.jointMap)
94  .pose(robot.config.globalPose);
95 
96  robotVisu.useFullModel();
97  // clang-format on
98 
99  layer.add(robotVisu);
100  }
101  }
102 
103  void
104  Visu::visualizeFrames(
105  viz::Layer& layerFrames,
106  const std::unordered_map<std::string, std::vector<Eigen::Affine3f>>& frames)
107  {
108  for (const auto& [robotName, robotFrames] : frames)
109  {
110  Eigen::Affine3f pose = Eigen::Affine3f::Identity();
111 
112  int i = 0;
113  for (const auto& frame : robotFrames)
114  {
115  Eigen::Affine3f from = pose;
116  Eigen::Affine3f to = pose * frame;
117 
118  pose = to;
119 
120  layerFrames.add(viz::Arrow(robotName + std::to_string(++i))
121  .fromTo(from.translation(), to.translation()));
122  }
123  }
124  }
125 
126  void
127  Visu::visualizeFramesIndividual(
128  viz::Layer& layerFrames,
129  const std::unordered_map<std::string, std::vector<Eigen::Affine3f>>& frames)
130  {
131 
132  std::vector<std::string> FRAME_NAMES{/*world*/ "map", "odom", "robot"};
133 
134  for (const auto& [robotName, robotFrames] : frames)
135  {
136  int i = 0;
137  for (const auto& frame : robotFrames)
138  {
139  layerFrames.add(
140  viz::Pose(robotName + FRAME_NAMES.at(i++)).pose(frame.matrix()).scale(3));
141  }
142  }
143  }
144 
145  void
146  Visu::visualizeRun()
147  {
148  CycleUtil cycle(static_cast<int>(1000 / p.frequencyHz));
149  while (updateTask and not updateTask->isStopped())
150  {
151  if (p.enabled)
152  {
153  const Time timestamp = Time::Now();
154  ARMARX_DEBUG << "Visu task at " << armem::toStringMilliSeconds(timestamp);
155 
156  try
157  {
158  visualizeOnce(timestamp);
159  }
160  catch (const std::out_of_range& e)
161  {
162  ARMARX_WARNING << "Caught std::out_of_range while visualizing robots: \n"
163  << e.what();
164  }
165  catch (const std::exception& e)
166  {
167  ARMARX_WARNING << "Caught exception while visualizing robots: \n" << e.what();
168  }
169  catch (...)
170  {
171  ARMARX_WARNING << "Caught unknown exception while visualizing robots.";
172  }
173 
174  if (debugObserver.has_value())
175  {
176  debugObserver->sendDebugObserverBatch();
177  }
178  }
179  cycle.waitForCycleDuration();
180  }
181  }
182 
183  void
184  Visu::visualizeOnce(const Time& timestamp)
185  {
186  TIMING_START(tVisuTotal);
187 
188  // TODO(fabian.reister): use timestamp
189 
190  // Get data.
191  TIMING_START(tVisuGetData);
192 
193  TIMING_START(tRobotDescriptions);
194  const description::RobotDescriptionMap robotDescriptions =
195  descriptionSegment.getRobotDescriptionsLocking(timestamp);
196  TIMING_END_STREAM(tRobotDescriptions, ARMARX_DEBUG);
197 
198  TIMING_START(tGlobalPoses);
199  const auto globalPoses = localizationSegment.getRobotGlobalPosesLocking(timestamp);
200  TIMING_END_STREAM(tGlobalPoses, ARMARX_DEBUG);
201 
202  TIMING_START(tRobotFramePoses);
203  const auto frames = localizationSegment.getRobotFramePosesLocking(timestamp);
204  TIMING_END_STREAM(tRobotFramePoses, ARMARX_DEBUG);
205 
206  TIMING_START(tSensorValues);
207  const proprioception::SensorValuesMap sensorValues =
208  proprioceptionSegment.getSensorValuesLocking(timestamp,
209  debugObserver ? &*debugObserver : nullptr);
210  TIMING_END_STREAM(tSensorValues, ARMARX_DEBUG);
211 
212  TIMING_END_STREAM(tVisuGetData, ARMARX_DEBUG);
213 
214 
215  // Build layers.
216  TIMING_START(tVisuBuildLayers);
217 
218  // We need all 3 information:
219  // - robot description
220  // - global pose
221  // - joint positions
222  // => this is nothing but an armem::Robot
223  ARMARX_DEBUG << "Combining robot ..."
224  << "\n- " << robotDescriptions.size() << " descriptions"
225  << "\n- " << globalPoses.size() << " global poses"
226  << "\n- " << sensorValues.size() << " joint positions";
227 
228  const robot::Robots robots =
229  combine(robotDescriptions, globalPoses, sensorValues, timestamp);
230 
231  ARMARX_DEBUG << "Visualize " << robots.size() << " robots ...";
232  std::vector<viz::Layer> layers;
233 
234  {
235  viz::Layer& layer = layers.emplace_back(arviz.layer("Robots"));
236  visualizeRobots(layer, robots);
237  }
238 
239  ARMARX_DEBUG << "Visualize frames ...";
240  if (p.framesEnabled)
241  {
242  viz::Layer& layer = layers.emplace_back(arviz.layer("Localization Frames"));
243  visualizeFrames(layer, frames);
244  }
245 
246  TIMING_END_STREAM(tVisuBuildLayers, ARMARX_DEBUG);
247 
248  {
249  viz::Layer& layer = layers.emplace_back(arviz.layer("Localization Frames Individual"));
250  visualizeFramesIndividual(layer, frames);
251  }
252 
253  if (p.forceTorque.enabled)
254  {
255  viz::Layer& layerForceTorque = layers.emplace_back(arviz.layer("Force Torque"));
256  std::stringstream log;
257 
258  for (const robot::Robot& robot : robots)
259  {
260  const std::string& robotName = robot.description.name;
261 
262  auto itSensorValues = sensorValues.find(robotName);
263  if (itSensorValues == sensorValues.end())
264  {
265  log << "\nNo robot '" << robotName << "' in sensor values. Available are: ";
266  log << simox::alg::join(simox::alg::get_keys(sensorValues), ", ");
267  continue;
268  }
269 
270  visualizeForceTorque(layerForceTorque, robot, itSensorValues->second);
271  }
272 
273  if (not log.str().empty())
274  {
275  ARMARX_INFO << "While visualizing robot force torques: " << log.str();
276  }
277  }
278 
279 
280  // Commit layers.
281 
282  ARMARX_DEBUG << "Commit visualization ...";
283  TIMING_START(tVisuCommit);
284  arviz.commit(layers);
285  TIMING_END_STREAM(tVisuCommit, ARMARX_DEBUG);
286 
287  TIMING_END_STREAM(tVisuTotal, ARMARX_DEBUG);
288 
289  if (debugObserver.has_value())
290  {
291  const std::string p = "Visu | ";
292  debugObserver->setDebugObserverDatafield(p + "t Total (ms)",
293  tVisuTotal.toMilliSecondsDouble());
294  debugObserver->setDebugObserverDatafield(p + "t 1 Get Data (ms)",
295  tVisuGetData.toMilliSecondsDouble());
296  debugObserver->setDebugObserverDatafield(p + "t 1.1 Descriptions (ms)",
297  tRobotDescriptions.toMilliSecondsDouble());
298  debugObserver->setDebugObserverDatafield(p + "t 1.2 Global Poses (ms)",
299  tGlobalPoses.toMilliSecondsDouble());
300  debugObserver->setDebugObserverDatafield(p + "t 1.3 Frames (ms)",
301  tRobotFramePoses.toMilliSecondsDouble());
302  debugObserver->setDebugObserverDatafield(p + "t 1.4 Sensor Values (ms)",
303  tSensorValues.toMilliSecondsDouble());
304  debugObserver->setDebugObserverDatafield(p + "t 2 Build Layers (ms)",
305  tVisuBuildLayers.toMilliSecondsDouble());
306  debugObserver->setDebugObserverDatafield(p + "t 3 Commit (ms)",
307  tVisuCommit.toMilliSecondsDouble());
308  }
309  }
310 
311  void
312  Visu::visualizeForceTorque(viz::Layer& layer,
313  const robot::Robot& robot,
314  const proprioception::SensorValues& sensorValues)
315  {
316  const std::string& robotName = robot.description.name;
317 
318  RobotModel* robotModel = nullptr;
319  if (auto it = models.find(robotName); it != models.end())
320  {
321  robotModel = &it->second;
322  }
323  else
324  {
325  const std::filesystem::path robotPath = robot.description.xml.toSystemPath();
326  ARMARX_INFO << "Loading robot model for '" << robotName << "' from " << robotPath
327  << " for visualization.";
328  auto [it2, _] = models.emplace(robotName, robotPath);
329  robotModel = &it2->second;
330  }
331 
332  robotModel->model->setJointValues(robot.config.jointMap);
333  robotModel->model->setGlobalPose(robot.config.globalPose.matrix());
334 
335  const proprioception::ForceTorqueValuesMap& forceTorques =
336  sensorValues.forceTorqueValuesMap;
337 
338  for (const auto& [side, ft] : forceTorques)
339  {
342  << side;
343 
344  const std::string forceTorqueSensorName =
345  robotModel->nameHelper->getArm(side).getForceTorqueSensor();
346 
347  const Eigen::Matrix4f forceTorqueSensorPose =
348  robotModel->model->getSensor(forceTorqueSensorName)->getGlobalPose();
349 
350  const std::string xyz = "XYZ";
351 
352  const Eigen::Vector3f from = simox::math::position(forceTorqueSensorPose);
353  for (int i = 0; i < 3; ++i)
354  {
355  simox::Color color =
356  simox::Color((255 * Eigen::Matrix3i::Identity().col(i)).eval());
357  color.a = 128;
358 
359  // Force arrows.
360  const float length = p.forceTorque.forceScale * ft.force(i);
361  const float width =
362  std::min(simox::math::rescale(std::abs(length), 0.F, 100.F, 1.F, 10.F), 10.F);
363 
364  const Eigen::Vector3f to =
365  from + length * simox::math::orientation(forceTorqueSensorPose).col(i);
366 
367  std::stringstream key;
368  ARMARX_CHECK_FITS_SIZE(i, xyz.size());
369  key << side << " Force " << xyz.at(i);
370  layer.add(viz::Arrow(key.str()).fromTo(from, to).color(color).width(width));
371 
372  // TODO: Torque circle arrows.
373  }
374  }
375  }
376 
377  Visu::RobotModel::RobotModel(const std::filesystem::path& robotPath) :
378  model{
379  VirtualRobot::RobotIO::loadRobot(robotPath, VirtualRobot::RobotIO::eStructure),
380  },
381  nameHelper{
382  RobotNameHelper::Create(robotPath),
383  }
384  {
385  }
386 
387 } // namespace armarx::armem::server::robot_state
armarx::RobotNameHelper::LocationLeft
static const std::string LocationLeft
Definition: RobotNameHelper.h:169
armarx::armem::robot::Robots
std::vector< Robot > Robots
Definition: types.h:80
armarx::SimpleRunningTask
Usage:
Definition: TaskUtil.h:70
armarx::viz::Client::commit
CommitResult commit(StagedCommit const &commit)
Definition: Client.cpp:80
TIMING_START
#define TIMING_START(name)
Definition: TimeUtil.h:280
armarx::armem::server::robot_state::Visu::init
void init()
Definition: Visu.cpp:59
ARMARX_CHECK_FITS_SIZE
#define ARMARX_CHECK_FITS_SIZE(number, size)
Check whether number is nonnegative (>= 0) and less than size. If it is not, throw an ExpressionExcep...
Definition: ExpressionException.h:159
robots
std::vector< VirtualRobot::RobotPtr > robots
Definition: VisualizationRobot.cpp:86
armarx::armem::robot::Robot
Definition: types.h:68
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:55
armarx::armem::server::robot_state::proprioception::Segment
Definition: Segment.h:47
armarx::armem::server::robot_state::localization::Segment
Definition: Segment.h:43
armarx::armem::server::robot_state::description::Segment
Definition: Segment.h:43
armarx::armem::server::robot_state::Visu::Visu
Visu(const description::Segment &descriptionSegment, const proprioception::Segment &proprioceptionSegment, const localization::Segment &localizationSegment)
Definition: Visu.cpp:31
armarx::armem::server::robot_state::proprioception::ForceTorqueValuesMap
std::unordered_map< std::string, ForceTorqueValues > ForceTorqueValuesMap
Definition: forward_declarations.h:81
armarx::viz::Arrow
Definition: Elements.h:198
armarx::RobotNameHelper::LocationRight
static const std::string LocationRight
Definition: RobotNameHelper.h:170
combine.h
armarx::viz::Layer::add
void add(ElementT const &element)
Definition: Layer.h:29
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
Elements.h
TIMING_END_STREAM
#define TIMING_END_STREAM(name, os)
Definition: TimeUtil.h:300
armarx::armem::server::robot_state
Definition: RobotStateMemory.cpp:40
armarx::viz::Robot::useFullModel
Robot & useFullModel()
Definition: Robot.h:29
armarx::armem::server::robot_state::Visu::connect
void connect(const viz::Client &arviz, DebugObserverInterfacePrx debugObserver=nullptr)
Definition: Visu.cpp:64
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:523
Color
uint32_t Color
RGBA color.
Definition: color.h:8
armarx::abs
std::vector< T > abs(const std::vector< T > &v)
Definition: VectorHelpers.h:253
armarx::viz::Arrow::width
Arrow & width(float w)
Definition: Elements.h:211
armarx::armem::human::Robot
@ Robot
Definition: util.h:14
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
armarx::armem::server::robot_state::localization::Segment::getRobotGlobalPosesLocking
RobotPoseMap getRobotGlobalPosesLocking(const armem::Time &timestamp) const
Definition: Segment.cpp:117
Segment.h
armarx::armem::server::robot_state::combine
robot::Robots combine(const description::RobotDescriptionMap &robotDescriptions, const localization::RobotPoseMap &globalPoses, const proprioception::SensorValuesMap &sensorValues, const armem::Time &timestamp)
Definition: combine.cpp:16
armarx::armem::toStringMilliSeconds
std::string toStringMilliSeconds(const Time &time, int decimals=3)
Returns time as e.g.
Definition: Time.cpp:11
armarx::viz::Pose
Definition: Elements.h:179
armarx::viz::Robot
Definition: Robot.h:9
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:40
armarx::armem::server::robot_state::proprioception::SensorValuesMap
std::unordered_map< std::string, SensorValues > SensorValuesMap
Definition: forward_declarations.h:82
armarx::armem::server::robot_state::description::RobotDescriptionMap
std::unordered_map< std::string, robot::RobotDescription > RobotDescriptionMap
Definition: forward_declarations.h:64
CycleUtil.h
armarx::viz::Arrow::fromTo
Arrow & fromTo(const Eigen::Vector3f &from, const Eigen::Vector3f &to)
Definition: Elements.h:218
Segment.h
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:601
TimeUtil.h
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
Segment.h
armarx::viz::ElementOps::pose
DerivedT & pose(Eigen::Matrix4f const &pose)
Definition: ElementOps.h:159
armarx::armem::server::robot_state::localization::Segment::getRobotFramePosesLocking
RobotFramePoseMap getRobotFramePosesLocking(const armem::Time &timestamp) const
Definition: Segment.cpp:71
armarx::armem::server::robot_state::description::Segment::getRobotDescriptionsLocking
RobotDescriptionMap getRobotDescriptionsLocking(const armem::Time &timestamp) const
Definition: Segment.cpp:123
armarx::viz::ElementOps::scale
DerivedT & scale(Eigen::Vector3f scale)
Definition: ElementOps.h:227
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::viz::ElementOps::color
DerivedT & color(Color color)
Definition: ElementOps.h:195
IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface >
F
Definition: ExportDialogControllerTest.cpp:16
Time.h
armarx::RobotNameHelper::Create
static RobotNameHelperPtr Create(const RobotInfoNodePtr &robotInfo, const StatechartProfilePtr &profile)
Definition: RobotNameHelper.cpp:96
armarx::armem::server::robot_state::proprioception::Segment::getSensorValuesLocking
SensorValuesMap getSensorValuesLocking(const armem::Time &timestamp, DebugObserverHelper *debugObserver=nullptr) const
Definition: Segment.cpp:76
armarx::Logging::setTag
void setTag(const LogTag &tag)
Definition: Logging.cpp:55
Logging.h
min
T min(T t1, T t2)
Definition: gdiam.h:42
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::viz::Client::layer
Layer layer(std::string const &name) const
Definition: Client.cpp:73
armarx::viz::Client
Definition: Client.h:109
Visu.h
armarx::viz::Layer
Definition: Layer.h:12
armarx::armem::server::robot_state::Visu::defineProperties
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="visu.")
Definition: Visu.cpp:42
armarx::DebugObserverHelper
Brief description of class DebugObserverHelper.
Definition: DebugObserverHelper.h:50
SensorValues.h