Skip to content

Commit 1a3c6d9

Browse files
committed
Refactor to use regular mutex instead of recursive_mutex
1 parent 42dab09 commit 1a3c6d9

2 files changed

Lines changed: 65 additions & 27 deletions

File tree

mola_state_estimation_smoother/include/mola_state_estimation_smoother/StateEstimationSmoother.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ class StateEstimationSmoother : public mola::NavStateFilter,
284284
RegexCache do_process_gnss_labels_re;
285285
};
286286

287-
State state_;
288-
std::recursive_mutex stateMutex_;
287+
State state_;
288+
std::mutex stateMutex_;
289289

290290
/// Creates a new frame index for timestamp t, or returns the existing one if close enough.
291291
/// This also is in charge of the complex task of finding nearby existing frames and adding the
@@ -297,6 +297,18 @@ class StateEstimationSmoother : public mola::NavStateFilter,
297297
/// Creates or returns the existing ID, for an odometry frame_id:
298298
[[nodiscard]] odometry_frameid_t add_or_get_odom_frame_id(const std::string& frame_id_name);
299299

300+
// ---- _locked variants: assume stateMutex_ is already held by the caller ----
301+
void reset_locked();
302+
void fuse_pose_locked(
303+
const mrpt::Clock::time_point& timestamp, const mrpt::poses::CPose3DPDFGaussian& pose,
304+
const std::string& frame_id);
305+
[[nodiscard]] frame_index_t create_or_get_keyframe_by_timestamp_locked(
306+
const mrpt::Clock::time_point& t,
307+
const std::optional<double>& overrideCloseEnough = std::nullopt);
308+
void process_pending_gtsam_updates_locked();
309+
[[nodiscard]] std::optional<mrpt::poses::CPose3DPDFGaussian> estimated_T_enu_to_map_locked()
310+
const;
311+
300312
/// Adds new factors to the smoother, optimizes it, and saves the variable values into
301313
/// state_.last_estimated_state
302314
void process_pending_gtsam_updates();

mola_state_estimation_smoother/src/StateEstimationSmoother.cpp

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ void StateEstimationSmoother::initialize(const mrpt::containers::yaml& cfg)
144144
auto lck = mrpt::lockHelper(stateMutex_);
145145

146146
// This also resets the GTSAM pimpl unique_ptr in state_
147-
reset();
147+
reset_locked();
148148

149149
// Load params:
150150
params_.loadFrom(cfg["params"]);
@@ -224,9 +224,14 @@ void StateEstimationSmoother::spinOnce()
224224
return;
225225
}
226226

227-
auto lck = mrpt::lockHelper(stateMutex_);
227+
// Read the extrapolated stamp under the lock, then release before calling estimated_navstate()
228+
// to avoid recursive locking (estimated_navstate() acquires the mutex internally).
229+
std::optional<mrpt::Clock::time_point> tNowOpt;
230+
{
231+
auto lck = mrpt::lockHelper(stateMutex_);
232+
tNowOpt = state_.get_current_extrapolated_stamp();
233+
}
228234

