2121#include < tuple>
2222
2323#include < beluga/type_traits/tuple_traits.hpp>
24+ #include < beluga/utility/time_stamped.hpp>
2425
2526#include < beluga/3d_embedding.hpp>
2627#include < sophus/se2.hpp>
@@ -39,33 +40,42 @@ namespace beluga {
3940 * See Probabilistic Robotics \cite thrun2005probabilistic Chapter 5.3, particularly table 5.3.
4041 */
4142struct VelocityDriveModelParam {
43+ // / Rotational noise from rotational velocity
44+ /* *
45+ * How much rotational noise is generated by the rotational velocity.
46+ * Also known as `alpha1 in the differential drive model param`.
47+ */
48+ double rotation_noise_from_rotation;
49+ // / Rotational noise from translation velocity
50+ /* *
51+ * How much rotational noise is generated by the linear velocity.
52+ * Also known as `alpha2 in the differential drive model param`.
53+ */
54+ double rotation_noise_from_translation;
4255 // / Translational noise from translation velocity
4356 /* *
44- * How much translational noise is generated by the translational velocity.
45- * Also known as `alpha1 `.
57+ * How much translational noise is generated by the linear velocity.
58+ * Also known as `alpha3 in the differential drive model param `.
4659 */
4760 double translation_noise_from_translation;
4861 // / Translational noise from rotational velocity
4962 /* *
5063 * How much translational noise is generated by the rotational velocity.
51- * Also known as `alpha2 `.
64+ * Also known as `alpha4 in the differential drive model param `.
5265 */
5366 double translation_noise_from_rotation;
54- // / Rotational noise from translation velocity
67+ // / Additional orientation noise from translational velocity
5568 /* *
56- * How much rotational noise is generated by the translational velocity.
57- * Also known as `alpha3 `.
69+ * How much extra orientation noise is generated by the linear velocity.
70+ * Also known as `alpha6 `.
5871 */
59- double rotation_noise_from_translation ;
60- // / Rotational noise from rotational velocity
72+ double orientation_noise_from_translation ;
73+ // / Additional orientation noise from rotational velocity
6174 /* *
62- * How much rotational noise is generated by the rotational velocity.
63- * Also known as `alpha4 `.
75+ * How much extra orientation noise is generated by the rotational velocity.
76+ * Also known as `alpha7 `.
6477 */
65- double rotation_noise_from_rotation;
66-
67- // / Distance threshold to detect in-place rotation.
68- double distance_threshold = 0.01 ;
78+ double orientation_noise_from_rotation;
6979};
7080
7181// / Sampled velocity model for a differential drive.
@@ -88,10 +98,10 @@ class VelocityDriveModel {
8898 using state_type = StateType;
8999
90100 // / Time point type for motion model control actions.
91- using time_point_type = std::chrono::time_point<std::chrono::steady_clock >;
101+ using timestamped_state_type = TimeStamped<state_type >;
92102
93103 // / Current and previous pose estimates and time points as motion model control action.
94- using control_type = std::tuple<state_type, state_type, time_point_type, time_point_type >;
104+ using control_type = std::tuple<timestamped_state_type, timestamped_state_type >;
95105
96106 // / Parameter type that the constructor uses to configure the motion model.
97107 using param_type = VelocityDriveModelParam;
@@ -111,7 +121,12 @@ class VelocityDriveModel {
111121 */
112122 template <class Control , typename = common_tuple_type_t <Control, control_type>>
113123 [[nodiscard]] auto operator ()(const Control& action) const {
114- const auto & [pose, previous_pose, time, previous_time] = action;
124+ const auto & [timestamped, previous_timestamped] = action;
125+ const auto & pose = timestamped.value ;
126+ const auto & previous_pose = previous_timestamped.value ;
127+
128+ auto time = timestamped.timestamp ;
129+ auto previous_time = previous_timestamped.timestamp ;
115130 const auto delta_time = std::chrono::duration<double >(time - previous_time).count ();
116131 if constexpr (std::is_same_v<state_type, Sophus::SE2d>) {
117132 return sampling_fn_2d (pose, previous_pose, delta_time);
@@ -121,8 +136,8 @@ class VelocityDriveModel {
121136 }
122137
123138 private:
124- using control_type_2d = std::tuple<Sophus::SE2d, Sophus::SE2d, double >;
125- using control_type_3d = std::tuple<Sophus::SE3d, Sophus::SE3d, double >;
139+ using control_type_2d = std::tuple<Sophus::SE2d, Sophus::SE2d>;
140+ using control_type_3d = std::tuple<Sophus::SE3d, Sophus::SE3d>;
126141
127142 [[nodiscard]] auto sampling_fn_3d (const Sophus::SE3d& pose, const Sophus::SE3d& previous_pose, double delta_time)
128143 const {
@@ -154,8 +169,8 @@ class VelocityDriveModel {
154169 const auto gamma_params = DistributionParam{
155170 0.0 , // zero mean
156171 std::sqrt (
157- params_.rotation_noise_from_translation * std::abs (linear_velocity) +
158- params_.rotation_noise_from_rotation * std::abs (angular_velocity))};
172+ params_.orientation_noise_from_translation * std::abs (linear_velocity) +
173+ params_.orientation_noise_from_rotation * std::abs (angular_velocity))};
159174
160175 return [=](const auto & state, auto & gen) {
161176 static thread_local auto distribution = std::normal_distribution<double >{};
@@ -173,24 +188,38 @@ class VelocityDriveModel {
173188 // / Calculate linear and angular velocities from two poses and delta time
174189 std::pair<double , double >
175190 calculate_velocities (const Sophus::SE2d& pose, const Sophus::SE2d& previous_pose, double delta_time) const {
176- // Distancia euclidiana
191+ // Euclidean distance (chord length between poses)
177192 const auto translation = pose.translation () - previous_pose.translation ();
178- const double distance = translation.norm ();
193+ const double chord_distance = translation.norm ();
179194
180- // Velocidad angular
195+ // Angular velocity from orientation change
181196 const auto angular_change = pose.so2 () * previous_pose.so2 ().inverse ();
182197 const double angle_change = angular_change.log ();
183198 const double angular_velocity = angle_change / delta_time;
184199
185- // Velocidad lineal
200+ // Determine direction sign (forward/backward motion)
201+ const auto forward_direction =
202+ Eigen::Vector2d{std::cos (previous_pose.so2 ().log ()), std::sin (previous_pose.so2 ().log ())};
203+ const double dot_product = translation.dot (forward_direction);
204+ const double sign = (dot_product >= 0 ) ? 1.0 : -1.0 ;
205+
206+ // Linear velocity calculation
186207 double linear_velocity = 0.0 ;
208+
187209 if (std::abs (angle_change) > 1e-6 ) {
188- // v = ω · r
189- const double radius = distance / std::abs (angle_change);
190- linear_velocity = std::abs (angular_velocity) * radius;
210+ // Circular motion: calculate radius from chord and angle
211+ // For an arc: chord = 2r·sin(θ/2), therefore r = chord / (2·sin(θ/2))
212+ const double radius = chord_distance / (2.0 * std::sin (std::abs (angle_change) / 2.0 ));
213+
214+ // Arc length: s = r · θ
215+ const double arc_distance = radius * std::abs (angle_change);
216+
217+ // Linear velocity with direction sign
218+ linear_velocity = sign * arc_distance / delta_time;
219+
191220 } else {
192- // Movimiento rectilíneo : v = distancia/tiempo
193- linear_velocity = distance / delta_time;
221+ // Straight line motion : v = distance / time
222+ linear_velocity = sign * chord_distance / delta_time;
194223 }
195224
196225 return {linear_velocity, angular_velocity};
@@ -206,7 +235,7 @@ class VelocityDriveModel {
206235
207236 Sophus::SE2d new_pose;
208237
209- if (std::abs (omega_hat) < 1e-6 ) {
238+ if (std::abs (omega_hat) < 1e-4 ) {
210239 // Nearly straight line motion
211240 const auto translation =
212241 Eigen::Vector2d{v_hat * delta_time * std::cos (current_theta), v_hat * delta_time * std::sin (current_theta)};
0 commit comments