Code Monkey home page Code Monkey logo

fuse's People

Contributors

ayrton04 avatar efernandez avatar fabianhirmann avatar facontidavide avatar garyservin avatar jakemclaughlin6 avatar locus-services avatar oscarmendezm avatar paulbovbel avatar sjphilli avatar svwilliams avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fuse's Issues

What are reasonable selections of lag_duration for state estimation?

Hi,

I'm watching your ROSCon talk and had a question on the lag_duration for the fixed lag smoother. It makes sense to keep a rolling buffer of measurements to bound the problem, but it doesn't tell us what a "reasonable" set of values for this are.

Your example shows 0.5 seconds, but if someone asked me in a vacuum, I would have thought something closer to 1-2 seconds. There's clearly a trade off for how often you cull out measurements to bound the graph size and how long you keep it for accuracy, so I was hoping you could shed some light from your experience what a reasonable range of values are for a usual setup (IMU + wheel ecoders, each publishing 50-100hz) from tuning your systems. This doesn't have to be very scientific, I'm really looking to query your intuition from building this project, though if you had actual numbers, that's good too ๐Ÿ˜†

(e.g. is 5s just insane because of the number of constraints in the graph for a typical robot CPU, or is 0.5s an actual recommended value or just a toy example for the talk, where's the rough point of diminishing returns on accuracy vs buffer length, etc)

A reasonable follow up question would be if there's a better trade off on lowering the frequency of optimization to allow more samples to come in during a time period and then increasing the lag_duration to make use of the extra compute time for improved accuracy. I wonder about the accuracy this can obtain if being run at 20hz with usual robot odometry / IMU at 50-100hz with respect to long term drift relative to an EKF.


tl;dr

  • What is a reasonable range of values for storing values / optimizing the graph for state estimation
  • Relative to traditional filters, should we prefer to store values longer and update the filter slower to gather more information per run to have decent performance?

Manual jacobian computation

When attempting to use a manual jacobian computation the main optimization does not produce expected results (monotonically decreasing cost) as the equivalent cost function using auto differentation. I have also verified that the two jacobians are equivalent by using them directly with ceres in a test case:

TEST(EuclideanReprojectionFunction, Validity) {
  // generate random T_WORLD_BASELINK
  const Eigen::Matrix4d T_WORLD_BASELINK = beam::GenerateRandomPose(1.0, 10.0);
  const Eigen::Quaterniond q_WORLD_BASELINK(T_WORLD_BASELINK.block<3, 3>(0, 0));
  const Eigen::Vector3d t_WORLD_BASELINK =
      T_WORLD_BASELINK.block<3, 1>(0, 3).transpose();

  // generate random K
  Eigen::Matrix3d K = GenerateRandomIntrinsicMatrix();

  // generate random T_CAM_BASELINK
  const Eigen::Matrix4d T_CAM_BASELINK = beam::GenerateRandomPose(0.0, 1.0);

  // generate random P_WORLD
  const Eigen::Vector3d P_CAM =
      beam::randf(5.0, 10.0) *
      beam::UniformRandomVector<3>(0.1, 1.0).normalized();
  const Eigen::Vector3d P_WORLD =
      (T_WORLD_BASELINK * beam::InvertTransform(T_CAM_BASELINK) *
       P_CAM.homogeneous())
          .hnormalized();

  const Eigen::Vector2d pixel =
      (K * P_CAM).hnormalized() + Eigen::Vector2d(10, 10);

  // create fuse variables
  ros::Time stamp(0.0);
  uint64_t id = 0;

  // create manual diff cost function
  auto manual_diff_cost_function = std::shared_ptr<ceres::CostFunction>(
      new bs_constraints::EuclideanReprojection(Eigen::Matrix2d::Identity(),
                                                pixel, K, T_CAM_BASELINK));

  // create autodiff cost function
  auto auto_diff_cost_function = std::shared_ptr<ceres::CostFunction>(
      new ceres::AutoDiffCostFunction<bs_constraints::ReprojectionFunctor, 2, 4,
                                      3, 3>(
          new bs_constraints::ReprojectionFunctor(Eigen::Matrix2d::Identity(),
                                                  pixel, K, T_CAM_BASELINK)));

  std::vector<int> manual_rows, auto_rows;
  std::vector<int> manual_cols, auto_cols;
  std::vector<double> manual_vals, auto_vals;
  {
    // Build the problem
    ceres::Problem::Options problem_options;
    problem_options.loss_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
    problem_options.cost_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
    ceres::Problem problem(problem_options);

    fuse_variables::Orientation3DStamped::SharedPtr orientation =
        fuse_variables::Orientation3DStamped::make_shared(stamp);
    orientation->w() = q_WORLD_BASELINK.w();
    orientation->x() = q_WORLD_BASELINK.x();
    orientation->y() = q_WORLD_BASELINK.y();
    orientation->z() = q_WORLD_BASELINK.z();

    fuse_variables::Position3DStamped::SharedPtr position =
        fuse_variables::Position3DStamped::make_shared(stamp);
    position->x() = t_WORLD_BASELINK[0];
    position->y() = t_WORLD_BASELINK[1];
    position->z() = t_WORLD_BASELINK[2];

    fuse_variables::Point3DLandmark::SharedPtr landmark =
        fuse_variables::Point3DLandmark::make_shared(id);
    landmark->x() = P_WORLD[0];
    landmark->y() = P_WORLD[1];
    landmark->z() = P_WORLD[2];

    problem.AddParameterBlock(orientation->data(), orientation->size(),
                              orientation->localParameterization());
    problem.AddParameterBlock(position->data(), position->size(),
                              position->localParameterization());
    problem.AddParameterBlock(landmark->data(), landmark->size(),
                              landmark->localParameterization());

    std::vector<double*> parameter_blocks;
    parameter_blocks.push_back(orientation->data());
    parameter_blocks.push_back(position->data());
    parameter_blocks.push_back(landmark->data());

    auto loss_function =
        std::shared_ptr<ceres::LossFunction>(new ceres::TrivialLoss());

    problem.AddResidualBlock(manual_diff_cost_function.get(),
                             loss_function.get(), parameter_blocks);

    double cost = 0.0;
    ceres::CRSMatrix jacobian;
    problem.Evaluate(ceres::Problem::EvaluateOptions(), &cost, nullptr, nullptr,
                     &jacobian);

    for (auto v : jacobian.values) { manual_vals.push_back(v); }
    for (auto c : jacobian.cols) { manual_cols.push_back(c); }
    for (auto r : jacobian.rows) { manual_rows.push_back(r); }
  }

  {
    // Build the problem
    ceres::Problem::Options problem_options;
    problem_options.loss_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
    problem_options.cost_function_ownership = ceres::DO_NOT_TAKE_OWNERSHIP;
    ceres::Problem problem(problem_options);

    fuse_variables::Orientation3DStamped::SharedPtr orientation =
        fuse_variables::Orientation3DStamped::make_shared(stamp);
    orientation->w() = q_WORLD_BASELINK.w();
    orientation->x() = q_WORLD_BASELINK.x();
    orientation->y() = q_WORLD_BASELINK.y();
    orientation->z() = q_WORLD_BASELINK.z();

    fuse_variables::Position3DStamped::SharedPtr position =
        fuse_variables::Position3DStamped::make_shared(stamp);
    position->x() = t_WORLD_BASELINK[0];
    position->y() = t_WORLD_BASELINK[1];
    position->z() = t_WORLD_BASELINK[2];

    fuse_variables::Point3DLandmark::SharedPtr landmark =
        fuse_variables::Point3DLandmark::make_shared(id);
    landmark->x() = P_WORLD[0];
    landmark->y() = P_WORLD[1];
    landmark->z() = P_WORLD[2];

    problem.AddParameterBlock(orientation->data(), orientation->size(),
                              orientation->localParameterization());
    problem.AddParameterBlock(position->data(), position->size(),
                              position->localParameterization());
    problem.AddParameterBlock(landmark->data(), landmark->size(),
                              landmark->localParameterization());

    std::vector<double*> parameter_blocks;
    parameter_blocks.push_back(orientation->data());
    parameter_blocks.push_back(position->data());
    parameter_blocks.push_back(landmark->data());

    auto loss_function =
        std::shared_ptr<ceres::LossFunction>(new ceres::TrivialLoss());

    problem.AddResidualBlock(auto_diff_cost_function.get(), loss_function.get(),
                             parameter_blocks);

    double cost = 0.0;
    ceres::CRSMatrix jacobian;
    problem.Evaluate(ceres::Problem::EvaluateOptions(), &cost, nullptr, nullptr,
                     &jacobian);

    for (auto v : jacobian.values) { auto_vals.push_back(v); }
    for (auto c : jacobian.cols) { auto_cols.push_back(c); }
    for (auto r : jacobian.rows) { auto_rows.push_back(r); }
  }

  EXPECT_TRUE(auto_vals.size() == manual_vals.size());
  for (int i = 0; i < auto_vals.size(); i++) {
    EXPECT_TRUE(std::abs(auto_vals[i] - manual_vals[i]) < 0.00001);
  }

  EXPECT_TRUE(auto_cols.size() == manual_cols.size());
  for (int i = 0; i < auto_cols.size(); i++) {
    EXPECT_TRUE(auto_cols[i] == manual_cols[i]);
  }

  EXPECT_TRUE(auto_rows.size() == manual_rows.size());
  for (int i = 0; i < auto_rows.size(); i++) {
    EXPECT_TRUE(auto_rows[i] == manual_rows[i]);
  }
}

Switching costFunction() in my constraint object from:

ceres::CostFunction* EuclideanReprojectionConstraint::costFunction() const {
   return new ceres::AutoDiffCostFunction<ReprojectionFunctor, 2, 4, 3, 3>(
       new ReprojectionFunctor(sqrt_information_, pixel_, intrinsic_matrix_,
                               T_cam_baselink_));
}

To:

ceres::CostFunction* EuclideanReprojectionConstraint::costFunction() const {
  return new EuclideanReprojection(sqrt_information_, pixel_, intrinsic_matrix_,
                                   T_cam_baselink_);
}

Causes the actual optimization through fuse to not be equivalent, is there something I am missing when switching from auto diff to manual? I make sure to compute the jacobian wrt the orientation to be wrt the quaternion representation

Infinite wait for onStop() to be called

I am using the reset service server to reset my slam system when I detect a failure, this is so I can automatically reset my initialization sensor models and odometry sensor model simultaneously. While my initialization sensor model stops just fine, my odometry seems to wait infinitely for the result in the stop() function (it is an async sensor model). Is there anything I can do to debug this,or if there is any common causes for this problem?

Marginalization speed

Implementing visual odometry with fuse is showing be rather tricky.I have noticed that in the optimization loop, marginalization is the main bottleneck. Notable within marginalization the most expensive step seems to be the qr decomposition:
https://github.com/locusrobotics/fuse/blob/devel/fuse_constraints/src/marginalize_variables.cpp#L483-L498

This isn't an issue when marginalization only needs to marginalize position/orientation variables since there aren't too many, but for visual odometry, marginalization may need to compute this step for ~100 landmark variables and it can take up to ~1s. I was wondering if there is any way I can implement this with another QR implementation to speed it up? I noticed the SPQR module (https://eigen.tuxfamily.org/dox/group__SPQRSupport__Module.html) from eigen, is it possible to use this if its available? or has it been investigated?

Location of throttled_callback.h inconsistent across branches

My team is developing a SLAM package to work with ROS Kinetic, Melodic, and (if we are able to resolve compile issues with our proprietary library) Noetic. Right now we have to develop our SLAM package on two seperate branches, one for Kinetic and one for Melodic, since the location of throttled_callback.h in fuse is different between the kinetic-devel and devel branches. In kinetic-devel, the location of throttled_callback.h is:

<fuse_models/common/throttled_callback.h>

where as in devel, the location of throttled_callback.h is:

<fuse_core/throttled_callback.h>

Would it be possible to pull throttled_callback.h from the devel branch into the kinetic-devel branch? This will also allow us to make use of ThrottledMessageCallback in our SLAM package. Once rectified, we may develop our SLAM package on one branch.

ROS2 active developpment ?

Hello,

I'm considering to use Fuse for a ROS2 Humble project. I'm wondering if I can rely on updates on the ROS2 branch, as there has been no commit for 10 months, unlike the master branch which is more active.

Add Demo-Launchfiles

To get started, it would be nice to have several Demo launch-files with artificial data, that run several flavors/configs of fuse localization, visualize the data in RViz and maybe some plots.

Support for ROS2

Hello, I was wondering if/when you all intend to extend this to ROS2?

Imu and Encoder fusion question

I have created a static publisher frame called "world" to transform all the sensor measurements (IMU and encoder) into the world frame before fusing. Please see the attached frames.pdf.
tbDemo

I get the following errors:

[ WARN] [1587245697.790895414, 14458.245000000]: No valid state data yet. Delaying tf broadcast.

[ERROR] [1587245697.811071435, 14458.266000000]: Invalid partial absolute pose measurement from 'imu_sensor' source: Invalid partial mean [-nan]

[ERROR] [1587245697.812112254, 14458.267000000]: Invalid partial angular velocity measurement from 'imu_sensor' source: Invalid partial mean [-nan]

[ERROR] [1587245697.812920705, 14458.267000000]: Invalid partial linear acceleration measurement from 'imu_sensor' source: Invalid partial mean [-nan]
[-nan]

Turns out I get nan values after the transformation inside the function bool transformMessage(const tf2_ros::Buffer& tf_buffer, const T& input, T& output) possible that world frame transformation does not exist. To test I changed the target_frame to be the base_footprint and as expected I don't get nan values, but covar. is non positive definite.

I get the following errors:

`[ WARN] [1587244909.151203910, 13670.531000000]: No valid state data yet. Delaying tf broadcast.
[ERROR] [1587244909.165917967, 13670.545000000]: Invalid partial absolute pose measurement from 'imu_sensor' source: Non-positive-definite partial covariance matrix
[0]

[ERROR] [1587244909.167231158, 13670.546000000]: Invalid partial angular velocity measurement from 'imu_sensor' source: Non-positive-definite partial covariance matrix
[0]

[ERROR] [1587244909.171330343, 13670.551000000]: Invalid partial linear acceleration measurement from 'imu_sensor' source: Non-positive-definite partial covariance matrix
[0, 0]
[0, 0]

[ERROR] [1587244909.189903674, 13670.569000000]: Invalid partial linear velocity measurement from 'encoder_sensor' source: Non-positive-definite partial covariance matrix
[0, 0]
[0, 0]`

Questions:

  1. Is it vaid transforming IMU and encoder measurements into the world frame before fusing? It does not make sense if IMU measurements are in base_footprint (robot body frame) and encoder's in "odom" frame.

  2. Should the imu and encoder measurements covariance be non-zero when published to ros? For example: rostopic echo /imu gives

header:
seq: 12477
stamp:
secs: 14962
nsecs: 36000000
frame_id: "base_footprint"
orientation:
x: 0.0015566085891899162
y: 0.0003276490868402762
z: -0.9788036429173815
w: 0.2047947709963295
orientation_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
angular_velocity:
x: -0.0005358902335171238
y: -0.0003909577325524005
z: 0.19488579839896925
angular_velocity_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
linear_acceleration:
x: 5.083136873524716e-05
y: 0.00010048728744395968
z: 2.618836550644121e-07
linear_acceleration_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

Shim for translation of varaible types

I'd like to discuss a feature concept so I can get it out of my head, and get on with the ROS2 port.
I'm working with Fuse and GTsam, and I keep seeing a limitation in the expression of state variables.

Constraints are a function that creates a vector of residuals,
Variables are data structures that hold a parametrisation of state variables.
Ceres is fed cost functions that take Variables' values directly, and an automatic derivative of the measurement characteristics as provided by the Constraint.
This means that if you want to change the nature of a Variable, you also need to rewrite all of your Constraints.

In a hypothetical deep refactor in the distant not-now, Would it be reasonable to modify the Variable so that it exposed measurable properties that are a function of its parametrisation instead of exposing the parameters directly?

This would allow a Constraint to be defined over, the distance between two 2d points at some as normal, but the Variable would be able to hold the control points of an interpolated trajectory and calculate a 2d point representing the location at the time of measurement, and have the relationship with the control points be fed through Ceres auto-differentiation with the rest of the Cost Function

Seeking discussion only, I don't intend to add this feature in a hurry

Cannot create constraints for IMU Twist messages with less than 2ms delay

Board: Nvidia Jetson Nano (Jetpack 4.4)
OS: Ubuntu 18.04
ROS: Melodic

Fuse sounds very promising and I am eager to use it for my AMR navigation stack. I am using fuse to combine data from Wheel odometry and IMU readings. IMU data is coming from Intel D435i via Madgwick Filter.
My launch file and smoother.yaml file is as follows:

<node name="smoother" pkg="fuse_optimizers" type="fixed_lag_smoother_node" output="screen">
       <rosparam command="load" file="$(find loc_mod)/params/fuse_imu.yaml" subst_value="true"/>
#Fixed-lag smoother configuration
optimization_frequency: 10  # The best-effort frequency (in Hz) of the optimization loop. This means that the optimizer will run every 0.1s and trigger all of the publishers when it is done
lag_duration: 0.5  # The size of the fixed-lag window, in seconds. The larger the window, the more variables will be inside the optimizer at any given time, which affects CPU usage.

# Define the set of motion model plugins to load
# Currently fuse only includes a 2D motion model. This is roughly equivalent to the robot_localization state, including the linear and angular position, the linear and angular velocity, and the linear acceleration. A turtlebot is a 2D robot, so this is fine.
# Multiple motion models can be loaded, and each sensor defines which set of motion models are used. We only have one motion model currently, and all sensors should use it.
motion_models:
  unicycle_motion_model:
    type: fuse_models::Unicycle2D

# Next define the set of sensor plugins to load
# You naturally want an IMU sensor and an Odometry sensor
# Additionally, you may want an "ignition" sensor. Ignition sensors tell the optimizer when to start running and what the initial state should be. fuse ships with one ignition sensor that initializes the Unicycle2D state variables.
sensor_models:
  ignition_sensor:
    type: fuse_models::Unicycle2DIgnition
    motion_models: [unicycle_motion_model]
    ignition: true
  odometry_sensor:
    type: fuse_models::Odometry2D
    motion_models: [unicycle_motion_model]
  imu_sensor:
    type: fuse_models::Imu2D
    motion_models: [unicycle_motion_model]

# And finally, define the set of publishers. fuse_models includes a robot_localization like publisher that publishes the latest state to the odom and tf topics.
publishers:
  odom_publisher:
    type: fuse_models::Odometry2DPublisher

# That is it for the optimizer itself, but each plugin has its own set of configuration. That configuration is specified in a sub-namespace of the plugin's name. E.g. ignition_sensor, odometry_sensor, imu_sensor
# These parameters are not strictly backwards-compatible with robot_localization configuration, but basically all of the same functionality exists.
unicycle_motion_model:
  buffer_length: 1.0  # How long to keep a local history. This should be at least as long as the smoother lag
  process_noise_diagonal: [0.001, 0.001, 0.001, 0.2, 0.2, 0.2, 0.15, 0.001]  # These are in order {x, y, yaw, vx, vy, vyaw, ax, ay}. And note these are variances. The numerical values should be adjusted to the platform.

ignition_sensor:
  publish_on_startup: true  # Just start immediately. If false, it waits for a service to send it initial state values
  initial_state: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]  # The same order as the process noise above
  initial_sigma: [0.000001, 0.000001, 0.000001, 10.0, 10.0, 10.0, 1.0, 0.000001]   # The same order as the process noise above. Note these are standard deviations. The numerical values should be adjusted to the platform.

odometry_sensor:
  topic: /odom/wheel
  twist_target_frame: base_link
  linear_velocity_dimensions: ['x', 'y']
  angular_velocity_dimensions: ['yaw']
  # The above configuration only uses the odometry velocity information. There are several options for using the odometry pose information as well.

imu_sensor:
  topic: /imu/data
  angular_velocity_dimensions: ['yaw']
  linear_acceleration_dimensions: ['x']
  twist_target_frame: base_link
  # The above configuration only uses the yaw velocity of the IMU measurement. Depending on the IMU data available, additional measurement dimensions can be added

odom_publisher:
  topic: odom
  base_link_frame_id: base_link
  odom_frame_id: odom
  map_frame_id: map
  world_frame_id: odom
  publish_tf: true
  # The odometry publisher also has several configuration modes, again very similar to the robot_localization package. The exact settings will depend on whether you are trying to fuse multiple dead reckoning sensors to make a better "odom" source, or if you are fusing in global state data and want to publish the map->odom transform.

The delay in the IMU time stamp is hardly +-0.001~0.002 ms and I am getting the following error on running the lag_smoother.

[ERROR] [1612442903.265861936]: Cannot create constraint from twist message with stamp 1612442903.265639067
[ERROR] [1612442903.269917145]: Cannot create constraint from twist message with stamp 1612442903.268141985
[ERROR] [1612442903.270205582]: Cannot create constraint from twist message with stamp 1612442903.270646095
[ERROR] [1612442903.273827301]: Cannot create constraint from twist message with stamp 1612442903.273149014
[ERROR] [1612442903.277885374]: Cannot create constraint from twist message with stamp 1612442903.275653124
[ERROR] [1612442903.278127666]: Cannot create constraint from twist message with stamp 1612442903.278156042
[ERROR] [1612442903.282078759]: Cannot create constraint from twist message with stamp 1612442903.280660152
[ERROR] [1612442903.282325686]: Cannot create constraint from twist message with stamp 1612442903.283163071
[ WARN] [1612442903.282408082]: Optimization exceeded the configured duration by 0.003019425s
[ERROR] [1612442903.285876728]: Cannot create constraint from twist message with stamp 1612442903.285665989
[ERROR] [1612442903.289928499]: Cannot create constraint from twist message with stamp 1612442903.288170099
[ERROR] [1612442903.290246988]: Cannot create constraint from twist message with stamp 1612442903.290674210

Thanks for your help.

Missing ROS Doc

As a user, it would be nice to have an overview about nodes, parameters, launch-files, API etc. Either on wiki.ros.org/fuse or docs.ros.org, or both.

Holding variables through transactions

When using a graph directly it is possible to hold a variable constant during optimization. But when using the optimizer and sensor models, the main and only form of communication to the main graph is through transactions. Is it possible to notify the optimizer to hold a specific variable constant through a transaction?

catkin_make failure fuse_optimizers

/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:148:78: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
       motion_model_configs.emplace_back(static_cast<std::string>(motion_model["name"]),
                                                                              ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:148:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       motion_model_configs.emplace_back(static_cast<std::string>(motion_model["name"]),
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:148:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       motion_model_configs.emplace_back(static_cast<std::string>(motion_model["name"]),
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:149:78: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                         static_cast<std::string>(motion_model["type"]), motion_model);
                                                                              ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:149:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(motion_model["type"]), motion_model);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:149:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(motion_model["type"]), motion_model);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:166:85: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                         static_cast<std::string>(motion_model_config["type"]), motion_model_config);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:166:92: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(motion_model_config["type"]), motion_model_config);
                                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:166:92: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(motion_model_config["type"]), motion_model_config);
                                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp: In member function โ€˜void fuse_optimizers::Optimizer::loadSensorModels()โ€™:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:214:78: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
       sensor_model_configs.emplace_back(static_cast<std::string>(sensor_model["name"]),
                                                                              ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:214:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       sensor_model_configs.emplace_back(static_cast<std::string>(sensor_model["name"]),
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:214:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       sensor_model_configs.emplace_back(static_cast<std::string>(sensor_model["name"]),
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:215:78: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                         static_cast<std::string>(sensor_model["type"]), sensor_model);
                                                                              ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:215:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(sensor_model["type"]), sensor_model);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:215:85: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(sensor_model["type"]), sensor_model);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:233:85: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                         static_cast<std::string>(sensor_model_config["type"]), sensor_model_config);
                                                                                     ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:233:92: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(sensor_model_config["type"]), sensor_model_config);
                                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:233:92: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                         static_cast<std::string>(sensor_model_config["type"]), sensor_model_config);
                                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:247:96: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [9]โ€™)
     const bool ignition = config.config.hasMember("ignition") ? static_cast<bool>(config.config["ignition"]) : false;
                                                                                                ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:247:107: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
     const bool ignition = config.config.hasMember("ignition") ? static_cast<bool>(config.config["ignition"]) : false;
                                                                                                           ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:247:107: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
     const bool ignition = config.config.hasMember("ignition") ? static_cast<bool>(config.config["ignition"]) : false;
                                                                                                           ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:261:24: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [14]โ€™)
       && (config.config["motion_models"].getType() == XmlRpc::XmlRpcValue::TypeArray))
                        ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:261:40: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       && (config.config["motion_models"].getType() == XmlRpc::XmlRpcValue::TypeArray))
                                        ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:261:40: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       && (config.config["motion_models"].getType() == XmlRpc::XmlRpcValue::TypeArray))
                                        ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:263:60: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [14]โ€™)
       XmlRpc::XmlRpcValue motion_model_list = config.config["motion_models"];
                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:263:76: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       XmlRpc::XmlRpcValue motion_model_list = config.config["motion_models"];
                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:263:76: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       XmlRpc::XmlRpcValue motion_model_list = config.config["motion_models"];
                                                                            ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp: In member function โ€˜void fuse_optimizers::Optimizer::loadPublishers()โ€™:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:307:72: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
       publisher_configs.emplace_back(static_cast<std::string>(publisher["name"]),
                                                                        ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:307:79: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       publisher_configs.emplace_back(static_cast<std::string>(publisher["name"]),
                                                                               ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:307:79: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
       publisher_configs.emplace_back(static_cast<std::string>(publisher["name"]),
                                                                               ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:308:72: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                      static_cast<std::string>(publisher["type"]), publisher);
                                                                        ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:308:79: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                      static_cast<std::string>(publisher["type"]), publisher);
                                                                               ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:308:79: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                      static_cast<std::string>(publisher["type"]), publisher);
                                                                               ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:326:79: error: ambiguous overload for โ€˜operator[]โ€™ (operand types are โ€˜const XmlRpc::XmlRpcValueโ€™ and โ€˜const char [5]โ€™)
                                      static_cast<std::string>(publisher_config["type"]), publisher_config);
                                                                               ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note: candidate: const XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) const <near match>
     XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
                        ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:97:24: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:326:86: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                      static_cast<std::string>(publisher_config["type"]), publisher_config);
                                                                                      ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](int) <near match>
     XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:98:18: note:   conversion of argument 1 would be ill-formed:
/mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:326:86: error: invalid conversion from โ€˜const char*โ€™ to โ€˜intโ€™ [-fpermissive]
                                      static_cast<std::string>(publisher_config["type"]), publisher_config);
                                                                                      ^
In file included from /opt/abunt/include/ros/node_handle.h:52:0,
                 from /opt/abunt/include/diagnostic_updater/diagnostic_updater.h:42,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/include/fuse_optimizers/optimizer.h:37,
                 from /mnt/943ec2c2-6cda-4cd0-887c-1fed9ec45b2e/fuse_ws/src/fuse/fuse_optimizers/src/optimizer.cpp:38:
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const string&) <near match>
     XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:100:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note: candidate: XmlRpc::XmlRpcValue& XmlRpc::XmlRpcValue::operator[](const char*) <near match>
     XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }
                  ^~~~~~~~
/opt/abunt/include/xmlrpcpp/XmlRpcValue.h:101:18: note:   passing โ€˜const XmlRpc::XmlRpcValue*โ€™ as โ€˜thisโ€™ argument discards qualifiers
CMakeFiles/fuse_optimizers.dir/build.make:110: recipe for target 'CMakeFiles/fuse_optimizers.dir/src/optimizer.cpp.o' failed
make[2]: *** [CMakeFiles/fuse_optimizers.dir/src/optimizer.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
CMakeFiles/Makefile2:2793: recipe for target 'CMakeFiles/fuse_optimizers.dir/all' failed
make[1]: *** [CMakeFiles/fuse_optimizers.dir/all] Error 2
Makefile:140: recipe for target 'all' failed
make: *** [all] Error 2

XmlRpcValue has the following overload operators:

XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
    XmlRpcValue& operator[](int i)             { assertArray(i+1); return _value.asArray->at(i); }

    XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
    XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s]; }