229-
const auto tNowOpt = state_.get_current_extrapolated_stamp();
230235
if (!tNowOpt)
231236
{
232237
MRPT_LOG_THROTTLE_WARN(5.0, "Cannot publish vehicle pose (no input data yet?)");
@@ -260,11 +265,11 @@ void StateEstimationSmoother::spinOnce()
260265
void StateEstimationSmoother::reset()
261266
{
262267
auto lck = mrpt::lockHelper(stateMutex_);
263-
264-
// reset:
265-
state_ = State();
268+
reset_locked();
266269
}
267270

271+
void StateEstimationSmoother::reset_locked() { state_ = State(); }
272+
268273
void StateEstimationSmoother::fuse_odometry(
269274
const mrpt::obs::CObservationOdometry& odom, const std::string& odomName)
270275
{
@@ -318,15 +323,15 @@ void StateEstimationSmoother::fuse_odometry(
318323
state_.last_wheels_odometry = odom.odometry;
319324

320325
// Fuse this new probabilistic pose observation:
321-
this->fuse_pose(odom.timestamp, newOdomPosePdf, odomName);
326+
fuse_pose_locked(odom.timestamp, newOdomPosePdf, odomName);
322327
}
323328

324329
void StateEstimationSmoother::fuse_imu(const mrpt::obs::CObservationIMU& imu)
325330
{
326331
auto lck = mrpt::lockHelper(stateMutex_);
327332

328333
// Create a new KF id (or reuse a very close match):
329-
const auto this_kf_id = create_or_get_keyframe_by_timestamp(
334+
const auto this_kf_id = create_or_get_keyframe_by_timestamp_locked(
330335
imu.timestamp, params_.imu_nearby_keyframe_stamp_tolerance);
331336

332337
MRPT_LOG_DEBUG_FMT(
@@ -459,7 +464,7 @@ void StateEstimationSmoother::fuse_gnss(const mrpt::obs::CObservationGPS& gps)
459464
mrpt::topography::geodeticToENU_WGS84(geoCoords, ENU_point, *refGeoCoords);
460465

461466
// Create a new KF id (or reuse a very close match):
462-
const auto this_kf_id = create_or_get_keyframe_by_timestamp(
467+
const auto this_kf_id = create_or_get_keyframe_by_timestamp_locked(
463468
gps.timestamp, params_.gnss_nearby_keyframe_stamp_tolerance);
464469

465470
MRPT_LOG_DEBUG_FMT(
@@ -471,7 +476,7 @@ void StateEstimationSmoother::fuse_gnss(const mrpt::obs::CObservationGPS& gps)
471476
const auto observedEnu = mrpt::gtsam_wrappers::toPoint3(ENU_point);
472477
const auto enuNoise = gtsam::noiseModel::Gaussian::Covariance(gps.covariance_enu->asEigen());
473478
auto enuNoiseRobust = gtsam::noiseModel::Robust::Create(
474-
gtsam::noiseModel::mEstimator::Huber::Create(1.5), enuNoise);
479+
gtsam::noiseModel::mEstimator::Huber::Create(1.5), enuNoise);
475480

476481
state_.gtsam->newFactors.emplace_shared<mola::factors::FactorGnssMapEnu>(
477482
symbol_T_enu_to_map, T(this_kf_id), sensorOnVehicle, observedEnu, enuNoiseRobust);
@@ -482,12 +487,18 @@ void StateEstimationSmoother::fuse_pose(
482487
const std::string& frame_id)
483488
{
484489
auto lck = mrpt::lockHelper(stateMutex_);
490+
fuse_pose_locked(timestamp, pose, frame_id);
491+
}
485492

493+
void StateEstimationSmoother::fuse_pose_locked(
494+
const mrpt::Clock::time_point& timestamp, const mrpt::poses::CPose3DPDFGaussian& pose,
495+
const std::string& frame_id)
496+
{
486497
// get this numerical frame_id :
487498
const auto frame_id_idx = add_or_get_odom_frame_id(frame_id);
488499

489500
// Create a new KF id (or reuse a very close match):
490-
const auto this_kf_id = create_or_get_keyframe_by_timestamp(timestamp);
501+
const auto this_kf_id = create_or_get_keyframe_by_timestamp_locked(timestamp);
491502

492503
MRPT_LOG_DEBUG_FMT(
493504
"[fuse_pose]: kf_idx=%zu t=%f frame='%s' (idx=%zu) p=%s sigmas=%.02e %.02e %.02e (m) %.02e "
@@ -539,7 +550,7 @@ void StateEstimationSmoother::fuse_twist(
539550
gtsam::Matrix3 wCov = twistCov.asEigen().block<3, 3>(3, 3);
540551

541552
// Create a new KF id (or reuse a very close match):
542-
const auto this_kf_id = create_or_get_keyframe_by_timestamp(timestamp);
553+
const auto this_kf_id = create_or_get_keyframe_by_timestamp_locked(timestamp);
543554

544555
{
545556
auto noiseV = gtsam::noiseModel::Gaussian::Covariance(vCov);
@@ -588,13 +599,14 @@ void StateEstimationSmoother::fuse_twist(
588599
std::optional<NavState> StateEstimationSmoother::estimated_navstate(
589600
const mrpt::Clock::time_point& timestamp, const std::string& frame_id)
590601
{
602+
auto lck = mrpt::lockHelper(stateMutex_);
603+
591604
// 1) Make sure we processed all pending sensor data, and have updated the cached values from
592605
// GTSAM values
593-
process_pending_gtsam_updates();
606+
process_pending_gtsam_updates_locked();
594607

595608
// 2) Get the vehicle state from cached optimized values:
596609
// Look for the closest frame and extrapolate.
597-
auto lck = mrpt::lockHelper(stateMutex_);
598610

599611
std::optional<double> closestFrameDt;
600612
double closestFrameDtSigned = 0;
@@ -943,9 +955,15 @@ void StateEstimationSmoother::delete_too_old_entries()
943955
StateEstimationSmoother::frame_index_t StateEstimationSmoother::create_or_get_keyframe_by_timestamp(
944956
const mrpt::Clock::time_point& t, const std::optional<double>& overrideCloseEnough)
945957
{
946-
const auto tle = mola::ProfilerEntry(profiler_, "create_or_get_keyframe_by_timestamp");
947-
948958
auto lck = mrpt::lockHelper(stateMutex_);
959+
return create_or_get_keyframe_by_timestamp_locked(t, overrideCloseEnough);
960+
}
961+
962+
StateEstimationSmoother::frame_index_t
963+
StateEstimationSmoother::create_or_get_keyframe_by_timestamp_locked(
964+
const mrpt::Clock::time_point& t, const std::optional<double>& overrideCloseEnough)
965+
{
966+
const auto tle = mola::ProfilerEntry(profiler_, "create_or_get_keyframe_by_timestamp");
949967

950968
const double threshold = overrideCloseEnough ? *overrideCloseEnough
951969
: params_.min_time_difference_to_create_new_frame;
@@ -1055,9 +1073,13 @@ StateEstimationSmoother::odometry_frameid_t StateEstimationSmoother::add_or_get_
10551073

10561074
void StateEstimationSmoother::process_pending_gtsam_updates()
10571075
{
1058-
const auto tle = mola::ProfilerEntry(profiler_, "process_pending_gtsam_updates");
1059-
10601076
auto lck = mrpt::lockHelper(stateMutex_);
1077+
process_pending_gtsam_updates_locked();
1078+
}
1079+
1080+
void StateEstimationSmoother::process_pending_gtsam_updates_locked()
1081+
{
1082+
const auto tle = mola::ProfilerEntry(profiler_, "process_pending_gtsam_updates");
10611083

10621084
// Even if we have no new factors/values, do update the stamps of "persistent" variables:
10631085
if (state_.last_observation_stamp.has_value())
@@ -1432,10 +1454,9 @@ void StateEstimationSmoother::initialize_new_frame(
14321454
// Add planar constraints:
14331455
if (params_.enforce_planar_motion)
14341456
{
1435-
const auto planar_z_noise = gtsam::noiseModel::Diagonal::Sigmas(
1436-
gtsam::Vector6(
1437-
PLANAR_Z_SIGMA, PLANAR_Z_SIGMA, PLANAR_XY_SIGMA, // rx≈0, ry≈0, rz free
1438-
PLANAR_XY_SIGMA, PLANAR_XY_SIGMA, PLANAR_Z_SIGMA) // tx free, ty free, tz≈0
1457+
const auto planar_z_noise = gtsam::noiseModel::Diagonal::Sigmas(gtsam::Vector6(
1458+
PLANAR_Z_SIGMA, PLANAR_Z_SIGMA, PLANAR_XY_SIGMA, // rx≈0, ry≈0, rz free
1459+
PLANAR_XY_SIGMA, PLANAR_XY_SIGMA, PLANAR_Z_SIGMA) // tx free, ty free, tz≈0
14391460
);
14401461

14411462
state_.gtsam->newFactors.addPrior(T(id), gtsam::Pose3::Identity(), planar_z_noise);
@@ -1532,7 +1553,13 @@ std::optional<mrpt::poses::CPose3DPDFGaussian> StateEstimationSmoother::estimate
15321553
const
15331554
{
15341555
auto lck = mrpt::lockHelper(stateMutex_);
1556+
return estimated_T_enu_to_map_locked();
1557+
}
15351558

1559+
std::optional<mrpt::poses::CPose3DPDFGaussian>
1560+
StateEstimationSmoother::estimated_T_enu_to_map_locked() const
1561+
{
1562+
// Called with stateMutex_ already held by the caller.
15361563
auto it = state_.last_estimated_frames.find(REFERENCE_FRAME_ID);
15371564
if (it == state_.last_estimated_frames.end())
15381565
{
@@ -1545,8 +1572,7 @@ std::optional<mrpt::poses::CPose3DPDFGaussian>
15451572
StateEstimationSmoother::get_estimated_T_map_to_odometry_frame(const frame_index_t idx) const
15461573
{
15471574
ASSERT_GE_(idx, 1);
1548-
auto lck = mrpt::lockHelper(stateMutex_);
1549-
1575+
// Called with stateMutex_ already held by the caller.
15501576
auto it = state_.last_estimated_frames.find(idx);
15511577
if (it == state_.last_estimated_frames.end())
15521578
{
@@ -1623,7 +1649,7 @@ void StateEstimationSmoother::publishEstimatedGeoreferencing()
16231649
return;
16241650
}
16251651

1626-
auto T_enu_map_opt = estimated_T_enu_to_map();
1652+
auto T_enu_map_opt = estimated_T_enu_to_map_locked();
16271653
if (!T_enu_map_opt.has_value())
16281654
{
16291655
return;

0 commit comments

Comments
 (0)