Commit 50929c20 authored by Valentin Platzgummer's avatar Valentin Platzgummer

1243

parent 65679db5
...@@ -28,11 +28,13 @@ QGCROOT = $$PWD ...@@ -28,11 +28,13 @@ QGCROOT = $$PWD
DebugBuild { DebugBuild {
DESTDIR = $${OUT_PWD}/debug DESTDIR = $${OUT_PWD}/debug
DEFINES += DEBUG DEFINES += DEBUG
DEFINES += SNAKE_SHOW_TIME
#DEFINES += ROS_BRIDGE_DEBUG #DEFINES += ROS_BRIDGE_DEBUG
} }
else { else {
DESTDIR = $${OUT_PWD}/release DESTDIR = $${OUT_PWD}/release
#DEFINES += ROS_BRIDGE_DEBUG #DEFINES += ROS_BRIDGE_DEBUG
DEFINES += SNAKE_SHOW_TIME
DEFINES += NDEBUG DEFINES += NDEBUG
} }
...@@ -438,11 +440,11 @@ HEADERS += \ ...@@ -438,11 +440,11 @@ HEADERS += \
src/Wima/Snake/QNemoHeartbeat.h \ src/Wima/Snake/QNemoHeartbeat.h \
src/Wima/Snake/QNemoProgress.h \ src/Wima/Snake/QNemoProgress.h \
src/Wima/Snake/QNemoProgress.h \ src/Wima/Snake/QNemoProgress.h \
src/Wima/Snake/SnakeThread.h \
src/Wima/Snake/SnakeTile.h \ src/Wima/Snake/SnakeTile.h \
src/Wima/Snake/SnakeTileLocal.h \ src/Wima/Snake/SnakeTileLocal.h \
src/Wima/Snake/SnakeTiles.h \ src/Wima/Snake/SnakeTiles.h \
src/Wima/Snake/SnakeTilesLocal.h \ src/Wima/Snake/SnakeTilesLocal.h \
src/Wima/Snake/SnakeDataManager.h \
src/Wima/WaypointManager/AreaInterface.h \ src/Wima/WaypointManager/AreaInterface.h \
src/Wima/WaypointManager/DefaultManager.h \ src/Wima/WaypointManager/DefaultManager.h \
src/Wima/WaypointManager/GenericWaypointManager.h \ src/Wima/WaypointManager/GenericWaypointManager.h \
...@@ -503,7 +505,7 @@ SOURCES += \ ...@@ -503,7 +505,7 @@ SOURCES += \
src/Wima/Geometry/GeoPoint3D.cpp \ src/Wima/Geometry/GeoPoint3D.cpp \
src/Wima/Snake/NemoInterface.cpp \ src/Wima/Snake/NemoInterface.cpp \
src/Wima/Snake/QNemoProgress.cc \ src/Wima/Snake/QNemoProgress.cc \
src/Wima/Snake/SnakeDataManager.cc \ src/Wima/Snake/SnakeThread.cc \
src/Wima/Snake/SnakeTile.cpp \ src/Wima/Snake/SnakeTile.cpp \
src/Wima/WaypointManager/AreaInterface.cpp \ src/Wima/WaypointManager/AreaInterface.cpp \
src/Wima/WaypointManager/DefaultManager.cpp \ src/Wima/WaypointManager/DefaultManager.cpp \
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
using namespace operations_research; using namespace operations_research;
#ifndef NDEBUG #ifndef NDEBUG
//#define SHOW_TIME //#define SNAKE_SHOW_TIME
#endif #endif
namespace bg = boost::geometry; namespace bg = boost::geometry;
...@@ -104,7 +104,7 @@ bool minimalBoundingBox(const BoostPolygon &polygon, BoundingBox &minBBox) { ...@@ -104,7 +104,7 @@ bool minimalBoundingBox(const BoostPolygon &polygon, BoundingBox &minBBox) {
//# Compute edges (x2-x1,y2-y1) //# Compute edges (x2-x1,y2-y1)
std::vector<BoostPoint> edges; std::vector<BoostPoint> edges;
auto convex_hull_outer = convex_hull.outer(); const auto &convex_hull_outer = convex_hull.outer();
for (long i = 0; i < long(convex_hull_outer.size()) - 1; ++i) { for (long i = 0; i < long(convex_hull_outer.size()) - 1; ++i) {
BoostPoint p1 = convex_hull_outer.at(i); BoostPoint p1 = convex_hull_outer.at(i);
BoostPoint p2 = convex_hull_outer.at(i + 1); BoostPoint p2 = convex_hull_outer.at(i + 1);
...@@ -711,13 +711,12 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength, ...@@ -711,13 +711,12 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength,
// Rotate measurement area by angle and calculate bounding box. // Rotate measurement area by angle and calculate bounding box.
auto &mArea = scenario.measurementArea(); auto &mArea = scenario.measurementArea();
BoostPolygon mAreaRotated; BoostPolygon mAreaRotated;
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(-angle.value() * trans::rotate_transformer<bg::degree, double, 2, 2> rotate(angle.value() *
180 / M_PI); 180 / M_PI);
bg::transform(mArea, mAreaRotated, rotate); bg::transform(mArea, mAreaRotated, rotate);
BoostBox box; BoostBox box;
boost::geometry::envelope(mAreaRotated, box); boost::geometry::envelope(mAreaRotated, box);
double x0 = box.min_corner().get<0>(); double x0 = box.min_corner().get<0>();
double y0 = box.min_corner().get<1>(); double y0 = box.min_corner().get<1>();
double x1 = box.max_corner().get<0>(); double x1 = box.max_corner().get<0>();
...@@ -725,8 +724,6 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength, ...@@ -725,8 +724,6 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength,
// Generate transects and convert them to clipper path. // Generate transects and convert them to clipper path.
size_t num_t = int(ceil((y1 - y0) / distance.value())); // number of transects size_t num_t = int(ceil((y1 - y0) / distance.value())); // number of transects
trans::rotate_transformer<bg::degree, double, 2, 2> rotate_back(
angle.value() * 180 / M_PI);
vector<ClipperLib::Path> transectsClipper; vector<ClipperLib::Path> transectsClipper;
transectsClipper.reserve(num_t); transectsClipper.reserve(num_t);
for (size_t i = 0; i < num_t; ++i) { for (size_t i = 0; i < num_t; ++i) {
...@@ -736,17 +733,20 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength, ...@@ -736,17 +733,20 @@ bool flight_plan::transectsFromScenario(Length distance, Length minLength,
BoostLineString transect; BoostLineString transect;
transect.push_back(v1); transect.push_back(v1);
transect.push_back(v2); transect.push_back(v2);
// transform back // transform back
BoostLineString temp_transect; BoostLineString temp_transect;
trans::rotate_transformer<bg::degree, double, 2, 2> rotate_back(
-angle.value() * 180 / M_PI);
bg::transform(transect, temp_transect, rotate_back); bg::transform(transect, temp_transect, rotate_back);
// to clipper
ClipperLib::IntPoint c1{ ClipperLib::IntPoint c1{static_cast<ClipperLib::cInt>(
static_cast<ClipperLib::cInt>(transect[0].get<0>() * CLIPPER_SCALE), temp_transect[0].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(transect[0].get<1>() * CLIPPER_SCALE)}; static_cast<ClipperLib::cInt>(
ClipperLib::IntPoint c2{ temp_transect[0].get<1>() * CLIPPER_SCALE)};
static_cast<ClipperLib::cInt>(transect[1].get<0>() * CLIPPER_SCALE), ClipperLib::IntPoint c2{static_cast<ClipperLib::cInt>(
static_cast<ClipperLib::cInt>(transect[1].get<1>() * CLIPPER_SCALE)}; temp_transect[1].get<0>() * CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(
temp_transect[1].get<1>() * CLIPPER_SCALE)};
ClipperLib::Path path{c1, c2}; ClipperLib::Path path{c1, c2};
transectsClipper.push_back(path); transectsClipper.push_back(path);
} }
...@@ -852,22 +852,22 @@ void generateRoutingModel(const BoostLineString &vertices, ...@@ -852,22 +852,22 @@ void generateRoutingModel(const BoostLineString &vertices,
const BoostPolygon &polygonOffset, size_t n0, const BoostPolygon &polygonOffset, size_t n0,
RoutingDataModel &dataModel, Matrix<double> &graph) { RoutingDataModel &dataModel, Matrix<double> &graph) {
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif #endif
graphFromPolygon(polygonOffset, vertices, graph); graphFromPolygon(polygonOffset, vertices, graph);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>( auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "Execution time graphFromPolygon(): " << delta.count() << " ms" cout << "Execution time graphFromPolygon(): " << delta.count() << " ms"
<< endl; << endl;
#endif #endif
Matrix<double> distanceMatrix(graph); Matrix<double> distanceMatrix(graph);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
start = std::chrono::high_resolution_clock::now(); start = std::chrono::high_resolution_clock::now();
#endif #endif
toDistanceMatrix(distanceMatrix); toDistanceMatrix(distanceMatrix);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
delta = std::chrono::duration_cast<std::chrono::milliseconds>( delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "Execution time toDistanceMatrix(): " << delta.count() << " ms" cout << "Execution time toDistanceMatrix(): " << delta.count() << " ms"
...@@ -934,12 +934,12 @@ bool flight_plan::route(const BoostPolygon &area, ...@@ -934,12 +934,12 @@ bool flight_plan::route(const BoostPolygon &area,
// Offset joined area. // Offset joined area.
BoostPolygon areaOffset; BoostPolygon areaOffset;
offsetPolygon(area, areaOffset, detail::offsetConstant); offsetPolygon(area, areaOffset, detail::offsetConstant);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif #endif
generateRoutingModel(vertices, areaOffset, n0, dataModel, connectionGraph); generateRoutingModel(vertices, areaOffset, n0, dataModel, connectionGraph);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
delta = std::chrono::duration_cast<std::chrono::milliseconds>( auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "Execution time _generateRoutingModel(): " << delta.count() << " ms" cout << "Execution time _generateRoutingModel(): " << delta.count() << " ms"
<< endl; << endl;
...@@ -995,11 +995,11 @@ bool flight_plan::route(const BoostPolygon &area, ...@@ -995,11 +995,11 @@ bool flight_plan::route(const BoostPolygon &area,
searchParameters.set_allocated_time_limit(tMax); searchParameters.set_allocated_time_limit(tMax);
// Solve the problem. // Solve the problem.
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
start = std::chrono::high_resolution_clock::now(); start = std::chrono::high_resolution_clock::now();
#endif #endif
const Assignment *solution = routing.SolveWithParameters(searchParameters); const Assignment *solution = routing.SolveWithParameters(searchParameters);
#ifdef SHOW_TIME #ifdef SNAKE_SHOW_TIME
delta = std::chrono::duration_cast<std::chrono::milliseconds>( delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "Execution time routing.SolveWithParameters(): " << delta.count() cout << "Execution time routing.SolveWithParameters(): " << delta.count()
......
...@@ -173,7 +173,7 @@ public: ...@@ -173,7 +173,7 @@ public:
const BoundingBox &measurementAreaBBox() const; const BoundingBox &measurementAreaBBox() const;
const BoostPoint &homePositon() const; const BoostPoint &homePositon() const;
bool update() const; bool update();
mutable string errorString; mutable string errorString;
......
...@@ -213,6 +213,7 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -213,6 +213,7 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
this->pRosBridge->subscribe( this->pRosBridge->subscribe(
"/nemo/heartbeat", "/nemo/heartbeat",
/* callback */ [this](JsonDocUPtr pDoc) { /* callback */ [this](JsonDocUPtr pDoc) {
// auto start = std::chrono::high_resolution_clock::now();
UniqueLock lk(this->heartbeatMutex); UniqueLock lk(this->heartbeatMutex);
auto &heartbeatMsg = this->heartbeat; auto &heartbeatMsg = this->heartbeat;
...@@ -223,8 +224,15 @@ bool NemoInterface::Impl::doTopicServiceSetup() { ...@@ -223,8 +224,15 @@ bool NemoInterface::Impl::doTopicServiceSetup() {
this->nextTimeout = this->nextTimeout =
std::chrono::high_resolution_clock::now() + timeoutInterval; std::chrono::high_resolution_clock::now() + timeoutInterval;
} }
lk.unlock();
emit this->parent->statusChanged(); emit this->parent->statusChanged();
// auto delta =
// std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::high_resolution_clock::now() - start);
// std::cout << "/nemo/heartbeat callback time: " <<
// delta.count() << " ms"
// << std::endl;
}); });
// Advertise /snake/get_origin. // Advertise /snake/get_origin.
...@@ -289,11 +297,12 @@ void NemoInterface::Impl::loop() { ...@@ -289,11 +297,12 @@ void NemoInterface::Impl::loop() {
} }
// Check if heartbeat timeout occured. // Check if heartbeat timeout occured.
if (this->running && this->topicServiceSetupDone && if (this->running && this->topicServiceSetupDone) {
this->nextTimeout != TimePoint::max()) {
if (this->nextTimeout < std::chrono::high_resolution_clock::now()) {
UniqueLock lk(this->heartbeatMutex); UniqueLock lk(this->heartbeatMutex);
if (this->nextTimeout != TimePoint::max() &&
this->nextTimeout < std::chrono::high_resolution_clock::now()) {
this->heartbeat.setStatus(integral(NemoStatus::Timeout)); this->heartbeat.setStatus(integral(NemoStatus::Timeout));
lk.unlock();
emit this->parent->statusChanged(); emit this->parent->statusChanged();
} }
} }
...@@ -321,6 +330,13 @@ void NemoInterface::Impl::publishENUOrigin() { ...@@ -321,6 +330,13 @@ void NemoInterface::Impl::publishENUOrigin() {
this->pRosBridge->publish(std::move(jOrigin), "/snake/origin"); this->pRosBridge->publish(std::move(jOrigin), "/snake/origin");
} }
// ===============================================================
// NemoInterface
NemoInterface::NemoInterface(QObject *parent)
: QObject(parent), pImpl(std::make_unique<NemoInterface::Impl>(this)) {}
NemoInterface::~NemoInterface() {}
void NemoInterface::start() { this->pImpl->start(); } void NemoInterface::start() { this->pImpl->start(); }
void NemoInterface::stop() { this->pImpl->stop(); } void NemoInterface::stop() { this->pImpl->stop(); }
...@@ -333,8 +349,8 @@ void NemoInterface::setENUOrigin(const QGeoCoordinate &ENUOrigin) { ...@@ -333,8 +349,8 @@ void NemoInterface::setENUOrigin(const QGeoCoordinate &ENUOrigin) {
this->pImpl->setENUOrigin(ENUOrigin); this->pImpl->setENUOrigin(ENUOrigin);
} }
NemoInterface::NemoStatus NemoInterface::status() { NemoInterface::NemoStatus NemoInterface::status() const {
return this->pImpl->status(); return this->pImpl->status();
} }
QVector<int> NemoInterface::progress() { return this->pImpl->progress(); } QVector<int> NemoInterface::progress() const { return this->pImpl->progress(); }
...@@ -21,6 +21,7 @@ public: ...@@ -21,6 +21,7 @@ public:
}; };
explicit NemoInterface(QObject *parent = nullptr); explicit NemoInterface(QObject *parent = nullptr);
~NemoInterface() override;
void start(); void start();
void stop(); void stop();
...@@ -28,8 +29,8 @@ public: ...@@ -28,8 +29,8 @@ public:
void setTilesENU(const SnakeTilesLocal &tilesENU); void setTilesENU(const SnakeTilesLocal &tilesENU);
void setENUOrigin(const QGeoCoordinate &ENUOrigin); void setENUOrigin(const QGeoCoordinate &ENUOrigin);
NemoStatus status(); NemoStatus status() const;
QVector<int> progress(); QVector<int> progress() const;
signals: signals:
void statusChanged(); void statusChanged();
......
...@@ -15,29 +15,34 @@ using namespace boost::units; ...@@ -15,29 +15,34 @@ using namespace boost::units;
using Length = quantity<si::length>; using Length = quantity<si::length>;
using Area = quantity<si::area>; using Area = quantity<si::area>;
class SnakeDataManager : public QThread { class SnakeThread : public QThread {
Q_OBJECT Q_OBJECT
class Impl; class Impl;
using PImpl = std::unique_ptr<Impl>; using PImpl = std::unique_ptr<Impl>;
public: public:
SnakeDataManager(QObject *parent = nullptr); SnakeThread(QObject *parent = nullptr);
~SnakeDataManager() override; ~SnakeThread() override;
void setMeasurementArea(const QList<QGeoCoordinate> &measurementArea); void setMeasurementArea(const QList<QGeoCoordinate> &measurementArea);
void setServiceArea(const QList<QGeoCoordinate> &serviceArea); void setServiceArea(const QList<QGeoCoordinate> &serviceArea);
void setCorridor(const QList<QGeoCoordinate> &corridor); void setCorridor(const QList<QGeoCoordinate> &corridor);
void setProgress(const QVector<int> &progress);
SnakeTiles tiles() const; SnakeTiles tiles() const;
SnakeTilesLocal tilesENU() const; SnakeTilesLocal tilesENU() const;
QGeoCoordinate ENUOrigin() const; QGeoCoordinate ENUOrigin() const;
QVariantList tileCenterPoints() const; QVariantList tileCenterPoints() const;
QNemoProgress progress() const; QVector<int> progress() const;
bool calcInProgress() const; bool calcInProgress() const;
QString errorMessage() const; QString errorMessage() const;
bool success() const; bool success() const;
bool tilesUpdated();
bool waypointsUpdated();
bool progressUpdated();
QVector<QGeoCoordinate> waypoints() const; QVector<QGeoCoordinate> waypoints() const;
QVector<QGeoCoordinate> arrivalPath() const; QVector<QGeoCoordinate> arrivalPath() const;
QVector<QGeoCoordinate> returnPath() const; QVector<QGeoCoordinate> returnPath() const;
......
#include "SnakeTile.h" #include "SnakeTile.h"
SnakeTile::SnakeTile() : WimaAreaData() SnakeTile::SnakeTile() : WimaAreaData() {}
{
} SnakeTile::SnakeTile(const SnakeTile &other, QObject *parent)
: WimaAreaData(parent) {
SnakeTile::SnakeTile(const SnakeTile &other) : WimaAreaData()
{
*this = other; *this = other;
} }
SnakeTile &SnakeTile::operator=(const SnakeTile &other) SnakeTile &SnakeTile::operator=(const SnakeTile &other) {
{
this->assign(other); this->assign(other);
return *this; return *this;
} }
void SnakeTile::assign(const SnakeTile &other) void SnakeTile::assign(const SnakeTile &other) { WimaAreaData::assign(other); }
{
WimaAreaData::assign(other);
}
...@@ -2,18 +2,16 @@ ...@@ -2,18 +2,16 @@
#include "Wima/Geometry/WimaAreaData.h" #include "Wima/Geometry/WimaAreaData.h"
class SnakeTile : public WimaAreaData class SnakeTile : public WimaAreaData {
{
public: public:
SnakeTile(); SnakeTile();
SnakeTile(const SnakeTile&other); SnakeTile(const SnakeTile &other, QObject *parent = nullptr);
QString type() const {return "Tile";} QString type() const { return "Tile"; }
SnakeTile* Clone() const {return new SnakeTile(*this);} SnakeTile *Clone() const { return new SnakeTile(*this); }
SnakeTile& operator=(const SnakeTile &other); SnakeTile &operator=(const SnakeTile &other);
protected: protected:
void assign(const SnakeTile &other); void assign(const SnakeTile &other);
}; };
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
#include <memory> #include <memory>
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value) {
return static_cast<typename std::underlying_type<T>::type>(value);
}
#define SMART_RTL_MAX_ATTEMPTS 3 // times #define SMART_RTL_MAX_ATTEMPTS 3 // times
#define SMART_RTL_ATTEMPT_INTERVAL 200 // ms #define SMART_RTL_ATTEMPT_INTERVAL 200 // ms
#define EVENT_TIMER_INTERVAL 50 // ms #define EVENT_TIMER_INTERVAL 50 // ms
...@@ -73,10 +78,11 @@ WimaController::WimaController(QObject *parent) ...@@ -73,10 +78,11 @@ WimaController::WimaController(QObject *parent)
_snakeMinTransectLength(settingsGroup, _snakeMinTransectLength(settingsGroup,
_metaDataMap[snakeMinTransectLengthName]), _metaDataMap[snakeMinTransectLengthName]),
_lowBatteryHandlingTriggered(false), _measurementPathLength(-1), _lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
_currentDM(&_emptyDM), _snakeThread(this), _emptyThread(this), _currentThread(&_emptyThread),
_nemoInterface(this),
_batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) { _batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {
// Set up facts. // Set up facts for waypoint manager.
_showAllMissionItems.setRawValue(true); _showAllMissionItems.setRawValue(true);
_showCurrentMissionItems.setRawValue(true); _showCurrentMissionItems.setRawValue(true);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this, connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
...@@ -112,21 +118,23 @@ WimaController::WimaController(QObject *parent) ...@@ -112,21 +118,23 @@ WimaController::WimaController(QObject *parent)
&WimaController::_eventTimerHandler); &WimaController::_eventTimerHandler);
_eventTimer.start(EVENT_TIMER_INTERVAL); _eventTimer.start(EVENT_TIMER_INTERVAL);
// Snake Data Manager. // SnakeThread.
connect(_currentDM, &SnakeDataManager::finished, this, connect(_currentThread, &SnakeThread::finished, this,
&WimaController::_DMFinishedHandler); &WimaController::_threadFinishedHandler);
connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this, connect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
connect(this, &QObject::destroyed, &this->_snakeThread, &SnakeThread::quit);
connect(this, &QObject::destroyed, &this->_emptyThread, &SnakeThread::quit);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler); &WimaController::_progressChangedHandler);
connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged); &WimaController::nemoStatusChanged);
connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged); &WimaController::nemoStatusStringChanged);
connect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
connect(this, &QObject::destroyed, &this->_snakeDM, &SnakeDataManager::quit);
connect(this, &QObject::destroyed, &this->_emptyDM, &SnakeDataManager::quit);
// Enable/disable snake.
connect(&_enableSnake, &Fact::rawValueChanged, this, connect(&_enableSnake, &Fact::rawValueChanged, this,
&WimaController::_enableSnakeChangedHandler); &WimaController::_enableSnakeChangedHandler);
_enableSnakeChangedHandler(); _enableSnakeChangedHandler();
...@@ -185,16 +193,14 @@ Fact *WimaController::arrivalReturnSpeed() { return &_arrivalReturnSpeed; } ...@@ -185,16 +193,14 @@ Fact *WimaController::arrivalReturnSpeed() { return &_arrivalReturnSpeed; }
Fact *WimaController::altitude() { return &_altitude; } Fact *WimaController::altitude() { return &_altitude; }
QmlObjectListModel *WimaController::snakeTiles() { QmlObjectListModel *WimaController::snakeTiles() { return &this->tiles; }
return const_cast<QmlObjectListModel *>(this->_currentDM->tiles());
}
QVariantList WimaController::snakeTileCenterPoints() { QVariantList WimaController::snakeTileCenterPoints() {
return _currentDM->tileCenterPoints(); return _currentThread->tileCenterPoints();
} }
QVector<int> WimaController::nemoProgress() { QVector<int> WimaController::nemoProgress() {
return _currentDM->progress().progress(); return _currentThread->progress();
} }
double WimaController::phaseDistance() const { double WimaController::phaseDistance() const {
...@@ -207,14 +213,16 @@ double WimaController::phaseDuration() const { ...@@ -207,14 +213,16 @@ double WimaController::phaseDuration() const {
return 0.0; return 0.0;
} }
int WimaController::nemoStatus() const { return _currentDM->nemoStatus(); } int WimaController::nemoStatus() const {
return integral(_nemoInterface.status());
}
QString WimaController::nemoStatusString() const { QString WimaController::nemoStatusString() const {
return _nemoStatusMap.at(nemoStatus()); return _nemoStatusMap.at(nemoStatus());
} }
bool WimaController::snakeCalcInProgress() const { bool WimaController::snakeCalcInProgress() const {
return _currentDM->calcInProgress(); return _currentThread->calcInProgress();
} }
void WimaController::setMasterController(PlanMasterController *masterC) { void WimaController::setMasterController(PlanMasterController *masterC) {
...@@ -432,10 +440,10 @@ bool WimaController::setWimaPlanData(const WimaPlanData &planData) { ...@@ -432,10 +440,10 @@ bool WimaController::setWimaPlanData(const WimaPlanData &planData) {
emit currentWaypointPathChanged(); emit currentWaypointPathChanged();
// Update Snake Data Manager // Update Snake Data Manager
_snakeDM.setMeasurementArea(_measurementArea.coordinateList()); _snakeThread.setMeasurementArea(_measurementArea.coordinateList());
_snakeDM.setServiceArea(_serviceArea.coordinateList()); _snakeThread.setServiceArea(_serviceArea.coordinateList());
_snakeDM.setCorridor(_corridor.coordinateList()); _snakeThread.setCorridor(_corridor.coordinateList());
_currentDM->start(); _currentThread->start();
_localPlanDataValid = true; _localPlanDataValid = true;
return true; return true;
...@@ -710,16 +718,32 @@ void WimaController::_initSmartRTL() { ...@@ -710,16 +718,32 @@ void WimaController::_initSmartRTL() {
} }
} }
void WimaController::_DMFinishedHandler() { void WimaController::_threadFinishedHandler() {
if (!_snakeDM.success()) { if (!_snakeThread.errorMessage().isEmpty()) {
qDebug() << _snakeDM.errorMessage(); qDebug() << _snakeThread.errorMessage();
// qgcApp()->showMessage(_snakeDM.errorMessage()); }
return;
if (_snakeThread.tilesUpdated()) {
this->tiles.clearAndDeleteContents();
auto tls = _snakeThread.tiles().polygons();
for (const auto &t : tls) {
this->tiles.append(new SnakeTile(t, &tiles));
}
emit snakeTilesChanged();
emit snakeTileCenterPointsChanged();
_nemoInterface.setTilesENU(_snakeThread.tilesENU());
_nemoInterface.setENUOrigin(_snakeThread.ENUOrigin());
}
if (_snakeThread.progressUpdated()) {
emit nemoProgressChanged();
} }
if (_snakeThread.waypointsUpdated()) {
// Copy waypoints to waypoint manager. // Copy waypoints to waypoint manager.
_snakeWM.clear(); _snakeWM.clear();
auto waypoints = _snakeDM.waypoints(); auto waypoints = _snakeThread.waypoints();
if (waypoints.size() < 1) { if (waypoints.size() < 1) {
return; return;
} }
...@@ -730,13 +754,11 @@ void WimaController::_DMFinishedHandler() { ...@@ -730,13 +754,11 @@ void WimaController::_DMFinishedHandler() {
// Do update. // Do update.
this->_snakeWM.update(); // this can take a while (ca. 200ms) this->_snakeWM.update(); // this can take a while (ca. 200ms)
emit snakeTilesChanged();
emit snakeTileCenterPointsChanged();
emit nemoProgressChanged();
emit missionItemsChanged(); emit missionItemsChanged();
emit currentMissionItemsChanged(); emit currentMissionItemsChanged();
emit currentWaypointPathChanged(); emit currentWaypointPathChanged();
emit waypointPathChanged(); emit waypointPathChanged();
}
} }
void WimaController::_switchToSnakeWaypointManager(QVariant variant) { void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
...@@ -747,32 +769,35 @@ void WimaController::_switchToSnakeWaypointManager(QVariant variant) { ...@@ -747,32 +769,35 @@ void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
} }
} }
void WimaController::_switchDataManager(SnakeDataManager &dataManager) { void WimaController::_switchThreadObject(SnakeThread &thread) {
if (_currentDM != &dataManager) { if (_currentThread != &thread) {
// SnakeThread.
disconnect(_currentDM, &SnakeDataManager::finished, this, disconnect(_currentThread, &SnakeThread::finished, this,
&WimaController::_DMFinishedHandler); &WimaController::_threadFinishedHandler);
disconnect(_currentDM, &SnakeDataManager::nemoProgressChanged, this, disconnect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
// NemoInterface.
disconnect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler); &WimaController::_progressChangedHandler);
disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, disconnect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged); &WimaController::nemoStatusChanged);
disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, disconnect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged); &WimaController::nemoStatusStringChanged);
disconnect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
_currentDM = &dataManager; _currentThread = &thread;
connect(_currentDM, &SnakeDataManager::finished, this, // SnakeThread.
&WimaController::_DMFinishedHandler); connect(_currentThread, &SnakeThread::finished, this,
connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this, &WimaController::_threadFinishedHandler);
connect(_currentThread, &SnakeThread::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
// NemoInterface.
connect(&_nemoInterface, &NemoInterface::progressChanged, this,
&WimaController::_progressChangedHandler); &WimaController::_progressChangedHandler);
connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusChanged); &WimaController::nemoStatusChanged);
connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this, connect(&_nemoInterface, &NemoInterface::statusChanged, this,
&WimaController::nemoStatusStringChanged); &WimaController::nemoStatusStringChanged);
connect(_currentDM, &SnakeDataManager::calcInProgressChanged, this,
&WimaController::snakeCalcInProgressChanged);
emit snakeCalcInProgressChanged(); emit snakeCalcInProgressChanged();
emit snakeTilesChanged(); emit snakeTilesChanged();
...@@ -783,17 +808,21 @@ void WimaController::_switchDataManager(SnakeDataManager &dataManager) { ...@@ -783,17 +808,21 @@ void WimaController::_switchDataManager(SnakeDataManager &dataManager) {
} }
} }
void WimaController::_progressChangedHandler() { _snakeDM.start(); } void WimaController::_progressChangedHandler() {
this->_snakeThread.setProgress(this->_nemoInterface.progress());
this->_snakeThread.start();
}
void WimaController::_enableSnakeChangedHandler() { void WimaController::_enableSnakeChangedHandler() {
if (this->_enableSnake.rawValue().toBool()) { if (this->_enableSnake.rawValue().toBool()) {
qDebug() << "WimaController: enabling snake."; qDebug() << "WimaController: enabling snake.";
_switchDataManager(this->_snakeDM); _switchThreadObject(this->_snakeThread);
this->_snakeDM.enableRosBridge(); this->_nemoInterface.start();
_currentDM->start(); this->_snakeThread.start();
} else { } else {
qDebug() << "WimaController: disabling snake."; qDebug() << "WimaController: disabling snake.";
this->_snakeDM.disableRosBride(); this->_nemoInterface.stop();
_switchDataManager(_emptyDM); this->_snakeThread.quit();
_switchThreadObject(_emptyThread);
} }
} }
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
#include "SurveyComplexItem.h" #include "SurveyComplexItem.h"
#include "Geometry/GeoPoint3D.h" #include "Geometry/GeoPoint3D.h"
#include "Snake/SnakeDataManager.h" #include "Snake/NemoInterface.h"
#include "Snake/SnakeThread.h"
#include "Snake/SnakeTiles.h" #include "Snake/SnakeTiles.h"
#include "Snake/SnakeTilesLocal.h" #include "Snake/SnakeTilesLocal.h"
...@@ -237,19 +238,16 @@ private slots: ...@@ -237,19 +238,16 @@ private slots:
void _initSmartRTL(); void _initSmartRTL();
void _smartRTLCleanUp(bool flying); void _smartRTLCleanUp(bool flying);
// Snake. // Snake.
void _DMFinishedHandler(); void _threadFinishedHandler();
void _switchWaypointManager(WaypointManager::ManagerBase &manager);
void _switchToSnakeWaypointManager(QVariant variant); void _switchToSnakeWaypointManager(QVariant variant);
void _switchDataManager(SnakeDataManager &dataManager); void _switchThreadObject(SnakeThread &thread);
void _progressChangedHandler(); void _progressChangedHandler();
void _enableSnakeChangedHandler(); void _enableSnakeChangedHandler();
// Periodic tasks. // Periodic tasks.
void _eventTimerHandler(void); void _eventTimerHandler(void);
// Waypoint manager handling.
void _switchWaypointManager(WaypointManager::ManagerBase &manager);
private: private:
using StatusMap = std::map<int, QString>;
// Controllers. // Controllers.
PlanMasterController *_masterController; PlanMasterController *_masterController;
MissionController *_missionController; MissionController *_missionController;
...@@ -310,9 +308,12 @@ private: ...@@ -310,9 +308,12 @@ private:
double _measurementPathLength; // the lenght of the phase in meters double _measurementPathLength; // the lenght of the phase in meters
// Snake // Snake
SnakeDataManager _snakeDM; // Snake Data Manager QmlObjectListModel tiles;
SnakeDataManager _emptyDM; SnakeThread _snakeThread; // Snake Data Manager
SnakeDataManager *_currentDM; SnakeThread _emptyThread;
SnakeThread *_currentThread;
NemoInterface _nemoInterface;
using StatusMap = std::map<int, QString>;
static StatusMap _nemoStatusMap; static StatusMap _nemoStatusMap;
// Periodic tasks. // Periodic tasks.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
#include "ros_bridge/rapidjson/include/rapidjson/document.h" #include "ros_bridge/rapidjson/include/rapidjson/document.h"
#include <memory>
#include <deque> #include <deque>
#include <memory>
#include <unordered_map> #include <unordered_map>
namespace ros_bridge { namespace ros_bridge {
...@@ -16,11 +16,6 @@ typedef std::size_t HashType; ...@@ -16,11 +16,6 @@ typedef std::size_t HashType;
using ClientMap = std::unordered_map<HashType, std::string>; using ClientMap = std::unordered_map<HashType, std::string>;
static const char* _topicAdvertiserKey = "topic_advertiser";
static const char* _topicPublisherKey = "topic_publisher";
static const char* _serviceAdvertiserKey = "service_advertiser";
static const char* _topicSubscriberKey = "topic_subscriber";
std::size_t getHash(const std::string &str); std::size_t getHash(const std::string &str);
std::size_t getHash(const char *str); std::size_t getHash(const char *str);
...@@ -30,5 +25,5 @@ bool getType(const JsonDoc &doc, std::string &type); ...@@ -30,5 +25,5 @@ bool getType(const JsonDoc &doc, std::string &type);
bool removeTopic(JsonDoc &doc); bool removeTopic(JsonDoc &doc);
bool removeType(JsonDoc &doc); bool removeType(JsonDoc &doc);
} } // namespace com_private
} } // namespace ros_bridge
...@@ -2,18 +2,15 @@ ...@@ -2,18 +2,15 @@
#include "rapidjson/include/rapidjson/ostreamwrapper.h" #include "rapidjson/include/rapidjson/ostreamwrapper.h"
ros_bridge::com_private::Server::Server(RosbridgeWsClient &rbc) : static const char *serviceAdvertiserKey = "service_advertiser";
_rbc(rbc)
, _stopped(std::make_shared<std::atomic_bool>(true))
{
} ros_bridge::com_private::Server::Server(RosbridgeWsClient &rbc)
: _rbc(rbc), _stopped(std::make_shared<std::atomic_bool>(true)) {}
void ros_bridge::com_private::Server::advertiseService(const std::string &service, void ros_bridge::com_private::Server::advertiseService(
const std::string &type, const std::string &service, const std::string &type,
const Server::CallbackType &userCallback) const Server::CallbackType &userCallback) {
{ std::string clientName = serviceAdvertiserKey + service;
std::string clientName = _serviceAdvertiserKey + service;
auto it = _serviceMap.find(clientName); auto it = _serviceMap.find(clientName);
if (it != _serviceMap.end()) if (it != _serviceMap.end())
return; // Service allready advertised. return; // Service allready advertised.
...@@ -21,74 +18,66 @@ void ros_bridge::com_private::Server::advertiseService(const std::string &servic ...@@ -21,74 +18,66 @@ void ros_bridge::com_private::Server::advertiseService(const std::string &servic
_rbc.addClient(clientName); _rbc.addClient(clientName);
auto rbc = &_rbc; auto rbc = &_rbc;
_rbc.advertiseService(clientName, service, type, _rbc.advertiseService(
[userCallback, rbc]( clientName, service, type,
std::shared_ptr<WsClient::Connection>, [userCallback, rbc](std::shared_ptr<WsClient::Connection>,
std::shared_ptr<WsClient::InMessage> in_message){ std::shared_ptr<WsClient::InMessage> in_message) {
// message->string() is destructive, so we have to buffer it first // message->string() is destructive, so we have to buffer it first
std::string messagebuf = in_message->string(); std::string messagebuf = in_message->string();
//std::cout << "advertiseServiceCallback(): Message Received: " // std::cout << "advertiseServiceCallback(): Message Received: "
// << messagebuf << std::endl; // << messagebuf << std::endl;
rapidjson::Document document; rapidjson::Document document;
if (document.Parse(messagebuf.c_str()).HasParseError()) if (document.Parse(messagebuf.c_str()).HasParseError()) {
{ std::cerr << "advertiseServiceCallback(): Error in parsing service "
std::cerr << "advertiseServiceCallback(): Error in parsing service request message: " "request message: "
<< messagebuf << std::endl; << messagebuf << std::endl;
return; return;
} }
if ( !document.HasMember("args") || !document["args"].IsObject()){ if (!document.HasMember("args") || !document["args"].IsObject()) {
std::cerr << "advertiseServiceCallback(): message has no args member: " std::cerr
<< "advertiseServiceCallback(): message has no args member: "
<< messagebuf << std::endl; << messagebuf << std::endl;
return; return;
} }
if ( !document.HasMember("service") || !document["service"].IsString()){ if (!document.HasMember("service") || !document["service"].IsString()) {
std::cerr << "advertiseServiceCallback(): message has no service member: " std::cerr
<< "advertiseServiceCallback(): message has no service member: "
<< messagebuf << std::endl; << messagebuf << std::endl;
return; return;
} }
if ( !document.HasMember("id") || !document["id"].IsString()){ if (!document.HasMember("id") || !document["id"].IsString()) {
std::cerr << "advertiseServiceCallback(): message has no id member: " std::cerr << "advertiseServiceCallback(): message has no id member: "
<< messagebuf << std::endl; << messagebuf << std::endl;
return; return;
} }
JsonDocUPtr pDoc(new JsonDoc()); JsonDocUPtr pDoc(new JsonDoc());
std::cout << "args member count: " << document["args"].MemberCount(); std::cout << "args member count: " << document["args"].MemberCount();
if ( document["args"].MemberCount() > 0) if (document["args"].MemberCount() > 0)
pDoc->CopyFrom(document["args"].Move(), document.GetAllocator()); pDoc->CopyFrom(document["args"].Move(), document.GetAllocator());
JsonDocUPtr pDocResponse = userCallback(std::move(pDoc)); JsonDocUPtr pDocResponse = userCallback(std::move(pDoc));
rbc->serviceResponse( rbc->serviceResponse(
document["service"].GetString(), document["service"].GetString(), document["id"].GetString(),
document["id"].GetString(), pDocResponse->MemberCount() > 0 ? true : false, *pDocResponse);
pDocResponse->MemberCount() > 0 ? true : false,
*pDocResponse);
return; return;
}); });
} }
ros_bridge::com_private::Server::~Server() ros_bridge::com_private::Server::~Server() { this->reset(); }
{
this->reset();
}
void ros_bridge::com_private::Server::start() void ros_bridge::com_private::Server::start() { _stopped->store(false); }
{
_stopped->store(false);
}
void ros_bridge::com_private::Server::reset() void ros_bridge::com_private::Server::reset() {
{ if (_stopped->load())
if ( _stopped->load() )
return; return;
std::cout << "Server: _stopped->store(true)" << std::endl; std::cout << "Server: _stopped->store(true)" << std::endl;
_stopped->store(true); _stopped->store(true);
for (const auto& item : _serviceMap){ for (const auto &item : _serviceMap) {
std::cout << "Server: unadvertiseService " << item.second << std::endl; std::cout << "Server: unadvertiseService " << item.second << std::endl;
_rbc.unadvertiseService(item.second); _rbc.unadvertiseService(item.second);
std::cout << "Server: removeClient " << item.first << std::endl; std::cout << "Server: removeClient " << item.first << std::endl;
......
#include "topic_publisher.h" #include "topic_publisher.h"
#include <unordered_map> static const char *topicAdvertiserKey = "topic_advertiser";
ros_bridge::com_private::TopicPublisher::TopicPublisher(RosbridgeWsClient &rbc) : #include <unordered_map>
_stopped(std::make_shared<std::atomic_bool>(true))
, _rbc(rbc)
{
} ros_bridge::com_private::TopicPublisher::TopicPublisher(RosbridgeWsClient &rbc)
: _stopped(std::make_shared<std::atomic_bool>(true)), _rbc(rbc) {}
ros_bridge::com_private::TopicPublisher::~TopicPublisher() ros_bridge::com_private::TopicPublisher::~TopicPublisher() { this->reset(); }
{
this->reset();
}
void ros_bridge::com_private::TopicPublisher::start() void ros_bridge::com_private::TopicPublisher::start() {
{ if (!_stopped->load()) // start called while thread running.
if ( !_stopped->load() ) // start called while thread running.
return; return;
_stopped->store(false); _stopped->store(false);
_pThread = std::make_unique<std::thread>([this]{ _pThread = std::make_unique<std::thread>([this] {
// Main Loop. // Main Loop.
while( !this->_stopped->load() ){ while (!this->_stopped->load()) {
std::unique_lock<std::mutex> lk(this->_mutex); std::unique_lock<std::mutex> lk(this->_mutex);
// Check if new data available, wait if not. // Check if new data available, wait if not.
if (this->_queue.empty()){ if (this->_queue.empty()) {
if ( _stopped->load() ) // Check condition again while holding the lock. if (_stopped->load()) // Check condition again while holding the lock.
break; break;
this->_cv.wait(lk); // Wait for condition, spurious wakeups don't matter in this case. this->_cv.wait(lk); // Wait for condition, spurious wakeups don't matter
// in this case.
continue; continue;
} }
// Pop message from queue. // Pop message from queue.
...@@ -41,7 +36,6 @@ void ros_bridge::com_private::TopicPublisher::start() ...@@ -41,7 +36,6 @@ void ros_bridge::com_private::TopicPublisher::start()
assert(ret); assert(ret);
(void)ret; (void)ret;
// Debug // Debug
rapidjson::StringBuffer sb; rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb); rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
...@@ -49,18 +43,16 @@ void ros_bridge::com_private::TopicPublisher::start() ...@@ -49,18 +43,16 @@ void ros_bridge::com_private::TopicPublisher::start()
std::cout << "message: " << sb.GetString() << std::endl; std::cout << "message: " << sb.GetString() << std::endl;
std::cout << "topic: " << topic << std::endl; std::cout << "topic: " << topic << std::endl;
ret = com_private::removeTopic(*pJsonDoc); ret = com_private::removeTopic(*pJsonDoc);
assert(ret); assert(ret);
(void)ret; (void)ret;
// Wait for topic (Rosbridge needs some time to process a advertise() request). // Wait for topic (Rosbridge needs some time to process a advertise()
this->_rbc.waitForTopic(topic, [this]{ // request).
return this->_stopped->load(); this->_rbc.waitForTopic(topic, [this] { return this->_stopped->load(); });
});
// Publish Json message. // Publish Json message.
if ( !this->_stopped->load() ) if (!this->_stopped->load())
this->_rbc.publish(topic, *pJsonDoc); this->_rbc.publish(topic, *pJsonDoc);
} // while loop } // while loop
#ifdef ROS_BRIDGE_DEBUG #ifdef ROS_BRIDGE_DEBUG
...@@ -69,22 +61,21 @@ void ros_bridge::com_private::TopicPublisher::start() ...@@ -69,22 +61,21 @@ void ros_bridge::com_private::TopicPublisher::start()
}); });
} }
void ros_bridge::com_private::TopicPublisher::reset() void ros_bridge::com_private::TopicPublisher::reset() {
{ if (_stopped->load()) // stop called while thread not running.
if ( _stopped->load() ) // stop called while thread not running.
return; return;
std::unique_lock<std::mutex> lk(_mutex); std::unique_lock<std::mutex> lk(_mutex);
_stopped->store(true); _stopped->store(true);
_cv.notify_one(); // Wake publisher thread. _cv.notify_one(); // Wake publisher thread.
lk.unlock(); lk.unlock();
if ( !_pThread ) if (!_pThread)
return; return;
_pThread->join(); _pThread->join();
lk.lock(); lk.lock();
// Tidy up. // Tidy up.
for (auto& it : this->_topicMap){ for (auto &it : this->_topicMap) {
this->_rbc.unadvertise(it.first); this->_rbc.unadvertise(it.first);
this->_rbc.removeClient(it.second); this->_rbc.removeClient(it.second);
} }
...@@ -93,18 +84,16 @@ void ros_bridge::com_private::TopicPublisher::reset() ...@@ -93,18 +84,16 @@ void ros_bridge::com_private::TopicPublisher::reset()
} }
void ros_bridge::com_private::TopicPublisher::publish( void ros_bridge::com_private::TopicPublisher::publish(
ros_bridge::com_private::JsonDocUPtr docPtr, ros_bridge::com_private::JsonDocUPtr docPtr, const char *topic) {
const char *topic)
{
// Check if topic was advertised. // Check if topic was advertised.
std::string t(topic); std::string t(topic);
std::unique_lock<std::mutex> lk(this->_mutex); std::unique_lock<std::mutex> lk(this->_mutex);
auto it = this->_topicMap.find(t); auto it = this->_topicMap.find(t);
if ( it == this->_topicMap.end()) { // Not yet advertised? if (it == this->_topicMap.end()) { // Not yet advertised?
lk.unlock(); lk.unlock();
#ifdef ROS_BRIDGE_DEBUG #ifdef ROS_BRIDGE_DEBUG
std::cerr << "TopicPublisher: topic " std::cerr << "TopicPublisher: topic " << t << " not yet advertised"
<< t << " not yet advertised" << std::endl; << std::endl;
#endif #endif
return; return;
} }
...@@ -122,15 +111,13 @@ void ros_bridge::com_private::TopicPublisher::publish( ...@@ -122,15 +111,13 @@ void ros_bridge::com_private::TopicPublisher::publish(
_cv.notify_one(); // Wake publisher thread. _cv.notify_one(); // Wake publisher thread.
} }
bool ros_bridge::com_private::TopicPublisher::advertise(const char *topic, const char *type) bool ros_bridge::com_private::TopicPublisher::advertise(const char *topic,
{ const char *type) {
std::unique_lock<std::mutex> lk(this->_mutex); std::unique_lock<std::mutex> lk(this->_mutex);
std::string t(topic); std::string t(topic);
auto it = this->_topicMap.find(t); auto it = this->_topicMap.find(t);
if ( it == this->_topicMap.end()) { // Need to advertise topic? if (it == this->_topicMap.end()) { // Need to advertise topic?
std::string clientName = std::string clientName = std::string(topicAdvertiserKey) + t;
std::string(ros_bridge::com_private::_topicAdvertiserKey)
+ t;
this->_topicMap.insert(std::make_pair(t, clientName)); this->_topicMap.insert(std::make_pair(t, clientName));
lk.unlock(); lk.unlock();
this->_rbc.addClient(clientName); this->_rbc.addClient(clientName);
...@@ -139,9 +126,9 @@ bool ros_bridge::com_private::TopicPublisher::advertise(const char *topic, const ...@@ -139,9 +126,9 @@ bool ros_bridge::com_private::TopicPublisher::advertise(const char *topic, const
} else { } else {
lk.unlock(); lk.unlock();
#if ROS_BRIDGE_DEBUG #if ROS_BRIDGE_DEBUG
std::cerr << "TopicPublisher: topic " << topic << " already advertised" << std::endl; std::cerr << "TopicPublisher: topic " << topic << " already advertised"
<< std::endl;
#endif #endif
return false; return false;
} }
} }
...@@ -2,29 +2,23 @@ ...@@ -2,29 +2,23 @@
#include <thread> #include <thread>
ros_bridge::com_private::TopicSubscriber::TopicSubscriber(RosbridgeWsClient &rbc) : static const char *topicSubscriberKey = "topic_subscriber";
_rbc(rbc)
, _stopped(std::make_shared<std::atomic_bool>(true))
{
} ros_bridge::com_private::TopicSubscriber::TopicSubscriber(
RosbridgeWsClient &rbc)
: _rbc(rbc), _stopped(std::make_shared<std::atomic_bool>(true)) {}
ros_bridge::com_private::TopicSubscriber::~TopicSubscriber() ros_bridge::com_private::TopicSubscriber::~TopicSubscriber() { this->reset(); }
{
this->reset();
}
void ros_bridge::com_private::TopicSubscriber::start() void ros_bridge::com_private::TopicSubscriber::start() {
{
_stopped->store(false); _stopped->store(false);
} }
void ros_bridge::com_private::TopicSubscriber::reset() void ros_bridge::com_private::TopicSubscriber::reset() {
{ if (!_stopped->load()) {
if ( !_stopped->load() ){
_stopped->store(true); _stopped->store(true);
{ {
for (auto &item : _topicMap){ for (auto &item : _topicMap) {
_rbc.unsubscribe(item.second); _rbc.unsubscribe(item.second);
_rbc.removeClient(item.first); _rbc.removeClient(item.first);
} }
...@@ -34,37 +28,31 @@ void ros_bridge::com_private::TopicSubscriber::reset() ...@@ -34,37 +28,31 @@ void ros_bridge::com_private::TopicSubscriber::reset()
} }
void ros_bridge::com_private::TopicSubscriber::subscribe( void ros_bridge::com_private::TopicSubscriber::subscribe(
const char *topic, const char *topic, const std::function<void(JsonDocUPtr)> &callback) {
const std::function<void(JsonDocUPtr)> &callback) if (_stopped->load())
{
if ( _stopped->load() )
return; return;
std::string clientName = ros_bridge::com_private::_topicSubscriberKey std::string clientName = topicSubscriberKey + std::string(topic);
+ std::string(topic);
auto it = _topicMap.find(clientName); auto it = _topicMap.find(clientName);
if ( it != _topicMap.end() ){ // Topic already subscribed? if (it != _topicMap.end()) { // Topic already subscribed?
return; return;
} }
_topicMap.insert(std::make_pair(clientName, std::string(topic))); _topicMap.insert(std::make_pair(clientName, std::string(topic)));
// Wrap callback. // Wrap callback.
auto callbackWrapper = [callback]( auto callbackWrapper =
std::shared_ptr<WsClient::Connection>, [callback](std::shared_ptr<WsClient::Connection>,
std::shared_ptr<WsClient::InMessage> in_message) std::shared_ptr<WsClient::InMessage> in_message) {
{
// Parse document. // Parse document.
JsonDoc docFull; JsonDoc docFull;
docFull.Parse(in_message->string().c_str()); docFull.Parse(in_message->string().c_str());
if ( docFull.HasParseError() ) { if (docFull.HasParseError()) {
std::cout << "Json document has parse error: " std::cout << "Json document has parse error: " << in_message->string()
<< in_message->string()
<< std::endl; << std::endl;
return; return;
} else if (!docFull.HasMember("msg")) { } else if (!docFull.HasMember("msg")) {
std::cout << "Json document does not contain a message (\"msg\"): " std::cout << "Json document does not contain a message (\"msg\"): "
<< in_message->string() << in_message->string() << std::endl;
<< std::endl;
return; return;
} }
...@@ -74,26 +62,26 @@ void ros_bridge::com_private::TopicSubscriber::subscribe( ...@@ -74,26 +62,26 @@ void ros_bridge::com_private::TopicSubscriber::subscribe(
callback(std::move(pDoc)); callback(std::move(pDoc));
}; };
if ( !_rbc.topicAvailable(topic) ){ if (!_rbc.topicAvailable(topic)) {
// Wait until topic is available. // Wait until topic is available.
std::cout << "TopicSubscriber: Starting wait thread, " << clientName << std::endl; std::cout << "TopicSubscriber: Starting wait thread, " << clientName
std::thread t([this, clientName, topic, callbackWrapper]{ << std::endl;
this->_rbc.waitForTopic(topic, [this]{ std::thread t([this, clientName, topic, callbackWrapper] {
return this->_stopped->load(); this->_rbc.waitForTopic(topic, [this] { return this->_stopped->load(); });
}); if (!this->_stopped->load()) {
if ( !this->_stopped->load() ){
this->_rbc.addClient(clientName); this->_rbc.addClient(clientName);
this->_rbc.subscribe(clientName, topic, callbackWrapper); this->_rbc.subscribe(clientName, topic, callbackWrapper);
std::cout << "TopicSubscriber: wait thread subscription successfull: " << clientName << std::endl; std::cout << "TopicSubscriber: wait thread subscription successfull: "
<< clientName << std::endl;
} }
std::cout << "TopicSubscriber: wait thread end, " << clientName << std::endl; std::cout << "TopicSubscriber: wait thread end, " << clientName
<< std::endl;
}); });
t.detach(); t.detach();
} else { } else {
_rbc.addClient(clientName); _rbc.addClient(clientName);
_rbc.subscribe(clientName, topic, callbackWrapper); _rbc.subscribe(clientName, topic, callbackWrapper);
std::cout << "TopicSubscriber: subscription successfull: " << clientName << std::endl; std::cout << "TopicSubscriber: subscription successfull: " << clientName
<< std::endl;
} }
} }
...@@ -29,6 +29,7 @@ Item { ...@@ -29,6 +29,7 @@ Item {
QGCPalette { id: qgcPal; colorGroupEnabled: true } QGCPalette { id: qgcPal; colorGroupEnabled: true }
property real fps: 0.0
property var currentPopUp: null property var currentPopUp: null
property real currentCenterX: 0 property real currentCenterX: 0
property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
......
...@@ -39,6 +39,7 @@ Window { ...@@ -39,6 +39,7 @@ Window {
Loader { Loader {
id: mainWindowInner id: mainWindowInner
anchors.fill: parent anchors.fill: parent
anchors.margins: 10
source: "MainWindowInner.qml" source: "MainWindowInner.qml"
Connections { Connections {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment