1use std::marker::PhantomData;
4
5use nalgebra::SVector;
6use num_traits::Zero;
7use serde::{de::DeserializeOwned, Deserialize, Serialize};
8
9use crate::cspace::CSpace;
10use crate::error::Result;
11use crate::obstacles::ObstacleSpace;
12use crate::params::FromParams;
13use crate::run::Runnable;
14use crate::scalar::Scalar;
15use crate::trajectories::{FullTrajOwned, FullTrajRefOwned, FullTrajectory};
16
17#[derive(Clone, Copy, Debug)]
19pub enum MoveGoal<X, const N: usize> {
20 New(SVector<X, N>),
22 Old(SVector<X, N>),
24 Finished,
26}
27
28#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
30#[serde(bound(
31 serialize = "X: Serialize,",
32 deserialize = "X: DeserializeOwned,",
33))]
34pub struct RobotSpecs<X: Scalar> {
35 pub robot_radius: X,
37 pub sensor_radius: X,
39}
40
41pub trait PathPlanner<X, CS, OS, const N: usize>: Sized
43where
44 X: Scalar,
45 CS: CSpace<X, N>,
46 OS: ObstacleSpace<X, CS, N>,
47{
48 type Params: Clone;
49 type State: Clone;
50
51 fn new(
65 init: SVector<X, N>,
66 goal: SVector<X, N>,
67 robot_specs: RobotSpecs<X>,
68 cspace: CS,
69 obs_space: OS,
70 params: Self::Params,
71 ) -> Result<Self>;
72
73 fn create_node(&mut self) -> &Self::State;
77
78 fn sample_node(&mut self) -> Option<&Self::State>;
82
83 fn check_sensors(&mut self);
85
86 fn get_obs_space(&self) -> &OS;
88
89 fn get_obs_space_mut(&mut self) -> &mut OS;
94
95 fn get_cspace(&self) -> &CS;
97
98 fn get_cspace_mut(&mut self) -> &mut CS;
103
104 fn check_nodes(&mut self, obs_space: bool, cspace: bool);
109
110 fn update_pose(
118 &mut self,
119 pose: SVector<X, N>,
120 nearest: bool,
121 ) -> Option<MoveGoal<X, N>>;
122
123 fn get_tree(&self) -> Vec<FullTrajRefOwned<X, CS::Traj, N>>;
125
126 fn get_current_path(&self) -> Option<FullTrajOwned<X, CS::Traj, N>>;
128
129 fn get_path_to_goal(&self) -> Option<Vec<SVector<X, N>>>;
131
132 fn get_cost_to_goal(&self) -> Option<X> {
134 let iter = self.get_path_to_goal()?;
135
136 let mut cost = X::zero();
137 let mut last_pose = self.get_last_pose().clone();
138
139 for pose in iter {
140 cost += self.get_cspace().cost(&last_pose, &pose);
141 last_pose = pose;
142 }
143
144 Some(cost)
145 }
146
147 fn get_cost_to_move_goal(&self) -> Option<X> {
148 let current_path = self.get_current_path()?;
149 let move_goal = current_path.end();
150 let pose = self.get_last_pose().clone();
151
152 Some(self.get_cspace().cost(&pose, &move_goal))
153 }
154
155 fn get_last_pose(&self) -> &SVector<X, N>;
157
158 fn get_state(&self) -> &Self::State;
160
161 fn get_goal(&self) -> &SVector<X, N>;
163
164 fn count(&self) -> usize;
166}
167
168#[derive(Serialize, Deserialize)]
169#[serde(bound(
170 serialize = "X: Serialize, PP::Params: Serialize, <CS as FromParams>::Params: Serialize, <OS as FromParams>::Params: Serialize",
171 deserialize = "X: DeserializeOwned, PP::Params: DeserializeOwned, <CS as FromParams>::Params: DeserializeOwned, <OS as FromParams>::Params: DeserializeOwned",
172))]
173pub struct PathPlannerParams<X, CS, OS, PP, const N: usize>
174where
175 X: Scalar,
176 CS: CSpace<X, N>,
177 OS: ObstacleSpace<X, CS, N>,
178 PP: PathPlanner<X, CS, OS, N>,
179{
180 pub init: SVector<X, N>,
181 pub goal: SVector<X, N>,
182 pub robot_specs: RobotSpecs<X>,
183 pub nodes_per_step: usize,
184 pub max_translation_per_step: X,
185 pub planner_params: PP::Params,
186 pub cspace: <CS as FromParams>::Params,
187 pub obstacles: <OS as FromParams>::Params,
188}
189
190impl<X, CS, OS, PP, const N: usize> Clone
191 for PathPlannerParams<X, CS, OS, PP, N>
192where
193 X: Scalar,
194 CS: CSpace<X, N>,
195 OS: ObstacleSpace<X, CS, N>,
196 PP: PathPlanner<X, CS, OS, N>,
197{
198 fn clone(&self) -> Self {
199 Self {
200 init: self.init.clone(),
201 goal: self.goal.clone(),
202 robot_specs: self.robot_specs.clone(),
203 nodes_per_step: self.nodes_per_step.clone(),
204 max_translation_per_step: self.max_translation_per_step.clone(),
205 planner_params: self.planner_params.clone(),
206 cspace: self.cspace.clone(),
207 obstacles: self.obstacles.clone(),
208 }
209 }
210}
211
212pub struct RunPathPlanner<X, CS, OS, PP, const N: usize>
214where
215 X: Scalar,
216 CS: CSpace<X, N>,
217 OS: ObstacleSpace<X, CS, N>,
218 PP: PathPlanner<X, CS, OS, N>,
219{
220 path_planner: PP,
221 nodes_per_step: usize,
222 max_translation_per_step: X,
223 phantom_data: PhantomData<(CS, OS)>,
224}
225
226impl<X, CS, OS, PP, const N: usize> FromParams
227 for RunPathPlanner<X, CS, OS, PP, N>
228where
229 X: Scalar,
230 CS: CSpace<X, N>,
231 OS: ObstacleSpace<X, CS, N>,
232 PP: PathPlanner<X, CS, OS, N>,
233{
234 type Params = PathPlannerParams<X, CS, OS, PP, N>;
235
236 fn from_params(params: Self::Params) -> Result<Self> {
237 let path_planner = PP::new(
238 params.init,
239 params.goal,
240 params.robot_specs,
241 CS::from_params(params.cspace)?,
242 OS::from_params(params.obstacles)?,
243 params.planner_params,
244 )?;
245
246 Ok(Self {
247 path_planner,
248 nodes_per_step: params.nodes_per_step,
249 max_translation_per_step: params.max_translation_per_step,
250 phantom_data: PhantomData,
251 })
252 }
253}
254
255impl<X, CS, OS, PP, const N: usize> Runnable
256 for RunPathPlanner<X, CS, OS, PP, N>
257where
258 X: Scalar,
259 CS: CSpace<X, N>,
260 OS: ObstacleSpace<X, CS, N>,
261 PP: PathPlanner<X, CS, OS, N>,
262 PP::Params: Clone,
263 PP::State: Clone,
264{
265 type State = PP::State;
266
267 fn step(&mut self) -> Option<&Self::State> {
270 let begin_count = self.path_planner.count();
272 for _ in 0..self.nodes_per_step {
273 self.path_planner.create_node();
274 log::debug!("Added node {} to tree", self.path_planner.count());
275 }
276 log::info!(
277 "Added nodes {}-{} to the tree",
278 begin_count,
279 self.path_planner.count()
280 );
281
282 let pose = self.path_planner.get_last_pose().clone();
285 if let Some(MoveGoal::Finished) = self.path_planner.update_pose(pose, false)
286 {
287 return None;
288 }
289
290 if let Some(traj) = self.path_planner.get_current_path() {
291 let target = traj.end();
292 let cspace = self.path_planner.get_cspace();
293 let cost = cspace.cost(&pose, target);
294
295 let new_pose = if cost >= self.max_translation_per_step {
296 let direction = *target - pose;
297 let unit_direction =
298 direction / cspace.cost(&SVector::zero(), &direction);
299 let direction = unit_direction * self.max_translation_per_step;
300 let new_pose = pose + direction;
301 new_pose
302 } else {
303 target.clone()
304 };
305
306 if let Some(MoveGoal::Finished) =
307 self.path_planner.update_pose(new_pose, false)
308 {
309 return None;
310 }
311 }
312 Some(self.path_planner.get_state())
313 }
314}