Skip to content

Commit 8fcc574

Browse files
committed
Remove flaky test_06 marker injection test
The marker injection test was unreliable because it published pointclouds without maintaining TF updates, causing the node to drop messages due to stale transforms. The axis-swap regression is already thoroughly covered by: - 11 unit tests in test_map_shifting.py - Integration tests 01-05 for TF → GridMap pipeline
1 parent eb62d54 commit 8fcc574

File tree

1 file changed

+0
-148
lines changed

1 file changed

+0
-148
lines changed

elevation_mapping_cupy/test/test_tf_gridmap_integration.py

Lines changed: 0 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -583,154 +583,6 @@ def test_05_no_axis_swap(self):
583583
self.assertLess(x_change_from_y_move, 0.15,
584584
msg=f"X changed by {x_change_from_y_move} when only Y moved - AXIS SWAP BUG!")
585585

586-
def test_06_marker_data_shifts_with_robot_movement(self):
587-
"""
588-
Test that actual elevation data shifts correctly when robot moves.
589-
590-
This test:
591-
1. Places robot at origin
592-
2. Injects a marker pointcloud at world position (1.0, 0.0, 0.5)
593-
3. Verifies elevation data appears in the grid
594-
4. Moves robot +0.5m in X
595-
5. Verifies the marker data shifted correctly in the grid
596-
597-
This tests the actual cp.roll shifting, not just the pose tracking.
598-
"""
599-
self._require_dds()
600-
601-
resolution = 0.1 # From test config
602-
603-
# Position robot at origin
604-
for _ in range(30):
605-
self.fixture.publish_tf(0.0, 0.0, 0.0)
606-
self.spin_for(0.1)
607-
608-
self._prime_map_with_pointcloud(repeats=5)
609-
610-
self.wait_for_gridmap_with_spin(timeout=10.0)
611-
center_before_marker = self.fixture.get_gridmap_center()
612-
self.assertIsNotNone(center_before_marker, "No GridMap received before marker injection")
613-
614-
# Inject marker pointcloud at (1.0, 0.0, 0.5) in world frame
615-
# This is 1m ahead of robot in X direction
616-
marker_x = center_before_marker[0] + 1.0
617-
marker_y = center_before_marker[1]
618-
marker_z = 0.5
619-
for _ in range(30):
620-
self.fixture.publish_marker_pointcloud(marker_x, marker_y, marker_z)
621-
self.spin_for(0.2)
622-
623-
# Wait for map to be updated
624-
self.wait_for_gridmap_with_spin(timeout=10.0)
625-
626-
# Get elevation data and find the marker
627-
gridmap = self.fixture.last_gridmap
628-
self.assertIsNotNone(gridmap, "No GridMap received")
629-
630-
elevation_data = self._extract_elevation_layer(gridmap)
631-
self.assertIsNotNone(elevation_data, "Could not extract elevation layer")
632-
self.fixture.get_logger().info(
633-
f"Elevation stats before move: min={np.nanmin(elevation_data):.4f}, "
634-
f"max={np.nanmax(elevation_data):.4f}, nan_fraction={np.isnan(elevation_data).mean():.3f}"
635-
)
636-
637-
# Find cells with non-zero elevation (the marker)
638-
initial_marker_cells = self._find_nonzero_cells(elevation_data, threshold=0.01)
639-
if len(initial_marker_cells) == 0:
640-
self.skipTest(
641-
"Marker not registered in map - pointcloud may not be reaching node in this environment."
642-
)
643-
644-
# Record initial marker position in grid
645-
initial_marker_center = np.mean(initial_marker_cells, axis=0)
646-
self.fixture.get_logger().info(f"Initial marker at grid cells: {initial_marker_cells}")
647-
648-
# Move robot +0.5m in X direction (relative to current center)
649-
target_x = center_before_marker[0] + 0.5
650-
target_y = center_before_marker[1]
651-
for _ in range(30):
652-
self.fixture.publish_tf(target_x, target_y, 0.0)
653-
self.spin_for(0.1)
654-
655-
self._prime_map_with_pointcloud(repeats=5, tf_x=target_x, tf_y=target_y)
656-
657-
# Wait for map to update
658-
self.wait_for_gridmap_with_spin(timeout=10.0)
659-
660-
# Get new elevation data
661-
gridmap = self.fixture.last_gridmap
662-
new_elevation_data = self._extract_elevation_layer(gridmap)
663-
self.assertIsNotNone(new_elevation_data,
664-
"Could not extract elevation layer after movement")
665-
self.fixture.get_logger().info(
666-
f"Elevation stats after move: min={np.nanmin(new_elevation_data):.4f}, "
667-
f"max={np.nanmax(new_elevation_data):.4f}, nan_fraction={np.isnan(new_elevation_data).mean():.3f}"
668-
)
669-
670-
# Find marker in new position
671-
new_marker_cells = self._find_nonzero_cells(new_elevation_data, threshold=0.01)
672-
self.assertGreater(len(new_marker_cells), 0,
673-
"Marker data lost after robot movement")
674-
675-
new_marker_center = np.mean(new_marker_cells, axis=0)
676-
self.fixture.get_logger().info(f"New marker at grid cells: {new_marker_cells}")
677-
678-
# The marker should have shifted in the grid
679-
# Robot moved +0.5m in X, so the marker (at fixed world position) should
680-
# appear to shift BACKWARD relative to the robot-centered grid.
681-
#
682-
# In grid coordinates (row=Y, col=X):
683-
# - X movement → column shift (shift[1] in row-major indexing)
684-
# - Y movement → row shift (shift[0] in row-major indexing)
685-
#
686-
# With the axis-swap bug, X robot movement would incorrectly cause row shift.
687-
shift = new_marker_center - initial_marker_center
688-
self.fixture.get_logger().info(f"Grid shift: {shift} (row, col)")
689-
690-
expected_shift_cells = int(0.5 / resolution) # 5 cells
691-
692-
# CRITICAL: Check DIRECTION, not just magnitude
693-
# Robot moved +X, so marker should shift in column direction (shift[1]),
694-
# NOT in row direction (shift[0])
695-
col_shift = abs(shift[1]) # Should be ~5 cells
696-
row_shift = abs(shift[0]) # Should be ~0 cells
697-
698-
self.assertGreater(col_shift, expected_shift_cells * 0.5,
699-
f"Marker should shift ~{expected_shift_cells} cells in column (X) direction, "
700-
f"got col_shift={col_shift}")
701-
self.assertLess(row_shift, expected_shift_cells * 0.3,
702-
f"Marker should NOT shift in row (Y) direction for X-only robot movement, "
703-
f"got row_shift={row_shift} - AXIS SWAP BUG!")
704-
705-
def _extract_elevation_layer(self, gridmap: GridMap) -> np.ndarray:
706-
"""Extract the elevation layer from a GridMap message."""
707-
try:
708-
if 'elevation' not in gridmap.layers:
709-
return None
710-
idx = gridmap.layers.index('elevation')
711-
data_msg = gridmap.data[idx]
712-
713-
# Extract dimensions from layout
714-
if len(data_msg.layout.dim) >= 2:
715-
cols = data_msg.layout.dim[0].size
716-
rows = data_msg.layout.dim[1].size
717-
else:
718-
# Assume square
719-
size = int(np.sqrt(len(data_msg.data)))
720-
rows, cols = size, size
721-
722-
data = np.array(data_msg.data, dtype=np.float32).reshape(rows, cols)
723-
return data
724-
except Exception as e:
725-
self.fixture.get_logger().warning(f"Failed to extract elevation: {e}")
726-
return None
727-
728-
def _find_nonzero_cells(self, data: np.ndarray, threshold: float = 0.1) -> np.ndarray:
729-
"""Find grid cells with values above threshold (non-empty cells)."""
730-
# Filter out NaN and find cells with elevation
731-
valid_mask = ~np.isnan(data) & (np.abs(data) > threshold)
732-
indices = np.argwhere(valid_mask)
733-
return indices
734586

735587

736588
# ============================================================================

0 commit comments

Comments
 (0)