stepper_motion/trajectory/
builder.rs1use heapless::String;
4
5use crate::config::{TrajectoryConfig, WaypointTrajectory};
6use crate::config::units::{Degrees, DegreesPerSecSquared};
7use crate::error::{Error, Result, TrajectoryError};
8
9#[derive(Debug, Clone)]
11pub struct TrajectoryBuilder {
12 motor: Option<String<32>>,
13 target_degrees: Option<Degrees>,
14 velocity_percent: u8,
15 acceleration_percent: u8,
16 acceleration: Option<DegreesPerSecSquared>,
17 deceleration: Option<DegreesPerSecSquared>,
18 dwell_ms: Option<u32>,
19}
20
21impl Default for TrajectoryBuilder {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl TrajectoryBuilder {
28 pub fn new() -> Self {
30 Self {
31 motor: None,
32 target_degrees: None,
33 velocity_percent: 100,
34 acceleration_percent: 100,
35 acceleration: None,
36 deceleration: None,
37 dwell_ms: None,
38 }
39 }
40
41 pub fn motor(mut self, name: &str) -> Self {
43 self.motor = String::try_from(name).ok();
44 self
45 }
46
47 pub fn target(mut self, position: Degrees) -> Self {
49 self.target_degrees = Some(position);
50 self
51 }
52
53 pub fn velocity_percent(mut self, percent: u8) -> Self {
55 self.velocity_percent = percent.clamp(1, 200);
56 self
57 }
58
59 pub fn acceleration_percent(mut self, percent: u8) -> Self {
61 self.acceleration_percent = percent.clamp(1, 200);
62 self
63 }
64
65 pub fn acceleration(mut self, accel: DegreesPerSecSquared) -> Self {
67 self.acceleration = Some(accel);
68 self
69 }
70
71 pub fn deceleration(mut self, decel: DegreesPerSecSquared) -> Self {
73 self.deceleration = Some(decel);
74 self
75 }
76
77 pub fn asymmetric(mut self, accel: DegreesPerSecSquared, decel: DegreesPerSecSquared) -> Self {
79 self.acceleration = Some(accel);
80 self.deceleration = Some(decel);
81 self
82 }
83
84 pub fn dwell(mut self, dwell_ms: u32) -> Self {
86 self.dwell_ms = Some(dwell_ms);
87 self
88 }
89
90 pub fn build(self) -> Result<TrajectoryConfig> {
96 let motor = self.motor.ok_or_else(|| {
97 Error::Trajectory(TrajectoryError::InvalidName(
98 String::try_from("motor not specified").unwrap(),
99 ))
100 })?;
101
102 let target_degrees = self.target_degrees.ok_or_else(|| {
103 Error::Trajectory(TrajectoryError::InvalidName(
104 String::try_from("target not specified").unwrap(),
105 ))
106 })?;
107
108 Ok(TrajectoryConfig {
109 motor,
110 target_degrees,
111 velocity_percent: self.velocity_percent,
112 acceleration_percent: self.acceleration_percent,
113 acceleration: self.acceleration,
114 deceleration: self.deceleration,
115 dwell_ms: self.dwell_ms,
116 })
117 }
118}
119
120pub const MAX_WAYPOINTS: usize = 32;
122
123#[derive(Debug, Clone)]
125pub struct WaypointTrajectoryBuilder {
126 motor: Option<String<32>>,
127 waypoints: heapless::Vec<Degrees, MAX_WAYPOINTS>,
128 velocity_percent: u8,
129 dwell_ms: u32,
130}
131
132impl Default for WaypointTrajectoryBuilder {
133 fn default() -> Self {
134 Self::new()
135 }
136}
137
138impl WaypointTrajectoryBuilder {
139 pub fn new() -> Self {
141 Self {
142 motor: None,
143 waypoints: heapless::Vec::new(),
144 velocity_percent: 100,
145 dwell_ms: 0,
146 }
147 }
148
149 pub fn motor(mut self, name: &str) -> Self {
151 self.motor = String::try_from(name).ok();
152 self
153 }
154
155 pub fn waypoint(mut self, position: Degrees) -> Self {
157 let _ = self.waypoints.push(position);
158 self
159 }
160
161 pub fn waypoints(mut self, positions: &[Degrees]) -> Self {
163 for pos in positions {
164 let _ = self.waypoints.push(*pos);
165 }
166 self
167 }
168
169 pub fn velocity_percent(mut self, percent: u8) -> Self {
171 self.velocity_percent = percent.clamp(1, 200);
172 self
173 }
174
175 pub fn dwell(mut self, dwell_ms: u32) -> Self {
177 self.dwell_ms = dwell_ms;
178 self
179 }
180
181 pub fn build(self) -> Result<WaypointTrajectory> {
187 let motor = self.motor.ok_or_else(|| {
188 Error::Trajectory(TrajectoryError::InvalidName(
189 String::try_from("motor not specified").unwrap(),
190 ))
191 })?;
192
193 if self.waypoints.is_empty() {
194 return Err(Error::Trajectory(TrajectoryError::Empty));
195 }
196
197 Ok(WaypointTrajectory {
198 motor,
199 waypoints: self.waypoints,
200 velocity_percent: self.velocity_percent,
201 dwell_ms: self.dwell_ms,
202 })
203 }
204}