8#include <Eigen/Geometry>
10#include <SimoxUtility/algorithm/apply.hpp>
11#include <SimoxUtility/algorithm/get_map_keys_values.h>
12#include <SimoxUtility/color/Color.h>
13#include <SimoxUtility/color/ColorMap.h>
14#include <SimoxUtility/color/hsv.h>
15#include <SimoxUtility/math/pose.h>
20#include <ArmarXCore/interface/core/PackagePath.h>
30#include <RobotAPI/interface/components/TrajectoryPlayerInterface.h>
32#include <RobotAPI/libraries/armem_laser_scans/aron/LaserScan.aron.generated.h>
49 p.enabled, prefix +
"enabled",
"Enable or disable visualization of objects.");
50 defs->optional(p.frequencyHz, prefix +
"frequenzyHz",
"Frequency of visualization.");
52 p.uniformColor, prefix +
"uniformColor",
"If enabled, points will be drawn in red.");
53 defs->optional(p.maxRobotAgeMs,
54 prefix +
"maxRobotAgeMs",
55 "Maximum age of robot state before a new one is retrieved in milliseconds.");
56 defs->optional(p.colorByIntensity,
"colorByIntensity",
"");
57 defs->optional(p.pointSizeInPixels, prefix +
"pointSizeInPixels",
"Point size in pixels.");
64 this->coreSegment = coreSegment;
65 this->virtualRobotReader = virtualRobotReader;
74 bool batchMode =
true;
90 const std::string& tabName)
93 remoteGuiTabName_ = tabName;
99 if (needsTabRebuild_.exchange(
false))
101 createOrUpdateCalibrationTab();
105 bool anyChanged =
false;
106 for (
const auto& [frame, spinboxes] : calibrationTab_.sensors)
108 for (
const auto& sb : spinboxes)
110 anyChanged = anyChanged || sb.hasValueChanged();
116 std::lock_guard<std::mutex> lock(sensorMutex_);
117 for (
const auto& [frame, spinboxes] : calibrationTab_.sensors)
119 calibrationData_[frame] = {
120 spinboxes[0].getValue(), spinboxes[1].getValue(), spinboxes[2].getValue()};
126 Visu::createOrUpdateCalibrationTab()
131 std::set<std::string> frames;
132 std::map<std::string, SensorCalibrationData> currentData;
134 std::lock_guard<std::mutex> lock(sensorMutex_);
135 frames = knownSensorFrames_;
136 currentData = calibrationData_;
140 calibrationTab_.sensors.clear();
145 grid.
add(
Label(
"Sensor"), {.row = row, .column = 0})
146 .add(
Label(
"x [mm]"), {.row = row, .column = 1})
147 .add(
Label(
"y [mm]"), {.row = row, .column = 2})
148 .add(
Label(
"yaw [deg]"), {.row = row, .column = 3});
151 for (
const auto& frame : frames)
153 const auto& d = currentData[frame];
154 auto& sb = calibrationTab_.sensors[frame];
156 sb[0].setRange(-10.f, 10.f);
157 sb[0].setDecimals(1);
160 sb[1].setRange(-10.f, 10.f);
161 sb[1].setDecimals(1);
164 sb[2].setRange(-5.f, 5.f);
165 sb[2].setDecimals(2);
166 sb[2].setValue(d.yaw);
168 grid.
add(
Label(frame), {.row = row, .column = 0})
169 .add(sb[0], {.row = row, .column = 1})
170 .add(sb[1], {.row = row, .column = 2})
171 .add(sb[2], {.row = row, .column = 3});
175 VBoxLayout root = {grid, VSpacer()};
176 guiUser_->RemoteGui_createTab(remoteGuiTabName_, root, &calibrationTab_);
180 Visu::getCalibrationOffset(
const std::string& sensorFrame)
const
182 std::lock_guard<std::mutex> lock(sensorMutex_);
183 const auto it = calibrationData_.find(sensorFrame);
184 if (it == calibrationData_.end())
186 return Eigen::Isometry3f::Identity();
189 const auto& d = it->second;
190 constexpr float kDegToRad =
static_cast<float>(
M_PI) / 180.f;
192 Eigen::Isometry3f offset = Eigen::Isometry3f::Identity();
193 offset.translation().x() = d.x;
194 offset.translation().y() = d.y;
196 Eigen::AngleAxisf(d.yaw * kDegToRad, Eigen::Vector3f::UnitZ()).toRotationMatrix();
203 CycleUtil cycle(
static_cast<int>(1000 / p.frequencyHz));
204 while (updateTask and not updateTask->isStopped())
215 catch (
const std::exception& e)
217 ARMARX_WARNING <<
"Caught exception while visualizing robots: \n" << e.what();
221 ARMARX_WARNING <<
"Caught unknown exception while visualizing robots.";
224 if (debugObserver.has_value())
226 debugObserver->sendDebugObserverBatch();
229 cycle.waitForCycleDuration();
234 Visu::visualizeScan(
const std::vector<ScanPoint>& points,
235 const std::string& sensorName,
236 const std::string& agentName,
237 const viz::Color& color)
239 viz::PointCloud pointCloud(
"laser_scan");
241 ARMARX_VERBOSE <<
"Point cloud with " << points.size() <<
" points";
243 for (
const auto& point : points)
247 const viz::Color specificColor = [&point, &color,
this]() -> viz::Color
249 if (p.colorByIntensity)
251 Eigen::Vector3f hsv = simox::color::rgb_to_hsv(
252 Eigen::Vector3f(
static_cast<float>(color.r) / 255.f,
253 static_cast<float>(color.g) / 255.f,
254 static_cast<float>(color.b) / 255.f));
258 hsv(2) = std::clamp<float>(point.intensity, 0., 1.);
260 const Eigen::Vector3f rgb = simox::color::hsv_to_rgb(hsv);
262 return viz::Color{rgb(0), rgb(1), rgb(2)};
268 pointCloud.addPoint(point.point.x(), point.point.y(), point.point.z(), specificColor);
271 pointCloud.pointSizeInPixels(p.pointSizeInPixels);
273 viz::Layer l = arviz.layer(agentName +
"/" + sensorName);
279 std::vector<ScanPoint>
281 const Eigen::Isometry3f& global_T_sensor)
283 const auto scanCartesian =
286 std::vector<ScanPoint> points;
287 points.reserve(scan.
data.size());
289 for (std::size_t i = 0; i < scan.
data.size(); i++)
291 const auto& point = scanCartesian.at(i);
292 const auto& raw = scan.
data.at(i);
294 const Eigen::Vector3f pointGlobal = global_T_sensor * point;
295 points.push_back(
ScanPoint{.point = pointGlobal, .intensity = raw.intensity});
343 std::map<std::string, armem::laser_scans::LaserScanStamped>
344 Visu::getCurrentLaserScans()
351 const std::optional<armarx::armem::laser_scans::arondto::LaserScanStamped>
dto =
359 const auto ndArrayNavigator =
364 laserScanStamped.
data =
369 return laserScanStamped;
372 std::map<std::string, armem::laser_scans::LaserScanStamped> scans;
376 const auto scan =
convert(instance);
377 scans[instance.id().providerSegmentName +
"/" + instance.id().entityName] = scan;
380 const auto applyToEntity = [&](
const wm::Entity& entity)
387 const auto& snapshot = entity.getLatestSnapshot();
389 snapshot.forEachInstance(applyToInstance);
392 const auto applyToProviderSegment = [&](
const auto& providerSegment)
393 { providerSegment.forEachEntity(applyToEntity); };
395 coreSegment->forEachProviderSegment(applyToProviderSegment);
404 std::map<std::string, armem::laser_scans::LaserScanStamped> currentLaserScans =
405 getCurrentLaserScans();
410 bool newSensors =
false;
412 std::lock_guard<std::mutex> lock(sensorMutex_);
413 for (
const auto& [provider, scan] : currentLaserScans)
415 if (knownSensorFrames_.insert(scan.header.frame).second)
417 calibrationData_[scan.header.frame] = {};
424 needsTabRebuild_ =
true;
430 for (
const auto& [provider, scan] : currentLaserScans)
434 const auto global_T_sensor = [&]() -> Eigen::Isometry3f
436 const auto robot = getSynchronizedRobot(scan.header.agent, scan.header.timestamp);
441 return Eigen::Isometry3f::Identity();
444 const auto sensorNode = robot->getRobotNode(scan.header.frame);
446 <<
"` for robot `" << scan.header.agent <<
"`";
448 ARMARX_VERBOSE <<
"Sensor position for sensor `" << scan.header.frame <<
"` is "
449 << sensorNode->getGlobalPosition();
450 return Eigen::Isometry3f{sensorNode->getGlobalPose()};
453 const Eigen::Isometry3f global_T_sensorCalibrated =
454 global_T_sensor * getCalibrationOffset(scan.header.frame);
456 const std::vector<ScanPoint> points =
459 const auto color = [&]() -> simox::Color
463 return simox::Color::red();
466 return simox::color::GlasbeyLUT::at(i++);
469 visualizeScan(points, scan.header.frame, scan.header.agent, color);
474 Visu::getSynchronizedRobot(
const std::string& name,
const DateTime&
timestamp)
476 if (robots.count(name) == 0)
479 const auto robot = virtualRobotReader->getRobot(name);
491 auto& entry = robots.at(name);
492 if (entry.second.isInvalid() ||
495 if (virtualRobotReader->synchronizeRobotPose(*entry.first,
timestamp))
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
static DateTime Invalid()
Brief description of class DebugObserverHelper.
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
void setTag(const LogTag &tag)
The VirtualRobotReader class.
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="visu.")
void connect(const viz::Client &arviz, DebugObserverInterfacePrx debugObserver=nullptr)
void init(const wm::CoreSegment *coreSegment, armem::robot_state::VirtualRobotReader *virtualRobotReader)
void connectRemoteGui(armarx::LightweightRemoteGuiComponentPluginUser *guiUser, const std::string &tabName)
static PointerType DynamicCast(const VariantPtr &n)
static Duration MilliSeconds(std::int64_t milliSeconds)
Constructs a duration in milliseconds.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#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 ARMARX_VERBOSE
The logging level for verbose information.
std::shared_ptr< class Robot > RobotPtr
EigenVectorT toCartesian(const LaserScanStep &laserScanStep)
SensorHeader fromAron(const arondto::SensorHeader &aronSensorHeader)
This file is part of ArmarX.
std::vector< ScanPoint > convertScanToGlobal(const armem::laser_scans::LaserScanStamped &scan, const Eigen::Isometry3f &global_T_sensor)
armem::wm::EntityInstance EntityInstance
void fromAron(const arondto::MemoryID &dto, MemoryID &bo)
armarx::core::time::DateTime Time
std::string toStringMilliSeconds(const Time &time, int decimals=3)
Returns time as e.g.
std::optional< AronClass > tryCast(const wm::EntityInstance &item)
Tries to cast a armem::EntityInstance to AronClass.
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
armem::articulated_object::ArticulatedObject convert(const VirtualRobot::Robot &obj, const armem::Time ×tamp)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
SimpleRunningTask(Ts...) -> SimpleRunningTask< std::function< void(void)> >
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
void add(ElementT const &element)