When to send transactions

I am implementing visual odometry and the transaction sizes/frequency can be pretty large (i.e. sending a transaction for very image with ~ 100 constraints and at least 1 new variable (new pose) and multiple new landmark variables. I am running into an issue where my pose estimates seem to be fine as I run my sensor model but when I pause my bag then restart I get a large jump in my pose. I was guessing this is potentially from the pause allowing for the "queue" of transactions to catch up and optimize causing a big change in the trajectory. Would it be better to instead buffer my transactions and send them only on a graph update, as one unified transaction?

Adding a new model

Hello,

We have been trying to add a bicycle model to the package, without success. Our current progress is visible on this fork. Basically, we started from the unicycle model and we just added a new variable called steering, which is used in the predictions. We made sure to create all appropriate model files corresponding to the new state of size 9 (was 8 before adding steering).
However, when running it the state and the jacobians quickly become extremely large values. Our guess is that some other part of the repo is not adapted for this new model of state size 9 but we have a hard time finding what is going on.

Do you have any idea or suggestion? We would be happy to contribute the bicycle model to the repo afterward if we manage to make it work.

The fuse_models package needs an optional dependency on `benchmark`

The fuse_models package uses the benchmark library as part of the test build. That library is not available for Xenial/Kinetic. The CMake build system conditionally compiles the benchmark test correctly, but I know of no way to specify a conditional/optional dependency in the package.xml file. As such, adding the benchmark dependency to the fuse_models package.xml breaks the Xenial/Kinetic buildfarm build. See PR #124.

Attempting to remove a variable ... that is used by existing constraints ...

When running a fixed lag smoother occasionally the following error will occur at random times, despite no client side code removing any variables, so I am assuming this is from the marginalization. This error is uncatchable in the sensor model code. Is it possible to have this be changed to be a warning message so that it does not crash the program, or does this error cause a total failure of the problem being optimized? Is it possible to have a setting where if this is the case, then said constraints can be removed?

Odometry sensor namespace error

I am using the "issue223-tf-timeout" branch that added the tf_timeout parameter to the sensor model, it is working well. However, I came across an error while trying to add a second odometry source by the name odometry_sensor1. But, the fixed_lag_smoother is expecting a mistyped namespace odometert_sensor1. Changing the namespace to that in the smoother.yaml solved the problem.

The devs might want to look at the expected namespace for multiple odometry sources. Also wanted to know if the tf_timeout parameter changes would be merged to the melodic-devel branch soon.

reset on backwards jumps in time (e.g. looping rosbag)

I'm using fuse_simple_tutorial.launch to test with (and it is using fixed_lag_smoother):

roslaunch fuse_tutorials fuse_simple_tutorial.launch

Currently when rosbag -l is used the jump back in time causes the state_estimation node to refuse all the old incoming messages:

...ers/src/fixed_lag_smoother.cpp:379]: The current lag expiration time is 203.372000000. The queued transaction with timestamp 162.504000000 from sensor imu_sensor has a minimum involved timestamp of 162.504000000, which is 40.868000000 seconds too old. Ignoring this transaction.

