-
Notifications
You must be signed in to change notification settings - Fork 34
Integrated velocity motion model #501
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
base: fbattocchia/increase-propagation-rate
Are you sure you want to change the base?
Changes from 2 commits
4f5d8d4
3d98bfe
1cee41d
554ea7b
49424a0
4284785
5c61f56
1305df6
ae399ae
0ea2fe3
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,8 +12,8 @@ | |||||
| // See the License for the specific language governing permissions and | ||||||
| // limitations under the License. | ||||||
|
|
||||||
| #ifndef BELUGA_MOTION_ACKERMAN_DRIVE_MODEL_HPP | ||||||
| #define BELUGA_MOTION_ACKERMAN_DRIVE_MODEL_HPP | ||||||
| #ifndef BELUGA_MOTION_ACKERMANN_DRIVE_MODEL_HPP | ||||||
| #define BELUGA_MOTION_ACKERMANN_DRIVE_MODEL_HPP | ||||||
|
|
||||||
| #include <chrono> | ||||||
| #include <random> | ||||||
|
|
@@ -36,9 +36,8 @@ | |||||
| namespace beluga { | ||||||
|
|
||||||
| /// Velocity components for differential drive motion model. | ||||||
| struct Velocity { | ||||||
| struct AckermannControls { | ||||||
| double v; ///< Linear velocity (m/s) | ||||||
| double w; ///< Angular velocity (rad/s) | ||||||
| double phi; ///< Steering angle (rad) | ||||||
| }; | ||||||
|
|
||||||
|
|
@@ -47,64 +46,61 @@ struct Velocity { | |||||
| * See Probabilistic Robotics \cite thrun2005probabilistic Chapter 5.3, particularly table 5.3. | ||||||
| */ | ||||||
| struct AckermannDriveModelParam { | ||||||
| /// Rotational noise from rotational velocity | ||||||
| /// Steering noise from steering angle | ||||||
| /** | ||||||
| * How much rotational noise is generated by the rotational velocity. | ||||||
| * Also known as `alpha1 in the differential drive model param`. | ||||||
| * How much steering noise is generated by the steering angle. | ||||||
| * Also known as `alpha1 in the Ackermann drive model param`. | ||||||
| */ | ||||||
| double rotation_noise_from_rotation; | ||||||
| /// Rotational noise from translation velocity | ||||||
| double steering_noise_from_steering; | ||||||
| /// Steering noise from linear velocity | ||||||
| /** | ||||||
| * How much rotational noise is generated by the linear velocity. | ||||||
| * Also known as `alpha2 in the differential drive model param`. | ||||||
| * How much steering noise is generated by the linear velocity. | ||||||
| * Also known as `alpha2 in the Ackermann drive model param`. | ||||||
| */ | ||||||
| double rotation_noise_from_translation; | ||||||
| /// Translational noise from translation velocity | ||||||
| double steering_noise_from_velocity; | ||||||
| /// Velocity noise from linear velocity | ||||||
| /** | ||||||
| * How much translational noise is generated by the linear velocity. | ||||||
| * Also known as `alpha3 in the differential drive model param`. | ||||||
| * How much velocity noise is generated by the linear velocity. | ||||||
| * Also known as `alpha3 in the Ackermann drive model param`. | ||||||
| */ | ||||||
| double translation_noise_from_translation; | ||||||
| /// Translational noise from rotational velocity | ||||||
| double velocity_noise_from_velocity; | ||||||
| /// Velocity noise from steering angle | ||||||
| /** | ||||||
| * How much translational noise is generated by the rotational velocity. | ||||||
| * Also known as `alpha4 in the differential drive model param`. | ||||||
| * How much velocity noise is generated by the steering angle. | ||||||
| * Also known as `alpha4 in the Ackermann drive model param`. | ||||||
| */ | ||||||
| double translation_noise_from_rotation; | ||||||
| /// Additional orientation noise from translational velocity | ||||||
| double velocity_noise_from_steering; | ||||||
| /// Additional orientation noise from linear velocity | ||||||
| /** | ||||||
| * How much extra orientation noise is generated by the linear velocity. | ||||||
| * Also known as `alpha6`. | ||||||
| */ | ||||||
| double orientation_noise_from_translation; | ||||||
| /// Additional orientation noise from rotational velocity | ||||||
| double orientation_noise_from_velocity; | ||||||
| /// Additional orientation noise from steering angle | ||||||
| /** | ||||||
| * How much extra orientation noise is generated by the rotational velocity. | ||||||
| * How much extra orientation noise is generated by the steering angle. | ||||||
| * Also known as `alpha7`. | ||||||
| */ | ||||||
| double orientation_noise_from_rotation; | ||||||
| double orientation_noise_from_steering; | ||||||
|
|
||||||
|
Collaborator
Author
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. @glpuga The
Collaborator
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. As we discussed in the meeting yesterday, let's keep them. From the arguments in Probabilistic Roboticis, they have the same reason to exist in our hybrid model as they do in the diff model. |
||||||
| /// Threshold for distinguishing between straight-line and circular motion. | ||||||
| /** | ||||||
| * Below this threshold (~0.57 degrees), motion is treated as straight-line to avoid | ||||||
| * numerical instabilities in radius calculations for nearly-zero angular velocities. | ||||||
| */ | ||||||
| static constexpr double small_angle_threshold = 0.01; | ||||||
|
|
||||||
| /// Length of the robot (meters). | ||||||
| /// Distance between the rear and front wheel axles (meters). | ||||||
| /** | ||||||
| * See \cite Localization and Mapping in Local Occupancy Grid Maps: Simulation | ||||||
| * in Ackerman model mobile robot by Ronald A. Cardenas , Jasper W. Huanay | ||||||
| * in Ackermann model mobile robot by Ronald A. Cardenas , Jasper W. Huanay | ||||||
| * and Ivan Calle | ||||||
| */ | ||||||
| double wheelbase; | ||||||
| }; | ||||||
|
|
||||||
| /// Sampled velocity model for a differential drive. | ||||||
| /// Velocity model for a Ackermann drive. | ||||||
| /** | ||||||
| * Supports 2D and (flattened) 3D state types. | ||||||
| * This class satisfies \ref MotionModelPage. | ||||||
| * | ||||||
| * The model is and adaptation using the single track kinematic model | ||||||
|
Collaborator
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.
Suggested change
|
||||||
| * and the noise models of Probabilistic Robotics. | ||||||
| * The model serves for any drive that can be simplified to a Single Track vehicle: | ||||||
| * ackermann, bicycle, tri-cycle, etc. | ||||||
| * See Probabilistic Robotics \cite thrun2005probabilistic Chapter 5.3. | ||||||
| * | ||||||
|
Comment on lines
+104
to
+105
Collaborator
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. Explain here that the model is and adaptation using the single track kinematic model and the noise models of Probabilistic Robotics.
Collaborator
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. Notice that this model serves for any drive that can be simplified to a Single Track vehicle: ackermann, bicycle, tri-cycle, etc. |
||||||
| * \tparam StateType Type for particle's state. Either Sophus::SE2d or Sophus::SE3d. | ||||||
|
|
@@ -161,28 +157,28 @@ class AckermannDriveModel { | |||||
| const Sophus::SE2d& previous_pose, | ||||||
| std::chrono::duration<double> delta_time) const { | ||||||
| // Calculate velocities from poses | ||||||
| const auto velocity = calculate_velocities(pose, previous_pose, delta_time); | ||||||
| const auto controls = calculate_velocities(pose, previous_pose, delta_time); | ||||||
|
|
||||||
| // Velocity noise parameters (following velocity motion model from Probabilistic Robotics) | ||||||
| // Use temporary distributions to safely extract param_type objects | ||||||
| const auto linear_velocity_distribution = std::normal_distribution<double>{ | ||||||
| velocity.v, std::sqrt( | ||||||
| params_.translation_noise_from_translation * velocity.v * velocity.v + | ||||||
| params_.translation_noise_from_rotation * velocity.w * velocity.w)}; | ||||||
| controls.v, std::sqrt( | ||||||
| params_.velocity_noise_from_velocity * controls.v * controls.v + | ||||||
| params_.velocity_noise_from_steering * controls.phi * controls.phi)}; | ||||||
| const auto linear_velocity_params = linear_velocity_distribution.param(); | ||||||
|
|
||||||
| const auto steering_angle_distribution = std::normal_distribution<double>{ | ||||||
| velocity.phi, std::sqrt( | ||||||
| params_.rotation_noise_from_translation * velocity.v * velocity.v + | ||||||
| params_.rotation_noise_from_rotation * velocity.phi * velocity.phi)}; | ||||||
| controls.phi, std::sqrt( | ||||||
| params_.steering_noise_from_velocity * controls.v * controls.v + | ||||||
| params_.steering_noise_from_steering * controls.phi * controls.phi)}; | ||||||
| const auto steering_angle_params = steering_angle_distribution.param(); | ||||||
|
|
||||||
| // Additional orientation noise (gamma_hat) using rotation parameters | ||||||
| const auto gamma_distribution = std::normal_distribution<double>{ | ||||||
| 0.0, // zero mean | ||||||
| std::sqrt( | ||||||
| params_.orientation_noise_from_translation * velocity.v * velocity.v + | ||||||
| params_.orientation_noise_from_rotation * velocity.w * velocity.w)}; | ||||||
| params_.orientation_noise_from_velocity * controls.v * controls.v + | ||||||
| params_.orientation_noise_from_steering * controls.phi * controls.phi)}; | ||||||
| const auto gamma_params = gamma_distribution.param(); | ||||||
|
|
||||||
| return [=](const auto& state, auto& gen) { | ||||||
|
|
@@ -200,7 +196,7 @@ class AckermannDriveModel { | |||||
| } | ||||||
|
|
||||||
| /// Calculate linear and angular velocities from two poses and delta time | ||||||
| Velocity calculate_velocities( | ||||||
| AckermannControls calculate_velocities( | ||||||
| const Sophus::SE2d& pose, | ||||||
| const Sophus::SE2d& previous_pose, | ||||||
| std::chrono::duration<double> delta_time) const { | ||||||
|
|
@@ -210,20 +206,20 @@ class AckermannDriveModel { | |||||
| const auto translation = pose.translation() - previous_pose.translation(); | ||||||
| const double chord_distance = translation.norm(); | ||||||
|
|
||||||
| const auto relative_transform = previous_pose.inverse() * pose; | ||||||
| // Angular velocity from orientation change | ||||||
| const auto angular_change = pose.so2() * previous_pose.so2().inverse(); | ||||||
| const auto angular_change = relative_transform.so2(); | ||||||
|
Collaborator
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. 💯 |
||||||
| const double angle_change = angular_change.log(); | ||||||
| const double angular_velocity = angle_change / delta_t_sec; | ||||||
|
|
||||||
| // Determine direction sign (forward/backward motion) | ||||||
| const auto relative_transform = previous_pose.inverse() * pose; | ||||||
| const double dx = relative_transform.translation().x(); | ||||||
| const double sign = (dx >= 0.0) ? 1.0 : -1.0; | ||||||
|
|
||||||
| // Linear velocity calculation | ||||||
| double linear_velocity = 0.0; | ||||||
|
|
||||||
| if (std::abs(angle_change) > params_.small_angle_threshold) { | ||||||
| double steering_angle = 0.0; | ||||||
| if (std::abs(angle_change) > small_angle_threshold) { | ||||||
| // Circular motion: calculate radius from chord and angle | ||||||
| // For an arc: chord = 2r·sin(θ/2), therefore r = chord / (2·sin(θ/2)) | ||||||
| const double radius = chord_distance / (2.0 * std::sin(std::abs(angle_change) / 2.0)); | ||||||
|
|
@@ -233,20 +229,15 @@ class AckermannDriveModel { | |||||
|
|
||||||
| // Linear velocity with direction sign | ||||||
| linear_velocity = sign * arc_distance / delta_t_sec; | ||||||
|
|
||||||
| if (std::abs(linear_velocity) > small_angle_threshold) { | ||||||
| const double ratio = params_.wheelbase * angular_velocity / linear_velocity; | ||||||
| steering_angle = std::atan(ratio); | ||||||
| } | ||||||
|
Comment on lines
+231
to
+235
Collaborator
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. I need to think this, the fact that we need to guard this is flagging me that there's an problem with how we are calculating motion. |
||||||
| } else { | ||||||
| // Straight line motion: v = distance / time | ||||||
| linear_velocity = sign * chord_distance / delta_t_sec; | ||||||
| } | ||||||
|
|
||||||
| double steering_angle = 0.0; | ||||||
|
|
||||||
| if (std::abs(linear_velocity) > params_.small_angle_threshold) { | ||||||
| const double ratio = params_.wheelbase * angular_velocity / linear_velocity; | ||||||
| steering_angle = std::atan(ratio); | ||||||
| } | ||||||
|
|
||||||
| return Velocity{linear_velocity, angular_velocity, steering_angle}; | ||||||
| return AckermannControls{linear_velocity, steering_angle}; | ||||||
| } | ||||||
| /// Apply velocity motion model to get new pose | ||||||
| Sophus::SE2d apply_velocity_motion( | ||||||
|
|
@@ -261,7 +252,7 @@ class AckermannDriveModel { | |||||
|
|
||||||
| Sophus::SE2d new_pose; | ||||||
|
|
||||||
| if (std::abs(omega_hat) < params_.small_angle_threshold) { | ||||||
| if (std::abs(omega_hat) < small_angle_threshold) { | ||||||
| // Nearly straight line motion | ||||||
| const auto translation = | ||||||
| Eigen::Vector2d{v_hat * delta_t_sec * std::cos(current_theta), v_hat * delta_t_sec * std::sin(current_theta)}; | ||||||
|
|
@@ -277,14 +268,20 @@ class AckermannDriveModel { | |||||
| const auto new_theta = current_theta + omega_hat * delta_t_sec + gamma_hat * delta_t_sec; | ||||||
| new_pose = Sophus::SE2d{Sophus::SO2d{new_theta}, state.translation() + translation}; | ||||||
| } | ||||||
|
|
||||||
| return new_pose; | ||||||
| } | ||||||
|
|
||||||
| param_type params_; | ||||||
|
|
||||||
| /// Threshold for distinguishing between straight-line and circular motion. | ||||||
| /** | ||||||
| * Below this threshold (~0.57 degrees), motion is treated as straight-line to avoid | ||||||
| * numerical instabilities in radius calculations for nearly-zero angular velocities. | ||||||
| */ | ||||||
| static constexpr double small_angle_threshold = 0.01; | ||||||
| }; | ||||||
|
|
||||||
| /// Alias for a 2D Ackerman drive model, for convenience. | ||||||
| /// Alias for a 2D Ackermann drive model, for convenience. | ||||||
| using AckermannDriveModel2d = AckermannDriveModel<Sophus::SE2d>; | ||||||
| } // namespace beluga | ||||||
|
|
||||||
|
|
||||||
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.
@fbattocchia 💯