Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transmit Global Path Flow # 269 #344

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/network_systems/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
endif()
# Enable all warnings as errors except nested-anon-types, as it allows us to declare an unnamed struct within an
# anonymous union, which is allowed in the C++ standard. This appears to be a warning specific to clang++ with
# -Wpedantic, and does not appear with g++ or MSVC
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -Wall -Wextra -Wpedantic -Werror -Wno-nested-anon-types -pthread")
# Enable all warnings as errors except unused parameter because auto-generated protobuf files trigger it,
# and clang-tidy can cover it without false-flagging the protobuf files.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter -pthread")
message(WARNING "Building Network Systems with build type '${CMAKE_BUILD_TYPE}' "
"and flags: '${CMAKE_CXX_FLAGS}'")

Expand Down
4 changes: 2 additions & 2 deletions src/network_systems/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ independent project.

## Setup

For comprehensive setup instructions, follow our [setup guide](https://ubcsailbot.github.io/sailbot_workspace/main/current/sailbot_workspace/usage/setup/).
For comprehensive setup instructions, follow our [setup guide](https://ubcsailbot.github.io/sailbot_workspace/main/current/sailbot_workspace/setup/).

## Building

Expand All @@ -18,7 +18,7 @@ For comprehensive setup instructions, follow our [setup guide](https://ubcsailbo

### ROS Launch

[Instructions found here.](https://ubcsailbot.github.io/sailbot_workspace/main/current/sailbot_workspace/reference/launch_files/)
[Instructions found here.](https://ubcsailbot.github.io/sailbot_workspace/main/current/sailbot_workspace/launch_files/)

For example:

Expand Down
43 changes: 35 additions & 8 deletions src/network_systems/lib/sailbot_db/inc/sailbot_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <mongocxx/instance.hpp>
#include <mongocxx/pool.hpp>

#include "global_path.pb.h"
#include "sensors.pb.h"
#include "waypoint.pb.h"

Expand All @@ -19,6 +20,7 @@ const std::string COLLECTION_DATA_SENSORS = "data_sensors";
const std::string COLLECTION_GPS = "gps";
const std::string COLLECTION_WIND_SENSORS = "wind_sensors";
const std::string COLLECTION_LOCAL_PATH = "local_path";
const std::string COLLECTION_GLOBAL_PATH = "global_path"; //added
const std::string MONGODB_CONN_STR = "mongodb://localhost:27017";

template <typename T>
Expand Down Expand Up @@ -46,14 +48,6 @@ class SailbotDB
* @brief overload stream operator
*/
friend std::ostream & operator<<(std::ostream & os, const RcvdMsgInfo & info);

/**
* @brief Get a properly formatted timestamp string
*
* @param tm standard C/C++ time structure
* @return tm converted to a timestamp string
*/
static std::string mkTimestamp(const std::tm & tm);
};

/**
Expand All @@ -79,6 +73,14 @@ class SailbotDB
*/
bool testConnection();

/**
* @brief Get a properly formatted timestamp string
*
* @param tm standard C/C++ time structure
* @return tm converted to a timestamp string
*/
static std::string mkTimestamp(const std::tm & tm);

/**
* @brief Write new sensor data to the database
*
Expand All @@ -90,6 +92,21 @@ class SailbotDB
*/
bool storeNewSensors(const Polaris::Sensors & sensors_pb, RcvdMsgInfo new_info);

bool storeNewGlobalPath(const Polaris::GlobalPath & global_pb, const std::string & timestamp);

/**
* @brief Write global path data to the database
*
* @param global_path_pb Protobuf list of global path objects
* @param timestamp transmission time <year - 2000>-<month>-<day> <hour>:<minute>:<second>
* @param client mongocxx::client instance for the current thread

* @return true if successful
* @return false on failure
*/
bool storeNewGlobalPath(
const Polaris::GlobalPath & global_path_pb, const std::string & timestamp, mongocxx::client & client);

protected:
const std::string db_name_; // Name of the database
std::unique_ptr<mongocxx::pool> pool_; // pool of clients for thread safety
Expand Down Expand Up @@ -172,4 +189,14 @@ class SailbotDB
*/
bool storeWindSensors(
const ProtoList<Polaris::Sensors::Wind> & wind_pb, const std::string & timestamp, mongocxx::client & client);

// /**
// * @brief Builds global path document by extracting waypoint information and adding it to document
// *
// * @param global_path_doc_arr bstream document builder array for global path
// * @param waypoints global path waypoints: <latitude: decimal>, <longitude: decimal>
// *
// */
// auto buildGlobalPathDoc(
// auto global_path_doc_arr, const ProtoList<Polaris::Waypoint>& waypoints);
};
12 changes: 12 additions & 0 deletions src/network_systems/lib/sailbot_db/inc/util_db.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class UtilDB : public SailbotDB
*/
Polaris::Sensors genRandSensors();

Polaris::GlobalPath genGlobalPath();

/**
* @return timestamp for the current time
*/
Expand All @@ -48,6 +50,8 @@ class UtilDB : public SailbotDB
*/
std::pair<Polaris::Sensors, SailbotDB::RcvdMsgInfo> genRandData(const std::tm & tm);

std::pair<Polaris::GlobalPath, std::string> genGlobalData(const std::tm & tm);

/**
* @brief Query the database and check that the sensor and message are correct
*
Expand All @@ -57,6 +61,9 @@ class UtilDB : public SailbotDB
bool verifyDBWrite(
std::span<Polaris::Sensors> expected_sensors, std::span<SailbotDB::RcvdMsgInfo> expected_msg_info);

bool verifyDBWrite_GlobalPath(
std::span<Polaris::GlobalPath> expected_globalpath, std::span<std::string> expected_timestamp);

/**
* @brief Dump and check all sensors and timestamps from the database
*
Expand All @@ -67,6 +74,9 @@ class UtilDB : public SailbotDB
std::pair<std::vector<Polaris::Sensors>, std::vector<std::string>> dumpSensors(
utils::FailTracker & tracker, size_t expected_num_docs = 1);

std::pair<std::vector<Polaris::GlobalPath>, std::vector<std::string>> dumpGlobalpath(
utils::FailTracker & tracker, size_t expected_num_docs = 1);

private:
std::shared_ptr<std::mt19937> rng_; // random number generator

Expand Down Expand Up @@ -111,4 +121,6 @@ class UtilDB : public SailbotDB
* @param path_data Path data to modify
*/
void genRandPathData(Polaris::Sensors::Path & path_data);

void genGlobalPathData(Polaris::GlobalPath & global_path_data);
};
37 changes: 36 additions & 1 deletion src/network_systems/lib/sailbot_db/src/sailbot_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
#include <mongocxx/instance.hpp>
#include <sstream>

#include "global_path.pb.h"
#include "sensors.pb.h"
#include "waypoint.pb.h"

namespace bstream = bsoncxx::builder::stream;
using Polaris::GlobalPath;
using Polaris::Sensors;

mongocxx::instance SailbotDB::inst_{}; // staticallly initialize instance
Expand All @@ -33,7 +35,7 @@ std::ostream & operator<<(std::ostream & os, const SailbotDB::RcvdMsgInfo & info
return os;
}

std::string SailbotDB::RcvdMsgInfo::mkTimestamp(const std::tm & tm)
std::string SailbotDB::mkTimestamp(const std::tm & tm)
{
// This is impossible to read. It's reading each field of tm and 0 padding it to 2 digits with either "-" or ":"
// in between each number
Expand Down Expand Up @@ -82,6 +84,12 @@ bool SailbotDB::storeNewSensors(const Sensors & sensors_pb, RcvdMsgInfo new_info

// END PUBLIC

bool SailbotDB::storeNewGlobalPath(const GlobalPath & global_pb, const std::string & timestamp)
{
mongocxx::pool::entry entry = pool_->acquire();
return storeNewGlobalPath(global_pb, timestamp, *entry);
}

// PRIVATE

bool SailbotDB::storeGps(const Sensors::Gps & gps_pb, const std::string & timestamp, mongocxx::client & client)
Expand Down Expand Up @@ -175,4 +183,31 @@ bool SailbotDB::storePathSensors(
return static_cast<bool>(local_path_coll.insert_one(local_path_doc.view()));
}

bool SailbotDB::storeNewGlobalPath(
const Polaris::GlobalPath & global_path_pb, const std::string & timestamp, mongocxx::client & client)
{
mongocxx::database db = client[db_name_];
mongocxx::collection global_path_coll = db[COLLECTION_GLOBAL_PATH];
bstream::document doc_builder{};
auto global_path_doc_arr = doc_builder << "waypoints" << bstream::open_array;
ProtoList<Polaris::Waypoint> waypoints = global_path_pb.waypoints();
for (const Polaris::Waypoint & waypoint : waypoints) {
global_path_doc_arr = global_path_doc_arr << bstream::open_document << "latitude" << waypoint.latitude()
<< "longitude" << waypoint.longitude() << bstream::close_document;
}
// global_path_doc_arr = buildGlobalPathDoc(global_path_doc_arr, waypoints);
DocVal global_path_doc = global_path_doc_arr << bstream::close_array << "timestamp" << timestamp
<< bstream::finalize;
return static_cast<bool>(global_path_coll.insert_one(global_path_doc.view()));
}

// buildGlobalPathDoc(auto global_path_doc_arr, const ProtoList<Polaris::Waypoint> & waypoints)
// {
// for (const Polaris::Waypoint & waypoint : waypoints) {
// global_path_doc_arr = global_path_doc_arr << bstream::open_document << "latitude" << waypoint.latitude()
// << "longitude" << waypoint.longitude() << bstream::close_document;
// }
// return global_path_doc_arr;
// }

// END PRIVATE
120 changes: 113 additions & 7 deletions src/network_systems/lib/sailbot_db/src/util_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,33 @@
#include <random>

#include "cmn_hdrs/shared_constants.h"
#include "sailbot_db/inc/sailbot_db.h"
#include "sailbot_db/inc/util_db.h"
#include "utils/utils.h"

using Polaris::GlobalPath;
using Polaris::Sensors;

void UtilDB::cleanDB()
{
mongocxx::pool::entry entry = pool_->acquire();
mongocxx::database db = (*entry)[db_name_];

mongocxx::collection gps_coll = db[COLLECTION_GPS];
mongocxx::collection ais_coll = db[COLLECTION_AIS_SHIPS];
mongocxx::collection generic_coll = db[COLLECTION_DATA_SENSORS];
mongocxx::collection batteries_coll = db[COLLECTION_BATTERIES];
mongocxx::collection wind_coll = db[COLLECTION_WIND_SENSORS];
mongocxx::collection local_path_coll = db[COLLECTION_LOCAL_PATH];
mongocxx::collection gps_coll = db[COLLECTION_GPS];
mongocxx::collection ais_coll = db[COLLECTION_AIS_SHIPS];
mongocxx::collection generic_coll = db[COLLECTION_DATA_SENSORS];
mongocxx::collection batteries_coll = db[COLLECTION_BATTERIES];
mongocxx::collection wind_coll = db[COLLECTION_WIND_SENSORS];
mongocxx::collection local_path_coll = db[COLLECTION_LOCAL_PATH];
mongocxx::collection global_path_coll = db[COLLECTION_GLOBAL_PATH];

gps_coll.delete_many(bsoncxx::builder::basic::make_document());
ais_coll.delete_many(bsoncxx::builder::basic::make_document());
generic_coll.delete_many(bsoncxx::builder::basic::make_document());
batteries_coll.delete_many(bsoncxx::builder::basic::make_document());
wind_coll.delete_many(bsoncxx::builder::basic::make_document());
local_path_coll.delete_many(bsoncxx::builder::basic::make_document());
global_path_coll.delete_many(bsoncxx::builder::basic::make_document());
}

Sensors UtilDB::genRandSensors()
Expand Down Expand Up @@ -71,6 +76,13 @@ Sensors UtilDB::genRandSensors()
return sensors;
}

GlobalPath UtilDB::genGlobalPath()
{
GlobalPath global_path;
genGlobalPathData(global_path);
return global_path;
}

std::tm UtilDB::getTimestamp()
{
// Get the current time
Expand All @@ -89,10 +101,18 @@ std::pair<Sensors, SailbotDB::RcvdMsgInfo> UtilDB::genRandData(const std::tm & t
.lat_ = 0, // Not processed yet, so just set to 0
.lon_ = 0, // Not processed yet, so just set to 0
.cep_ = 0, // Not processed yet, so just set to 0
.timestamp_ = SailbotDB::RcvdMsgInfo::mkTimestamp(tm)};
.timestamp_ = SailbotDB::mkTimestamp(tm)};
return {rand_sensors, rand_info};
}

std::pair<Polaris::GlobalPath, std::string> UtilDB::genGlobalData(const std::tm & tm)
{
Polaris::GlobalPath global_path_data = genGlobalPath();

std::string global_timestamp = {SailbotDB::mkTimestamp(tm)};
return {global_path_data, global_timestamp};
}

bool UtilDB::verifyDBWrite(std::span<Sensors> expected_sensors, std::span<SailbotDB::RcvdMsgInfo> expected_msg_info)
{
utils::FailTracker tracker;
Expand Down Expand Up @@ -169,6 +189,79 @@ bool UtilDB::verifyDBWrite(std::span<Sensors> expected_sensors, std::span<Sailbo
return !tracker.failed();
}

bool UtilDB::verifyDBWrite_GlobalPath(
std::span<GlobalPath> expected_globalpath, std::span<std::string> expected_timestamp)
{
utils::FailTracker tracker;

auto expectEQ = [&tracker]<not_float T>(T rcvd, T expected, const std::string & err_msg) -> void {
tracker.track(utils::checkEQ(rcvd, expected, err_msg));
};
auto expectFloatEQ = [&tracker]<std::floating_point T>(T rcvd, T expected, const std::string & err_msg) -> void {
tracker.track(utils::checkEQ(rcvd, expected, err_msg));
};

expectEQ(expected_globalpath.size(), expected_timestamp.size(), "Must have a timestamp for global path");
size_t num_docs = expected_globalpath.size();
auto [dumped_globalpath, dumped_timestamps] = dumpGlobalpath(tracker, num_docs);

expectEQ(dumped_globalpath.size(), num_docs, "");
expectEQ(dumped_timestamps.size(), num_docs, "");

for (size_t i = 0; i < num_docs; i++) {
expectEQ(dumped_timestamps[i], expected_timestamp[i], "");

// path waypoints
for (int j = 0; j < NUM_PATH_WAYPOINTS; j++) {
const Polaris::Waypoint & dumped_path_waypoint = dumped_globalpath[i].waypoints(j);
const Polaris::Waypoint & expected_path_waypoint = expected_globalpath[i].waypoints(j);
expectFloatEQ(dumped_path_waypoint.latitude(), expected_path_waypoint.latitude(), "");
expectFloatEQ(dumped_path_waypoint.longitude(), expected_path_waypoint.longitude(), "");
}
}
return !tracker.failed();
}

std::pair<std::vector<GlobalPath>, std::vector<std::string>> UtilDB::dumpGlobalpath(
utils::FailTracker & tracker, size_t num_docs)
{
auto expectEQ = [&tracker]<not_float T>(T rcvd, T expected, const std::string & err_msg) -> void {
tracker.track(utils::checkEQ(rcvd, expected, err_msg));
};

std::vector<GlobalPath> globalpath_vec(num_docs);
std::vector<std::string> timestamp_vec(num_docs);
mongocxx::pool::entry entry = pool_->acquire();
mongocxx::database db = (*entry)[db_name_];
// Set the find options to sort by timestamp
bsoncxx::document::value order = bsoncxx::builder::stream::document{} << "timestamp" << 1
<< bsoncxx::builder::stream::finalize;
mongocxx::options::find opts = mongocxx::options::find{};
opts.sort(order.view());

// global path
mongocxx::collection path_coll = db[COLLECTION_GLOBAL_PATH];
mongocxx::cursor global_path_docs = path_coll.find({}, opts);
expectEQ(
static_cast<uint64_t>(path_coll.count_documents({})), num_docs,
"Error: TestDB should only have " + std::to_string(num_docs) + " documents per collection");

for (auto [i, path_doc_it] = std::tuple{size_t{0}, global_path_docs.begin()}; i < num_docs; i++, path_doc_it++) {
GlobalPath & globalpath = globalpath_vec[i];
const bsoncxx::document::view path_doc = *path_doc_it;
timestamp_vec[i] = path_doc["timestamp"].get_utf8().value.to_string();
for (bsoncxx::array::element path_doc : path_doc["waypoints"].get_array().value) {
Polaris::Waypoint * path = globalpath.add_waypoints();
path->set_latitude(static_cast<float>(path_doc["latitude"].get_double().value));
path->set_longitude(static_cast<float>(path_doc["longitude"].get_double().value));
}
expectEQ(globalpath.waypoints_size(), NUM_PATH_WAYPOINTS, "Size mismatch when reading path waypoints from DB");
//expectEQ(path_doc["timestamp"].get_utf8().value.to_string(), timestamp, "Document timestamp mismatch"); // issue here
}

return {globalpath_vec, timestamp_vec};
}

std::pair<std::vector<Sensors>, std::vector<std::string>> UtilDB::dumpSensors(
utils::FailTracker & tracker, size_t num_docs)
{
Expand Down Expand Up @@ -397,3 +490,16 @@ void UtilDB::genRandPathData(Sensors::Path & path_data)
waypoint->set_longitude(longitude_path(*rng_));
}
}

void UtilDB::genGlobalPathData(Polaris::GlobalPath & global_path_data) //
{
std::uniform_real_distribution<float> latitude_path(LAT_LBND, LAT_UBND);
std::uniform_real_distribution<float> longitude_path(LON_LBND, LON_UBND);
(void)rng_;
for (int i = 0; i < NUM_PATH_WAYPOINTS; i++) {
Polaris::Waypoint * waypoint = global_path_data.add_waypoints();
waypoint->set_latitude(latitude_path(*rng_)); // this needs a float
waypoint->set_longitude(longitude_path(*rng_));
}
global_path_data.num_waypoints();
}
Loading