Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add likelihood field 3d model version #440

Open
wants to merge 79 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
d96bab0
Add pointcloud API contract and ROS interface
pvela2017 Sep 7, 2024
251c03b
Change PointCloud description for better clarification
pvela2017 Sep 10, 2024
370a6fa
Changed copyright year
pvela2017 Sep 10, 2024
54c4417
Add newlines
pvela2017 Sep 16, 2024
7481543
Expand testcase scenarios
pvela2017 Sep 16, 2024
104131b
Clarify documentation
pvela2017 Sep 16, 2024
b39afcd
Change to return Eigen::Map
pvela2017 Sep 16, 2024
18cbff5
Add make pointcloud message function
pvela2017 Sep 19, 2024
11fc506
Add non-aligned memory pointcloud wrapper
pvela2017 Sep 19, 2024
3111751
Add non-aligned memory pointcloud wrapper
pvela2017 Sep 19, 2024
d53e2d4
Add more restrictions to check
pvela2017 Sep 19, 2024
73df8e2
Change to pointfieldtypeastype templatization
pvela2017 Sep 19, 2024
674f7c4
Fix ROS1
pvela2017 Sep 19, 2024
d4e5767
Add eigen lib to test
pvela2017 Sep 19, 2024
3f5ec82
Fix ROS1 eigen compatibility
pvela2017 Sep 20, 2024
cff6c8f
Fix clang tidy
pvela2017 Sep 20, 2024
8f2718a
Rename sparse pointcloud
pvela2017 Sep 23, 2024
cc1a62c
Change using Pointfield
pvela2017 Sep 23, 2024
c703610
Change details
pvela2017 Sep 23, 2024
91606d5
Change to true types
pvela2017 Sep 23, 2024
96eab5d
Add sparse pointcloud API contract
pvela2017 Sep 25, 2024
3688a6a
Improve documentation
pvela2017 Sep 25, 2024
51ba647
Change name
pvela2017 Sep 25, 2024
29e838a
Fix clang
pvela2017 Sep 25, 2024
8229dcf
Fix is_dense bool noetic
pvela2017 Sep 25, 2024
b7c9c66
Fix clang jazzy
pvela2017 Sep 26, 2024
4870924
Add openvdb dependencies
pvela2017 Sep 26, 2024
0f135a1
Add likelihood 3D field model
pvela2017 Sep 30, 2024
580ce80
Add Openvdb dependencies
pvela2017 Oct 18, 2024
251bbd2
Add likelihood 3d field model test
pvela2017 Oct 18, 2024
c8c21e5
Add likelihood 3d field model to beluga
pvela2017 Oct 18, 2024
aeb7b94
Fix code
pvela2017 Oct 18, 2024
97c0269
Create minimal pointcloud interface for testing
pvela2017 Oct 21, 2024
aace826
Add openvdb and clean cmakes
pvela2017 Oct 21, 2024
48a91e4
Add likelihood 3D field sensor model
pvela2017 Oct 21, 2024
d5f800d
Fix return data
pvela2017 Oct 22, 2024
3be87cd
Fix cast eigen vector
pvela2017 Oct 22, 2024
a6b9e06
Fix openvdb map creation
pvela2017 Oct 23, 2024
a1a1eac
Fix compile with full options
pvela2017 Oct 23, 2024
015f1b7
Fix nit
pvela2017 Oct 26, 2024
ee56b7f
Add close and far point test
pvela2017 Oct 26, 2024
01018a3
Fix openvdb dependency
pvela2017 Oct 29, 2024
c0b1c45
Change test parameters
pvela2017 Oct 29, 2024
23056f0
Fix points not being a container
pvela2017 Nov 8, 2024
3a98181
Change OpenVDB as an optional dependency
pvela2017 Nov 12, 2024
b8e8665
Remove openvdb lib
pvela2017 Nov 14, 2024
c4d3b4a
Add boost dependency for openvdb
pvela2017 Nov 14, 2024
b40595c
Change points function to const
pvela2017 Nov 14, 2024
f1e7b76
Add test removed by mistake
pvela2017 Nov 14, 2024
bef40ad
Rework openvdb support options for beluga
pvela2017 Nov 14, 2024
ab138c5
Update to build with openvdb flag
pvela2017 Nov 14, 2024
88966dc
Fix openvdb dependency
pvela2017 Nov 14, 2024
a7c27ab
Fix clang tidy
pvela2017 Nov 14, 2024
b6073ee
Organize packages list
pvela2017 Nov 18, 2024
1d8696e
Generalize cmake and colcon arguments
pvela2017 Nov 18, 2024
54917a5
Fix nit
pvela2017 Nov 18, 2024
6759f96
Change minor tweaks
pvela2017 Nov 18, 2024
d4dc09e
Change from closestsurface to accessors
pvela2017 Nov 20, 2024
a61feed
Fix openvdb dependencies when building
pvela2017 Nov 22, 2024
8a354f3
Change nit
pvela2017 Nov 22, 2024
9a4c4cb
Fix libopenvdb not supported on noble
pvela2017 Nov 22, 2024
5f879c4
Fix boost dependency
pvela2017 Nov 23, 2024
0c0bb8f
Fix useopenvdb flag option
pvela2017 Nov 28, 2024
20050ab
Increase narrow band lenght of tests
pvela2017 Nov 28, 2024
2aabb60
Fix nit
pvela2017 Nov 28, 2024
7f2b27f
Remove openvdb from image
pvela2017 Nov 28, 2024
c8d773e
Change to not dynamically allocate memory
pvela2017 Dec 7, 2024
88a54ae
Move openvdb to beluga_vdb
pvela2017 Dec 7, 2024
ac98531
Remove openvdb to beluga
pvela2017 Dec 7, 2024
d802498
Add beluga_vdb package description
pvela2017 Dec 7, 2024
dae1efd
Remove LikelihoodFieldModel3 in doc
pvela2017 Dec 7, 2024
487901d
Update tools with beluga_vdb
pvela2017 Dec 7, 2024
5ed11f6
Fix beluga_vdb namespace
pvela2017 Dec 7, 2024
d6b1670
Fix beluga_vdb debug compile
pvela2017 Dec 7, 2024
fe6b594
Rename prob to distance
pvela2017 Dec 10, 2024
da0efb1
Merge branch 'main' into likelihood_field_3d_model
hidmic Dec 30, 2024
6b95d34
Please CI
hidmic Dec 31, 2024
b3c8448
Merge pull request #2 from hidmic/likelihood_field_3d_model
pvela2017 Jan 2, 2025
533086b
Remove const to checker
pvela2017 Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions beluga/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ project(beluga VERSION 1.0)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

