Skip to content

Commit 3b0e9a4

Browse files
committed
only consider conntected components as free space.
1 parent 6360b76 commit 3b0e9a4

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

hydra_ros/include/hydra_ros/active_window/tsdf_gradient_occupancy_publisher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class TsdfGradientOccupancyPublisher : public ReconstructionModule::Sink {
8686
float min_confidence = 0.5f; // min confidence (neighbors/8) for valid cell
8787
bool smoothing = true; // apply box filter to reduce TSDF ripple
8888
bool probabilistic = false; // continuous vs binary occupancy
89+
bool filter_disjoint = false; // remove free space not connected to robot
8990
} const config;
9091

9192
explicit TsdfGradientOccupancyPublisher(const Config& config);
@@ -124,6 +125,9 @@ class TsdfGradientOccupancyPublisher : public ReconstructionModule::Sink {
124125
const TsdfLayer& layer,
125126
nav_msgs::msg::OccupancyGrid& msg) const;
126127

128+
void filterDisjointFreeSpace(nav_msgs::msg::OccupancyGrid& msg,
129+
const Eigen::Isometry3d& world_T_body) const;
130+
127131
void publishHeightMapViz(const Index2DMap<float>& height_map,
128132
const TsdfLayer& layer,
129133
uint64_t timestamp_ns) const;

hydra_ros/src/active_window/tsdf_gradient_occupancy_publisher.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <hydra/common/global_info.h>
4242

4343
#include <cmath>
44+
#include <queue>
4445
#include <set>
4546

4647
namespace hydra {
@@ -80,6 +81,7 @@ void declare_config(TsdfGradientOccupancyPublisher::Config& config) {
8081
field(config.min_confidence, "min_confidence");
8182
field(config.smoothing, "smoothing");
8283
field(config.probabilistic, "probabilistic");
84+
field(config.filter_disjoint, "filter_disjoint");
8385

8486
checkCondition(config.gradient_threshold > 0.0f,
8587
"gradient_threshold must be positive");
@@ -141,6 +143,9 @@ void TsdfGradientOccupancyPublisher::call(uint64_t timestamp_ns,
141143
msg.info.map_load_time = msg.header.stamp;
142144

143145
fillOccupancyGrid(gradient_map, world_T_body, tsdf_layer, msg);
146+
if (config.filter_disjoint) {
147+
filterDisjointFreeSpace(msg, world_T_body);
148+
}
144149
pub_->publish(msg);
145150
}
146151

@@ -354,6 +359,85 @@ void TsdfGradientOccupancyPublisher::fillOccupancyGrid(
354359
}
355360
}
356361

362+
void TsdfGradientOccupancyPublisher::filterDisjointFreeSpace(
363+
nav_msgs::msg::OccupancyGrid& msg,
364+
const Eigen::Isometry3d& world_T_body) const {
365+
if (msg.data.empty()) {
366+
return;
367+
}
368+
369+
const int width = static_cast<int>(msg.info.width);
370+
const int height = static_cast<int>(msg.info.height);
371+
372+
// Convert robot world position to grid coordinates
373+
const auto robot_pos_world = world_T_body.translation();
374+
const float rel_x =
375+
static_cast<float>(robot_pos_world.x() - msg.info.origin.position.x);
376+
const float rel_y =
377+
static_cast<float>(robot_pos_world.y() - msg.info.origin.position.y);
378+
const int robot_r = static_cast<int>(std::floor(rel_y / msg.info.resolution));
379+
const int robot_c = static_cast<int>(std::floor(rel_x / msg.info.resolution));
380+
381+
// Check if robot is within grid bounds
382+
if (robot_r < 0 || robot_r >= height || robot_c < 0 || robot_c >= width) {
383+
return; // Robot outside grid - skip filtering
384+
}
385+
386+
const size_t robot_index = robot_r * width + robot_c;
387+
388+
// Only filter if robot is in free space
389+
if (msg.data[robot_index] != 0) {
390+
return; // Robot not in free space - skip filtering
391+
}
392+
393+
// BFS flood fill from robot position
394+
std::vector<bool> visited(msg.data.size(), false);
395+
std::queue<size_t> to_visit;
396+
397+
to_visit.push(robot_index);
398+
visited[robot_index] = true;
399+
400+
while (!to_visit.empty()) {
401+
const size_t current_index = to_visit.front();
402+
to_visit.pop();
403+
404+
const int r = current_index / width;
405+
const int c = current_index % width;
406+
407+
// Check 4-connected neighbors (up, down, left, right)
408+
const std::array<std::pair<int, int>, 4> neighbors = {{
409+
{r - 1, c}, {r + 1, c}, {r, c - 1}, {r, c + 1}
410+
}};
411+
412+
for (const auto& [nr, nc] : neighbors) {
413+
// Check bounds
414+
if (nr < 0 || nr >= height || nc < 0 || nc >= width) {
415+
continue;
416+
}
417+
418+
const size_t neighbor_index = nr * width + nc;
419+
420+
// Skip if already visited
421+
if (visited[neighbor_index]) {
422+
continue;
423+
}
424+
425+
// Only expand through free cells (value 0)
426+
if (msg.data[neighbor_index] == 0) {
427+
visited[neighbor_index] = true;
428+
to_visit.push(neighbor_index);
429+
}
430+
}
431+
}
432+
433+
// Mark unvisited free cells as occupied
434+
for (size_t i = 0; i < msg.data.size(); ++i) {
435+
if (msg.data[i] == 0 && !visited[i]) {
436+
msg.data[i] = 100; // Mark as occupied
437+
}
438+
}
439+
}
440+
357441
float TsdfGradientOccupancyPublisher::computeHorizontalDistance(
358442
const Index2D& offset, float voxel_size) const {
359443
// Diagonal: sqrt(2) * voxel_size

0 commit comments

Comments
 (0)