franka/robot/target_control/
options.rs1use super::cartesian::{CartesianObserver, CartesianSent};
4use super::joint::{JointObserver, JointSent};
5use super::{validate_common, Backend, ImpedanceOptions, Scheduling, Settle};
6use crate::control_types::ControllerMode;
7use crate::error::{FrankaError, FrankaResult};
8use crate::otg::{MultiOtg, OtgLimits};
9use crate::robot::control_loop::rate_limits;
10use crate::robot_state::RobotState;
11use crate::wire::robot::codec::FciVersion;
12
13pub const DEFAULT_LIMIT_FRACTION: f64 = 0.2;
15
16pub struct TargetControlOptions {
19 pub limits: OtgLimits,
25 pub rotation_limits: OtgLimits,
30 pub backend: Backend,
34 pub controller_mode: ControllerMode,
37 pub max_deviation: f64,
40 pub max_angular_deviation: f64,
43 pub settle: Settle,
46 pub limit_rate: bool,
50 pub realtime_priority: Option<i32>,
52 pub cpu: Option<usize>,
56 pub observer: Option<CartesianObserver>,
58}
59
60impl Default for TargetControlOptions {
61 fn default() -> Self {
62 TargetControlOptions {
63 limits: OtgLimits {
64 max_velocity: 0.3,
65 max_acceleration: 0.5,
66 max_jerk: 20.0,
67 },
68 rotation_limits: OtgLimits {
69 max_velocity: 0.5,
70 max_acceleration: 1.0,
71 max_jerk: 20.0,
72 },
73 backend: Backend::Impedance(ImpedanceOptions::cartesian()),
74 controller_mode: ControllerMode::CartesianImpedance,
75 max_deviation: 0.30,
76 max_angular_deviation: 0.5,
77 settle: Settle::default(),
78 limit_rate: true,
79 realtime_priority: None,
80 cpu: None,
81 observer: None,
82 }
83 }
84}
85
86impl std::fmt::Debug for TargetControlOptions {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 f.debug_struct("TargetControlOptions")
89 .field("limits", &self.limits)
90 .field("rotation_limits", &self.rotation_limits)
91 .field("backend", &self.backend)
92 .field("controller_mode", &self.controller_mode)
93 .field("max_deviation", &self.max_deviation)
94 .field("max_angular_deviation", &self.max_angular_deviation)
95 .field("settle", &self.settle)
96 .field("limit_rate", &self.limit_rate)
97 .field("realtime_priority", &self.realtime_priority)
98 .field("cpu", &self.cpu)
99 .field("observer", &self.observer.is_some())
100 .finish()
101 }
102}
103
104impl TargetControlOptions {
105 pub fn with_limits(mut self, limits: OtgLimits) -> Self {
107 self.limits = limits;
108 self
109 }
110
111 pub fn with_rotation_limits(mut self, limits: OtgLimits) -> Self {
113 self.rotation_limits = limits;
114 self
115 }
116
117 pub fn with_backend(mut self, backend: Backend) -> Self {
119 self.backend = backend;
120 self
121 }
122
123 pub fn with_controller_mode(mut self, mode: ControllerMode) -> Self {
125 self.controller_mode = mode;
126 self
127 }
128
129 pub fn with_max_deviation(mut self, metres: f64) -> Self {
131 self.max_deviation = metres;
132 self
133 }
134
135 pub fn with_max_angular_deviation(mut self, radians: f64) -> Self {
137 self.max_angular_deviation = radians;
138 self
139 }
140
141 pub fn with_settle(mut self, settle: Settle) -> Self {
143 self.settle = settle;
144 self
145 }
146
147 pub fn with_limit_rate(mut self, limit_rate: bool) -> Self {
149 self.limit_rate = limit_rate;
150 self
151 }
152
153 pub fn with_realtime_priority(mut self, priority: Option<i32>) -> Self {
155 self.realtime_priority = priority;
156 self
157 }
158
159 pub fn with_cpu(mut self, cpu: Option<usize>) -> Self {
161 self.cpu = cpu;
162 self
163 }
164
165 pub fn with_observer(
167 mut self,
168 observer: impl FnMut(&RobotState, &CartesianSent) + Send + 'static,
169 ) -> Self {
170 self.observer = Some(Box::new(observer));
171 self
172 }
173
174 pub fn validate(&self) -> FrankaResult<()> {
179 crate::otg::Otg::new(0.0, self.limits)?;
180 crate::otg::Otg::new(0.0, self.rotation_limits).map_err(|_| {
181 FrankaError::InvalidArgument(format!(
182 "target control: rotation_limits must be finite and positive, got {:?}",
183 self.rotation_limits
184 ))
185 })?;
186 if !(self.max_angular_deviation.is_finite() && self.max_angular_deviation > 0.0) {
187 return Err(FrankaError::InvalidArgument(format!(
188 "target control: max_angular_deviation must be finite and positive, got {}",
189 self.max_angular_deviation
190 )));
191 }
192 validate_common(
193 self.max_deviation,
194 self.settle,
195 self.scheduling(),
196 &self.backend,
197 )
198 }
199
200 pub(super) fn scheduling(&self) -> Scheduling {
201 Scheduling {
202 priority: self.realtime_priority,
203 cpu: self.cpu,
204 }
205 }
206}
207
208pub struct JointTargetControlOptions {
211 pub limits: Option<[OtgLimits; 7]>,
216 pub backend: Backend,
220 pub controller_mode: ControllerMode,
223 pub max_deviation: f64,
226 pub settle: Settle,
228 pub limit_rate: bool,
232 pub realtime_priority: Option<i32>,
234 pub cpu: Option<usize>,
238 pub observer: Option<JointObserver>,
240}
241
242impl Default for JointTargetControlOptions {
243 fn default() -> Self {
244 JointTargetControlOptions {
245 limits: None,
246 backend: Backend::Impedance(ImpedanceOptions::joint()),
247 controller_mode: ControllerMode::JointImpedance,
248 max_deviation: 1.0,
249 settle: Settle::default(),
250 limit_rate: true,
251 realtime_priority: None,
252 cpu: None,
253 observer: None,
254 }
255 }
256}
257
258impl std::fmt::Debug for JointTargetControlOptions {
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 f.debug_struct("JointTargetControlOptions")
261 .field("limits", &self.limits)
262 .field("backend", &self.backend)
263 .field("controller_mode", &self.controller_mode)
264 .field("max_deviation", &self.max_deviation)
265 .field("settle", &self.settle)
266 .field("limit_rate", &self.limit_rate)
267 .field("realtime_priority", &self.realtime_priority)
268 .field("cpu", &self.cpu)
269 .field("observer", &self.observer.is_some())
270 .finish()
271 }
272}
273
274impl JointTargetControlOptions {
275 pub fn scaled_limits(version: FciVersion, fraction: f64) -> [OtgLimits; 7] {
278 let rate = rate_limits(version);
279 let velocity = super::max_joint_velocity(version);
280 std::array::from_fn(|i| OtgLimits {
281 max_velocity: velocity[i] * fraction,
282 max_acceleration: rate.max_joint_acceleration[i] * fraction,
283 max_jerk: rate.max_joint_jerk[i] * fraction,
284 })
285 }
286
287 pub fn with_limits(mut self, limits: [OtgLimits; 7]) -> Self {
289 self.limits = Some(limits);
290 self
291 }
292
293 pub fn with_backend(mut self, backend: Backend) -> Self {
295 self.backend = backend;
296 self
297 }
298
299 pub fn with_controller_mode(mut self, mode: ControllerMode) -> Self {
301 self.controller_mode = mode;
302 self
303 }
304
305 pub fn with_max_deviation(mut self, radians: f64) -> Self {
307 self.max_deviation = radians;
308 self
309 }
310
311 pub fn with_settle(mut self, settle: Settle) -> Self {
313 self.settle = settle;
314 self
315 }
316
317 pub fn with_limit_rate(mut self, limit_rate: bool) -> Self {
319 self.limit_rate = limit_rate;
320 self
321 }
322
323 pub fn with_realtime_priority(mut self, priority: Option<i32>) -> Self {
325 self.realtime_priority = priority;
326 self
327 }
328
329 pub fn with_cpu(mut self, cpu: Option<usize>) -> Self {
331 self.cpu = cpu;
332 self
333 }
334
335 pub fn with_observer(
337 mut self,
338 observer: impl FnMut(&RobotState, &JointSent) + Send + 'static,
339 ) -> Self {
340 self.observer = Some(Box::new(observer));
341 self
342 }
343
344 pub fn validate(&self) -> FrankaResult<()> {
349 if let Some(limits) = self.limits {
350 MultiOtg::with_limits([0.0; 7], limits, true)?;
351 }
352 validate_common(
353 self.max_deviation,
354 self.settle,
355 self.scheduling(),
356 &self.backend,
357 )
358 }
359
360 pub(super) fn scheduling(&self) -> Scheduling {
361 Scheduling {
362 priority: self.realtime_priority,
363 cpu: self.cpu,
364 }
365 }
366}