option(
USE_OPENVDB
"Compiles with OpenVDB, required for the 3D likelihood field sensor model"
Off)
set(OPENVDB_CMAKE_MODULE_PATH
${OPENVDB_CMAKE_MODULE_PATH}
CACHE PATH "Path to OpenVDB CMake module")

if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE
Expand Down Expand Up @@ -48,6 +56,36 @@ find_package(range-v3 REQUIRED)
find_package(Sophus REQUIRED)
find_package(TBB REQUIRED)

# If USE_OPENVDB is enabled, proceed with finding OpenVDB
if(USE_OPENVDB)
if(NOT OPENVDB_CMAKE_MODULE_PATH)
file(
GLOB_RECURSE
OPENVDB_MODULES
/usr/lib/*/FindOpenVDB.cmake
/usr/local/lib/*/FindOpenVDB.cmake)
list(LENGTH OPENVDB_MODULES NUM_OPENVDB_MODULES)
if(NUM_OPENVDB_MODULES EQUAL 1)
list(
GET
OPENVDB_MODULES
0
OPENVDB_MODULE)
get_filename_component(OPENVDB_CMAKE_MODULE_PATH ${OPENVDB_MODULE}
DIRECTORY)
endif()
unset(NUM_OPENVDB_MODULES)
unset(OPENVDB_MODULES)
endif()
if(OPENVDB_CMAKE_MODULE_PATH)
list(APPEND CMAKE_MODULE_PATH ${OPENVDB_CMAKE_MODULE_PATH})
endif()
find_package(OpenVDB REQUIRED)
if(OPENVDB_CMAKE_MODULE_PATH)
list(POP_BACK CMAKE_MODULE_PATH)
endif()
endif()

add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(
${PROJECT_NAME}
Expand All @@ -60,10 +98,12 @@ target_link_libraries(
${HDF5_CXX_LIBRARIES}
Sophus::Sophus
TBB::tbb
range-v3::range-v3)
range-v3::range-v3
$<$<BOOL:${USE_OPENVDB}>:OpenVDB::openvdb>)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17)
target_compile_definitions(${PROJECT_NAME} INTERFACE EIGEN_NO_DEBUG
SOPHUS_USE_BASIC_LOGGING)
target_compile_definitions(
${PROJECT_NAME} INTERFACE EIGEN_NO_DEBUG SOPHUS_USE_BASIC_LOGGING
$<$<BOOL:${USE_OPENVDB}>:BELUGA_OPENVDB_SUPPORT>)

add_executable(clang_tidy_findable)
target_sources(clang_tidy_findable PRIVATE src/clang_tidy_findable.cpp)
Expand Down
5 changes: 5 additions & 0 deletions beluga/cmake/Config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ find_dependency(HDF5 COMPONENTS CXX REQUIRED)
find_dependency(Sophus REQUIRED)
find_dependency(TBB REQUIRED)

