26 #include <QDoubleSpinBox>
36 : setPoseState(SetPoseState::None)
40 painterWidget->
setupUi(widget.frame);
46 paintTimerId = startTimer(16);
75 localisation = getProxy<LaserScannerSelfLocalisationInterfacePrx>(localisationName);
76 localisationManager = getProxy<armarx::ArmarXManagerInterfacePrx>(localisationName +
"Manager");
77 localisationAdmin = localisationManager->getPropertiesAdmin();
80 map = localisation->getMap();
82 connect(widget.smoothingFrameSize, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
83 connect(widget.smoothingMergeDistance, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
84 connect(widget.matchingMaxDistance, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
85 connect(widget.matchingMinPoints, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
86 connect(widget.matchingCorrectionFactor, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
87 connect(widget.edgeMaxDistance, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
88 connect(widget.edgeMaxDeltaAngle, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
89 connect(widget.edgePointAddingThreshold, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
90 connect(widget.edgeEpsilon, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
91 connect(widget.edgeMinPoints, SIGNAL(valueChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
92 connect(widget.useMapCorrection, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
93 connect(widget.useOdometry, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
94 connect(widget.reportPoints, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
95 connect(widget.reportEdges, SIGNAL(stateChanged(
int)),
this, SLOT(
onSpinBoxChanged(
int)));
96 connect(widget.setPoseButton, SIGNAL(clicked()),
this, SLOT(
onSetPoseClick()));
97 connect(widget.sensorStdDev, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
98 connect(widget.velSensorStdDev, SIGNAL(valueChanged(
double)),
this, SLOT(
onSpinBoxChanged(
double)));
100 connect(painterWidget, SIGNAL(mousePressed(QPoint)),
this, SLOT(
onCanvasClick(QPoint)));
104 usingTopic(localisation->getReportTopicName());
113 dialog->addProxyFinder<LaserScannerSelfLocalisationInterfacePrx>({
"LaserScannerSelfLocalisation",
"",
"*"});
115 return qobject_cast<SimpleConfigDialog*>(dialog);
122 localisationName = dialog->getProxyName(
"LaserScannerSelfLocalisation");
129 float minX = FLT_MAX;
131 float minY = FLT_MAX;
132 for (LineSegment2D&
s : map)
144 float normX = 1.0f / (maxX - minX);
145 float normY = 1.0f / (maxY - minY);
146 float scaleFactorX = size.width() * normX;
147 float scaleFactorY = size.height() * normY;
148 float scaleFactor = 0.95f *
std::min(scaleFactorX, scaleFactorY);
149 float invScaleFactor = 1.0f / scaleFactor;
151 auto toCanvas = [ = ](armarx::Vector2f p)
153 float xCoord = scaleFactor * (p.e0 - minX);
154 float yCoord = scaleFactor * (p.e1 - minY);
155 return QPoint((
int)xCoord, (
int)(size.height() - 1 - yCoord));
158 auto toCanvasE = [ = ](Eigen::Vector2f p)
160 float xCoord = scaleFactor * (p.x() - minX);
161 float yCoord = scaleFactor * (p.y() - minY);
162 return QPoint((
int)xCoord, (
int)(size.height() - 1 - yCoord));
165 auto fromCanvas = [ = ](QPoint p)
167 float globalX = (invScaleFactor * p.x()) + minX;
168 float globalY = invScaleFactor * (size.height() - 1 - p.y()) + minY;
169 return Eigen::Vector2f(globalX, globalY);
172 if (setPoseState == SetPoseState::Wait)
174 setPoseState = SetPoseState::Orientation;
176 else if (setPoseState == SetPoseState::Finished)
179 Eigen::Vector2f globalPos = fromCanvas(setPosition);
180 Eigen::Vector2f globalOr = fromCanvas(setOrientation);
181 Eigen::Vector2f fromPosToOr = globalOr - globalPos;
182 float theta = std::atan2(fromPosToOr.y(), fromPosToOr.x()) - M_PI_2;
186 ARMARX_INFO <<
"Set global pose to (" << globalPos.x() <<
", " << globalPos.y() <<
", " << theta <<
")";
187 localisation->setAbsolutePose(globalPos.x(), globalPos.y(), theta);
189 catch (std::exception
const& ex)
194 setPoseState = SetPoseState::None;
197 QBrush whiteBrush(QColor(240, 240, 240));
198 QPen blackPen(QColor(0, 0, 0));
199 blackPen.setWidth(1);
200 painter.setBrush(whiteBrush);
201 painter.setPen(blackPen);
204 lines.reserve(map.size());
205 for (LineSegment2D
const&
s : map)
207 lines.emplace_back(toCanvas(
s.start), toCanvas(
s.end));
209 painter.drawLines(lines.data(), lines.size());
211 if (setPoseState == SetPoseState::Orientation)
213 QPoint setOrientation = painterWidget->mapFromGlobal(QCursor::pos());
214 Eigen::Vector2f globalPos = fromCanvas(setPosition);
215 Eigen::Vector2f globalOr = fromCanvas(setOrientation);
217 painter.setBrush(QColor(255, 0, 0));
218 painter.drawEllipse(toCanvasE(globalPos), 10, 10);
219 painter.drawLine(toCanvasE(globalPos), toCanvasE(globalOr));
223 Eigen::Vector2f robotPos(poseX, poseY);
224 float robotTheta = poseTheta;
226 armarx::Vector2f estRobotPos {robotPos.x(), robotPos.y()};
227 Eigen::Vector2f estRobotEnd = robotPos + 500.0f * Eigen::Vector2f(Eigen::Rotation2Df(robotTheta) * Eigen::Vector2f::UnitY());
228 armarx::Vector2f estRobotEnda {estRobotEnd.x(), estRobotEnd.y()};
229 painter.setBrush(QColor(0, 255, 255));
230 painter.drawEllipse(toCanvas(estRobotPos), 10, 10);
231 painter.drawLine(toCanvas(estRobotPos), toCanvas(estRobotEnda));
232 painter.setBrush(QColor(255, 255, 0, 25));
233 float posUncertaintyAverage = (poseUncertaintyX + poseUncertaintyY) * 0.5;
234 painter.drawEllipse(toCanvas(estRobotPos), (int)(posUncertaintyAverage * scaleFactor), (int)(posUncertaintyAverage * scaleFactor));
240 if (widget.reportPoints->checkState() == Qt::Checked)
243 qpoints.reserve(points.size());
244 for (armarx::Vector2f
const& point : points)
246 qpoints.push_back(toCanvas(point));
250 if (widget.reportEdges->checkState() == Qt::Checked)
253 qedges.reserve(edges.size());
254 for (armarx::LineSegment2D
const&
s : edges)
256 QPoint start = toCanvas(
s.start);
257 QPoint end = toCanvas(
s.end);
258 qedges.push_back(QLine(start, end));
264 float lineWidth = 1.0f;
265 QPen pointPen(QColor(0, 0, 255), lineWidth);
266 painter.setPen(pointPen);
268 painter.drawPoints(qpoints.data(), qpoints.size());
271 QPen edgePen(QColor(0, 255, 0), lineWidth);
272 painter.setPen(edgePen);
273 painter.drawLines(qedges.data(), qedges.size());
283 emit newDataReported();
288 poseUncertaintyX = x;
289 poseUncertaintyY = y;
290 poseUncertaintyTheta = theta;
301 points = globalPoints;
303 emit newDataReported();
312 emit newDataReported();
327 QString poseString = QString(
"Pose: ") + QString::number(poseX) +
", " + QString::number(poseY)
328 +
", " + QString::number(poseTheta) +
"\nUncertainty: " + QString::number(poseUncertaintyX,
'g', 4) +
", " + QString::number(poseUncertaintyY,
'g', 4)
329 +
", " + QString::number(poseUncertaintyTheta,
'g', 4);
330 widget.poseLabel->setText(poseString);
335 setPoseState = SetPoseState::Position;
341 if (setPoseState == SetPoseState::Position)
343 setPosition = setOrientation = p;
344 setPoseState = SetPoseState::Wait;
345 ARMARX_INFO <<
"Poistion set, now setting orientation";
347 else if (setPoseState == SetPoseState::Orientation)
350 setPoseState = SetPoseState::Finished;
351 ARMARX_INFO <<
"Orientation set, waiting for finish";
355 static std::string floatToString(
float v)
357 std::ostringstream
s;
358 s.imbue(std::locale::classic());
363 static float stringToFloat(std::string
const&
string)
365 std::istringstream
s(
string);
366 s.imbue(std::locale::classic());
374 void LaserScannerSelfLocalisationWidgetController::updateProperties()
376 if (!localisationAdmin)
378 ARMARX_WARNING <<
"Could not set properties because no admin proxy is set";
382 ARMARX_INFO <<
"start updating LaserScannerSelfLocalisationWidget properties";
383 int smoothingFrameSize = widget.smoothingFrameSize->value();
384 int smoothingMergeDistance = widget.smoothingMergeDistance->value();
385 float matchingMaxDistance = widget.matchingMaxDistance->value();
386 float matchingMinPoints = widget.matchingMinPoints->value();
387 float matchingCorrectionFactor = widget.matchingCorrectionFactor->value();
388 float edgeMaxDistance = widget.edgeMaxDistance->value();
389 float edgeMaxDeltaAngle = widget.edgeMaxDeltaAngle->value();
390 float edgePointAddingThreshold = widget.edgePointAddingThreshold->value();
391 int edgeEpsilon = widget.edgeEpsilon->value();
392 int edgeMinPoints = widget.edgeMinPoints->value();
393 bool useMapCorrection = widget.useMapCorrection->checkState() == Qt::Checked;
394 bool useOdometry = widget.useOdometry->checkState() == Qt::Checked;
395 bool reportPoints = widget.reportPoints->checkState() == Qt::Checked;
396 bool reportEdges = widget.reportEdges->checkState() == Qt::Checked;
397 float sensorStdDev = widget.sensorStdDev->value();
398 float velSensorStdDev = widget.velSensorStdDev->value();
400 Ice::PropertyDict properties;
403 properties[
PROPERTIES_PREFIX +
"MatchingMaxDistance"] = floatToString(matchingMaxDistance);
404 properties[
PROPERTIES_PREFIX +
"MatchingMinPoints"] = floatToString(matchingMinPoints);
405 properties[
PROPERTIES_PREFIX +
"MatchingCorrectionFactor"] = floatToString(matchingCorrectionFactor);
406 properties[
PROPERTIES_PREFIX +
"EdgeMaxDistance"] = floatToString(edgeMaxDistance);
407 properties[
PROPERTIES_PREFIX +
"EdgeMaxDeltaAngle"] = floatToString(edgeMaxDeltaAngle *
M_PI / 180.0);
408 properties[
PROPERTIES_PREFIX +
"EdgePointAddingThreshold"] = floatToString(edgePointAddingThreshold);
411 properties[
PROPERTIES_PREFIX +
"UseMapCorrection"] = useMapCorrection ?
"1" :
"0";
416 properties[
PROPERTIES_PREFIX +
"VelSensorStdDev"] = floatToString(velSensorStdDev);
418 ARMARX_INFO <<
"setting properties on local admin";
419 localisationAdmin->setProperties(properties);
420 ARMARX_INFO <<
"done updating LaserScannerSelfLocalisationWidget properties";
423 void LaserScannerSelfLocalisationWidgetController::readProperties()
426 ObjectPropertyInfos properties = localisationManager->getObjectPropertyInfos(localisationName);
432 float matchingCorrectionFactor = stringToFloat(properties[
PROPERTIES_PREFIX +
"MatchingCorrectionFactor"].
value);
435 float edgePointAddingThreshold = stringToFloat(properties[
PROPERTIES_PREFIX +
"EdgePointAddingThreshold"].
value);
438 bool useMapCorrection = properties[
PROPERTIES_PREFIX +
"UseMapCorrection"].value ==
"true";
439 bool useOdometry = properties[
PROPERTIES_PREFIX +
"UseOdometry"].value ==
"true";
440 bool reportPoints = properties[
PROPERTIES_PREFIX +
"ReportPoints"].value ==
"true";
441 bool reportEdges = properties[
PROPERTIES_PREFIX +
"ReportEdges"].value ==
"true";
445 widget.smoothingFrameSize->setValue(smoothingFrameSize);
446 widget.smoothingMergeDistance->setValue(smoothingMergeDistance);
447 widget.matchingMaxDistance->setValue(matchingMaxDistance);
448 widget.matchingMinPoints->setValue(matchingMinPoints);
449 widget.matchingCorrectionFactor->setValue(matchingCorrectionFactor);
450 widget.edgeMaxDistance->setValue(edgeMaxDistance);
451 widget.edgeMaxDeltaAngle->setValue(edgeMaxDeltaAngle);
452 widget.edgePointAddingThreshold->setValue(edgePointAddingThreshold);
453 widget.edgeEpsilon->setValue(edgeEpsilon);
454 widget.edgeMinPoints->setValue(edgeMinPoints);
455 widget.useMapCorrection->setChecked(useMapCorrection);
456 widget.useOdometry->setChecked(useOdometry);
457 widget.reportPoints->setChecked(reportPoints);
458 widget.reportEdges->setChecked(reportEdges);
459 widget.sensorStdDev->setValue(sensorStdDev);
460 widget.velSensorStdDev->setValue(velSensorStdDev);
465 painterWidget->update();