landmark_sensor_model.hpp
Go to the documentation of this file.
1 // Copyright 2023 Ekumen, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef BELUGA_SENSOR_LANDMARK_SENSOR_MODEL_HPP
16 #define BELUGA_SENSOR_LANDMARK_SENSOR_MODEL_HPP
17 
18 // external
19 #include <range/v3/range/conversion.hpp>
20 #include <range/v3/view/all.hpp>
21 #include <range/v3/view/transform.hpp>
22 #include <sophus/se2.hpp>
23 #include <sophus/so2.hpp>
24 
25 // standard library
26 #include <cmath>
27 #include <random>
28 #include <vector>
29 
30 // project
32 
38 namespace beluga {
39 
41 
45  double sigma_range{1.0};
46  double sigma_bearing{1.0};
47 };
48 
50 
62 template <class LandmarkMap, class StateType>
64  public:
66  using state_type = StateType;
68  using weight_type = double;
70  using measurement_type = std::vector<LandmarkPositionDetection>;
75 
77 
82  explicit LandmarkSensorModel(param_type params, LandmarkMap landmark_map)
83  : params_{std::move(params)}, landmark_map_{std::move(landmark_map)} {}
84 
86 
91  [[nodiscard]] auto operator()(measurement_type&& detections) const {
92  return [this, detections = std::move(detections)](const state_type& state) -> weight_type {
93  Sophus::SE3d robot_pose_in_world;
94 
95  if constexpr (std::is_same_v<state_type, Sophus::SE3d>) {
96  // The robot pose state is already given in 3D,
97  robot_pose_in_world = state;
98  } else {
99  // The robot pose state is given in 2D. Notice that in this case
100  // the 2D pose of the robot is assumed to be that of the robot footprint (projection of the robot
101  // on the z=0 plane of the 3D world frame). This is so that we can tie the sensor reference frame
102  // to the world frame where the landmarks are given without additional structural information.
103  robot_pose_in_world = Sophus::SE3d{
104  Sophus::SO3d::rotZ(state.so2().log()),
105  Eigen::Vector3d{state.translation().x(), state.translation().y(), 0.0}};
106  }
107 
108  const auto detection_weight = [this, &robot_pose_in_world](const auto& detection) {
109  // calculate range and detection_bearing_in_robot to the detection from the robot
110  // the detection is already in robot frame
111  const auto& detection_category = detection.category;
112  const auto& detection_position_in_robot = detection.detection_position_in_robot;
113 
114  const auto detection_range_in_robot = detection_position_in_robot.norm();
115  const auto detection_bearing_in_robot = detection_position_in_robot.normalized();
116 
117  // convert the detection to the world frame to query the map
118  const auto detection_position_in_world = robot_pose_in_world * detection_position_in_robot;
119 
120  // find the closest matching landmark in the world map
121  const auto opt_landmark_position_in_world =
122  landmark_map_.find_nearest_landmark(detection_position_in_world, detection_category);
123 
124  // if we did not find a matching landmark, return 0.0
125  if (!opt_landmark_position_in_world) {
126  return 0.0;
127  }
128 
129  // convert landmark pose to world frame
130  // ignore height, because we are modelling the detection in 2D
131  const auto& landmark_position_in_world = *opt_landmark_position_in_world;
132  const auto landmark_in_robot_position = robot_pose_in_world.inverse() * landmark_position_in_world;
133 
134  const auto landmark_range_in_robot = landmark_in_robot_position.norm();
135  const auto landmark_bearing_in_robot = landmark_in_robot_position.normalized();
136 
137  // calculate the aperture angle between the detection and the landmark
138  const auto cos_aperture = landmark_bearing_in_robot.dot(detection_bearing_in_robot);
139  const auto sin_aperture = landmark_bearing_in_robot.cross(detection_bearing_in_robot).norm();
140  const auto bearing_error = std::atan2(sin_aperture, cos_aperture);
141 
142  const auto range_error = detection_range_in_robot - landmark_range_in_robot;
143 
144  // apply the error model from Probabilistic Robotics
145  const auto range_error_prob =
146  std::exp(-range_error * range_error / (2. * params_.sigma_range * params_.sigma_range));
147  const auto bearing_error_prob =
148  std::exp(-bearing_error * bearing_error / (2. * params_.sigma_bearing * params_.sigma_bearing));
149 
150  // We'll assume the probability of identification error to be zero
151  return range_error_prob * bearing_error_prob;
152  };
153 
154  return std::transform_reduce(detections.cbegin(), detections.cend(), 1.0, std::multiplies{}, detection_weight);
155  };
156  }
157 
159  void update_map(map_type&& map) { landmark_map_ = std::move(map); }
160 
161  private:
164 };
165 
167 template <class LandmarkMap>
169 
171 template <class LandmarkMap>
173 
174 } // namespace beluga
175 
176 #endif
beluga::LandmarkModelParam::sigma_range
double sigma_range
Standard deviation of the range error.
Definition: landmark_sensor_model.hpp:45
beluga::LandmarkSensorModel::state_type
StateType state_type
State type of a particle.
Definition: landmark_sensor_model.hpp:66
beluga::state
constexpr state_detail::state_fn state
Customization point object for accessing the state of a particle.
Definition: primitives.hpp:163
beluga::LandmarkSensorModel::operator()
auto operator()(measurement_type &&detections) const
Returns a state weighting function conditioned on landmark position detections.
Definition: landmark_sensor_model.hpp:91
landmark_detection_types.hpp
Auxiliar types for landmark models.
beluga::LandmarkSensorModel::params_
param_type params_
Definition: landmark_sensor_model.hpp:162
beluga::LandmarkSensorModel
Generic landmark model for discrete detection sensors (both 2D and 3D).
Definition: landmark_sensor_model.hpp:63
se2.hpp
beluga::LandmarkSensorModel::measurement_type
std::vector< LandmarkPositionDetection > measurement_type
Measurement type of the sensor, detection position in robot frame.
Definition: landmark_sensor_model.hpp:70
beluga::LandmarkSensorModel::weight_type
double weight_type
Weight type of the particle.
Definition: landmark_sensor_model.hpp:68
so2.hpp
beluga::LandmarkMap::find_nearest_landmark
std::optional< LandmarkPosition3 > find_nearest_landmark(const LandmarkPosition3 &detection_position_in_world, const LandmarkCategory &detection_category) const
Finds the nearest landmark to a given detection and returns it's data.
Definition: landmark_map.hpp:60
Sophus::SE3
beluga::LandmarkSensorModel::update_map
void update_map(map_type &&map)
Update the sensor model with a new landmark map.
Definition: landmark_sensor_model.hpp:159
beluga::LandmarkMap
Basic 3D landmark map datatype.
Definition: landmark_map.hpp:39
beluga::LandmarkModelParam::sigma_bearing
double sigma_bearing
Standard deviation of the bearing error.
Definition: landmark_sensor_model.hpp:46
Sophus::SO3::rotZ
static SOPHUS_FUNC SO3 rotZ(Scalar const &z)
beluga::LandmarkSensorModel::LandmarkSensorModel
LandmarkSensorModel(param_type params, LandmarkMap landmark_map)
Constructs a LandmarkSensorModel instance.
Definition: landmark_sensor_model.hpp:82
beluga::LandmarkSensorModel::landmark_map_
LandmarkMap landmark_map_
Definition: landmark_sensor_model.hpp:163
beluga::LandmarkModelParam
Parameters used to construct a LandmarkSensorModel instance (both 2D and 3D).
Definition: landmark_sensor_model.hpp:44
beluga
The main Beluga namespace.
Definition: 3d_embedding.hpp:21


beluga
Author(s):
autogenerated on Tue Jul 16 2024 02:59:53