path_planning/cspace/leader_follower/
polar.rs

1/* Copyright (C) 2020 Dylan Staatz - All Rights Reserved. */
2
3use nalgebra::constraint::{SameNumberOfRows, ShapeConstraint};
4use nalgebra::storage::Storage;
5use nalgebra::{Const, Dim, RealField, SVector, Vector};
6use num_traits::Float;
7use rand::distributions::{uniform::SampleUniform, Distribution};
8use rand::{thread_rng, SeedableRng};
9use serde::{de::DeserializeOwned, Deserialize, Serialize};
10
11use crate::error::{InvalidParamError, Result};
12use crate::params::FromParams;
13use crate::rng::{LinearCoordinates, RNG};
14use crate::scalar::Scalar;
15use crate::trajectories::{EuclideanTrajectory, FullTraj};
16use crate::util::bounds::Bounds;
17use crate::util::math::{atan2, unit_d_ball_vol};
18
19use super::super::CSpace;
20use super::LeaderFollowerCSpace;
21
22pub const D: usize = 2;
23pub const N: usize = D * 2;
24
25#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
26#[serde(bound(
27  serialize = "X: Serialize",
28  deserialize = "X: DeserializeOwned"
29))]
30pub struct LeaderFollowerPolarSpaceParams<X: Scalar> {
31  pub bounds: Bounds<X, D>,
32  pub seed: Option<u64>,
33  pub sensor_range: (X, X),
34}
35
36/// A space with the state vector of [x1, y1, r2, theta2]
37///
38/// x1: x-coordinate of the leader robot
39/// y1: y-coordinate of the leader robot
40/// r2: radius polar coordinate offset of the follower relative to the leader
41/// theta2: angle off of x-axis polar coordinate offset of the follower relative
42/// to the leader
43pub struct LeaderFollowerPolarSpace<X>
44where
45  X: Scalar + SampleUniform,
46{
47  bounds: Bounds<X, D>,
48  volume: X,
49  rng: RNG,
50  distribution: LinearCoordinates<X, N>,
51  intial_sensor_range: (X, X),
52  sensor_range: (X, X),
53  sensor_range_squared: (X, X),
54}
55
56impl<X> LeaderFollowerPolarSpace<X>
57where
58  X: Scalar + SampleUniform,
59{
60  pub fn new(
61    bounds: Bounds<X, D>,
62    rng: RNG,
63    sensor_range: (X, X),
64  ) -> Result<Self> {
65    debug_assert_eq!(D * 2, N);
66
67    // Validate bounds
68    if !bounds.is_valid() {
69      Err(InvalidParamError {
70        parameter_name: "bounds",
71        parameter_value: format!("{:?}", bounds),
72      })?;
73    }
74
75    // Validate sensor range
76    if !(sensor_range.0 < sensor_range.1) {
77      Err(InvalidParamError {
78        parameter_name: "sensor_range",
79        parameter_value: format!("{:?}", sensor_range),
80      })?;
81    }
82
83    let sensor_range_squared = (
84      sensor_range.0 * sensor_range.0,
85      sensor_range.1 * sensor_range.1,
86    );
87
88    let sensor_space_volume = (sensor_range_squared.1 * unit_d_ball_vol(D))
89      - (sensor_range_squared.0 * unit_d_ball_vol(D));
90    let volume = bounds.volume() * sensor_space_volume;
91
92    let mins = SVector::<X, N>::from([
93      bounds.mins[0],
94      bounds.mins[1],
95      X::zero(),
96      X::zero(),
97    ]);
98
99    let maxs = SVector::<X, N>::from([
100      bounds.maxs[0],
101      bounds.maxs[1],
102      X::one(),
103      X::two_pi(),
104    ]);
105
106    let distribution = LinearCoordinates::new(mins, maxs);
107
108    Ok(Self {
109      bounds,
110      volume,
111      rng,
112      distribution,
113      intial_sensor_range: sensor_range,
114      sensor_range,
115      sensor_range_squared,
116    })
117  }
118
119  pub fn intial_sensor_range(&self) -> (X, X) {
120    self.intial_sensor_range
121  }
122
123  pub fn get_sensor_range(&self) -> (X, X) {
124    self.sensor_range
125  }
126
127  pub fn set_sensor_range(&mut self, sensor_range: (X, X)) -> Option<()> {
128    if sensor_range.0 < sensor_range.1 {
129      // Valid
130      self.sensor_range = sensor_range;
131      self.sensor_range_squared = (
132        sensor_range.0 * sensor_range.0,
133        sensor_range.1 * sensor_range.1,
134      );
135      Some(())
136    } else {
137      // Invalid value
138      None
139    }
140  }
141}
142
143impl<X> LeaderFollowerCSpace<X, D, N> for LeaderFollowerPolarSpace<X>
144where
145  X: Scalar + SampleUniform,
146{
147  // Default implementation okay
148}
149
150impl<X> CSpace<X, N> for LeaderFollowerPolarSpace<X>
151where
152  X: Scalar + SampleUniform,
153{
154  type Traj = EuclideanTrajectory<X, N>;
155
156  fn volume(&self) -> X {
157    self.volume
158  }
159
160  fn cost<R1, R2, S1, S2>(
161    &self,
162    a: &Vector<X, R1, S1>,
163    b: &Vector<X, R2, S2>,
164  ) -> X
165  where
166    X: Scalar,
167    R1: Dim,
168    R2: Dim,
169    S1: Storage<X, R1>,
170    S2: Storage<X, R2>,
171    ShapeConstraint: SameNumberOfRows<R1, R2>
172      + SameNumberOfRows<R1, Const<N>>
173      + SameNumberOfRows<R2, Const<N>>,
174  {
175    a.metric_distance(b)
176  }
177
178  fn trajectory<S1, S2>(
179    &self,
180    start: Vector<X, Const<N>, S1>,
181    end: Vector<X, Const<N>, S2>,
182  ) -> Option<FullTraj<X, Self::Traj, S1, S2, N>>
183  where
184    X: Scalar,
185    S1: Storage<X, Const<N>>,
186    S2: Storage<X, Const<N>>,
187  {
188    Some(FullTraj::new(start, end, EuclideanTrajectory::new()))
189  }
190
191  fn is_free<S>(&self, a: &Vector<X, Const<N>, S>) -> bool
192  where
193    S: Storage<X, Const<N>>,
194  {
195    let leader_abs = a.fixed_rows::<D>(0);
196    let follower_abs = a.fixed_rows::<D>(D);
197
198    if !self.bounds.within(&follower_abs) {
199      return false;
200    }
201
202    // Determine distance between leader and follower
203    let r2 = leader_abs.metric_distance(&follower_abs);
204    self.sensor_range.0 <= r2 && r2 <= self.sensor_range.1
205  }
206
207  fn saturate(&self, a: &mut SVector<X, N>, b: &SVector<X, N>, delta: X) {
208    // log::info!(
209    //   "saturate: {:?}, {:?}, {:?}",
210    //   <[X; N]>::from(a.clone_owned()),
211    //   <[X; N]>::from(b.clone_owned()),
212    //   delta
213    // );
214
215    let delta = delta / (X::one() + X::one());
216
217    // Saturate leader to be delta away
218    let mut a_lead_mut = a.fixed_rows_mut::<D>(0);
219    let b_lead = b.fixed_rows::<D>(0);
220
221    // println!("a_lead_mut: {:?}", <[X; D]>::from(a_lead_mut.clone_owned()));
222    // println!("b_lead: {:?}", <[X; D]>::from(b_lead.clone_owned()));
223
224    let lead_scale = delta / a_lead_mut.metric_distance(&b_lead);
225
226    a_lead_mut.set_column(0, &(&a_lead_mut - &b_lead));
227    a_lead_mut.set_column(0, &(&a_lead_mut * lead_scale));
228    a_lead_mut.set_column(0, &(&a_lead_mut + &b_lead));
229
230    // println!("a_lead_mut: {:?}", <[X; D]>::from(a_lead_mut.clone_owned()));
231    // println!();
232
233    // Saturate follower to be delta away
234    let a_lead = a.fixed_rows::<D>(0);
235    let a_fol = a.fixed_rows::<D>(D);
236
237    // println!("a_lead: {:?}", <[X; D]>::from(a_lead.clone_owned()));
238    // println!("a_fol: {:?}", <[X; D]>::from(a_fol.clone_owned()));
239
240    // Modifiy b follower to be an offset of the a_lead
241    let mut b = b.clone(); // Local copy of b for temporary modifications
242    let mut b_lead_mut = b.fixed_rows_mut::<D>(0);
243    b_lead_mut.set_column(0, &a_lead); // A leader, B follower
244
245    // println!("b: {:?}", <[X; N]>::from(b.clone_owned()));
246
247    let mut b_rel = abs_to_rel(&b); // B follower relative to new A leader
248
249    // println!("b_rel: {:?}", <[X; N]>::from(b_rel.clone_owned()));
250
251    // Narrow down to polar coordinates only
252    let mut b_fol_rel_mut = b_rel.fixed_rows_mut::<D>(D).into_owned();
253    let a_fol_rel = cartesian_to_polar(&a_fol);
254
255    // Bounds
256    let mut delta = delta;
257    if self.sensor_range.1 < b_fol_rel_mut[0] {
258      delta -= b_fol_rel_mut[0] - self.sensor_range.1;
259      b_fol_rel_mut[0] = self.sensor_range.1;
260    }
261    if b_fol_rel_mut[0] < self.sensor_range.0 {
262      delta -= self.sensor_range.0 - b_fol_rel_mut[0];
263      b_fol_rel_mut[0] = self.sensor_range.0;
264    }
265
266    if X::zero() < delta {
267      let mut star_fol_rel = saturate_polar(&a_fol_rel, &b_fol_rel_mut, delta);
268
269      log::debug!(
270        "sensor_range: {:?}, star_fol_rel: {:?}",
271        self.sensor_range,
272        <[X; D]>::from(star_fol_rel)
273      );
274
275      // bound rho
276      if self.sensor_range.1 < star_fol_rel[0] {
277        log::warn!("rho too big: [{}, {}]", star_fol_rel[0], star_fol_rel[1]);
278        star_fol_rel[0] = self.sensor_range.1;
279      }
280      if star_fol_rel[0] < self.sensor_range.0 {
281        log::warn!("rho too small: [{}, {}]", star_fol_rel[0], star_fol_rel[1]);
282        star_fol_rel[0] = self.sensor_range.0;
283      }
284
285      // Set a in relative polar coordinates
286      let mut a_fol_mut = a.fixed_rows_mut::<D>(D);
287      a_fol_mut.set_column(0, &star_fol_rel);
288    } else {
289      // Set a in relative polar coordinates
290      let mut a_fol_mut = a.fixed_rows_mut::<D>(D);
291      a_fol_mut.set_column(0, &b_fol_rel_mut);
292    }
293
294    // Convert relative polar coordinates back to absolute
295    *a = rel_to_abs(&a);
296  }
297
298  fn sample(&mut self) -> SVector<X, N> {
299    let mut sample = self.distribution.sample(&mut self.rng);
300
301    let a_2 = self.sensor_range_squared.0;
302    let b_2 = self.sensor_range_squared.1;
303    sample[2] = <X as Float>::sqrt(sample[2] * (b_2 - a_2) + a_2);
304
305    rel_to_abs(&sample)
306  }
307}
308
309impl<X> FromParams for LeaderFollowerPolarSpace<X>
310where
311  X: Scalar + SampleUniform,
312{
313  type Params = LeaderFollowerPolarSpaceParams<X>;
314  fn from_params(params: Self::Params) -> Result<Self> {
315    let rng = match params.seed {
316      Some(seed) => RNG::seed_from_u64(seed),
317      None => RNG::from_rng(thread_rng())?,
318    };
319
320    LeaderFollowerPolarSpace::new(params.bounds, rng, params.sensor_range)
321  }
322}
323
324/// Converts [x1, y1, r2, theta2] to [x1, y1, x2, y2]
325///
326/// Inverse of [`abs_to_rel`]
327pub fn rel_to_abs<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, N>
328where
329  X: RealField + Copy,
330  R: Dim,
331  S: Storage<X, R>,
332  ShapeConstraint: SameNumberOfRows<R, Const<N>>,
333{
334  let x1 = v[0];
335  let y1 = v[1];
336  let x2 = v[0] + (v[2] * v[3].cos());
337  let y2 = v[1] + (v[2] * v[3].sin());
338
339  [x1, y1, x2, y2].into()
340}
341
342/// Converts [r, theta] to [x, y]
343pub fn polar_to_cartesian<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, D>
344where
345  X: RealField + Copy,
346  R: Dim,
347  S: Storage<X, R>,
348  ShapeConstraint: SameNumberOfRows<R, Const<D>>,
349{
350  let x = v[0] * v[1].cos();
351  let y = v[0] * v[1].sin();
352  [x, y].into()
353}
354
355/// Converts [x1, y1, x2, y2] to [x1, y1, r2, theta2]
356///
357/// Inverse of [`rel_to_abs`]
358pub fn abs_to_rel<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, N>
359where
360  X: RealField + Copy,
361  R: Dim,
362  S: Storage<X, R>,
363  ShapeConstraint: SameNumberOfRows<R, Const<N>>,
364{
365  let x1 = v[0];
366  let y1 = v[1];
367  let x2 = v[2] - x1; // offset cartesian
368  let y2 = v[3] - y1; // offset cartesian
369
370  let r2 = (x2 * x2 + y2 * y2).sqrt();
371  let theta2 = atan2(y2, x2).unwrap_or(X::zero());
372
373  [x1, y1, r2, bound_theta(theta2)].into()
374}
375
376/// Converts [x, y] to [r, theta]
377pub fn cartesian_to_polar<X, R, S>(v: &Vector<X, R, S>) -> SVector<X, D>
378where
379  X: RealField + Copy,
380  R: Dim,
381  S: Storage<X, R>,
382  ShapeConstraint: SameNumberOfRows<R, Const<D>>,
383{
384  let r = (v[0] * v[0] + v[1] * v[1]).sqrt();
385  let theta = atan2(v[1], v[0]).unwrap_or(X::zero());
386  [r, bound_theta(theta)].into()
387}
388
389fn saturate_polar<X, R1, S1, R2, S2>(
390  a: &Vector<X, R1, S1>,
391  b: &Vector<X, R2, S2>,
392  delta: X,
393) -> SVector<X, D>
394where
395  X: RealField + Copy,
396  R1: Dim,
397  R2: Dim,
398  S1: Storage<X, R1>,
399  S2: Storage<X, R2>,
400  ShapeConstraint: SameNumberOfRows<R1, R2>
401    + SameNumberOfRows<R1, Const<D>>
402    + SameNumberOfRows<R2, Const<D>>,
403{
404  let r_a = a[0];
405  let theta_a = a[1];
406  let r_b = b[0];
407  let theta_b = b[1];
408
409  let (r_star, theta_star) =
410    saturate_polar_zero(r_a, bound_theta(theta_a - theta_b), r_b, delta);
411  [r_star, bound_theta(theta_star + theta_b)].into()
412}
413
414/// Assumes theta_b is 0
415pub fn saturate_polar_zero<X>(r_a: X, theta_a: X, r_b: X, delta: X) -> (X, X)
416where
417  X: RealField + Copy,
418{
419  let two = X::one() + X::one();
420
421  log::debug!("delta: {:?}", delta);
422
423  // Assert the correct bounds
424  assert!(X::zero() < delta);
425  assert!(X::zero() < r_a);
426  assert!(X::zero() < r_b);
427  assert!(X::zero() <= theta_a && theta_a < X::two_pi());
428
429  // Special case when point a and b are at the same angle
430  if theta_a == X::zero() {
431    let r_star = match r_b - r_a {
432      x if x > delta => r_a + delta,
433      x if -delta < x => r_a - delta,
434      _ => r_a,
435    };
436    return (r_star, X::zero());
437  }
438
439  // Determine which direction we should rotate from theta_b => theta_star => theta_a
440  let clockwise = X::pi() < theta_a;
441  log::debug!("clockwise: {:?}", clockwise);
442
443  let (theta_a, delta) = if clockwise {
444    (theta_a - X::two_pi(), -delta)
445  } else {
446    (theta_a, delta)
447  };
448
449  // theta_a is now on the domain [-pi, pi] still representing the same angle
450
451  // Determine spiral function
452  let m = (r_a - r_b) / theta_a;
453  let m_2 = m.powi(2);
454  let r_0 = r_b; // should be -m * theta_b + r_b, but theta_b is assumed to be 0
455  let r = |theta: X| m * theta + r_0;
456
457  // Indefinite Integral of spiral distance function
458  let integral = |theta: X| {
459    let r_theta = r(theta);
460    let temp = (r_theta.powi(2) + m_2).sqrt();
461
462    let term1 = (r_theta * temp) / (two * m);
463    let term2 = (m / two) * (temp + r_theta).ln();
464    term1 + term2
465  };
466
467  // The function the find the roots of
468  let constant = -integral(X::zero()) - delta;
469  let f = |theta: X| integral(theta) + constant;
470
471  // The derivative of the function we are finding the roots of
472  // (i.e. the spiral distance function)
473  let fd = |theta: X| (r(theta).powi(2) + m_2).sqrt();
474
475  // Newtons method
476  let mut theta_star = delta * two / (r_a + r_b);
477  let iterations = 2;
478  for _ in 0..iterations {
479    theta_star -= f(theta_star) / fd(theta_star);
480  }
481
482  // Bound theta_star to be between theta_a and theta_b (0.0)
483  if clockwise {
484    assert!(theta_a < X::zero());
485    theta_star = theta_star.max(theta_a);
486    theta_star = theta_star.min(X::zero());
487  } else {
488    assert!(X::zero() < theta_a);
489    theta_star = theta_star.max(X::zero());
490    theta_star = theta_star.min(theta_a);
491  }
492
493  let r_star = r(theta_star);
494
495  // Return and bound theta_star
496  (r_star, bound_theta(theta_star))
497}
498
499fn bound_theta<X>(mut theta: X) -> X
500where
501  X: RealField + Copy,
502{
503  // Lower bound (Inclusive)
504  while theta < X::zero() {
505    theta += X::two_pi()
506  }
507  // Upper bound (Exclusive)
508  while X::two_pi() <= theta {
509    theta -= X::two_pi()
510  }
511  theta
512}
513
514#[cfg(test)]
515mod tests {
516
517  use super::*;
518
519  fn rel_eq<X: RealField + Copy>(a: X, b: X) -> bool {
520    let abs_difference = (a - b).abs();
521    println!("{:?}", abs_difference);
522    abs_difference < X::from_subset(&10.0).powi(-3)
523  }
524
525  #[test]
526  fn test_polar_saturate() {
527    let params = LeaderFollowerPolarSpaceParams {
528      bounds: Bounds::new([-5.0, -5.0].into(), [5.0, 5.0].into()),
529      seed: Some(0x1234_5678_1234_5674),
530      sensor_range: (0.1, 2.0),
531    };
532
533    let space = LeaderFollowerPolarSpace::from_params(params).unwrap();
534
535    let mut a = [3.7375317, 0.9111872, 0.90473485, 4.3599744].into();
536    let b = [3.7432036, -2.570983, 2.502023, -4.0045195].into();
537
538    space.saturate(&mut a, &b, 1.0);
539
540    println!("a_star: {:?}", <[f32; N]>::from(a));
541  }
542
543  #[test]
544  fn test_saturate_polar_zero_counter_clockwise_f32() {
545    let r_b: f32 = 0.70710677;
546    let r_a = 1.7927681;
547    let theta_a = 1.4744684;
548    let _theta_b = 0.0;
549    let delta = 0.275;
550
551    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
552
553    assert!(rel_eq(r_star, 0.893392428268));
554    assert!(rel_eq(theta_star, 0.253));
555  }
556
557  #[test]
558  fn test_saturate_polar_zero_counter_clockwise_f64() {
559    let r_b: f64 = 0.70710677;
560    let r_a = 1.7927681;
561    let theta_a = 1.4744684;
562    let _theta_b = 0.0;
563    let delta = 0.275;
564
565    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
566
567    assert!(rel_eq(r_star, 0.893392428268));
568    assert!(rel_eq(theta_star, 0.253));
569  }
570
571  #[test]
572  fn test_saturate_polar_zero_clockwise_f32() {
573    let r_b: f32 = 0.70710677;
574    let r_a = 1.7927681;
575    let theta_a = bound_theta(-1.4744684);
576    let _theta_b = 0.0;
577    let delta = 0.275;
578
579    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
580
581    assert!(rel_eq(r_star, 0.893392428268));
582    assert!(rel_eq(theta_star, bound_theta(-0.253)));
583  }
584
585  #[test]
586  fn test_saturate_polar_zero_clockwise_f64() {
587    let r_b: f64 = 0.70710677;
588    let r_a = 1.7927681;
589    let theta_a = bound_theta(-1.4744684);
590    let _theta_b = 0.0;
591    let delta = 0.275;
592
593    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
594
595    assert!(rel_eq(r_star, 0.893392428268));
596    assert!(rel_eq(theta_star, bound_theta(-0.253)));
597  }
598
599  #[test]
600  fn test_saturate_polar_zero_counter_clockwise_long_f32() {
601    let r_b: f32 = 0.70710677;
602    let r_a = 1.7927681;
603    let theta_a = 3.127344367;
604    let _theta_b = 0.0;
605    let delta = 0.275;
606
607    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
608
609    assert!(rel_eq(r_star, 0.820972361522));
610    assert!(rel_eq(theta_star, 0.328));
611  }
612
613  #[test]
614  fn test_saturate_polar_zero_counter_clockwise_long_f64() {
615    let r_b: f64 = 0.70710677;
616    let r_a = 1.7927681;
617    let theta_a = 3.127344367;
618    let _theta_b = 0.0;
619    let delta = 0.275;
620
621    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
622
623    assert!(rel_eq(r_star, 0.820972361522));
624    assert!(rel_eq(theta_star, 0.328));
625  }
626
627  #[test]
628  fn test_saturate_polar_zero_clockwise_long_f32() {
629    let r_b: f32 = 0.70710677;
630    let r_a = 1.7927681;
631    let theta_a = bound_theta(-3.127344367);
632    let _theta_b = 0.0;
633    let delta = 0.275;
634
635    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
636
637    assert!(rel_eq(r_star, 0.820972361522));
638    assert!(rel_eq(theta_star, bound_theta(-0.328)));
639  }
640
641  #[test]
642  fn test_saturate_polar_zero_clockwise_long_f64() {
643    let r_b: f64 = 0.70710677;
644    let r_a = 1.7927681;
645    let theta_a = bound_theta(-3.127344367);
646    let _theta_b = 0.0;
647    let delta = 0.275;
648
649    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
650
651    assert!(rel_eq(r_star, 0.820972361522));
652    assert!(rel_eq(theta_star, bound_theta(-0.328)));
653  }
654
655  #[test]
656  fn test_saturate_polar_zero_counter_clockwise_short_f32() {
657    let r_b: f32 = 0.70710677;
658    let r_a = 1.7927681;
659    let theta_a = 0.3253262;
660    let _theta_b = 0.0;
661    let delta = 0.275;
662
663    let (r_star, theta_star) = saturate_polar_zero(r_a, theta_a, r_b, delta);
664
665    assert!(rel_eq(r_star, 0.974078524504));
666    assert!(rel_eq(theta_star, 0.080));
667  }
668}