mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 09:30:25 +08:00
Windows CI: make vcpkg download compatible with draft release (#1727)
* Windows CI: make vcpkg download compatible with draft release * forcing nvdia driver dll to be ignored in fixup_bundle * disabling opencv cudec and python * disabling rtabmap-console --version on cuda build * Added assert when bad imu data is provided. Added checks when zed sdk is returning nan imu data. * Updated zed sdk5 resolution and quality * Updated zed sdk5 resolution and quality * Fixing parameters reloaded when testing camera. Also fixed app freezing when closing Preferences dialog after using test camera dialog * cleanup and debug logs * Added dialogs when starting/stopping sensors/detection. Fixed nullptr bug on MainWindow::handleEvents * renamed * found a way to expose ZED model downloads * Updated default config path on Windows * Fixed extra endline in file logging (windows) * Fixed camera local transform when used with lidar and odomSensor * CI(macos): build g2o from source with OpenMP (libomp include/link fix) * Mac: added ceres dep, fixed omp not found by cmake * Mac: bundle orbbec extensions * stripping rpath of orbbec's extensions * cleanup * Realsense2 error as error (not warning) * Fixed config ownership changed to root when sarting in sudo. LidarVLP16: fixed crash on Mac by reimplementing our own socket threading * LidarVLP16: own socket implementation only for Mac (linux and windows use original PCL's reader)
This commit is contained in:
@@ -130,6 +130,12 @@ public:
|
||||
|
||||
virtual QString getIniFilePath() const;
|
||||
virtual QString getTmpIniFilePath() const;
|
||||
// When running under sudo, Qt's QSettings replaces the ini with a
|
||||
// root-owned file (write-temp + rename), so later non-root runs can no
|
||||
// longer save preferences. Restore the invoking user's ownership (from
|
||||
// SUDO_UID/SUDO_GID) on the config file and its directory. No-op on Windows
|
||||
// and when not running as root. Best-effort (ignores failures).
|
||||
static void restoreConfigOwnership(const QString & filePath);
|
||||
void init(const QString & iniFilePath = "");
|
||||
void setCurrentPanelToSource();
|
||||
virtual QString getDefaultWorkingDirectory() const;
|
||||
@@ -263,6 +269,9 @@ public:
|
||||
PreferencesDialog::Src getSourceDriver() const;
|
||||
QString getSourceDriverStr() const;
|
||||
QString getSourceDevice() const;
|
||||
// Non-empty warning to show before opening the selected source when init() is expected to be
|
||||
// unusually slow; empty otherwise.
|
||||
QString getSourceInitWarningMsg() const;
|
||||
PreferencesDialog::Src getLidarSourceDriver() const;
|
||||
PreferencesDialog::Src getOdomSourceDriver() const;
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QThread>
|
||||
#include <rtabmap/utilite/ULogger.h>
|
||||
#include <rtabmap/utilite/UDirectory.h>
|
||||
@@ -583,12 +586,33 @@ QString DatabaseViewer::getIniFilePath() const
|
||||
{
|
||||
return iniFilePath_;
|
||||
}
|
||||
#ifdef WIN32
|
||||
// Windows: store settings in the standard per-user config location (%LOCALAPPDATA%\rtabmap)
|
||||
// instead of a Unix-style dotfile in the home root. A fixed "rtabmap" folder (not the app name)
|
||||
// is used so the main GUI and DatabaseViewer share the same rtabmap.ini. Other platforms keep
|
||||
// ~/.rtabmap for consistency.
|
||||
QString privatePath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/rtabmap";
|
||||
#else
|
||||
QString privatePath = QDir::homePath() + "/.rtabmap";
|
||||
#endif
|
||||
if(!QDir(privatePath).exists())
|
||||
{
|
||||
QDir::home().mkdir(".rtabmap");
|
||||
QDir().mkpath(privatePath);
|
||||
}
|
||||
return privatePath + "/rtabmap.ini";
|
||||
QString iniPath = privatePath + "/rtabmap.ini";
|
||||
#ifdef WIN32
|
||||
// One-time migration: if there's no ini at the new location but the legacy ~/.rtabmap/rtabmap.ini
|
||||
// exists, copy it over so users keep their existing settings.
|
||||
if(!QFile::exists(iniPath))
|
||||
{
|
||||
QString legacyIni = QDir::homePath() + "/.rtabmap/rtabmap.ini";
|
||||
if(QFile::exists(legacyIni))
|
||||
{
|
||||
QFile::copy(legacyIni, iniPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return iniPath;
|
||||
}
|
||||
|
||||
void DatabaseViewer::readSettings()
|
||||
|
||||
@@ -78,6 +78,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QProgressDialog>
|
||||
#include <QLabel>
|
||||
#include <QGraphicsEllipseItem>
|
||||
#include <QDockWidget>
|
||||
#include <QtCore/QBuffer>
|
||||
@@ -958,7 +960,7 @@ bool MainWindow::handleEvent(UEvent* anEvent)
|
||||
else
|
||||
{
|
||||
Q_EMIT cameraInfoReceived(sensorEvent->info());
|
||||
if (_odomThread == 0 && (_sensorCapture->odomProvided()) && _preferencesDialog->isRGBDMode())
|
||||
if (_odomThread == 0 && _sensorCapture && _sensorCapture->odomProvided() && _preferencesDialog->isRGBDMode())
|
||||
{
|
||||
OdometryInfo odomInfo;
|
||||
odomInfo.reg.covariance = sensorEvent->info().odomCovariance;
|
||||
@@ -5528,6 +5530,10 @@ void MainWindow::saveConfigGUI()
|
||||
_preferencesDialog->saveSettings();
|
||||
this->saveFigures();
|
||||
this->setWindowModified(false);
|
||||
|
||||
// If running under sudo, the above writes recreate rtabmap.ini as root;
|
||||
// restore ownership so non-root runs can still save preferences.
|
||||
PreferencesDialog::restoreConfigOwnership(_preferencesDialog->getIniFilePath());
|
||||
}
|
||||
|
||||
void MainWindow::newDatabase()
|
||||
@@ -5932,6 +5938,31 @@ void MainWindow::startDetection()
|
||||
Camera * camera = 0;
|
||||
Lidar * lidar = 0;
|
||||
|
||||
// Creating the sensors below opens the devices (createLidar/createCamera/createOdomSensor ->
|
||||
// init(), a few seconds for ZED/RealSense) on the GUI thread; show a busy dialog (min==max==0
|
||||
// => indeterminate) so the window isn't just frozen. Hidden once all sensors are created below.
|
||||
QString startLabel = tr("Starting sensor...");
|
||||
QString initWarn = _preferencesDialog->getSourceInitWarningMsg();
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
startLabel += "\n\n" + initWarn;
|
||||
}
|
||||
QProgressDialog progress(startLabel, QString(), 0, 0, this);
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
QLabel * wrapLabel = new QLabel(startLabel);
|
||||
wrapLabel->setWordWrap(true);
|
||||
progress.setLabel(wrapLabel); // QProgressDialog takes ownership
|
||||
progress.setMinimumWidth(450);
|
||||
}
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setCancelButton(0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
|
||||
if(_preferencesDialog->getLidarSourceDriver() != PreferencesDialog::kSrcUndef)
|
||||
{
|
||||
lidar = _preferencesDialog->createLidar();
|
||||
@@ -5989,6 +6020,8 @@ void MainWindow::startDetection()
|
||||
}
|
||||
}
|
||||
|
||||
progress.hide(); // all sensors created/opened
|
||||
|
||||
_sensorCapture = new SensorCaptureThread(lidar, camera, odomSensor, extrinsics, poseTimeOffset, scaleFactor, waitTime, parameters);
|
||||
|
||||
_sensorCapture->setOdomAsGroundTruth(_preferencesDialog->isOdomSensorAsGt());
|
||||
@@ -6229,6 +6262,24 @@ void MainWindow::stopDetection()
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
// Closing the camera runs on the GUI thread in "delete _sensorCapture" below (via
|
||||
// ~SensorCaptureThread -> ~Camera::close()) and can block for a while - e.g. the first 2-3
|
||||
// RealSense closes per launch stall ~20s in the Motion Module stop() (librealsense warm-up).
|
||||
// Show a busy dialog (min==max==0 => indeterminate) so the window isn't just frozen. It is
|
||||
// declared here so it stays visible across the joins/deletes and closes on scope exit.
|
||||
QProgressDialog progress(tr("Stopping sensor..."), QString(), 0, 0, this);
|
||||
if(_sensorCapture)
|
||||
{
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setCancelButton(0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
}
|
||||
|
||||
// kill the processes
|
||||
if(_imuThread)
|
||||
{
|
||||
|
||||
@@ -39,9 +39,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QUrl>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // geteuid, chown
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib> // atoi, getenv
|
||||
#include <cerrno>
|
||||
#include <cstring> // strerror
|
||||
#endif
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
@@ -49,6 +60,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QtGui/QStandardItemModel>
|
||||
#include <QMainWindow>
|
||||
#include <QProgressDialog>
|
||||
#include <QApplication>
|
||||
#include <QLabel>
|
||||
#include <functional>
|
||||
#include <QScrollBar>
|
||||
#include <QStatusBar>
|
||||
#include <QFormLayout>
|
||||
@@ -437,12 +451,29 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->comboBox_cameraStereo->setItemData(kSrcStereoZed - kSrcStereo, 0, Qt::UserRole - 1);
|
||||
_ui->comboBox_odom_sensor->setItemData(2, 0, Qt::UserRole - 1);
|
||||
}
|
||||
else if(CameraStereoZed::sdkVersion() < 4)
|
||||
else
|
||||
{
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(1, 0, Qt::UserRole - 1);
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(4, 0, Qt::UserRole - 1);
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(6, 0, Qt::UserRole - 1);
|
||||
_ui->comboBox_stereoZed_quality->setItemData(3, 0, Qt::UserRole - 1);
|
||||
if(CameraStereoZed::sdkVersion() < 5)
|
||||
{
|
||||
// SDK 4.X
|
||||
_ui->comboBox_stereoZed_quality->setItemData(5, 0, Qt::UserRole - 1); // NEURAL_ULTRA
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(4, 0, Qt::UserRole - 1); //HD1536
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(10, 0, Qt::UserRole - 1); //XVGA
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(11, 0, Qt::UserRole - 1); //TXGA
|
||||
}
|
||||
if(CameraStereoZed::sdkVersion() < 4)
|
||||
{
|
||||
// SDK 3.X
|
||||
_ui->comboBox_stereoZed_quality->setItemData(3, 0, Qt::UserRole - 1); // NEURAL_LIGHT
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(1, 0, Qt::UserRole - 1); // HD4K
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(2, 0, Qt::UserRole - 1); // QHDPLUS
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(6, 0, Qt::UserRole - 1); // HD1200
|
||||
_ui->comboBox_stereoZed_resolution->setItemData(8, 0, Qt::UserRole - 1); // SVGA
|
||||
}
|
||||
if(CameraStereoZed::sdkVersion() < 3)
|
||||
{
|
||||
_ui->comboBox_stereoZed_quality->setItemData(4, 0, Qt::UserRole - 1); // NEURAL
|
||||
}
|
||||
}
|
||||
if (!CameraStereoTara::available())
|
||||
{
|
||||
@@ -985,7 +1016,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
connect(_ui->lineEdit_vlp16_pcap_path, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_ip1, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_ip2, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_ip2, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_ip3, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_ip4, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->spinBox_vlp16_port, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->checkBox_vlp16_organized, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
@@ -2440,10 +2471,10 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox)
|
||||
|
||||
_ui->lineEdit_lidar_local_transform->setText("0 0 0 0 0 0");
|
||||
_ui->lineEdit_vlp16_pcap_path->clear();
|
||||
_ui->spinBox_vlp16_ip1->setValue(192);
|
||||
_ui->spinBox_vlp16_ip2->setValue(168);
|
||||
_ui->spinBox_vlp16_ip3->setValue(1);
|
||||
_ui->spinBox_vlp16_ip4->setValue(201);
|
||||
_ui->spinBox_vlp16_ip1->setValue(0);
|
||||
_ui->spinBox_vlp16_ip2->setValue(0);
|
||||
_ui->spinBox_vlp16_ip3->setValue(0);
|
||||
_ui->spinBox_vlp16_ip4->setValue(0);
|
||||
_ui->spinBox_vlp16_port->setValue(2368);
|
||||
_ui->checkBox_vlp16_organized->setChecked(false);
|
||||
_ui->checkBox_vlp16_hostTime->setChecked(true);
|
||||
@@ -2559,12 +2590,33 @@ QString PreferencesDialog::getWorkingDirectory() const
|
||||
|
||||
QString PreferencesDialog::getIniFilePath() const
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Windows: store settings in the standard per-user config location (%LOCALAPPDATA%\rtabmap)
|
||||
// instead of a Unix-style dotfile in the home root. A fixed "rtabmap" folder (not the app name)
|
||||
// is used so the main GUI and DatabaseViewer share the same rtabmap.ini. Other platforms keep
|
||||
// ~/.rtabmap for consistency.
|
||||
QString privatePath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/rtabmap";
|
||||
#else
|
||||
QString privatePath = QDir::homePath() + "/.rtabmap";
|
||||
#endif
|
||||
if(!QDir(privatePath).exists())
|
||||
{
|
||||
QDir::home().mkdir(".rtabmap");
|
||||
QDir().mkpath(privatePath);
|
||||
}
|
||||
return privatePath + "/rtabmap.ini";
|
||||
QString iniPath = privatePath + "/rtabmap.ini";
|
||||
#ifdef WIN32
|
||||
// One-time migration: if there's no ini at the new location but the legacy ~/.rtabmap/rtabmap.ini
|
||||
// exists, copy it over so users keep their existing settings.
|
||||
if(!QFile::exists(iniPath))
|
||||
{
|
||||
QString legacyIni = QDir::homePath() + "/.rtabmap/rtabmap.ini";
|
||||
if(QFile::exists(legacyIni))
|
||||
{
|
||||
QFile::copy(legacyIni, iniPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return iniPath;
|
||||
}
|
||||
|
||||
QString PreferencesDialog::getTmpIniFilePath() const
|
||||
@@ -2572,6 +2624,41 @@ QString PreferencesDialog::getTmpIniFilePath() const
|
||||
return getIniFilePath()+".tmp";
|
||||
}
|
||||
|
||||
void PreferencesDialog::restoreConfigOwnership(const QString & filePath)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// Only relevant when the process is effectively root (e.g. launched with
|
||||
// sudo). getenv("SUDO_UID"/"SUDO_GID") give the invoking user.
|
||||
if(geteuid() == 0)
|
||||
{
|
||||
const char * sudoUid = getenv("SUDO_UID");
|
||||
const char * sudoGid = getenv("SUDO_GID");
|
||||
if(sudoUid && sudoGid)
|
||||
{
|
||||
uid_t uid = (uid_t)atoi(sudoUid);
|
||||
gid_t gid = (gid_t)atoi(sudoGid);
|
||||
// Restore the config file and its containing directory so the user
|
||||
// can still write preferences without sudo afterwards.
|
||||
if(!filePath.isEmpty() && QFile::exists(filePath))
|
||||
{
|
||||
if(chown(filePath.toStdString().c_str(), uid, gid) != 0)
|
||||
{
|
||||
UWARN("Could not restore ownership of \"%s\" to uid=%d (%s).",
|
||||
filePath.toStdString().c_str(), (int)uid, strerror(errno));
|
||||
}
|
||||
}
|
||||
QString dir = QFileInfo(filePath).absolutePath();
|
||||
if(!dir.isEmpty())
|
||||
{
|
||||
chown(dir.toStdString().c_str(), uid, gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(filePath);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PreferencesDialog::loadConfigFrom()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Load settings..."), this->getWorkingDirectory(), "*.ini");
|
||||
@@ -3242,6 +3329,9 @@ void PreferencesDialog::writeSettings(const QString & filePath)
|
||||
uInsert(_parameters, _modifiedParameters); // update cached parameters
|
||||
_modifiedParameters.clear();
|
||||
_obsoletePanels = kPanelDummy;
|
||||
|
||||
// Keep the ini writable by the invoking user even if we are running as root.
|
||||
restoreConfigOwnership(filePath.isEmpty() ? getIniFilePath() : filePath);
|
||||
}
|
||||
|
||||
void PreferencesDialog::writeGuiSettings(const QString & filePath) const
|
||||
@@ -6635,6 +6725,16 @@ QString PreferencesDialog::getSourceDriverStr() const
|
||||
return "";
|
||||
}
|
||||
|
||||
QString PreferencesDialog::getSourceInitWarningMsg() const
|
||||
{
|
||||
if(getSourceDriver() == kSrcStereoZed)
|
||||
{
|
||||
return QString::fromStdString(
|
||||
CameraStereoZed::getNeuralModelWarning(_ui->comboBox_stereoZed_quality->currentIndex()));
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString PreferencesDialog::getSourceDevice() const
|
||||
{
|
||||
return _ui->lineEdit_sourceDevice->text();
|
||||
@@ -6820,11 +6920,11 @@ double PreferencesDialog::getSourceScanForceGroundNormalsUp() const
|
||||
Camera * PreferencesDialog::createCamera(bool useRawImages, bool useColor)
|
||||
{
|
||||
return createCamera(
|
||||
this->getSourceDriver(),
|
||||
_ui->lineEdit_sourceDevice->text(),
|
||||
_ui->lineEdit_calibrationFile->text(),
|
||||
useRawImages,
|
||||
useColor,
|
||||
this->getSourceDriver(),
|
||||
_ui->lineEdit_sourceDevice->text(),
|
||||
_ui->lineEdit_calibrationFile->text(),
|
||||
useRawImages,
|
||||
useColor,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
@@ -7728,7 +7828,30 @@ void PreferencesDialog::setSLAMMode(bool enabled)
|
||||
|
||||
void PreferencesDialog::testOdometry()
|
||||
{
|
||||
QString startLabel = tr("Starting camera...");
|
||||
QString initWarn = getSourceInitWarningMsg();
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
startLabel += "\n\n" + initWarn;
|
||||
}
|
||||
QProgressDialog progress(startLabel, QString(), 0, 0, this);
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
QLabel * wrapLabel = new QLabel(startLabel);
|
||||
wrapLabel->setWordWrap(true);
|
||||
progress.setLabel(wrapLabel); // QProgressDialog takes ownership
|
||||
progress.setMinimumWidth(450);
|
||||
}
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setCancelButton(0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
|
||||
Camera * camera = this->createCamera();
|
||||
progress.hide();
|
||||
if(!camera)
|
||||
{
|
||||
return;
|
||||
@@ -7776,12 +7899,13 @@ void PreferencesDialog::testOdometry()
|
||||
_ui->odom_dataBufferSize->value());
|
||||
odomThread.registerToEventsManager();
|
||||
|
||||
// parent = 0 (not 'this'): see testCamera() - avoids the nested-modality crash.
|
||||
OdometryViewer * odomViewer = new OdometryViewer(10,
|
||||
_ui->spinBox_decimation_odom->value(),
|
||||
0.0f,
|
||||
_ui->doubleSpinBox_maxDepth_odom->value(),
|
||||
this->getOdomQualityWarnThr(),
|
||||
this,
|
||||
0,
|
||||
this->getAllParameters());
|
||||
odomViewer->setWindowTitle(tr("Odometry viewer"));
|
||||
odomViewer->resize(1280, 480+QPushButton().minimumHeight());
|
||||
@@ -7843,25 +7967,79 @@ void PreferencesDialog::testOdometry()
|
||||
}
|
||||
|
||||
odomViewer->exec();
|
||||
delete odomViewer;
|
||||
UDEBUG("Dialog closed, stopping sensor...");
|
||||
|
||||
// Tear down the pipes first so no more events are routed to the threads/viewer being
|
||||
// destroyed, then stop the threads, then delete the viewer. This avoids delivering
|
||||
// events to a handler that is being torn down.
|
||||
UEventsManager::removePipe(&cameraThread, &odomThread, "SensorEvent");
|
||||
if(imuThread)
|
||||
{
|
||||
UEventsManager::removePipe(imuThread, &odomThread, "IMUEvent");
|
||||
}
|
||||
UEventsManager::removePipe(&odomThread, odomViewer, "OdometryEvent");
|
||||
UEventsManager::removePipe(odomViewer, &odomThread, "OdometryResetEvent");
|
||||
|
||||
if(imuThread)
|
||||
{
|
||||
imuThread->join(true);
|
||||
delete imuThread;
|
||||
}
|
||||
|
||||
// Reuse the same dialog for the close. The device close() runs in cameraThread's destructor
|
||||
// at function scope end (not in join()), so 'progress' stays visible across it. On Windows
|
||||
// the first 2-3 RealSense closes per launch stall ~20s in the Motion Module stop().
|
||||
progress.setLabelText(tr("Closing camera..."));
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
cameraThread.join(true);
|
||||
odomThread.join(true);
|
||||
|
||||
// deleteLater() (not delete): see testCamera() - avoids a dangling OpenGL platform
|
||||
// window that crashes in QWindowsWindow::alertWindow when Preferences later closes.
|
||||
odomViewer->deleteLater();
|
||||
if(imuThread)
|
||||
{
|
||||
delete imuThread;
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::testCamera()
|
||||
{
|
||||
CameraViewer * window = new CameraViewer(this, this->getAllParameters());
|
||||
// Not parented to 'this': the Preferences dialog is itself application-modal, and making
|
||||
// the viewer a modal *child* of it (nested modality) with an OpenGL/VTK native window
|
||||
// crashes Qt (QWindowsWindow::alertWindow, this==nullptr) when Preferences later closes.
|
||||
// exec() below still makes the viewer application-modal, so interaction stays blocked.
|
||||
CameraViewer * window = new CameraViewer(nullptr, this->getAllParameters());
|
||||
window->setWindowTitle(tr("Camera viewer"));
|
||||
window->resize(1280, 480+QPushButton().minimumHeight());
|
||||
window->registerToEventsManager();
|
||||
|
||||
QString startLabel = tr("Starting camera...");
|
||||
QString initWarn = getSourceInitWarningMsg();
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
startLabel += "\n\n" + initWarn;
|
||||
}
|
||||
QProgressDialog progress(startLabel, QString(), 0, 0, this);
|
||||
if(!initWarn.isEmpty())
|
||||
{
|
||||
QLabel * wrapLabel = new QLabel(startLabel);
|
||||
wrapLabel->setWordWrap(true);
|
||||
progress.setLabel(wrapLabel); // QProgressDialog takes ownership
|
||||
progress.setMinimumWidth(450);
|
||||
}
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setCancelButton(0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
|
||||
// createCamera() init()s the device on the GUI thread (required by ZED) and takes a few seconds.
|
||||
Camera * camera = this->createCamera();
|
||||
progress.hide();
|
||||
if(camera)
|
||||
{
|
||||
SensorCaptureThread cameraThread(camera, this->getAllParameters());
|
||||
@@ -7906,12 +8084,26 @@ void PreferencesDialog::testCamera()
|
||||
|
||||
cameraThread.start();
|
||||
window->exec();
|
||||
delete window;
|
||||
cameraThread.join(true);
|
||||
UDEBUG("Dialog closed, stopping sensor...");
|
||||
UEventsManager::removePipe(&cameraThread, window, "SensorEvent");
|
||||
|
||||
// Reuse the same dialog for the close. The device close() runs in cameraThread's
|
||||
// destructor at scope end (not in join()), so 'progress' - declared in the outer scope -
|
||||
// stays visible across it. On Windows the first 2-3 RealSense closes per launch stall
|
||||
// ~20s in the Motion Module stop() (librealsense warm-up); this keeps the user informed.
|
||||
progress.setLabelText(tr("Closing camera..."));
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
cameraThread.join(true); // cameraThread's destructor (scope end) closes the device
|
||||
// deleteLater() (not delete): defer destruction to the event loop so Qt finishes
|
||||
// tearing down the OpenGL widget's context and window-proc subclass and drains
|
||||
// pending activation messages first.
|
||||
window->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete window;
|
||||
window->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8377,14 +8569,25 @@ void PreferencesDialog::calibrateOdomSensorExtrinsics()
|
||||
|
||||
void PreferencesDialog::testLidar()
|
||||
{
|
||||
CameraViewer * window = new CameraViewer(this, this->getAllParameters());
|
||||
// Not parented to 'this': see testCamera() - avoids the nested-modality crash.
|
||||
CameraViewer * window = new CameraViewer(nullptr, this->getAllParameters());
|
||||
window->setWindowTitle(tr("Lidar viewer"));
|
||||
window->setWindowFlags(Qt::Window);
|
||||
window->resize(1280, 480+QPushButton().minimumHeight());
|
||||
window->registerToEventsManager();
|
||||
window->setDecimation(1);
|
||||
|
||||
QProgressDialog progress(tr("Starting lidar..."), QString(), 0, 0, this);
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setCancelButton(0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.setValue(0);
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
|
||||
Lidar * lidar = this->createLidar();
|
||||
progress.hide();
|
||||
if(lidar)
|
||||
{
|
||||
SensorCaptureThread lidarThread(lidar, this->getAllParameters());
|
||||
@@ -8403,12 +8606,24 @@ void PreferencesDialog::testLidar()
|
||||
|
||||
lidarThread.start();
|
||||
window->exec();
|
||||
delete window;
|
||||
lidarThread.join(true);
|
||||
UDEBUG("Dialog closed, stopping sensor...");
|
||||
UEventsManager::removePipe(&lidarThread, window, "SensorEvent");
|
||||
|
||||
// Reuse the same dialog for the close. The device close() runs in lidarThread's
|
||||
// destructor at scope end (not in join()), so 'progress' - declared in the outer
|
||||
// scope - stays visible across it.
|
||||
progress.setLabelText(tr("Closing sensor..."));
|
||||
progress.show();
|
||||
QApplication::processEvents();
|
||||
QApplication::processEvents(); // make sure it is drawn
|
||||
lidarThread.join(true); // lidarThread's destructor (scope end) closes the device
|
||||
// deleteLater() (not delete): see testCamera() - avoids a dangling OpenGL platform
|
||||
// window that crashes in QWindowsWindow::alertWindow when Preferences later closes.
|
||||
window->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete window;
|
||||
window->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5740,11 +5740,21 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<string>ULTRA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>NEURAL LIGHT</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>NEURAL</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>NEURAL PLUS</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
@@ -5903,11 +5913,21 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<string>HD4K</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>QHDPLUS</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HD2K</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HD1536</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HD1080</string>
|
||||
@@ -5933,6 +5953,16 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<string>VGA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>XVGA</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>TXVGA</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -9387,9 +9417,6 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_vlp16_ip1">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>KITTI: 130 000 points</p></body></html></string>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@@ -9400,15 +9427,12 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>192</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_vlp16_ip2">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>KITTI: 130 000 points</p></body></html></string>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@@ -9419,15 +9443,12 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>168</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_vlp16_ip3">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>KITTI: 130 000 points</p></body></html></string>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@@ -9438,15 +9459,12 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_vlp16_ip4">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>KITTI: 130 000 points</p></body></html></string>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
@@ -9457,7 +9475,7 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>201</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -9498,8 +9516,11 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_743">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Local network interface (IP address of <span style=" font-weight:600;">this</span> computer) on which to listen for VLP16 packets. Use 0.0.0.0 to listen on all interfaces (recommended). This is NOT the sensor's IP address; the sensor decides where to send its data (configure its destination host in the sensor's own web interface).</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IP Address.</string>
|
||||
<string>Local IP to listen on (0.0.0.0 = all interfaces). See tooltip.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -9554,8 +9575,11 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_744">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Local UDP port on this computer to listen for VLP16 data packets (default 2368). The LiDAR must be configured to send its data to this port.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Port.</string>
|
||||
<string>Port to listen on (default 2368).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -9567,9 +9591,6 @@ when using the file type, logs are saved in LogRtabmap.txt (located in the worki
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_vlp16_port">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>KITTI: 130 000 points</p></body></html></string>
|
||||
</property>
|
||||
<property name="buttonSymbols">
|
||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
||||
</property>
|
||||
|
||||
Reference in New Issue
Block a user