1#![allow(unused_imports)]
2
3use ordered_float::NotNan;
4use serde::{Deserialize, Serialize};
5use std::ops::{Add, Mul, Sub};
6use uom::si::{
7 angle::{degree, radian},
8 angular_velocity::radian_per_second,
9 f64::{Angle, AngularVelocity, Length, Time, Velocity},
10 length::{meter, millimeter},
11 time::second,
12 velocity::meter_per_second,
13};
14
15#[derive(Serialize, Deserialize)]
16pub struct ChoreoTrajectory {
17 pub name: String,
18 pub version: u32,
19 pub snapshot: Snapshot,
20 pub params: Params,
21 pub trajectory: TrajectoryData,
22 pub events: Vec<Event>,
23}
24
25#[derive(Serialize, Deserialize)]
26pub struct Snapshot {
27 pub waypoints: Vec<SnapshotWaypoint>,
28 pub constraints: Vec<Constraint>,
29 #[serde(rename = "targetDt")]
30 pub target_dt: f64,
31}
32
33#[derive(Serialize, Deserialize)]
34pub struct SnapshotWaypoint {
35 pub x: f64,
36 pub y: f64,
37 pub heading: f64,
38 pub intervals: u32,
39 pub split: bool,
40 #[serde(rename = "fixTranslation")]
41 pub fix_translation: bool,
42 #[serde(rename = "fixHeading")]
43 pub fix_heading: bool,
44 #[serde(rename = "overrideIntervals")]
45 pub override_intervals: bool,
46}
47
48#[derive(Serialize, Deserialize)]
49pub struct Constraint {
50 }
52
53#[derive(Serialize, Deserialize)]
54pub struct Params {
55 }
57
58#[derive(Serialize, Deserialize)]
59pub struct Event {
60 }
62
63#[derive(Serialize, Deserialize)]
64pub struct TrajectoryData {
65 pub samples: Vec<Sample>,
66 pub waypoints: Vec<f64>,
67}
68
69#[derive(Serialize, Deserialize, Debug)]
70pub struct Sample {
71 pub t: f64,
72 pub x: f64,
73 pub y: f64,
74 pub heading: f64,
75 #[serde(rename = "vx")]
76 pub velocity_x: f64,
77 #[serde(rename = "vy")]
78 pub velocity_y: f64,
79 #[serde(rename = "omega")]
80 pub angular_velocity: f64,
81}
82
83pub struct Path {
84 samples: Vec<PoseSample>,
85 waypoints: Vec<f64>,
86}
87
88#[derive(Clone, Debug)]
89struct PoseSample {
90 time: f64,
91 pose: Pose,
92}
93
94impl Path {
95 pub fn from_trajectory(trajectory: &str) -> Result<Self, serde_json::Error> {
96 let choreo = serde_json::from_str::<ChoreoTrajectory>(trajectory)?;
97
98 let valid_waypoints = choreo
99 .snapshot
100 .waypoints
101 .iter()
102 .enumerate()
103 .filter(|(_, wp)| wp.split)
104 .map(|(i, _)| choreo.trajectory.waypoints[i])
105 .collect();
106
107 let trajectory_data = TrajectoryData {
108 samples: choreo.trajectory.samples,
109 waypoints: valid_waypoints,
110 };
111
112 Ok(Self::from_trajectory_data(trajectory_data))
113 }
114
115 fn from_trajectory_data(data: TrajectoryData) -> Self {
116 let mut samples = Vec::with_capacity(data.samples.len());
117 for sample in data.samples {
118 samples.push(PoseSample {
119 time: sample.t,
120 pose: sample.into(),
121 });
122 }
123
124 samples.sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
126
127 Self {
128 samples,
129 waypoints: data.waypoints,
130 }
131 }
132
133 pub fn get(&self, elapsed: Time) -> Pose {
134 let t = elapsed.get::<second>();
135
136 match self
137 .samples
138 .binary_search_by(|probe| probe.time.partial_cmp(&t).unwrap())
139 {
140 Ok(idx) => self.samples[idx].pose.clone(), Err(0) => self.samples[0].pose.clone(), Err(idx) if idx >= self.samples.len() => self.samples.last().unwrap().pose.clone(), Err(idx) => {
144 let before = &self.samples[idx - 1];
145 let after = &self.samples[idx];
146 let progress = (t - before.time) / (after.time - before.time);
147 before.pose.lerp(&after.pose, progress)
148 }
149 }
150 }
151
152 pub fn length(&self) -> Time {
153 Time::new::<second>(self.samples.last().unwrap().time)
154 }
155
156 pub fn waypoints(&self) -> &Vec<f64> {
157 &self.waypoints
158 }
159}
160
161#[derive(Clone, Debug)]
162pub struct Pose {
163 pub x: Length,
164 pub y: Length,
165 pub heading: Angle,
166 pub angular_velocity: AngularVelocity,
167 pub velocity_x: Velocity,
168 pub velocity_y: Velocity,
169}
170
171impl Pose {
172 fn lerp(&self, other: &Pose, l: f64) -> Pose {
173 Pose {
174 x: lerp(self.x, other.x, l),
175 y: lerp(self.y, other.y, l),
176 heading: lerp(self.heading, other.heading, l),
177 angular_velocity: lerp(self.angular_velocity, other.angular_velocity, l),
178 velocity_x: lerp(self.velocity_x, other.velocity_x, l),
179 velocity_y: lerp(self.velocity_y, other.velocity_y, l),
180 }
181 }
182
183 pub fn mirror(&self, x: Length, y: Length) -> Pose {
186 Pose {
187 x: x - self.x + x,
188 y: y - self.y + y,
189 heading: self.heading + Angle::new::<radian>(std::f64::consts::PI),
190 angular_velocity: -self.angular_velocity,
191 velocity_x: self.velocity_x,
192 velocity_y: self.velocity_y,
193 }
194 }
195}
196
197fn lerp<A>(a: A, b: A, l: f64) -> A
198where
199 A: Sub<A, Output = A> + Add<A, Output = A> + Mul<f64, Output = A> + Clone,
200{
201 a.clone() + (b - a) * l
202}
203
204impl From<Sample> for Pose {
205 fn from(value: Sample) -> Self {
206 Self {
207 x: Length::new::<meter>(value.x),
208 y: Length::new::<meter>(value.y),
209 heading: Angle::new::<radian>(value.heading),
210 angular_velocity: AngularVelocity::new::<radian_per_second>(value.angular_velocity),
211 velocity_x: Velocity::new::<meter_per_second>(value.velocity_x),
212 velocity_y: Velocity::new::<meter_per_second>(value.velocity_y),
213 }
214 }
215}
216
217