diff --git a/hello_wolf/CMakeLists.txt b/hello_wolf/CMakeLists.txt index b998b6f1c15ccb59d84e0a70ebbb6051a7301220..8d1114b65c1f81eb7fecf443abeeff16c723d6d3 100644 --- a/hello_wolf/CMakeLists.txt +++ b/hello_wolf/CMakeLists.txt @@ -13,7 +13,6 @@ SET(HDRS_PROCESSOR ${HDRS_PROCESSOR} ) SET(SRCS_HELLOWOLF -# ${CMAKE_CURRENT_SOURCE_DIR}/hello_wolf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/capture_range_bearing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/feature_range_bearing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/landmark_point_2D.cpp @@ -24,9 +23,16 @@ SET(HDRS_PROCESSOR ${HDRS_PROCESSOR} add_library(hellowolf SHARED ${SRCS_HELLOWOLF}) TARGET_LINK_LIBRARIES(hellowolf ${PROJECT_NAME}) + ADD_EXECUTABLE(hello_wolf hello_wolf.cpp) TARGET_LINK_LIBRARIES(hello_wolf ${PROJECT_NAME} hellowolf) -add_library(sensor_odom SHARED ../src/sensor/sensor_odom_2D.cpp ../src/processor/processor_odom_2D.cpp) -TARGET_LINK_LIBRARIES(sensor_odom ${PROJECT_NAME} hellowolf) -add_library(range_bearing SHARED sensor_range_bearing.cpp processor_range_bearing.cpp) -TARGET_LINK_LIBRARIES(range_bearing ${PROJECT_NAME} hellowolf) \ No newline at end of file + +ADD_EXECUTABLE(hello_wolf_autoconf hello_wolf_autoconf.cpp) +#TARGET_LINK_LIBRARIES(hello_wolf_autoconf ${PROJECT_NAME}) +TARGET_LINK_LIBRARIES(hello_wolf_autoconf ${PROJECT_NAME} hellowolf) + +#add_library(sensor_odom SHARED ../src/sensor/sensor_odom_2D.cpp ../src/processor/processor_odom_2D.cpp) +#TARGET_LINK_LIBRARIES(sensor_odom ${PROJECT_NAME} hellowolf) +# +#add_library(range_bearing SHARED sensor_range_bearing.cpp processor_range_bearing.cpp) +#TARGET_LINK_LIBRARIES(range_bearing ${PROJECT_NAME} hellowolf) diff --git a/hello_wolf/hello_wolf_autoconf.cpp b/hello_wolf/hello_wolf_autoconf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..502c38e2ac48ff2539ab95f8ca21c1b674973b1f --- /dev/null +++ b/hello_wolf/hello_wolf_autoconf.cpp @@ -0,0 +1,381 @@ +/** + * \file hello_wolf_autoconf.cpp + * + * Created on: Jul 16, 2019 + * \author: jsola + */ + + +// hello wolf local includes +#include "sensor_range_bearing.h" +#include "processor_range_bearing.h" +#include "capture_range_bearing.h" +#include "feature_range_bearing.h" +#include "factor_range_bearing.h" +#include "landmark_point_2D.h" + +// wolf core includes +#include "core/common/wolf.h" +#include "core/internal/config.h" +#include "core/yaml/parser_yaml.hpp" +#include "core/sensor/sensor_odom_2D.h" +#include "core/processor/processor_odom_2D.h" +#include "core/ceres_wrapper/ceres_manager.h" + +int main() + { + /* + * ============= PROBLEM DEFINITION ================== + * + * We have a planar robot with a range-and-bearing sensor 'S' mounted at its front-left corner, looking forward: + * + * ^ Y + * | + * ------------------S-> sensor at location (1,1) and orientation 0 degrees, that is, at pose (1,1,0). + * | | | + * | +--------|--> X robot axes X, Y + * | | + * ------------------- + * + * The robot performs a straight trajectory with 3 keyframes 'KF', and observes 3 landmarks 'L'. + * + * The 3 robot keyframes, the 3 resulting sensor poses, and the 3 landmark positions can be sketched as follows + * + * (1,2) (2,2) (3,2) landmark positions in world frame + * L1 L2 L3 LANDMARKS + * | \ | \ | + * | \ | \ | + * | \ | \ | + * (1,1,0) (2,1,0) (3,1,0) sensor poses in world frame + * S-> S-> S-> SENSOR + * (1,1,0) (1,1,0) (1,1,0) sensor poses in robot frame + * / / / + * / / / + * / / / + * KF1->---KF2->---KF3-> KEYFRAMES -- robot poses + * (0,0,0) (1,0,0) (2,0,0) keyframe poses in world frame + * | + * * prior Initial robot pose in world frame + * (0,0,0) + * + * where: + * the links '--' are the motion factors, + * the links '\' and '|' are the landmark measurement factors, and + * the links '/' are the robot-to-sensor transforms. + * + * That is: + * - KFs have ids '1', '2', '3' + * - All KFs look East, so all theta = 0 + * - KFs are at poses (0,0, 0), (1,0, 0), and (2,0, 0) + * - We set a prior at (0,0,0) on KF1 to render the system observable + * - The range-and-bearing sensor is mounted at pose (1,1, 0) w.r.t. the robot's origin + * - Lmks have ids '1', '2', '3' + * - Lmks are at positions (1,2), (2,2), (3,2) + * - Observations have ranges 1 or sqrt(2) + * - Observations have bearings pi/2 or 3pi/4 + * + * The robot starts at (0,0,0) with a map with no previously known landmarks. + * At each keyframe, it does: + * - Create a motion factor to the previous keyframe + * - Measure some landmarks. For each measurement, + * - If the landmark is unknown, add it to the map and create an observation factor + * - If the landmark is known, create an observation factor + * + * The landmarks observed at each keyframe are as follows: + * - KF1: lmk 1 + * - KF2: lmks 1 and 2 + * - KF3: lmks 2 and 3 + * + * After 3 keyframes, the problem is solved and the robot poses and landmark positions are optimized: + * - First, using the exact values as initial guess for the solver + * - Second, using random values + * Both solutions must produce the same exact values as in the sketches above. + * + * Optionally, the user can opt to self-calibrate the sensor's orientation (see NOTE within the code around Line 151) + * + * (c) 2017 Joan Sola @ IRI-CSIC + */ + + // SET PROBLEM ======================================================= + + using namespace wolf; + + + WOLF_TRACE("======== CONFIGURE PROBLEM =======") + + // Config file to parse. Here is where all the problem is defined: + std::string file = std::string(_WOLF_ROOT_DIR) + "/hello_wolf/hello_wolf_config.yaml"; + + // parse file into params server: each param will be retrievable from this params server: + ParserYAML parser = ParserYAML(file); + parser.parse(); + ParamsServer server = ParamsServer(parser.getParams(), parser.sensorsSerialization(), parser.processorsSerialization()); + + // Wolf problem: automatically build the left branch of the wolf tree from the contents of the params server: + ProblemPtr problem = Problem::autoSetup(server); + + // Print problem to see its status before processing any sensor data + problem->print(4,0,1,0); + + // recover sensor pointers for later use (access by sensor name) + SensorBasePtr sensor_odo = problem->getSensor("odom"); + SensorBasePtr sensor_rb = problem->getSensor("rb"); + + // Solver. Configure a Ceres solver + ceres::Solver::Options options; + options.max_num_iterations = 1000; // We depart far from solution, need a lot of iterations + CeresManagerPtr ceres = std::make_shared<CeresManager>(problem, options); + + + + // SELF CALIBRATION =================================================== + // These few lines control whether we calibrate some sensor parameters or not. + + // NOTE: SELF-CALIBRATION OF SENSOR ORIENTATION + // Uncomment this line below to achieve sensor self-calibration (of the orientation only, since the position is not observable) + sensor_rb->getO()->unfix(); + + // NOTE: SELF-CALIBRATION OF SENSOR POSITION + // The position is however not observable, and thus self-calibration would not work. You can try uncommenting it too. + // sensor_rb->getP()->unfix(); + + // CONFIGURE input data (motion and measurements) ============================================== + + // Motion data + Vector2s motion_data(1.0, 0.0); // Will advance 1m at each keyframe, will not turn. + Matrix2s motion_cov = 0.1 * Matrix2s::Identity(); + + // landmark observations data + VectorXi ids; + VectorXs ranges, bearings; + + // SET OF EVENTS: make things happen ======================================================= + std::cout << std::endl; + WOLF_TRACE("======== BUILD PROBLEM =======") + + // We'll do 3 steps of motion and landmark observations. + + // STEP 1 -------------------------------------------------------------- + + // initialize + TimeStamp t = problem->getTrajectory()->getFrameList().front()->getTimeStamp(); + + // observe lmks + ids.resize(1); ranges.resize(1); bearings.resize(1); + ids << 1; // will observe Lmk 1 + ranges << 1.0; // see drawing + bearings << M_PI/2; + CaptureRangeBearingPtr cap_rb = std::make_shared<CaptureRangeBearing>(t, sensor_rb, ids, ranges, bearings); + cap_rb->process(); // L1 : (1,2) + + // STEP 2 -------------------------------------------------------------- + t += 1.0; // t : 1.0 + + // motion + CaptureOdom2DPtr cap_motion = std::make_shared<CaptureOdom2D>(t, sensor_odo, motion_data, motion_cov); + cap_motion ->process(); // KF2 : (1,0,0) + + // observe lmks + ids.resize(2); ranges.resize(2); bearings.resize(2); + ids << 1, 2; // will observe Lmks 1 and 2 + ranges << sqrt(2.0), 1.0; // see drawing + bearings << 3*M_PI/4, M_PI/2; + + cap_rb = std::make_shared<CaptureRangeBearing>(t, sensor_rb, ids, ranges, bearings); + cap_rb ->process(); // L1 : (1,2), L2 : (2,2) + + // STEP 3 -------------------------------------------------------------- + t += 1.0; // t : 2.0 + + // motion + cap_motion ->setTimeStamp(t); + cap_motion ->process(); // KF3 : (2,0,0) + + // observe lmks + ids.resize(2); ranges.resize(2); bearings.resize(2); + ids << 2, 3; // will observe Lmks 2 and 3 + ranges << sqrt(2.0), 1.0; // see drawing + bearings << 3*M_PI/4, M_PI/2; + + cap_rb = std::make_shared<CaptureRangeBearing>(t, sensor_rb, ids, ranges, bearings); + cap_rb ->process(); // L1 : (1,2), L2 : (2,2), L3 : (3,2) + + problem->print(1,0,1,0); + + // SOLVE ================================================================ + + // SOLVE with exact initial guess + WOLF_TRACE("======== SOLVE PROBLEM WITH EXACT PRIORS =======") + std::string report = ceres->solve(wolf::SolverManager::ReportVerbosity::FULL); + WOLF_TRACE(report); // should show a very low iteration number (possibly 1) + problem->print(1,0,1,0); + + // PERTURB initial guess + WOLF_TRACE("======== PERTURB PROBLEM PRIORS =======") + for (auto sen : problem->getHardware()->getSensorList()) + for (auto sb : sen->getStateBlockVec()) + if (sb && !sb->isFixed()) + sb->setState(sb->getState() + VectorXs::Random(sb->getSize()) * 0.5); // We perturb A LOT ! + for (auto kf : problem->getTrajectory()->getFrameList()) + if (kf->isKeyOrAux()) + for (auto sb : kf->getStateBlockVec()) + if (sb && !sb->isFixed()) + sb->setState(sb->getState() + VectorXs::Random(sb->getSize()) * 0.5); // We perturb A LOT ! + for (auto lmk : problem->getMap()->getLandmarkList()) + for (auto sb : lmk->getStateBlockVec()) + if (sb && !sb->isFixed()) + sb->setState(sb->getState() + VectorXs::Random(sb->getSize()) * 0.5); // We perturb A LOT ! + problem->print(1,0,1,0); + + // SOLVE again + WOLF_TRACE("======== SOLVE PROBLEM WITH PERTURBED PRIORS =======") + report = ceres->solve(wolf::SolverManager::ReportVerbosity::FULL); + WOLF_TRACE(report); // should show a very high iteration number (more than 10, or than 100!) + problem->print(1,0,1,0); + + // GET COVARIANCES of all states + WOLF_TRACE("======== COVARIANCES OF SOLVED PROBLEM =======") + ceres->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL_MARGINALS); + for (auto kf : problem->getTrajectory()->getFrameList()) + if (kf->isKeyOrAux()) + { + Eigen::MatrixXs cov; + kf->getCovariance(cov); + WOLF_TRACE("KF", kf->id(), "_cov = \n", cov); + } + for (auto lmk : problem->getMap()->getLandmarkList()) + { + Eigen::MatrixXs cov; + lmk->getCovariance(cov); + WOLF_TRACE("L", lmk->id(), "_cov = \n", cov); + } + std::cout << std::endl; + + WOLF_TRACE("======== FINAL PRINT FOR INTERPRETATION =======") + problem->print(4,1,1,1); + + /* + * ============= FIRST COMMENT ON THE RESULTS ================== + * + * IF YOU SEE at the end of the printed problem the estimate for Lmk 3 as: + * + * L3 POINT 2D <-- c8 + * Est, x = ( 3 2 ) + * sb: Est + * + * it means WOLF SOLVED SUCCESSFULLY (L3 is effectively at location (3,2) ) ! + * + * Side notes: + * + * - Observe that all other KFs and Lmks are correct. + * + * - Try self-calibrating the sensor orientation by uncommenting line 151 (well, around 151) + * + */ + + /* + * ============= DETAILED DESCRIPTION OF THE PRINTED RESULT ================== + * + * The line problem->print(4,1,1,1) produces a printout of the status of the WOLF problem. + * The full message is explained below. + * + * P: wolf tree status --------------------- + Hardware + S1 ODOM 2D // Sensor 1, type ODOMETRY 2D. + Extr [Sta] = [ Fix( 0 0 ) Fix( 0 ) ] // Static extrinsics, fixed position, fixed orientation (See notes 1 and 2 below) + Intr [Sta] = [ ] // Static intrinsics, but no intrinsics anyway + pm1 ODOM 2D // Processor 1, type ODOMETRY 2D + o: C7 - F3 // origin at Capture 7, Frame 3 + l: C10 - F4 // last at Capture 10, frame 4 + S2 RANGE BEARING // Sensor 2, type RANGE and BEARING. + Extr [Sta] = [ Fix( 1 1 ) Est( 0 ) ] // Static extrinsics, fixed position, estimated orientation (See notes 1 and 2 below) + Intr [Sta] = [ ] // Static intrinsics, but no intrinsics anyway + pt2 RANGE BEARING // Processor 2: type Range and Bearing + Trajectory + KF1 <-- c3 // KeyFrame 1, constrained by Factor 3 + Est, ts=0, x = ( -1.6e-13 9.4e-11 1.4e-10 ) // State is estimated; time stamp and state vector + sb: Est Est // State's pos and orient are estimated + C1 FIX -> S- [ <-- // Capture 1, type FIX or Absolute + f1 FIX <-- // Feature 1, type Fix + m = ( 0 0 0 ) // The absolute measurement for this frame is (0,0,0) --> origin + c1 FIX --> A // Factor 1, type FIX, it is Absolute + CM2 ODOM 2D -> S1 [Sta, Sta] <-- // Capture 2, type ODOM, from Sensor 1 (static extr and intr) + C5 RANGE BEARING -> S2 [Sta, Sta] <-- // Capture 5, type R+B, from Sensor 2 (static extr and intr) + f2 RANGE BEARING <-- // Feature 2, type R+B + m = ( 1 1.57 ) // The feature's measurement is 1m, 1.57rad + c2 RANGE BEARING --> L1 // Factor 2 against Landmark 1 + KF2 <-- c6 + Est, ts=1, x = ( 1 2.5e-10 1.6e-10 ) + sb: Est Est + CM3 ODOM 2D -> S1 [Sta, Sta] <-- + f3 ODOM 2D <-- + m = ( 1 0 0 ) + c3 ODOM 2D --> F1 // Factor 3, type ODOM, against Frame 1 + C9 RANGE BEARING -> S2 [Sta, Sta] <-- + f4 RANGE BEARING <-- + m = ( 1.41 2.36 ) + c4 RANGE BEARING --> L1 + f5 RANGE BEARING <-- + m = ( 1 1.57 ) + c5 RANGE BEARING --> L2 + KF3 <-- + Est, ts=2, x = ( 2 4.1e-10 1.7e-10 ) + sb: Est Est + CM7 ODOM 2D -> S1 [Sta, Sta] <-- + f6 ODOM 2D <-- + m = ( 1 0 0 ) + c6 ODOM 2D --> F2 + C12 RANGE BEARING -> S2 [Sta, Sta] <-- + f7 RANGE BEARING <-- + m = ( 1.41 2.36 ) + c7 RANGE BEARING --> L2 + f8 RANGE BEARING <-- + m = ( 1 1.57 ) + c8 RANGE BEARING --> L3 + F4 <-- + Est, ts=2, x = ( 0.11 -0.045 0.26 ) + sb: Est Est + CM10 ODOM 2D -> S1 [Sta, Sta] <-- + Map + L1 POINT 2D <-- c2 c4 // Landmark 1, constrained by Factors 2 and 4 + Est, x = ( 1 2 ) // L4 state is estimated, state vector + sb: Est // L4 has 1 state block estimated + L2 POINT 2D <-- c5 c7 + Est, x = ( 2 2 ) + sb: Est + L3 POINT 2D <-- c8 + Est, x = ( 3 2 ) + sb: Est + ----------------------------------------- + * + * ============= GENERAL WOLF NOTES ================== + * + * Explanatory notes, general to the Wolf architecture design: + * + * (1): Sensor params (extrinsics and intrinsics) can be declared Dynamic or Static + * Static: they do not change with time --> stored in the Sensor + * Dynamic: they change with time --> stored in each Capture + * + * (2): General params can be declared Fixed or Estimated + * Fixed: they are used as constant values, never estimated + * Estimated: they are estimated by the solver iteratively + * + * Therefore, in the case of Sensors, each block of parameters can be Static/Dynamic and Fixed/Estimated. This produces 4 combinations: + * + * 1 Fixed + Static : general case of calibrated sensor. + * Example: rigidly fixed sensor with calibrated parameters + * This is the case for the current example (the SensorRangeBearing we use is like this) + * + * 2 Estimated + Static : Wolf performs self-calibration. + * Example: extrinsics self-calibration of a camera + * + * 3 Fixed + Dynamic : calibrated but variable parameters. + * Example: pan and tilt camera extrinsics, known at every time through precise encoders + * + * 4 Estimated + Dynamic : Wolf will track those sensor parameters that evolve with time. + * Example: IMU bias + * + */ + + return 0; +} diff --git a/hello_wolf/hello_wolf_config.yaml b/hello_wolf/hello_wolf_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..13472f71bde49c1e5f46272ea248274f8e77a4aa --- /dev/null +++ b/hello_wolf/hello_wolf_config.yaml @@ -0,0 +1,45 @@ +config: + + problem: + frame structure: "PO" + dimension: 2 + prior timestamp: 0.0 + prior state: [0,0,0] + prior cov: [[3,3],.01,0,0,0,.01,0,0,0,.01] + prior time tolerance: 0.1 + + + sensors: + - + type: "ODOM 2D" + name: "odom" + + - + type: "RANGE BEARING" + name: "rb" + noise range metres std: 0.1 + noise bearing degrees std: 0.5 + + processors: + - + type: "ODOM 2D" + name: "odom" + sensor name: "odom" + voting active: true + time tolerance: 0.1 + max time span: 999 + dist_traveled: 0.95 + angle_turned: 999 + cov_det: 999 + unmeasured_perturbation_std: 0.001 + + - + type: "RANGE BEARING" + name: "rb" + sensor name: "rb" + + +files: +# - "/Users/jsola/dev/wolf_lib/core/lib/libhellowolf.dylib" + + \ No newline at end of file diff --git a/hello_wolf/processor_range_bearing.cpp b/hello_wolf/processor_range_bearing.cpp index 7cf2c04facbba1b1523d533a05f83ddba3e6a853..54bbb3aec498cacc736321f77abc127a24414106 100644 --- a/hello_wolf/processor_range_bearing.cpp +++ b/hello_wolf/processor_range_bearing.cpp @@ -52,7 +52,6 @@ void ProcessorRangeBearing::processCapture(CaptureBasePtr _capture) // 2. cast incoming capture to the range-and-bearing type, add it to the keyframe CaptureRangeBearingPtr capture_rb = std::static_pointer_cast<CaptureRangeBearing>(_capture); - // kf->addCapture(capture_rb); capture_rb->link(kf); // 3. explore all observations in the capture @@ -76,40 +75,33 @@ void ProcessorRangeBearing::processCapture(CaptureBasePtr _capture) { // new landmark: // - create landmark - // lmk = std::make_shared<LandmarkPoint2D>(id, invObserve(range, bearing)); lmk = std::static_pointer_cast<LandmarkPoint2D>(LandmarkBase::emplace<LandmarkPoint2D>(getProblem()->getMap(), id, invObserve(range, bearing))); WOLF_TRACE("new lmk(", id, "): ", lmk->getP()->getState().transpose()); - // getProblem()->getMap()->addLandmark(lmk); // - add to known landmarks known_lmks.emplace(id, lmk); } // 5. create feature Vector2s rb(range,bearing); - auto ftr = std::make_shared<FeatureRangeBearing>(rb, - getSensor()->getNoiseCov()); - // capture_rb->addFeature(ftr); - FeatureBase::emplace<FeatureRangeBearing>(capture_rb, rb, getSensor()->getNoiseCov()); + auto ftr = FeatureBase::emplace<FeatureRangeBearing>(capture_rb, + rb, + getSensor()->getNoiseCov()); // 6. create factor auto prc = shared_from_this(); - // auto ctr = std::make_shared<FactorRangeBearing>(capture_rb, - // lmk, - // prc, - // false, - // FAC_ACTIVE); - auto ctr = FactorBase::emplace<FactorRangeBearing>(ftr, capture_rb, + auto ctr = FactorBase::emplace<FactorRangeBearing>(ftr, + capture_rb, lmk, prc, false, FAC_ACTIVE); - // ftr->addFactor(ctr); - // lmk->addConstrainedBy(ctr); } } -ProcessorBasePtr ProcessorRangeBearing::create(const std::string& _unique_name, const ProcessorParamsBasePtr _params, const SensorBasePtr _sen_ptr) +ProcessorBasePtr ProcessorRangeBearing::create(const std::string& _unique_name, + const ProcessorParamsBasePtr _params, + const SensorBasePtr _sen_ptr) { SensorRangeBearingPtr sensor_rb = std::static_pointer_cast<SensorRangeBearing>(_sen_ptr); ProcessorParamsRangeBearingPtr params = std::static_pointer_cast<ProcessorParamsRangeBearing>(_params); @@ -124,8 +116,8 @@ ProcessorBasePtr ProcessorRangeBearing::create(const std::string& _unique_name, } ProcessorBasePtr ProcessorRangeBearing::createAutoConf(const std::string& _unique_name, - const ParamsServer& _server, - const SensorBasePtr _sensor_ptr) + const ParamsServer& _server, + const SensorBasePtr _sensor_ptr) { SensorRangeBearingPtr sensor_rb = std::static_pointer_cast<SensorRangeBearing>(_sensor_ptr); ProcessorParamsRangeBearingPtr params = std::make_shared<ProcessorParamsRangeBearing>(); diff --git a/hello_wolf/processor_range_bearing.h b/hello_wolf/processor_range_bearing.h index ff99fddfba05ce919949b115c74c6b73a429b633..2bc4767c14f0c9619534d3bd6f6ae1dc5d4f506b 100644 --- a/hello_wolf/processor_range_bearing.h +++ b/hello_wolf/processor_range_bearing.h @@ -22,19 +22,19 @@ WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsRangeBearing); struct ProcessorParamsRangeBearing : public ProcessorParamsBase { // We do not need special parameters, but in case you need they should be defined here. - ProcessorParamsRangeBearing() - { - //DEFINED FOR COMPATIBILITY PURPOSES. TO BE REMOVED IN THE FUTURE. - } - ProcessorParamsRangeBearing(std::string _unique_name, const ParamsServer& _server): - ProcessorParamsBase(_unique_name, _server) - { - // - } - std::string print() - { - return "\n" + ProcessorParamsBase::print(); - } + ProcessorParamsRangeBearing() + { + //DEFINED FOR COMPATIBILITY PURPOSES. TO BE REMOVED IN THE FUTURE. + } + ProcessorParamsRangeBearing(std::string _unique_name, const ParamsServer& _server) : + ProcessorParamsBase(_unique_name, _server) + { + // + } + std::string print() + { + return "\n" + ProcessorParamsBase::print(); + } }; using namespace Eigen; diff --git a/hello_wolf/sensor_range_bearing.cpp b/hello_wolf/sensor_range_bearing.cpp index 7be1171b9b6cf3fdbd46104bad76e509f96ddf82..964b909338dfd1062012c73e1aaf0a7b33999295 100644 --- a/hello_wolf/sensor_range_bearing.cpp +++ b/hello_wolf/sensor_range_bearing.cpp @@ -45,10 +45,10 @@ SensorBasePtr SensorRangeBearing::create(const std::string& _unique_name, // SensorBasePtr SensorRangeBearing::createAutoConf(const std::string& _unique_name, // const ParamsServer& _server) { - Eigen::Vector2s noise_std(0.1,1.0); + IntrinsicsRangeBearing intr(_unique_name, _server); + Eigen::Vector2s noise_std(intr.noise_range_metres_std, intr.noise_bearing_degrees_std); SensorRangeBearingPtr sensor = std::make_shared<SensorRangeBearing>(Eigen::Vector3s(1,1,0), noise_std); sensor->setName(_unique_name); - // sensor->node_name_ = _unique_name; return sensor; } diff --git a/hello_wolf/sensor_range_bearing.h b/hello_wolf/sensor_range_bearing.h index f3ed332fffdbab37fd51072eb0b58cee82f43d05..161818df65a56f5b2df02d9a66327a71e80a63a0 100644 --- a/hello_wolf/sensor_range_bearing.h +++ b/hello_wolf/sensor_range_bearing.h @@ -26,12 +26,13 @@ struct IntrinsicsRangeBearing : public IntrinsicsBase IntrinsicsRangeBearing(std::string _unique_name, const ParamsServer& _server): IntrinsicsBase(_unique_name, _server) { - noise_range_metres_std = _server.getParam<Scalar>(_unique_name + "/noise_range_metres_std", "0.05"); - noise_bearing_degrees_std = _server.getParam<Scalar>(_unique_name + "/noise_bearing_degrees_std", "0.5"); + noise_range_metres_std = _server.getParam<Scalar>(_unique_name + "/noise range metres std", "0.05"); + noise_bearing_degrees_std = _server.getParam<Scalar>(_unique_name + "/noise bearing degrees std", "0.5"); } std::string print() { - return "\n" + IntrinsicsBase::print() + "noise_range_metres_std: " + std::to_string(noise_range_metres_std) + "\n" + return "" + IntrinsicsBase::print() + + "noise_range_metres_std: " + std::to_string(noise_range_metres_std) + "\n" + "noise_bearing_degrees_std: " + std::to_string(noise_bearing_degrees_std) + "\n"; } }; diff --git a/include/core/processor/processor_odom_2D.h b/include/core/processor/processor_odom_2D.h index 5bb0732f9a6e46acdc53658ebc881786ff48f2e2..7c7c1cd0a431d4c4c0053598fa9567854cc09742 100644 --- a/include/core/processor/processor_odom_2D.h +++ b/include/core/processor/processor_odom_2D.h @@ -21,18 +21,19 @@ WOLF_STRUCT_PTR_TYPEDEFS(ProcessorParamsOdom2D); struct ProcessorParamsOdom2D : public ProcessorParamsMotion { - Scalar cov_det = 1.0; // 1 rad^2 - ProcessorParamsOdom2D() = default; - ProcessorParamsOdom2D(std::string _unique_name, const wolf::ParamsServer & _server): - ProcessorParamsMotion(_unique_name, _server) - { - cov_det = _server.getParam<Scalar>(_unique_name + "/cov_det", "1.0"); - } - std::string print() - { - return "\n" + ProcessorParamsMotion::print() + "cov_det: " + std::to_string(cov_det) + "\n"; - } + Scalar cov_det = 1.0; // 1 rad^2 + ProcessorParamsOdom2D() = default; + ProcessorParamsOdom2D(std::string _unique_name, const wolf::ParamsServer & _server) : + ProcessorParamsMotion(_unique_name, _server) + { + cov_det = _server.getParam<Scalar>(_unique_name + "/cov_det", "1.0"); + } + std::string print() + { + return "\n" + ProcessorParamsMotion::print() + "cov_det: " + std::to_string(cov_det) + "\n"; + } }; + class ProcessorOdom2D : public ProcessorMotion { public: diff --git a/include/core/utils/params_server.hpp b/include/core/utils/params_server.hpp index 34d2f8734625a32bca587d45a34844a2a898e5c7..94e8f1a8468a89749685ad471ee9b234e392f84d 100644 --- a/include/core/utils/params_server.hpp +++ b/include/core/utils/params_server.hpp @@ -1,20 +1,26 @@ #ifndef PARAMS_SERVER_HPP #define PARAMS_SERVER_HPP + +#include "core/utils/converter.h" +//#include "core/yaml/parser_yaml.hpp" + #include <vector> #include <regex> #include <map> -#include "core/utils/converter.h" + namespace wolf{ class ParamsServer{ struct ParamsInitSensor{ std::string _type; std::string _name; }; + struct ParamsInitProcessor{ std::string _type; std::string _name; std::string _name_assoc_sensor; }; + std::map<std::string, std::string> _params; std::map<std::string,ParamsInitSensor> _paramsSens; std::map<std::string,ParamsInitProcessor> _paramsProc; @@ -42,21 +48,26 @@ public: ~ParamsServer(){ // } + void print(){ for(auto it : _params) std::cout << it.first << "~~" << it.second << std::endl; } + void addInitParamsSensor(std::string type, std::string name){ ParamsInitSensor params = {type, name}; _paramsSens.insert(std::pair<std::string, ParamsInitSensor>(type + "/" + name + "/", params)); } + void addInitParamsProcessor(std::string type, std::string name, std::string name_assoc_sensor){ ParamsInitProcessor params = {type, name, name_assoc_sensor}; _paramsProc.insert(std::pair<std::string, ParamsInitProcessor>(type + "/" + name + "/", params)); } + void addParam(std::string key, std::string value){ _params.insert(std::pair<std::string, std::string>(key, value)); } + template<typename T> T getParam(std::string key, std::string def_value) const { if(_params.find(key) != _params.end()){ @@ -65,6 +76,7 @@ public: return converter<T>::convert(def_value); } } + template<typename T> T getParam(std::string key) const { if(_params.find(key) != _params.end()){ @@ -73,16 +85,20 @@ public: throw std::runtime_error("The following key: '" + key + "' has not been found in the parameters server and no default value was provided."); } } + std::vector<ParamsInitSensor> getSensors(){ std::vector<ParamsInitSensor> rtn = std::vector<ParamsInitSensor>(); std::transform(this->_paramsSens.begin(), this->_paramsSens.end(), back_inserter(rtn), [](const std::pair<std::string,ParamsInitSensor> v){return v.second;}); return rtn; } + std::vector<ParamsInitProcessor> getProcessors(){ std::vector<ParamsInitProcessor> rtn = std::vector<ParamsInitProcessor>(); std::transform(this->_paramsProc.begin(), this->_paramsProc.end(), back_inserter(rtn), [](const std::pair<std::string,ParamsInitProcessor> v){return v.second;}); return rtn; } }; + } -#endif \ No newline at end of file + +#endif diff --git a/include/core/yaml/parser_yaml.hpp b/include/core/yaml/parser_yaml.hpp index 226d3cca16e7eb31ebb4a294c003500c86b51dbb..3af5c1630da3e1bbeba9ec0ec4c6cc8ab5c63cfb 100644 --- a/include/core/yaml/parser_yaml.hpp +++ b/include/core/yaml/parser_yaml.hpp @@ -1,8 +1,11 @@ #ifndef PARSER_YAML_HPP #define PARSER_YAML_HPP -#include "yaml-cpp/yaml.h" + #include "core/utils/converter.h" #include "core/common/wolf.h" + +#include "yaml-cpp/yaml.h" + #include <vector> #include <regex> #include <map> diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp index 4565bb62293ec1ba1f1df56b74f32dc3e0124200..eab55cc02cf4d12045fddf7813c4d7cdf87f35b4 100644 --- a/src/problem/problem.cpp +++ b/src/problem/problem.cpp @@ -73,14 +73,19 @@ ProblemPtr Problem::create(const std::string& _frame_structure, SizeEigen _dim) p->setup(); return p->shared_from_this(); } + ProblemPtr Problem::autoSetup(ParamsServer &_server) { - std::string frame_structure = _server.getParam<std::string>("problem/frame structure", "PO"); - int dim = _server.getParam<int>("problem/dimension", "2"); - auto p = Problem::create(frame_structure, dim); + // Problem structure and dimension + std::string frame_structure = _server.getParam<std::string> ("problem/frame structure", "PO"); + int dim = _server.getParam<int> ("problem/dimension", "2"); + auto problem = Problem::create(frame_structure, dim); // cout << "PRINTING SERVER MAP" << endl; // _server.print(); // cout << "-----------------------------------" << endl; + WOLF_TRACE("Setting up problem with frame structure {" + frame_structure + "} and dimension " + std::to_string(dim) + "D"); + + // Load plugins auto loaders = std::vector<Loader*>(); for(auto it : _server.getParam<std::vector<std::string>>("files")) { WOLF_TRACE("Loading file " + it) @@ -88,27 +93,37 @@ ProblemPtr Problem::autoSetup(ParamsServer &_server) l->load(); loaders.push_back(l); } - WOLF_TRACE("Setting up problem with frame structure {" + frame_structure + "} and dimension {" + std::to_string(dim) + "}"); - Eigen::VectorXs prior_state = _server.getParam<Eigen::VectorXs>("problem/prior state"); - Eigen::MatrixXs prior_cov = _server.getParam<Eigen::MatrixXs>("problem/prior cov"); - Scalar time_tolerance = _server.getParam<Scalar>("problem/time tolerance"); - auto ts = TimeStamp(); - WOLF_TRACE("prior timestamp:\n",ts); - WOLF_TRACE("prior state:\n", prior_state.transpose()); - WOLF_TRACE("prior covariance:\n", prior_cov); - WOLF_TRACE("prior time tolerance:\n", time_tolerance); - p->setPrior(prior_state, prior_cov, ts, time_tolerance); + + // Install sensors and processors auto sensorMap = std::map<std::string, SensorBasePtr>(); auto procesorMap = std::map<std::string, ProcessorBasePtr>(); - for(auto s : _server.getSensors()){ - sensorMap.insert(std::pair<std::string, SensorBasePtr>(s._name,p->installSensor(s._type, s._name, _server))); + + for(auto sen : _server.getSensors()){ + sensorMap.insert(std::pair<std::string, SensorBasePtr>(sen._name, problem->installSensor(sen._type, sen._name, _server))); } - for(auto s : _server.getProcessors()){ - procesorMap.insert(std::pair<std::string, ProcessorBasePtr>(s._name,p->installProcessor(s._type, s._name, s._name_assoc_sensor, _server))); + + for(auto prc : _server.getProcessors()){ + procesorMap.insert(std::pair<std::string, ProcessorBasePtr>(prc._name, problem->installProcessor(prc._type, prc._name, prc._name_assoc_sensor, _server))); } - return p; + + // Prior + Eigen::VectorXs prior_state = _server.getParam<Eigen::VectorXs>("problem/prior state"); + Eigen::MatrixXs prior_cov = _server.getParam<Eigen::MatrixXs>("problem/prior cov"); + Scalar prior_time_tolerance = _server.getParam<Scalar>("problem/prior time tolerance"); + Scalar prior_ts = _server.getParam<Scalar>("problem/prior timestamp"); + + WOLF_TRACE("prior timestamp:\n" , prior_ts); + WOLF_TRACE("prior state:\n" , prior_state.transpose()); + WOLF_TRACE("prior covariance:\n" , prior_cov); + WOLF_TRACE("prior time tolerance:\n", prior_time_tolerance); + + problem->setPrior(prior_state, prior_cov, prior_ts, prior_time_tolerance); + + // Done + return problem; } + Problem::~Problem() { // WOLF_DEBUG("destructed -P");