-
Notifications
You must be signed in to change notification settings - Fork 20
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
base: main
Are you sure you want to change the base?
Changes from 62 commits
d96bab0
251c03b
370a6fa
54c4417
7481543
104131b
b39afcd
18cbff5
11fc506
3111751
d53e2d4
73df8e2
674f7c4
d4e5767
3f5ec82
cff6c8f
8f2718a
cc1a62c
c703610
91606d5
96eab5d
3688a6a
51ba647
29e838a
8229dcf
b7c9c66
4870924
0f135a1
580ce80
251bbd2
c8c21e5
aeb7b94
97c0269
aace826
48a91e4
d5f800d
3be87cd
a6b9e06
a1a1eac
015f1b7
ee56b7f
01018a3
c0b1c45
23056f0
3a98181
b8e8665
c4d3b4a
b40595c
f1e7b76
bef40ad
ab138c5
88966dc
a7c27ab
b6073ee
1d8696e
54917a5
6759f96
d4dc09e
a61feed
8a354f3
9a4c4cb
5f879c4
0c0bb8f
20050ab
2aabb60
7f2b27f
c8d773e
88a54ae
ac98531
d802498
dae1efd
487901d
5ed11f6
d6b1670
fe6b594
da0efb1
6b95d34
b3c8448
533086b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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@) | ||
|
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. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other instances that need replacement.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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()) | | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pvela2017 nit: we can fetch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
|
||||||
// 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 |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in 2aabb60