Skip to content

Commit 21bf424

Browse files
committed
Adjust output time in costamp stack
Signed-off-by: Francisco Martín Rico <fmrico@gmail.com>
1 parent 83a9827 commit 21bf424

6 files changed

Lines changed: 67 additions & 31 deletions

File tree

controllers/easynav_serest_controller/include/easynav_serest_controller/SerestController.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class SerestController : public ControllerMethodBase
182182
* @return double Minimum obstacle distance (m). Infinity if none is found.
183183
*/
184184
double closest_obstacle_distance(
185-
const NavState & nav_state) const;
185+
const NavState & nav_state);
186186

187187
/**
188188
* @brief Compute a safe linear speed bound from obstacle distance and slope.
@@ -226,7 +226,7 @@ class SerestController : public ControllerMethodBase
226226
void safety_limits(
227227
const NavState & nav_state,
228228
const RefKinematics & rk,
229-
double & d_closest, double & v_safe, double & v_curv) const;
229+
double & d_closest, double & v_safe, double & v_curv);
230230

231231
// Aplica corner‑guard: ajusta v_prog_ref y obtiene omega_boost + término ápice.
232232
void apply_corner_guard(
@@ -354,6 +354,8 @@ class SerestController : public ControllerMethodBase
354354
double last_vrot_{0.0};
355355
/// @brief Last update timestamp.
356356
rclcpp::Time last_update_ts_;
357+
/// @brief Last input timestamp (max of path and odom).
358+
rclcpp::Time last_input_ts_;
357359
/// @brief Output TwistStamped buffer.
358360
geometry_msgs::msg::TwistStamped twist_stamped_;
359361
};

controllers/easynav_serest_controller/src/easynav_serest_controller/SerestController.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ SerestController::frenet_errors(
287287

288288
double
289289
SerestController::closest_obstacle_distance(
290-
const NavState & nav_state) const
290+
const NavState & nav_state)
291291
{
292292
// 1) Prefer direct measurement if it exists
293293
if (nav_state.has("closest_obstacle_distance")) {
@@ -304,14 +304,18 @@ SerestController::closest_obstacle_distance(
304304
const auto & perceptions = nav_state.get<PointPerceptions>("points");
305305
const auto & tf_info = RTTFBuffer::getInstance()->get_tf_info();
306306

307-
auto fused = PointPerceptionsOpsView(perceptions)
308-
.downsample(0.3)
309-
.fuse(tf_info.robot_footprint_frame)
310-
.filter({-dist_search_radius_, -dist_search_radius_, NAN},
311-
{dist_search_radius_, dist_search_radius_, 2.0})
312-
.collapse({NAN, NAN, 0.1})
313-
.downsample(0.3)
314-
.as_points();
307+
auto view = PointPerceptionsOpsView(perceptions);
308+
view.downsample(0.3)
309+
.fuse(tf_info.robot_footprint_frame)
310+
.filter({-dist_search_radius_, -dist_search_radius_, NAN},
311+
{dist_search_radius_, dist_search_radius_, 2.0})
312+
.collapse({NAN, NAN, 0.1})
313+
.downsample(0.3);
314+
const auto & fused = view.as_points();
315+
316+
if (last_input_ts_ < view.get_latest_stamp()) {
317+
last_input_ts_ = view.get_latest_stamp();
318+
}
315319

316320
double min_dist = std::numeric_limits<double>::infinity();
317321
for (const auto p : fused) {
@@ -377,6 +381,13 @@ SerestController::fetch_required_inputs(
377381
path = nav_state.get<nav_msgs::msg::Path>("path");
378382
odom = nav_state.get<nav_msgs::msg::Odometry>("robot_pose");
379383

384+
if (rclcpp::Time(path.header.stamp, last_input_ts_.get_clock_type()) > last_input_ts_) {
385+
last_input_ts_ = path.header.stamp;
386+
}
387+
if (rclcpp::Time(odom.header.stamp, last_input_ts_.get_clock_type()) > last_input_ts_) {
388+
last_input_ts_ = odom.header.stamp;
389+
}
390+
380391
if (path.poses.empty()) {
381392
publish_stop(nav_state, path.header.frame_id);
382393
return false;
@@ -427,7 +438,7 @@ void
427438
SerestController::safety_limits(
428439
const NavState & nav_state,
429440
const RefKinematics & rk,
430-
double & d_closest, double & v_safe, double & v_curv) const
441+
double & d_closest, double & v_safe, double & v_curv)
431442
{
432443
d_closest = closest_obstacle_distance(nav_state);
433444
v_safe = v_safe_from_distance(d_closest, /*slope_sin=*/0.0);
@@ -535,7 +546,7 @@ SerestController::maybe_final_align_and_publish(
535546

536547
// Publicación y actualización de estado
537548
twist_stamped_.header.frame_id = path.header.frame_id;
538-
twist_stamped_.header.stamp = get_node()->now();
549+
twist_stamped_.header.stamp = last_input_ts_;
539550
twist_stamped_.twist.linear.x = vlin;
540551
twist_stamped_.twist.angular.z = vrot;
541552

@@ -578,7 +589,7 @@ SerestController::publish_cmd_and_debug(
578589
int in_final_align, int arrived)
579590
{
580591
twist_stamped_.header.frame_id = path.header.frame_id;
581-
twist_stamped_.header.stamp = get_node()->now();
592+
twist_stamped_.header.stamp = last_input_ts_;
582593
twist_stamped_.twist.linear.x = vlin;
583594
twist_stamped_.twist.angular.z = vrot;
584595
nav_state.set("cmd_vel", twist_stamped_);
@@ -601,7 +612,7 @@ SerestController::publish_cmd_and_debug(
601612
void
602613
SerestController::publish_stop(NavState & nav_state, const std::string & frame_id)
603614
{
604-
auto now = get_node()->now();
615+
auto now = last_input_ts_;
605616
twist_stamped_.header.frame_id = frame_id;
606617
twist_stamped_.header.stamp = now;
607618
twist_stamped_.twist.linear.x = 0.0;
@@ -655,13 +666,12 @@ SerestController::update_rt(NavState & nav_state)
655666

656667
// 6.5) Early turn-in-place with hysteresis (start-of-path aware)
657668
{
658-
const double PI = 3.14159265358979323846;
659669
const double s_total = pd.s_acc.back();
660670
const double dist_to_end = s_total - prj.s_star;
661671

662672
// Internal angular thresholds (enter/exit)
663-
const double thr_enter = 60.0 * PI / 180.0;
664-
const double thr_exit = 35.0 * PI / 180.0;
673+
const double thr_enter = 60.0 * M_PI / 180.0;
674+
const double thr_exit = 35.0 * M_PI / 180.0;
665675
const double near_start_s = 0.30; // treat the first 30 cm as the start region
666676

667677
// Base request from the regular criterion (using the provided threshold)

localizers/easynav_costmap_localizer/src/easynav_costmap_localizer/AMCLLocalizer.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -583,19 +583,22 @@ AMCLLocalizer::correct(NavState & nav_state)
583583
const auto & map_static = nav_state.get<Costmap2D>("map.static");
584584

585585
const auto & tf_info = RTTFBuffer::getInstance()->get_tf_info();
586-
const auto & filtered = PointPerceptionsOpsView(perceptions)
587-
.downsample(map_static.getResolution())
588-
.fuse(tf_info.robot_footprint_frame)
589-
.filter({NAN, NAN, 0.1}, {NAN, NAN, NAN})
590-
.collapse({NAN, NAN, 0.1})
591-
.downsample(map_static.getResolution())
592-
.as_points();
586+
587+
auto view = PointPerceptionsOpsView(perceptions);
588+
view.downsample(map_static.getResolution())
589+
.fuse(tf_info.robot_footprint_frame)
590+
.filter({NAN, NAN, 0.1}, {NAN, NAN, NAN})
591+
.collapse({NAN, NAN, 0.1})
592+
.downsample(map_static.getResolution());
593+
const auto & filtered = view.as_points();
593594

594595
if (filtered.empty()) {
595596
RCLCPP_WARN(get_node()->get_logger(), "No points to correct");
596597
return;
597598
}
598599

600+
last_input_time_ = view.get_latest_stamp();
601+
599602
for (auto & particle : particles_) {
600603
int hits = 0;
601604
int possible_hits = 0;

maps_managers/easynav_costmap_maps_manager/src/easynav_costmap_maps_manager/CostmapMapsManager.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ CostmapMapsManager::update(NavState & nav_state)
195195

196196
nav_state.set("map.dynamic.filtered", dynamic_map_);
197197

198+
if (!nav_state.has("map_time")) {
199+
nav_state.set("map_time", get_node()->now());
200+
}
201+
198202
for (const auto & filter : costmap_filters_) {
199203
filter->update(nav_state);
200204
}
@@ -203,9 +207,11 @@ CostmapMapsManager::update(NavState & nav_state)
203207

204208
const auto & tf_info = RTTFBuffer::getInstance()->get_tf_info();
205209

210+
rclcpp::Time map_stamp = nav_state.get<rclcpp::Time>("map_time");
211+
206212
dynamic_map_->toOccupancyGridMsg(dynamic_grid_msg_);
207213
dynamic_grid_msg_.header.frame_id = tf_info.map_frame;
208-
dynamic_grid_msg_.header.stamp = get_node()->now();
214+
dynamic_grid_msg_.header.stamp = map_stamp;
209215
dynamic_occ_pub_->publish(dynamic_grid_msg_);
210216
}
211217

maps_managers/easynav_costmap_maps_manager/src/easynav_costmap_maps_manager/filters/ObstacleFilter.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,15 @@ ObstacleFilter::update(NavState & nav_state)
5555
Costmap2D & dynamic_map = *dynamic_map_ptr;
5656
const auto & tf_info = RTTFBuffer::getInstance()->get_tf_info();
5757

58-
auto fused = PointPerceptionsOpsView(perceptions)
59-
.downsample(dynamic_map.getResolution())
60-
.fuse(tf_info.map_frame)
61-
.filter({NAN, NAN, 0.1}, {NAN, NAN, NAN})
62-
.as_points();
58+
auto view = PointPerceptionsOpsView(perceptions);
59+
view.downsample(dynamic_map.getResolution())
60+
.fuse(tf_info.map_frame)
61+
.filter({NAN, NAN, 0.1}, {NAN, NAN, NAN});
62+
63+
const auto stamp = view.get_latest_stamp();
64+
const auto & fused = view.as_points();
65+
66+
nav_state.set("map_time", stamp);
6367

6468
double min_x = std::numeric_limits<double>::max();
6569
double min_y = std::numeric_limits<double>::max();

planners/easynav_costmap_planner/src/easynav_costmap_planner/CostmapPlanner.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ void CostmapPlanner::update(NavState & nav_state)
158158
const auto & goal = goals.goals.front().pose;
159159
const auto & tf_info = RTTFBuffer::getInstance()->get_tf_info();
160160

161+
rclcpp::Time latest_stamp = nav_state.get<rclcpp::Time>("map_time");
162+
if (rclcpp::Time(robot_pose.header.stamp, latest_stamp.get_clock_type()) > latest_stamp) {
163+
latest_stamp = robot_pose.header.stamp;
164+
}
165+
if (rclcpp::Time(goals.goals.front().header.stamp,
166+
latest_stamp.get_clock_type()) > latest_stamp)
167+
{
168+
latest_stamp = goals.goals.front().header.stamp;
169+
}
170+
current_path_.header.stamp = latest_stamp;
171+
161172
if (goals.header.frame_id != tf_info.map_frame) {
162173
RCLCPP_WARN(get_node()->get_logger(), "Goals frame is not 'map': %s",
163174
goals.header.frame_id.c_str());

0 commit comments

Comments
 (0)