I initially tried detecting the jump back in time within FixedLagSmoother::optimizationLoop() then called resetServiceCallback(), but that locks up that loop (haven't tracked it down yet, could try building with debug symbols next). lucasw@f368a28#diff-969711c8c46e1a4ced29c0acd11c4939bcfa965ef47be0d91d4a9449b0c5e079R171-R181

This log message continues on though:

[W] [1637859555.355, , 193.055 /state_estimator .../src/odometry_2d_publisher.cpp:339]: No valid state data yet. Delaying tf broadcast.
...

When I call reset from the service call before the bag loop the same lockup happens (so that seems like a separate issue, and it isn't my fault for calling reset from a thread I shouldn't be?):

rosservice call /state_estimator/reset "{}"

The solution I currently have is to detect the time jumps in an outer loop, and just remake the whole fuse_optimizers::FixedLagSmoother object. which is maybe slower meaning more missed messages- but if it is good enough I could make a PR of it:

lucasw@5d43eb2

Sensor model constraints with initial guess from current graph optimization

Hi,

We are fusing sensor data from odometry, IMU and laser data scan-to-scan and scan-to-map using fuse with the fixed lag smoother optimizer and noticed an issue for our scan-to-scan and scan-to-map sensor models/constraints. Especially our used scan-to-map algorithm needs a good initial guess and therefore we wrote our own ceres cost function to take the guess from the optimization loop. At our own cost function we take at the overridden function Evaluate the (first) incoming guess, compute the scan-to-map pose estimate, cache it for subsequent calls, and then calculate the residuals and jacobians based on the pose error and covariance of the pose estimate.

This approach works most times fine but at some strange situations we noticed that our localization is moving either just shortly for a few samples but sometimes even permanent although the robot is at standstill. We found then out that the initial guess at the Evaluate function of the cost function is sometimes uninitialized and exactly zero which in some situations causes the above described behavior.

So our questions are now:

  1. How would you set an initial guess (for a scan-to-map algorithm) when at the callback when getting the sensor data (in this case laser pointcloud) the initial guess is not known? At best we would like to incorporate also the other new sensor data (in this case odometry and IMU) in the initial guess such that the initial guess is as good as possible.
  2. If there is no good option for the first question, what would you think of extending the fixed lag smoother optimizer with a variant of stepwise optimization with configurable stages with for example first optimize using only odometry and IMU and then optimize using all sensors? If you think this is a good idea without any bad side effects, we could also try to implement this in a PR ourselves.

If you have any further questions, don't hesitate asking.

Thanks,
Fabian

Inverse Depth Visual Parameterization

I just have a question about if the current marginalisation strategy could handle inverse depth parameterizations for visual landmarks. The constraint would be attached to 3(5) variables, an anchor pose, measurement pose and landmark variable. How would marginalisation handle the case where the anchor pose is to be marginalised but the measurement pose is still in the sliding window?

Extending the sensor processing to 3D

Hi there,

We am currently trying to use fuse to estimate the state of a 3D robot. Unless we are mistaken, the sensor processing models are not available for 3D robots (i.e. IMU, twist, pose messages will be interpreted as 2D).

Do you plan on committing something soon, or should we develop them and propose a PR ? The plan we have right now is to implement 3D models in addition to the exiting 2D models, so we were wondering if you'd be interested in merging the results in a near future.

FYI, we would be at least two qualified robotics engineer from Forssea Robotics working on the matter. We are working with ROS2 Humble on Ubuntu/debian platforms.

Thank you in advance for your answer,

Auguste Bourgois

Add reset() support to the Transaction object

From @efernandez

I've been thinking of some changes for the ignition/reset logic. Below I try to explain my proposed changes in brief:

  1. As a building piece, let's add the ability to remove all the variables or constraints in the graph by specifying that in the Transaction and changing the Graph::update logic, which is currently implemented as follows, clearly not supporting that:

void Graph::update(const Transaction& transaction)
{
// Update the graph with a new transaction. In order to keep the graph consistent, variables are added first,
// followed by the constraints which might use the newly added variables. Then constraints are removed so that
// the variable usage is updated. Finally, variables are removed.
// Insert the new variables into the graph
for (const auto& variable : transaction.addedVariables())
{
addVariable(variable.clone());
}
// Insert the new constraints into the graph
for (const auto& constraint : transaction.addedConstraints())
{
addConstraint(constraint.clone());
}
// Delete constraints from the graph
for (const auto& constraint_uuid : transaction.removedConstraints())
{
removeConstraint(constraint_uuid);
}
// Delete variables from the graph
for (const auto& variable_uuid : transaction.removedVariables())
{
removeVariable(variable_uuid);
}
}

  1. Since we currently serialize the Transaction class, we don't want to break any previously serialized transaction recorded, so we can use fuse_core::uuid::NIL as a special value to indicate ALL variables or constraints, and use that in the removedConstraints() or removedVariables() to indicate we want all of them removed from the graph. This means any sensor model can request the graph to be cleared at any time by sending a transaction like the following to the optimizer:
fuse_core::Transaction transaction;
transaction.removeVariable(fuse_core::uuid::NIL);
transaction.removeConstraint(fuse_core::uuid::NIL);

The actual way we request all variables or constraints to be removed from the graphs could be done hiding the detail of the special UUID value used to indicate that. That means we could have:

transaction.removeAllVaraibles();
transaction.removeAllConstraints();

or probably only allow to remove all variables if also all constraints are removed, in which case we could simply expose a method to do transaction.removeAll(); or transaction.clear();, or something similar.

  1. The Graph::update logic should handle this new case. This could be done with the following naive implementation:
void Graph::update(const Transaction& transaction)
{
  // Remove all constraints from the graph
  for (const auto& constraint_uuid : transaction.removedConstraints())
  {
    if (constraint_uuid == fuse_core::uuid::NIL)
    {
      clearConstraints();
      break;
    }
  }
  // Remove all variables from the graph
  for (const auto& variable_uuid : transaction.removedVariables())
  {
    if (variable_uuid == fuse_core::uuid::NIL)
    {
      clearVariables();
      break;
    }
  }
  // Insert the new variables into the graph
  for (const auto& variable : transaction.addedVariables())
  {
    addVariable(variable.clone());
  }
  // Insert the new constraints into the graph
  for (const auto& constraint : transaction.addedConstraints())
  {
    addConstraint(constraint.clone());
  }
  // Delete constraints from the graph
  for (const auto& constraint_uuid : transaction.removedConstraints())
  {
    if (constraint_uuid != fuse_core::uuid::NIL)
    {
      removeConstraint(constraint_uuid);
    }
  }
  // Delete variables from the graph
  for (const auto& variable_uuid : transaction.removedVariables())
  {
    if (variable_uuid != fuse_core::uuid::NIL)
    {
      removeVariable(variable_uuid);
    }
  }
}

where clearConstraints() and clearVariables() could be new pure virtual methods:

virtual void clearConstraints() = 0;
virtual void clearVariables() = 0;

that could be efficiently implemented as follows for the fuse_graphs::HashGraph:

void clearConstraints()
{
  constraints_.clear();
  constraints_by_variable_uuid_.clear();
}

void clearVariables()
{
  variables_.clear();
  variables_on_hold_.clear();
}

I believe Transaction::merge() should work as is:

void Transaction::merge(const Transaction& other, bool overwrite)
{
stamp_ = std::max(stamp_, other.stamp_);
involved_stamps_.insert(other.involved_stamps_.begin(), other.involved_stamps_.end());
for (const auto& added_constraint : other.added_constraints_)
{
addConstraint(added_constraint, overwrite);
}
for (const auto& removed_constraint : other.removed_constraints_)
{
removeConstraint(removed_constraint);
}
for (const auto& added_variable : other.added_variables_)
{
addVariable(added_variable, overwrite);
}
for (const auto& removed_variable : other.removed_variables_)
{
removeVariable(removed_variable);
}
}

It shouldn't be a problem to have more than one fuse_core::uuid::NIL removed variable or constraint, although it'd be handled as a single one. Similarly, with the implementation proposed above for the Graph::update() method, the removal of all variables or constraints in the graph would happen before any additions. This allows an ignition sensor to create a new prior constraint at the same time it request the current graph to be cleared. For instance, the fuse_models::Unicycle2DIgnition that sends this transaction:

auto transaction = fuse_core::Transaction::make_shared();
transaction->stamp(stamp);
transaction->addInvolvedStamp(stamp);
transaction->addVariable(position);
transaction->addVariable(orientation);
transaction->addVariable(linear_velocity);
transaction->addVariable(angular_velocity);
transaction->addVariable(linear_acceleration);
transaction->addConstraint(position_constraint);
transaction->addConstraint(orientation_constraint);
transaction->addConstraint(linear_velocity_constraint);
transaction->addConstraint(angular_velocity_constraint);
transaction->addConstraint(linear_acceleration_constraint);
// Send the transaction to the optimizer.
sendTransaction(transaction);

Would simply have to add this to that transaction before calling sendTransaction:

transaction->removeVariable(fuse_core::uuid::NIL);
transaction->removeConstraint(fuse_core::uuid::NIL);

It shouldn't be a problem if this transactions get merged with others, that would add more variables and constraints, because the graph would be cleared before adding any variables or constraints. This will still rely on the optimizer to purge any transaction before the ignition one. If we want, I think it'd be possible to detect a transaction has fuse_core::uuid::NIL, and consider that as an ignition transaction, or a non-mergeable transaction. Technically, it can get merged with future transaction, but not with past ones. But if we never merge it, it'd be fine, and equivalent to what we do now.

I believe this would allow us to get rid of the reset logic in the ignition sensor models:

if (!params_.reset_service.empty())
{
// Wait for the reset service
while (!reset_client_.waitForExistence(ros::Duration(10.0)) && ros::ok())
{
ROS_WARN_STREAM("Waiting for '" << reset_client_.getService() << "' service to become avaiable.");
}
auto srv = std_srvs::Empty();
if (!reset_client_.call(srv))
{
// The reset() service failed. Propagate that failure to the caller of this service.
throw std::runtime_error("Failed to call the '" + reset_client_.getService() + "' service.");
}
}

This would make them easier to implement. It'd also make things faster to update and we wouldn't lose any transactions that we currently lose when we call the reset service. That happens because it takes time to reset, and it stops all the plugins, so they stop receiving measurements. The approach proposed here is equivalent to not using the reset service, which can actually be used now. So certainly, this functionality already exists. The only difference is that with this change we can indicate we want the graph to be cleared at the transaction level, which I believe we can't do now.

I wonder if ignition sensor really have to support calling the reset service. After all, if the graph gets cleared, all plugins will get notified about that. Maybe it's too late and some sensor models could have already generated constraints that reference variables from the graph before clearing it. ๐Ÿค”

ROS2 change of param types, backporting the use of dynamic reconfigure

I'm documenting the parameters used by the various aspects of Fuse, some of them can't be migrated to ros2 because ROS2 has stricter type checking

Specifically, optimiser/motion_models and optimiser/sensor_models use XmlRpc::XmlRpcValue::TypeArray which doesn't exist in ROS2.
In the ROS2 branch, I need to change the yaml structure to declare the names of the motion_models and sensor_models first, then fill in the properties of each afterwards.

examples of a proposed ROS2 compatible format: fuse_simple_tutorial range_sensor_tutorial

ROS2 also encourages the use of a built-in callback that is triggered when parameters change. In ROS1, this was handled by dynamic_reconfigure.
It seems like dynamic_reconfigure would be useful, should I make the effort to streamline a back-port?

Question about C++17

Hello there, I'm certain that you are aware of this

If you define a structure having members of fixed-size vectorizable Eigen types, you must ensure
that calling operator new on it allocates properly aligned buffers. If you're compiling in [c++17]
mode only with a sufficiently recent compiler (e.g., GCC>=7, clang>=5, MSVC>=19.12), then everything
is taken care by the compiler and you can stop reading.

Then my question would be: Do you have any particular reason to support pre C++17 build?

I'm happy to contribute a small migration, I got rid of these types of macros, did a diff on the assembly and nothing changed for me (using the default C++17 standard)

#if __cpp_aligned_new

Cheers!

Sliding window optimizer

I am interested in implementing an optimizer that works similarly to the fixed lag smoother however rather than marginalizing out variables that are outside of the time window, it'll instead keep a fixed # of the most recent "states". States in this case would any variables associated to the set of unique timestamps in the graph. This model is specifically useful in the case of visual odometry since new states arent necessarily created using time but motion so two states could be arbitrarily far apart temporally if there hasn't been much motion. I am wondering if this optimizer would be something that could be merged into the main devel branch?

ROS2 port in progress - was: use of ros::time vs std::chrono

I'm working on a ros2 port, and I'm seeing a lot of files that only depend on ROS for its time class.

I really appreciate how Fuse is built as a standalone algorithm with clearly defined bindings for ROS, and I think this can go a little deeper.

I have a multi-agent application where no system has access to an accurate time, so I need to use the optimiser to establish relationships between clocks.

Is a switch from ros::time to std::chrono something that you would like back-ported?

Documentation and performance metrics

Hi developers,
This sensor fusion approach looks quite attractive. Thank you for your great work. I read the README and slides, and currently wanted to ask you:

  • Are you planning on publishing some other reference or paper?
  • Have you measured in some way the computational performance of this optimization approach?
  • If you have some metrics on its accuracy. (I know fuse is a generic approach, which makes measuring the accuracy somewhat dependable on the plugins you use, but it would be interesting to have some numbers)
  • Do you have some examples for running this package?

Thank you.

Yoshua Nava

IMU + Pose example?

Hi, I am looking to fuse a transform (tx,ty,tz, qx,qy,qz,qw) with inertial data(accel, gyro).
Is there an example for this in the repo? i can't see anything for this kind of fusion.

Thank you

Handle optimization failures in the fixed-lag smoother

As discussed in PR#208: @ayrton04 @efernandez

@efernandez 7 days ago Author Collaborator
I wonder if we should do something when the solver doesn't converge. I'd like to discuss the options and listen to your thoughts, so maybe we can do something on another PR.

One option is to check if (summary_.isSolutionUsable()): http://ceres-solver.org/nnls_solving.html#_CPPv4NK5ceres6Solver7Summary16IsSolutionUsableEv

If it's not usable we could do one of the following:

Abort
Don't notify, but still do the rest, i.e. prepare the marginalization for the next cycle
Roll back the graph to the state before adding the transaction, but this isn't trivial
Note that isSolutionUsable() returns true also if the solver doesn't converge and finishes because it reached the max time or iterations limit. In that case, the diagnostic warning should be enough, and we can simply continue as normal.

@svwilliams svwilliams 16 hours ago Member
I agree we should be checking if the output is usable before using it. Though I'm not sure what should be done when it is not...which is probably why I didn't bother checking in the first place. slightly_smiling_face

We could try "rolling back" the transaction. For the graph itself, it would not actually be that hard. We clone the graph anyway a few lines down (https://github.com/locusrobotics/fuse/blob/devel/fuse_optimizers/src/fixed_lag_smoother.cpp#L207). With a small modification, we could clone the graph before merging in the transaction, optimize the clone, and swap it in for the "real" graph if the optimization succeeds, or drop the clone if the optimization fails.

However, that doesn't fix any of the supporting infrastructure. The motion models generally track which constraint segments have been sent to the optimizer, and only send new or modified constraints in the future. If the optimizer throws away a transaction without somehow telling the motion models about it, then the two could get out of sync. That would lead to missing constraints and potentially a disconnected graph and future failures.

It would definitely be possible to modify the motion model interface to require some sort of ACK from the optimizer for each motion model segment that was successfully incorporated...but that will be a big change.

And then there are things like visual landmark observations, where the sensor model may create special constraints when a visual landmark is first added to the system (e.g. a prior on the landmark position, or some sort of 3-view constraint to ensure the landmark position is solvable). If such a constraint was thrown out without also informing the sensor models, we again get out of sync and set ourselves up for future optimization failures.

Continuing on is basically what we do now. But based on earlier errors, once the graph cannot be optimized correctly, I'm not sure anything in the future will ever fix that. I suspect you will get a constant stream of failures moving forward.

I'm inclined to go with the "abort" option. Log a descriptive message of the failure and exit(), throw an exception, or similar. If the optimization fails, we should make this as noticeable as possible. This is likely caused by a configuration or usage error, and nothing we can do in code will fix it.

But I'm not sure how you feel about it. I can be convinced otherwise.

@efernandez efernandez 9 hours ago โ€ข
Author Collaborator
The sensor and motion models going out of sync if we roll back to the graph before updating it with the last transaction is a very good point. I admit I didn't think much about that, although I already anticipated it wouldn't be trivial to roll back the graph.

I agree aborting is the best (and simplest) thing we can do. In such a case, I could print the last transaction, blaming it.
Indeed, if the optimization failed it should be because of something related with one or more constraints in the transaction, or the initial values provided in the variables, or the implementation of the constraints cost functions.
We would still have to narrow that down, but it sounds like we should be able to that after if we record the graph and transactions.
Actually, we need to print the transaction, because the last transaction hasn't been published yet. It sounds like we should still notify the publishers, so the bad graph and transaction are published. Then, in the optimization loop we only need to print the transaction timestamp when aborting.

I've updated this PR with a commit that does that.

Does this sound like a good plan to you?

@ayrton04 ayrton04 5 hours ago Member
Just thinking about this from a "robot in the real world" stance, if the node in question goes down due to the exception or exit call, then even if the node respawns, won't it be completely lost? Just wondering if logging (loudly) and rolling back the graph is a good idea. Won't it be the case that, depending on how things are configured, the "bad" constraint will eventually not be included in the optimization? I guess I'm just wondering if crashing is better/worse than attempting to get back on track and yelling. Obviously the inability to tell the models which constraint/transaction is faulty makes this difficult.

@efernandez efernandez 5 hours ago Author Collaborator
I thought about that, but I believe a failure here only happens if a cost function yields a bad result, like NaN. TBH I've not been able to test a failure mode because my current configuration just works. smile

I think when a failure happens, the solver itself prints some diagnostic messages, and it usually crashes after, if NaNs pollute the state. This is speculation though. It'd be great if I could test a failure mode. Then, maybe what we can do is be more informative when it happens, in terms of transaction and graph. Ideally, rolling back the graph would be great, but it'd be quite difficult to do that atm, as already pointed out.

Any suggestion to force a failure? Maybe adding a division by zero in a cost function, or sth like that. Or just returning false always, so the cost function always fails to evaluate. thinking

@ayrton04 ayrton04 5 hours ago Member
If this is just a one-off test with throwaway code, then maybe throw a quick static counter variable into one of the cost functions, and after it reaches N iterations, we do what you suggested and divide by 0 or something?

Fuse -> ROS 2 Rolling Porting Progress

Description

This issue tracks the progress of the ROS 2 port for Fuse, targeting the rolling release of ROS 2.
Some of the work here will be based off the work mentioned in #257.

Architectural Decisions

I will be prioritising API consistency between the ROS 1 and ROS 2 versions of Fuse. This means I won't be looking at high level architectural changes at this time.

Approach

PRs will be sent against the rolling branch on fuse and tf2_2d, working up the dependency graph and doubling back as necessary. (Or more likely, finding features to port as I work up the dependency graph, and port them for downstream packages as well.)

Changes in dependent packages that have to be made as a result of a change in a dependency packages will be made on a best effort basis, but can't be confirmed until they're buildable, so expect bugs in those PRs.

I fully expect fuse_core to take up the bulk of the migration effort. And I also fully expect needing to circle back after things finally build and run.

image

Progress

General

  • Logging #279
  • Resolve macro usage warnings #280
  • Port Time:
  • Port messages #285 (DEFERRED to on a per-package basis)
  • Linting

BONUS (if time permits)

  • (Probably bonus, too many parts to shake up) Port the pluginlib usage to rclcpp_components
  • "Dynamic reconfigure" for params

Down (Up?) The Dependency Tree

Additional Notes

  • I've tried to migrate away from boost as much as possible (into std), but there aren't equivalents for everything (e.g. serialization).

3D example

I can't find a 3D example in fuse_models.
Is 3D supported?

Missing humble-devel branch

Dear all,

We are going to introduce IMU on our 2D mobile robot. An online search showed that fuse is going to be considered the future for sensor fusion in the ROS framework. Our software is based on the humble distro, and we noticed that fuse misses that. Is there any intention to have this package on humble too?

MinusJacobian Orientation3dStamped

I am attempting to compute jacobians with respect to the orientation. I am computing them wrt the 3d tangent space. I am assuming to "lift" them back into the manifold that ceres expects (4d quaternion) I multiply my jacobian on the right with the jacobian computed in ComputeMinusJacobian? I am assuming the quaternion is given as (w, x, y, z).

i.e.

jacobian = df_dq * ComputeMinusJacobian(q)

where df_dq is the jacobian of function f wrt q, and is a 3x3 matrix

However when i compare the analytical jacobian of this to the numerical jacobian they are not close. I am computing the numerical jacobian directly in the 4d quaternion space by perturbing it as if it were a 4d vector.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.