Skip to content

Commit 6f993c6

Browse files
committed
Add basic occupancy_grid_implementation
-- Added placeholder implementation for bresenham line algo and ray trace. -- Added world to grid and grid to world and error utility functions -- Added test code to check whether the basic occupancy grid with const log odds working fine.
1 parent 3cc4351 commit 6f993c6

File tree

4 files changed

+157
-6
lines changed

4 files changed

+157
-6
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ target_include_directories(visualizer INTERFACE src/visualizer)
2424
target_link_libraries(visualizer INTERFACE Open3D::Open3D Eigen3::Eigen)
2525

2626
#will have occupancy grid logic
27-
add_executable(occupancy_grid_main src/main.cpp src/data_analyser.cpp)
27+
add_executable(occupancy_grid_main src/main.cpp src/occupancy_grid.cpp src/data_analyser.cpp)
2828

2929
target_link_libraries(occupancy_grid_main PRIVATE dataloader visualizer)
3030

src/main.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
#include "occupancy_grid.hpp"
33
#include "data_analyser.hpp"
44

5+
#define TEST
6+
57
int main(int argc, char* argv[]) {
8+
9+
#ifndef TEST
610
if (argc != 2) {
711
std::cerr << "Usage: " << argv[0] << " <data_directory>" << std::endl;
812
return -1;
@@ -85,6 +89,40 @@ int main(int argc, char* argv[]) {
8589
//OccupancyGrid grid(grid_dims, resolution, optimal_origin);
8690

8791
std::cout << "\n=== STARTING MAPPING ===" << std::endl;
92+
#else
93+
// Test with small grid first
94+
std::cout << "=== TESTING BASIC FUNCTIONALITY ===" << std::endl;
95+
96+
std::array<size_t, 3> test_dims = {50, 50, 25}; // Small test grid
97+
double test_resolution = 1.0; // 1m voxels for testing
98+
Vector3d test_origin(-25.0, -25.0, 0.0);
99+
100+
OccupancyGrid grid(test_dims, test_resolution, test_origin);
101+
102+
// Test coordinate conversions
103+
Vector3d test_world(5.5, -3.2, 2.8);
104+
Vector3i test_grid = grid.world_to_grid(test_world);
105+
Vector3d back_world = grid.grid_to_world(test_grid);
106+
107+
std::cout << "Coordinate Conversion Test:" << std::endl;
108+
std::cout << " World: " << test_world.transpose() << std::endl;
109+
std::cout << " Grid: " << test_grid.transpose() << std::endl;
110+
std::cout << " Back to World: " << back_world.transpose() << std::endl;
111+
std::cout << " In Bounds: " << (grid.is_InBounds(test_grid) ? "YES" : "NO") << std::endl;
88112

113+
// Test occupancy updates
114+
grid.update_occupied(test_grid);
115+
std::cout << " Occupancy after update: " << grid.getOccupancy(test_grid) << std::endl;
116+
117+
// Test multiple updates
118+
for (int i = 0; i < 5; ++i) {
119+
grid.update_occupied(test_grid);
120+
}
121+
std::cout << " Occupancy after 5 updates: " << grid.getOccupancy(test_grid) << std::endl;
122+
123+
std::cout << "\n=== BASIC FUNCTIONALITY TEST COMPLETED ===" << std::endl;
124+
#endif
125+
126+
89127
return 0;
90128
}

src/occupancy_grid.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "occupancy_grid.hpp"
2+
#include <algorithm>
3+
#include <iostream>
4+
#include <cmath>
5+
6+
7+
// Log-odds constants
8+
constexpr float LOG_ODDS_OCCUPIED = 0.85f;
9+
constexpr float LOG_ODDS_FREE = -0.4f;
10+
constexpr float LOG_ODDS_MIN = -5.0f;
11+
constexpr float LOG_ODDS_MAX = 5.0f;
12+
13+
OccupancyGrid::OccupancyGrid(const std::array<size_t, 3>& dimensions,
14+
double resolution, const Vector3d& origin)
15+
:grid_dimensions(dimensions), voxel_resolution(resolution), grid_origin(origin) {
16+
17+
size_t total_cells = grid_dimensions[0] * grid_dimensions[1] * grid_dimensions[2];
18+
grid_data.resize(total_cells,0.0f);
19+
20+
std::cout << "OccupancyGrid3D initialized:" << std::endl;
21+
std::cout << " Dimensions: " << grid_dimensions[0] << "×" << grid_dimensions[1] << "×" << grid_dimensions[2] << std::endl;
22+
std::cout << " Resolution: " << voxel_resolution << "m" << std::endl;
23+
std::cout << " Origin: " << grid_origin.transpose() << std::endl;
24+
std::cout << " Total voxels: " << total_cells << std::endl;
25+
26+
}
27+
28+
// converts world coordinates to grid coordinates, assuming grid origin starts in bottom left corner of the map.
29+
Vector3i OccupancyGrid::world_to_grid(const Vector3d& world_coord) const {
30+
Vector3d diff = world_coord - grid_origin;
31+
return Vector3i(
32+
static_cast<int>(std::floor(diff.x()/voxel_resolution)),
33+
static_cast<int>(std::floor(diff.y()/voxel_resolution)),
34+
static_cast<int>(std::floor(diff.z()/voxel_resolution))
35+
);
36+
}
37+
38+
// converts grid coordinates to world coordinates
39+
Vector3d OccupancyGrid::grid_to_world(const Vector3i& grid_index) const {
40+
return grid_origin + Vector3d((grid_index.x() + 0.5) * voxel_resolution,
41+
(grid_index.y() + 0.5) * voxel_resolution,
42+
(grid_index.z() + 0.5) * voxel_resolution);
43+
}
44+
45+
// check if the index is valid and within the grid dimensions
46+
bool OccupancyGrid::is_InBounds(const Vector3i& idx) const {
47+
return idx.x() >= 0 && idx.x() < static_cast<int>(grid_dimensions[0]) &&
48+
idx.y() >= 0 && idx.y() < static_cast<int>(grid_dimensions[1]) &&
49+
idx.z() >= 0 && idx.z() < static_cast<int>(grid_dimensions[2]);
50+
}
51+
52+
//converts 3d grid coordinates to 1d index.
53+
size_t OccupancyGrid::to_LinearIndex(const Vector3i& idx) const {
54+
return static_cast<size_t>(idx.z()) * grid_dimensions[0] * grid_dimensions[1] +
55+
static_cast<size_t>(idx.y()) * grid_dimensions[0] +
56+
static_cast<size_t>(idx.x());
57+
}
58+
59+
// updates occupancy
60+
void OccupancyGrid::update_occupied(const Vector3i& idx) {
61+
if(!is_InBounds(idx)) return;
62+
size_t index = to_LinearIndex(idx);
63+
grid_data[index] = std::clamp(grid_data[index]+ LOG_ODDS_OCCUPIED,
64+
LOG_ODDS_MIN, LOG_ODDS_MAX);
65+
}
66+
67+
// updates occupancy
68+
void OccupancyGrid::update_free(const Vector3i& idx) {
69+
if(!is_InBounds(idx)) return;
70+
size_t index = to_LinearIndex(idx);
71+
grid_data[index] = std::clamp(grid_data[index]+ LOG_ODDS_FREE,
72+
LOG_ODDS_MIN, LOG_ODDS_MAX);
73+
}
74+
75+
// Simple getOccupancy for testing
76+
float OccupancyGrid::getOccupancy(const Vector3i& grid_index) const {
77+
if (!is_InBounds(grid_index)) return 0.0f;
78+
return grid_data[to_LinearIndex(grid_index)];
79+
}
80+
81+
// PLACEHOLDER FUNCTIONS - IMPLEMENT
82+
std::vector<Vector3i> OccupancyGrid::draw_bresenham3d_line(const Vector3i& start, const Vector3i& end) const {
83+
// TODO: Implement 3D Bresenham algorithm
84+
// PRIORITY: CRITICAL - Core mapping algorithm
85+
std::vector<Vector3i> voxels;
86+
voxels.push_back(start);
87+
voxels.push_back(end); // Temporary placeholder
88+
return voxels;
89+
}
90+
91+
void OccupancyGrid::rayTrace(const Vector3d& start, const Vector3d& end) {
92+
// TODO: Implement ray tracing
93+
// PRIORITY: CRITICAL - Main occupancy update method
94+
Vector3i start_grid = world_to_grid(start);
95+
Vector3i end_grid = world_to_grid(end);
96+
97+
if (is_InBounds(start_grid) && is_InBounds(end_grid)) {
98+
update_occupied(end_grid); // Temporary: just mark endpoint
99+
}
100+
}
101+
102+
Vector3dVector OccupancyGrid::getOccupiedVoxels(float threshold) const {
103+
// TODO: Implement visualization extraction
104+
// PRIORITY: HIGH - Needed for final visualization
105+
Vector3dVector occupied_points;
106+
return occupied_points;
107+
}

src/occupancy_grid.hpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ using Vector3i = Eigen::Vector3i;
1111
//TODO: implement the member functions
1212
class OccupancyGrid {
1313
private:
14-
std::array<size_t, 3> voxel_dimensions;
14+
std::array<size_t, 3> grid_dimensions;
1515
double voxel_resolution;
1616
// links grid coordinates with world coordinates
1717
Vector3d grid_origin;
1818
std::vector<float> grid_data;
1919
// connects the start and end point of lidar ray in voxel map
2020
std::vector<Vector3i> draw_bresenham3d_line(const Vector3i& start, const Vector3i& end) const;
21-
// updates the log odds aka grid data for the voxel
22-
void update_occupied(const Vector3i& idx);
21+
// updates the log odds in the grid data for the voxel
22+
// void update_occupied(const Vector3i& idx);
2323
void update_free(const Vector3i& idx);
2424
// check if the index within the grid boundary
25-
bool is_InBounds(const Vector3i& idx) const;
25+
//bool is_InBounds(const Vector3i& idx) const;
2626
// converts voxel index 3D to 1D index to fetch grid data when required.
2727
size_t to_LinearIndex(const Vector3i& idx) const;
2828
public:
@@ -31,13 +31,19 @@ class OccupancyGrid {
3131
// TODO: implement transformations
3232
Vector3i world_to_grid(const Vector3d& world_coord) const;
3333
Vector3d grid_to_world(const Vector3i& grid_index) const;
34+
//for simple test
35+
float getOccupancy(const Vector3i& grid_index) const;
36+
3437
// to update occupancy probability along the lidar scan
3538
void rayTrace(const Vector3d& start, const Vector3d& end);
3639
// to return the voxels which are occupied either by obstacles or grid boundary
3740
Vector3dVector getOccupiedVoxels(float threshold = 0.0f) const;
3841
//to detect if the lidar ray is crossing the grid boundary
3942
Vector3i findGridBoundaryIntersection(const Vector3i& start, const Vector3i& end) const;
40-
};
43+
44+
bool is_InBounds(const Vector3i& idx) const;
45+
void update_occupied(const Vector3i& idx);
46+
};
4147

4248

4349

0 commit comments

Comments
 (0)