29 #include <QDoubleSpinBox>
36 setPoseState(SetPoseState::None)
40 painterWidget->
setupUi(widget.frame);
44 paintTimerId = startTimer(16);
70 localisation = getProxy<LaserScannerSelfLocalisationInterfacePrx>(localisationName);
71 localisationManager = getProxy<armarx::ArmarXManagerInterfacePrx>(localisationName +
"Manager");
72 localisationAdmin = localisationManager->getPropertiesAdmin();
75 map = localisation->getMap();
78 widget.smoothingFrameSize, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
79 connect(widget.smoothingMergeDistance,
80 SIGNAL(valueChanged(
int)),
83 connect(widget.matchingMaxDistance,
84 SIGNAL(valueChanged(
double)),
87 connect(widget.matchingMinPoints,
88 SIGNAL(valueChanged(
double)),
91 connect(widget.matchingCorrectionFactor,
92 SIGNAL(valueChanged(
double)),
96 widget.edgeMaxDistance, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
97 connect(widget.edgeMaxDeltaAngle,
98 SIGNAL(valueChanged(
double)),
101 connect(widget.edgePointAddingThreshold,
102 SIGNAL(valueChanged(
double)),
105 connect(widget.edgeEpsilon, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
106 connect(widget.edgeMinPoints, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
107 connect(widget.useMapCorrection, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
108 connect(widget.useOdometry, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
109 connect(widget.reportPoints, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
110 connect(widget.reportEdges, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
111 connect(widget.setPoseButton, SIGNAL(clicked()),
this, SLOT(
onSetPoseClick()));
113 widget.sensorStdDev, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
115 widget.velSensorStdDev, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
117 connect(painterWidget, SIGNAL(mousePressed(QPoint)),
this, SLOT(
onCanvasClick(QPoint)));
121 usingTopic(localisation->getReportTopicName());
130 dialog->addProxyFinder<LaserScannerSelfLocalisationInterfacePrx>(
131 {
"LaserScannerSelfLocalisation",
"",
"*"});
133 return qobject_cast<SimpleConfigDialog*>(dialog);
141 localisationName = dialog->getProxyName(
"LaserScannerSelfLocalisation");
149 float minX = FLT_MAX;
151 float minY = FLT_MAX;
152 for (LineSegment2D&
s : map)
164 float normX = 1.0f / (maxX - minX);
165 float normY = 1.0f / (maxY - minY);
166 float scaleFactorX = size.width() * normX;
167 float scaleFactorY = size.height() * normY;
168 float scaleFactor = 0.95f *
std::min(scaleFactorX, scaleFactorY);
169 float invScaleFactor = 1.0f / scaleFactor;
171 auto toCanvas = [=](armarx::Vector2f p)
173 float xCoord = scaleFactor * (p.e0 - minX);
174 float yCoord = scaleFactor * (p.e1 - minY);
175 return QPoint((
int)xCoord, (
int)(size.height() - 1 - yCoord));
178 auto toCanvasE = [=](Eigen::Vector2f p)
180 float xCoord = scaleFactor * (p.x() - minX);
181 float yCoord = scaleFactor * (p.y() - minY);
182 return QPoint((
int)xCoord, (
int)(size.height() - 1 - yCoord));
185 auto fromCanvas = [=](QPoint p)
187 float globalX = (invScaleFactor * p.x()) + minX;
188 float globalY = invScaleFactor * (size.height() - 1 - p.y()) + minY;
189 return Eigen::Vector2f(globalX, globalY);
192 if (setPoseState == SetPoseState::Wait)
194 setPoseState = SetPoseState::Orientation;
196 else if (setPoseState == SetPoseState::Finished)
199 Eigen::Vector2f globalPos = fromCanvas(setPosition);
200 Eigen::Vector2f globalOr = fromCanvas(setOrientation);
201 Eigen::Vector2f fromPosToOr = globalOr - globalPos;
202 float theta = std::atan2(fromPosToOr.y(), fromPosToOr.x()) - M_PI_2;
206 ARMARX_INFO <<
"Set global pose to (" << globalPos.x() <<
", " << globalPos.y() <<
", "
208 localisation->setAbsolutePose(globalPos.x(), globalPos.y(), theta);
210 catch (std::exception
const& ex)
215 setPoseState = SetPoseState::None;
218 QBrush whiteBrush(QColor(240, 240, 240));
219 QPen blackPen(QColor(0, 0, 0));
220 blackPen.setWidth(1);
221 painter.setBrush(whiteBrush);
222 painter.setPen(blackPen);
225 lines.reserve(map.size());
226 for (LineSegment2D
const&
s : map)
228 lines.emplace_back(toCanvas(
s.start), toCanvas(
s.end));
230 painter.drawLines(lines.data(), lines.size());
232 if (setPoseState == SetPoseState::Orientation)
234 QPoint setOrientation = painterWidget->mapFromGlobal(QCursor::pos());
235 Eigen::Vector2f globalPos = fromCanvas(setPosition);
236 Eigen::Vector2f globalOr = fromCanvas(setOrientation);
238 painter.setBrush(QColor(255, 0, 0));
239 painter.drawEllipse(toCanvasE(globalPos), 10, 10);
240 painter.drawLine(toCanvasE(globalPos), toCanvasE(globalOr));
244 Eigen::Vector2f robotPos(poseX, poseY);
245 float robotTheta = poseTheta;
247 armarx::Vector2f estRobotPos{robotPos.x(), robotPos.y()};
248 Eigen::Vector2f estRobotEnd =
250 500.0f * Eigen::Vector2f(Eigen::Rotation2Df(robotTheta) * Eigen::Vector2f::UnitY());
251 armarx::Vector2f estRobotEnda{estRobotEnd.x(), estRobotEnd.y()};
252 painter.setBrush(QColor(0, 255, 255));
253 painter.drawEllipse(toCanvas(estRobotPos), 10, 10);
254 painter.drawLine(toCanvas(estRobotPos), toCanvas(estRobotEnda));
255 painter.setBrush(QColor(255, 255, 0, 25));
256 float posUncertaintyAverage = (poseUncertaintyX + poseUncertaintyY) * 0.5;
257 painter.drawEllipse(toCanvas(estRobotPos),
258 (int)(posUncertaintyAverage * scaleFactor),
259 (int)(posUncertaintyAverage * scaleFactor));
265 if (widget.reportPoints->checkState() == Qt::Checked)
268 qpoints.reserve(points.size());
269 for (armarx::Vector2f
const& point : points)
271 qpoints.push_back(toCanvas(point));
275 if (widget.reportEdges->checkState() == Qt::Checked)
278 qedges.reserve(edges.size());
279 for (armarx::LineSegment2D
const&
s : edges)
281 QPoint start = toCanvas(
s.start);
282 QPoint end = toCanvas(
s.end);
283 qedges.push_back(QLine(start, end));
289 float lineWidth = 1.0f;
290 QPen pointPen(QColor(0, 0, 255), lineWidth);
291 painter.setPen(pointPen);
293 painter.drawPoints(qpoints.data(), qpoints.size());
296 QPen edgePen(QColor(0, 255, 0), lineWidth);
297 painter.setPen(edgePen);
298 painter.drawLines(qedges.data(), qedges.size());
311 emit newDataReported();
320 poseUncertaintyX = x;
321 poseUncertaintyY = y;
322 poseUncertaintyTheta = theta;
329 const Vector2fSeq& globalPoints,
334 points = globalPoints;
336 emit newDataReported();
341 const LineSegment2DSeq& globalEdges,
348 emit newDataReported();
366 QString poseString = QString(
"Pose: ") + QString::number(poseX) +
", " +
367 QString::number(poseY) +
", " + QString::number(poseTheta) +
368 "\nUncertainty: " + QString::number(poseUncertaintyX,
'g', 4) +
", " +
369 QString::number(poseUncertaintyY,
'g', 4) +
", " +
370 QString::number(poseUncertaintyTheta,
'g', 4);
371 widget.poseLabel->setText(poseString);
377 setPoseState = SetPoseState::Position;
384 if (setPoseState == SetPoseState::Position)
386 setPosition = setOrientation = p;
387 setPoseState = SetPoseState::Wait;
388 ARMARX_INFO <<
"Poistion set, now setting orientation";
390 else if (setPoseState == SetPoseState::Orientation)
393 setPoseState = SetPoseState::Finished;
394 ARMARX_INFO <<
"Orientation set, waiting for finish";
399 floatToString(
float v)
401 std::ostringstream
s;
402 s.imbue(std::locale::classic());
408 stringToFloat(std::string
const&
string)
410 std::istringstream
s(
string);
411 s.imbue(std::locale::classic());
420 LaserScannerSelfLocalisationWidgetController::updateProperties()
422 if (!localisationAdmin)
424 ARMARX_WARNING <<
"Could not set properties because no admin proxy is set";
428 ARMARX_INFO <<
"start updating LaserScannerSelfLocalisationWidget properties";
429 int smoothingFrameSize = widget.smoothingFrameSize->value();
430 int smoothingMergeDistance = widget.smoothingMergeDistance->value();
431 float matchingMaxDistance = widget.matchingMaxDistance->value();
432 float matchingMinPoints = widget.matchingMinPoints->value();
433 float matchingCorrectionFactor = widget.matchingCorrectionFactor->value();
434 float edgeMaxDistance = widget.edgeMaxDistance->value();
435 float edgeMaxDeltaAngle = widget.edgeMaxDeltaAngle->value();
436 float edgePointAddingThreshold = widget.edgePointAddingThreshold->value();
437 int edgeEpsilon = widget.edgeEpsilon->value();
438 int edgeMinPoints = widget.edgeMinPoints->value();
439 bool useMapCorrection = widget.useMapCorrection->checkState() == Qt::Checked;
440 bool useOdometry = widget.useOdometry->checkState() == Qt::Checked;
441 bool reportPoints = widget.reportPoints->checkState() == Qt::Checked;
442 bool reportEdges = widget.reportEdges->checkState() == Qt::Checked;
443 float sensorStdDev = widget.sensorStdDev->value();
444 float velSensorStdDev = widget.velSensorStdDev->value();
446 Ice::PropertyDict properties;
449 properties[
PROPERTIES_PREFIX +
"MatchingMaxDistance"] = floatToString(matchingMaxDistance);
450 properties[
PROPERTIES_PREFIX +
"MatchingMinPoints"] = floatToString(matchingMinPoints);
452 floatToString(matchingCorrectionFactor);
453 properties[
PROPERTIES_PREFIX +
"EdgeMaxDistance"] = floatToString(edgeMaxDistance);
455 floatToString(edgeMaxDeltaAngle *
M_PI / 180.0);
457 floatToString(edgePointAddingThreshold);
460 properties[
PROPERTIES_PREFIX +
"UseMapCorrection"] = useMapCorrection ?
"1" :
"0";
465 properties[
PROPERTIES_PREFIX +
"VelSensorStdDev"] = floatToString(velSensorStdDev);
467 ARMARX_INFO <<
"setting properties on local admin";
468 localisationAdmin->setProperties(properties);
469 ARMARX_INFO <<
"done updating LaserScannerSelfLocalisationWidget properties";
473 LaserScannerSelfLocalisationWidgetController::readProperties()
476 ObjectPropertyInfos properties = localisationManager->getObjectPropertyInfos(localisationName);
479 int smoothingMergeDistance =
481 float matchingMaxDistance =
483 float matchingMinPoints =
485 float matchingCorrectionFactor =
488 float edgeMaxDeltaAngle =
490 float edgePointAddingThreshold =
494 bool useMapCorrection = properties[
PROPERTIES_PREFIX +
"UseMapCorrection"].value ==
"true";
495 bool useOdometry = properties[
PROPERTIES_PREFIX +
"UseOdometry"].value ==
"true";
496 bool reportPoints = properties[
PROPERTIES_PREFIX +
"ReportPoints"].value ==
"true";
497 bool reportEdges = properties[
PROPERTIES_PREFIX +
"ReportEdges"].value ==
"true";
501 widget.smoothingFrameSize->setValue(smoothingFrameSize);
502 widget.smoothingMergeDistance->setValue(smoothingMergeDistance);
503 widget.matchingMaxDistance->setValue(matchingMaxDistance);
504 widget.matchingMinPoints->setValue(matchingMinPoints);
505 widget.matchingCorrectionFactor->setValue(matchingCorrectionFactor);
506 widget.edgeMaxDistance->setValue(edgeMaxDistance);
507 widget.edgeMaxDeltaAngle->setValue(edgeMaxDeltaAngle);
508 widget.edgePointAddingThreshold->setValue(edgePointAddingThreshold);
509 widget.edgeEpsilon->setValue(edgeEpsilon);
510 widget.edgeMinPoints->setValue(edgeMinPoints);
511 widget.useMapCorrection->setChecked(useMapCorrection);
512 widget.useOdometry->setChecked(useOdometry);
513 widget.reportPoints->setChecked(reportPoints);
514 widget.reportEdges->setChecked(reportEdges);
515 widget.sensorStdDev->setValue(sensorStdDev);
516 widget.velSensorStdDev->setValue(velSensorStdDev);
522 painterWidget->update();