use crate::error::ControlError;
use crate::kinematics::BodyTwist;
use crate::linear_algebra::Vector2D;
use crate::scalar::Numeric;
use crate::spatial::SE2;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Curvature<T: Numeric = f64> {
value: T,
}
impl<T: Numeric> Curvature<T> {
#[inline]
#[must_use]
pub fn new(value: T) -> Self {
Self { value }
}
#[inline]
#[must_use]
pub fn value(self) -> T {
self.value
}
#[inline]
#[must_use]
pub fn to_body_twist(self, forward_speed: T) -> BodyTwist<T> {
BodyTwist::new(forward_speed, forward_speed * self.value)
}
}
pub fn pure_pursuit_curvature<T: Numeric>(
pose: SE2<T>,
lookahead_point: Vector2D<T>,
lookahead_distance: T,
) -> Result<Curvature<T>, ControlError> {
if !lookahead_distance.is_finite() || lookahead_distance <= T::ZERO {
return Err(ControlError::NonPositiveLookaheadDistance);
}
if !lookahead_point.is_finite() {
return Err(ControlError::NonFinite);
}
let [_forward, lateral] = pose.inverse().act(lookahead_point).into_array();
let curvature = (T::TWO * lateral) / (lookahead_distance * lookahead_distance);
Ok(Curvature::new(curvature))
}