if("@USE_OPENVDB@")
list(APPEND CMAKE_MODULE_PATH "@OPENVDB_CMAKE_MODULE_PATH@")
find_dependency(OpenVDB REQUIRED)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")

set(@PROJECT_NAME@_LIBRARIES @PROJECT_NAME@::@PROJECT_NAME@)
Expand Down
5 changes: 5 additions & 0 deletions beluga/include/beluga/sensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
*
* \section SensorModelLinks See also
* - beluga::LikelihoodFieldModel
* - beluga::Likelihood3DFieldModel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* - beluga::Likelihood3DFieldModel
* - beluga::LikelihoodFieldModel3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 2aabb60

* - beluga::BeamSensorModel
* - beluga::LandmarkSensorModel
* - beluga::BearingSensorModel
Expand All @@ -65,4 +66,8 @@
#include <beluga/sensor/likelihood_field_model.hpp>
#include <beluga/sensor/ndt_sensor_model.hpp>

#ifdef BELUGA_OPENVDB_SUPPORT
#include <beluga/sensor/likelihood_field_model3.hpp>
#endif

#endif
168 changes: 168 additions & 0 deletions beluga/include/beluga/sensor/likelihood_field_model3.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Copyright 2024 Ekumen, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BELUGA_SENSOR_LIKELIHOOD_FIELD_MODEL3_HPP
#define BELUGA_SENSOR_LIKELIHOOD_FIELD_MODEL3_HPP

#include <algorithm>
#include <cmath>
#include <random>
#include <vector>

#include <openvdb/openvdb.h>

#include <Eigen/Core>

#include <range/v3/range/conversion.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/transform.hpp>
#include <sophus/se3.hpp>
#include <sophus/so3.hpp>

/**
* \file
* \brief Implementation of a likelihood field sensor model for 3D Lidars.
*/

namespace beluga {

/// Parameters used to construct a LikelihoodFieldModel3 instance.
/**
* See Probabilistic Robotics \cite thrun2005probabilistic Chapter 6.4, particularly Table 6.3.
*/
struct LikelihoodFieldModel3Param {
/// Maximum distance to obstacle.
/**
* When creating a distance map, if the distance to an obstacle is higher than the value specified here,
* then this value will be used.
*/
double max_obstacle_distance = 100.0;
/// Maximum range of a laser ray.
double max_laser_distance = 2.0;
/// Weight used to combine the probability of hitting an obstacle.
double z_hit = 0.5;
/// Weight used to combine the probability of random noise in perception.
double z_random = 0.5;
/// Standard deviation of a gaussian centered arounds obstacles.
/**
* Used to calculate the probability of the obstacle being hit.
*/
double sigma_hit = 0.2;
};

/// Likelihood field sensor model for range finders.
/**
* This model relies on a pre-computed likelihood map of the environment.
* It is less computationally intensive than the beluga::BeamSensorModel
* because no ray-tracing is required, and it can also provide better
* performance in environments with non-smooth occupation maps. See
* Probabilistic Robotics \cite thrun2005probabilistic, Chapter 6.4,
* for further reference.
*
* \note This class satisfies \ref SensorModelPage.
*
* \tparam OpenVDB grid type.
*/
template <typename GridT, typename PointCloud>
class LikelihoodFieldModel3 {
public:
/// State type of a particle.
using state_type = Sophus::SE3d;

/// Weight type of the particle.
using weight_type = double;

/// Measurement type given by the interface.
using measurement_type = PointCloud;

/// Map representation type.
using map_type = GridT;

/// Parameter type that the constructor uses to configure the likelihood field model.
using param_type = LikelihoodFieldModel3Param;

/// Constructs a Likelihood3DFieldModel instance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other instances that need replacement.

Suggested change
/// Constructs a Likelihood3DFieldModel instance.
/// Constructs a LikelihoodFieldModel3 instance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 2aabb60

/**
* \param params Parameters to configure this instance.
* See beluga::Likelihood3DFieldModelParam for details.
* \param grid Narrow band Level set grid representing the static map that the sensor model
* uses to compute a likelihood field for lidar hits and compute importance weights
* for particle states.
* Currently only supports OpenVDB Level sets.
*/
explicit LikelihoodFieldModel3(const param_type& params, const map_type& grid)
: params_{params},
grid_{openvdb::gridPtrCast<map_type>(grid.deepCopyGrid())},
accessor_{grid_->getConstAccessor()},
transform_{grid_->transform()},
background_{grid_->background()},
two_squared_sigma_{2 * params.sigma_hit * params.sigma_hit},
amplitude_{params.z_hit / (params.sigma_hit * std::sqrt(2 * Sophus::Constants<double>::pi()))},
offset_{params.z_random / params.max_laser_distance} {
openvdb::initialize();
/// Pre-computed parameters
assert(two_squared_sigma_ > 0.0);
assert(amplitude_ > 0.0);
}

/// Returns a state weighting function conditioned on 3D lidar hits.
/**
* \param measurement 3D lidar measurement containing the hit points and the transform to the origin.
* \return a state weighting function satisfying \ref StateWeightingFunctionPage
* and borrowing a reference to this sensor model (and thus their lifetime are bound).
*/
[[nodiscard]] auto operator()(measurement_type&& measurement) const {
const size_t pointcloud_size = measurement.points().size();
// Transform each point from the sensor frame to the origin frame
auto transformed_points = ranges::views::all(measurement.points()) |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ranges::views::all should not be needed. The transform view will do the conversion.

Suggested change
auto transformed_points = ranges::views::all(measurement.points()) |
auto transformed_points = measurement.points() |

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 2aabb60

ranges::views::transform([&](const auto& point) {
return measurement.origin() * point.template cast<double>();
}) |
ranges::to<std::vector>();

return [this, pointcloud_size, points = std::move(transformed_points)](const state_type& state) -> weight_type {
std::vector<float> distances;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meta: It doesn't seem like we need to dynamically allocate the distances since we will iterate over them only once. Non-blocking though.

Copy link
Contributor Author

@pvela2017 pvela2017 Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 2aabb60

edit: I was thinking, if we dont allocate memory for the distances, wouldn't it loose performance since everytime the vector is getting full it would have to allocate more memory? Since there are a lot of points this would happen several time or would this be negligible?

distances.reserve(pointcloud_size);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pvela2017 nit: we can fetch pointcloud_size as points.size().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think points type changed to Eigen after transforming the points to base_link frame.

But now reserve was removed according to this so no need for this variable.

Changed in 2aabb60


// Transform each point to every particle state
std::transform(points.begin(), points.end(), std::back_inserter(distances), [this, state](const auto& point) {
// OpenVDB grid already in world coordinates
const Eigen::Vector3d point_in_state_frame = state * point;
const openvdb::math::Coord ijk = transform_.worldToIndexCellCentered(
openvdb::math::Vec3d(point_in_state_frame.x(), point_in_state_frame.y(), point_in_state_frame.z()));
return accessor_.isValueOn(ijk) ? accessor_.getValue(ijk) : background_;
});

// Calculates the probality based on the distance
return std::transform_reduce(
distances.cbegin(), distances.cend(), 1.0, std::plus{}, [this](const auto& distance) {
return amplitude_ * std::exp(-(distance * distance) / two_squared_sigma_) + offset_;
});
};
}

private:
param_type params_;
const typename map_type::Ptr grid_;
const typename map_type::ConstAccessor accessor_;
const openvdb::math::Transform transform_;
const typename map_type::ValueType background_;
double two_squared_sigma_;
double amplitude_;
double offset_;
};

} // namespace beluga

