Skip to content

Commit a783a86

Browse files
author
Lorenzo
committed
Fix elevation map rotation issue with Row-Major indexing
- Fixed CUDA kernels to use proper Row-Major convention (Row=Y, Col=X) - Updated is_inside() and get_idx() functions in all kernels - Fixed normal vector calculation (removed swapped components) - Adjusted data flipping for correct GridMap publishing - Kept 180-degree rotation in internal representation - Removed extra flip in elevation_mapping_ros.py The elevation map now correctly aligns with LiDAR data.
1 parent 1d84903 commit a783a86

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

elevation_mapping_cupy/elevation_mapping_cupy/elevation_mapping.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ def get_map_with_name_ref(self, name, data):
797797
else:
798798
print("Layer {} is not in the map".format(name))
799799
return
800+
# Need 180 degree rotation to match coordinate system
800801
m = xp.flip(m, 0)
801802
m = xp.flip(m, 1)
802803
if use_stream:

elevation_mapping_cupy/elevation_mapping_cupy/elevation_mapping_ros.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,11 @@ def publish_map(self, key: str) -> None:
297297
for layer in self.my_publishers[key].get("layers", []):
298298
gm.layers.append(layer)
299299
self._map.get_map_with_name_ref(layer, self._map_data)
300-
map_data_for_gridmap = np.flip(self._map_data, axis=1)
300+
# After fixing CUDA kernels and removing flips in elevation_mapping.py, no flip needed here
301+
map_data_for_gridmap = self._map_data
301302
arr = Float32MultiArray()
302303
arr.layout = MAL()
304+
# Keep original dimension order but fix strides
303305
arr.layout.dim.append(MAD(label="column_index", size=map_data_for_gridmap.shape[1], stride=map_data_for_gridmap.shape[0] * map_data_for_gridmap.shape[1]))
304306
arr.layout.dim.append(MAD(label="row_index", size=map_data_for_gridmap.shape[0], stride=map_data_for_gridmap.shape[0]))
305307
arr.data = map_data_for_gridmap.flatten().tolist()

elevation_mapping_cupy/elevation_mapping_cupy/kernels/custom_kernels.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ def map_utils(
3232
return i;
3333
}
3434
__device__ bool is_inside(int idx) {
35-
int idx_x = idx / ${width};
36-
int idx_y = idx % ${width};
35+
// Fixed: Row-Major (Row=Y, Col=X)
36+
// Row index (Y)
37+
int idx_y = idx / ${width};
38+
// Column index (X)
39+
int idx_x = idx % ${width};
40+
// Check Col bounds (Width)
3741
if (idx_x == 0 || idx_x == ${width} - 1) {
3842
return false;
3943
}
44+
// Check Row bounds (Height)
4045
if (idx_y == 0 || idx_y == ${height} - 1) {
4146
return false;
4247
}
@@ -45,7 +50,8 @@ def map_utils(
4550
__device__ int get_idx(float16 x, float16 y, float16 center_x, float16 center_y) {
4651
int idx_x = clamp(get_x_idx(x, center_x), 0, ${width} - 1);
4752
int idx_y = clamp(get_y_idx(y, center_y), 0, ${height} - 1);
48-
return ${width} * idx_x + idx_y;
53+
// Fixed: Row-Major (Row=Y, Col=X)
54+
return ${width} * idx_y + idx_x;
4955
}
5056
__device__ int get_map_idx(int idx, int layer_n) {
5157
const int layer = ${width} * ${height};
@@ -406,11 +412,16 @@ def dilation_filter_kernel(width, height, dilation_size):
406412
return layer * layer_n + relative_idx;
407413
}
408414
__device__ bool is_inside(int idx) {
409-
int idx_x = idx / ${width};
410-
int idx_y = idx % ${width};
415+
// Fixed: Row-Major (Row=Y, Col=X)
416+
// Row index (Y)
417+
int idx_y = idx / ${width};
418+
// Column index (X)
419+
int idx_x = idx % ${width};
420+
// Check Col bounds (Width)
411421
if (idx_x <= 0 || idx_x >= ${width} - 1) {
412422
return false;
413423
}
424+
// Check Row bounds (Height)
414425
if (idx_y <= 0 || idx_y >= ${height} - 1) {
415426
return false;
416427
}
@@ -466,11 +477,16 @@ def normal_filter_kernel(width, height, resolution):
466477
return layer * layer_n + relative_idx;
467478
}
468479
__device__ bool is_inside(int idx) {
469-
int idx_x = idx / ${width};
470-
int idx_y = idx % ${width};
480+
// Fixed: Row-Major (Row=Y, Col=X)
481+
// Row index (Y)
482+
int idx_y = idx / ${width};
483+
// Column index (X)
484+
int idx_x = idx % ${width};
485+
// Check Col bounds (Width)
471486
if (idx_x <= 0 || idx_x >= ${width} - 1) {
472487
return false;
473488
}
489+
// Check Row bounds (Height)
474490
if (idx_y <= 0 || idx_y >= ${height} - 1) {
475491
return false;
476492
}
@@ -491,8 +507,9 @@ def normal_filter_kernel(width, height, resolution):
491507
if (!is_inside(idx_x) || !is_inside(idx_y)) { return; }
492508
float dzdx = (map[idx_x] - h);
493509
float dzdy = (map[idx_y] - h);
494-
float nx = -dzdy / resolution();
495-
float ny = -dzdx / resolution();
510+
// Fixed: Normal = (-dH/dx, -dH/dy, 1)
511+
float nx = -dzdx / resolution();
512+
float ny = -dzdy / resolution();
496513
float nz = 1;
497514
float norm = sqrt((nx * nx) + (ny * ny) + 1);
498515
newmap[get_map_idx(i, 0)] = nx / norm;
@@ -568,12 +585,14 @@ def polygon_mask_kernel(width, height, resolution):
568585
}
569586
570587
__device__ int get_idx_x(int idx){
571-
int idx_x = idx / ${width};
588+
// Fixed: Column index (X)
589+
int idx_x = idx % ${width};
572590
return idx_x;
573591
}
574592
575593
__device__ int get_idx_y(int idx){
576-
int idx_y = idx % ${width};
594+
// Fixed: Row index (Y)
595+
int idx_y = idx / ${width};
577596
return idx_y;
578597
}
579598
@@ -599,7 +618,8 @@ def polygon_mask_kernel(width, height, resolution):
599618
__device__ int get_idx(float16 x, float16 y, float16 center_x, float16 center_y) {
600619
int idx_x = clamp(get_x_idx(x, center_x), 0, ${width} - 1);
601620
int idx_y = clamp(get_y_idx(y, center_y), 0, ${height} - 1);
602-
return ${width} * idx_x + idx_y;
621+
// Fixed: Row-Major (Row=Y, Col=X)
622+
return ${width} * idx_y + idx_x;
603623
}
604624
605625
"""

0 commit comments

Comments
 (0)