use std::marker::PhantomData;
use nalgebra::SVector;
use num_traits::Zero;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::cspace::CSpace;
use crate::error::Result;
use crate::obstacles::ObstacleSpace;
use crate::params::FromParams;
use crate::run::Runnable;
use crate::scalar::Scalar;
use crate::trajectories::{FullTrajOwned, FullTrajRefOwned, FullTrajectory};
#[derive(Clone, Copy, Debug)]
pub enum MoveGoal<X, const N: usize> {
New(SVector<X, N>),
Old(SVector<X, N>),
Finished,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(bound(
serialize = "X: Serialize,",
deserialize = "X: DeserializeOwned,",
))]
pub struct RobotSpecs<X: Scalar> {
pub robot_radius: X,
pub sensor_radius: X,
}
pub trait PathPlanner<X, CS, OS, const N: usize>: Sized
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
{
type Params: Clone;
type State: Clone;
fn new(
init: SVector<X, N>,
goal: SVector<X, N>,
robot_specs: RobotSpecs<X>,
cspace: CS,
obs_space: OS,
params: Self::Params,
) -> Result<Self>;
fn create_node(&mut self) -> &Self::State;
fn sample_node(&mut self) -> Option<&Self::State>;
fn check_sensors(&mut self);
fn get_obs_space(&self) -> &OS;
fn get_obs_space_mut(&mut self) -> &mut OS;
fn get_cspace(&self) -> &CS;
fn get_cspace_mut(&mut self) -> &mut CS;
fn check_nodes(&mut self, obs_space: bool, cspace: bool);
fn update_pose(
&mut self,
pose: SVector<X, N>,
nearest: bool,
) -> Option<MoveGoal<X, N>>;
fn get_tree(&self) -> Vec<FullTrajRefOwned<X, CS::Traj, N>>;
fn get_current_path(&self) -> Option<FullTrajOwned<X, CS::Traj, N>>;
fn get_path_to_goal(&self) -> Option<Vec<SVector<X, N>>>;
fn get_cost_to_goal(&self) -> Option<X> {
let iter = self.get_path_to_goal()?;
let mut cost = X::zero();
let mut last_pose = self.get_last_pose().clone();
for pose in iter {
cost += self.get_cspace().cost(&last_pose, &pose);
last_pose = pose;
}
Some(cost)
}
fn get_cost_to_move_goal(&self) -> Option<X> {
let current_path = self.get_current_path()?;
let move_goal = current_path.end();
let pose = self.get_last_pose().clone();
Some(self.get_cspace().cost(&pose, &move_goal))
}
fn get_last_pose(&self) -> &SVector<X, N>;
fn get_state(&self) -> &Self::State;
fn get_goal(&self) -> &SVector<X, N>;
fn count(&self) -> usize;
}
#[derive(Serialize, Deserialize)]
#[serde(bound(
serialize = "X: Serialize, PP::Params: Serialize, <CS as FromParams>::Params: Serialize, <OS as FromParams>::Params: Serialize",
deserialize = "X: DeserializeOwned, PP::Params: DeserializeOwned, <CS as FromParams>::Params: DeserializeOwned, <OS as FromParams>::Params: DeserializeOwned",
))]
pub struct PathPlannerParams<X, CS, OS, PP, const N: usize>
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
PP: PathPlanner<X, CS, OS, N>,
{
pub init: SVector<X, N>,
pub goal: SVector<X, N>,
pub robot_specs: RobotSpecs<X>,
pub nodes_per_step: usize,
pub max_translation_per_step: X,
pub planner_params: PP::Params,
pub cspace: <CS as FromParams>::Params,
pub obstacles: <OS as FromParams>::Params,
}
impl<X, CS, OS, PP, const N: usize> Clone
for PathPlannerParams<X, CS, OS, PP, N>
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
PP: PathPlanner<X, CS, OS, N>,
{
fn clone(&self) -> Self {
Self {
init: self.init.clone(),
goal: self.goal.clone(),
robot_specs: self.robot_specs.clone(),
nodes_per_step: self.nodes_per_step.clone(),
max_translation_per_step: self.max_translation_per_step.clone(),
planner_params: self.planner_params.clone(),
cspace: self.cspace.clone(),
obstacles: self.obstacles.clone(),
}
}
}
pub struct RunPathPlanner<X, CS, OS, PP, const N: usize>
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
PP: PathPlanner<X, CS, OS, N>,
{
path_planner: PP,
nodes_per_step: usize,
max_translation_per_step: X,
phantom_data: PhantomData<(CS, OS)>,
}
impl<X, CS, OS, PP, const N: usize> FromParams
for RunPathPlanner<X, CS, OS, PP, N>
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
PP: PathPlanner<X, CS, OS, N>,
{
type Params = PathPlannerParams<X, CS, OS, PP, N>;
fn from_params(params: Self::Params) -> Result<Self> {
let path_planner = PP::new(
params.init,
params.goal,
params.robot_specs,
CS::from_params(params.cspace)?,
OS::from_params(params.obstacles)?,
params.planner_params,
)?;
Ok(Self {
path_planner,
nodes_per_step: params.nodes_per_step,
max_translation_per_step: params.max_translation_per_step,
phantom_data: PhantomData,
})
}
}
impl<X, CS, OS, PP, const N: usize> Runnable
for RunPathPlanner<X, CS, OS, PP, N>
where
X: Scalar,
CS: CSpace<X, N>,
OS: ObstacleSpace<X, CS, N>,
PP: PathPlanner<X, CS, OS, N>,
PP::Params: Clone,
PP::State: Clone,
{
type State = PP::State;
fn step(&mut self) -> Option<&Self::State> {
let begin_count = self.path_planner.count();
for _ in 0..self.nodes_per_step {
self.path_planner.create_node();
log::debug!("Added node {} to tree", self.path_planner.count());
}
log::info!(
"Added nodes {}-{} to the tree",
begin_count,
self.path_planner.count()
);
let pose = self.path_planner.get_last_pose().clone();
if let Some(MoveGoal::Finished) = self.path_planner.update_pose(pose, false)
{
return None;
}
if let Some(traj) = self.path_planner.get_current_path() {
let target = traj.end();
let cspace = self.path_planner.get_cspace();
let cost = cspace.cost(&pose, target);
let new_pose = if cost >= self.max_translation_per_step {
let direction = *target - pose;
let unit_direction =
direction / cspace.cost(&SVector::zero(), &direction);
let direction = unit_direction * self.max_translation_per_step;
let new_pose = pose + direction;
new_pose
} else {
target.clone()
};
if let Some(MoveGoal::Finished) =
self.path_planner.update_pose(new_pose, false)
{
return None;
}
}
Some(self.path_planner.get_state())
}
}