#endif
3 changes: 3 additions & 0 deletions beluga/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
<buildtool_depend>cmake</buildtool_depend>

<depend>eigen</depend>
<depend>libboost-iostreams-dev</depend>
<depend>libboost-thread-dev</depend>
<depend>libhdf5-dev</depend>
<depend>libopenvdb-dev</depend>
<depend>range-v3</depend>
<depend>sophus</depend>
<depend>tbb</depend>
Expand Down
1 change: 1 addition & 0 deletions beluga/test/beluga/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ file(COPY test_data DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

add_executable(
test_beluga
$<IF:$<BOOL:${USE_OPENVDB}>,sensor/test_likelihood_3d_field_model.cpp,>
actions/test_assign.cpp
actions/test_normalize.cpp
actions/test_overlay.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2024 Ekumen, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BELUGA_TEST_SIMPLE_POINTCLOUD_INTERFACE_HPP
#define BELUGA_TEST_SIMPLE_POINTCLOUD_INTERFACE_HPP

#include <range/v3/view/iota.hpp>
#include <sophus/se3.hpp>

namespace beluga::testing {

template <typename T>
class SimpleSparsePointCloud3 {
public:
explicit SimpleSparsePointCloud3(std::vector<Eigen::Vector3<T>> points, Sophus::SE3d origin = Sophus::SE3d{})
: points_(std::move(points)), origin_(std::move(origin)) {}

/// Get the point cloud frame origin in the filter frame.
[[nodiscard]] const auto& origin() const { return origin_; }

/// Get the 3D points collection.
[[nodiscard]] const auto& points() const { return points_; }

private:
std::vector<Eigen::Vector3<T>> points_;
Sophus::SE3d origin_;
};

using SimpleSparsePointCloud3d = SimpleSparsePointCloud3<double>;
using SimpleSparsePointCloud3f = SimpleSparsePointCloud3<float>;

} // namespace beluga::testing

#endif
Loading
Loading