franka/robot/target_control/
options.rs1use super::cartesian::{CartesianObserver, CartesianSent};
4use super::joint::{JointObserver, JointSent};
5use super::{validate_common, Backend, ImpedanceOptions, Settle};
6use crate::control_types::ControllerMode;
7use crate::error::{FrankaError, FrankaResult};
8use crate::otg::{MultiOtg, OtgLimits};
9use crate::rate_limiting;
10use crate::robot::control_loop::rate_limits;
11use crate::robot_state::RobotState;
12use crate::wire::robot::codec::FciVersion;
13
14const FR3_MAX_JOINT_VELOCITY: [f64; 7] = [2.62, 2.62, 2.62, 2.62, 5.26, 4.18, 5.26];
18
19pub const DEFAULT_LIMIT_FRACTION: f64 = 0.2;
21
22pub struct TargetControlOptions {
25 pub limits: OtgLimits,
31 pub rotation_limits: OtgLimits,
36 pub backend: Backend,
40 pub controller_mode: ControllerMode,
43 pub max_deviation: f64,
46 pub max_angular_deviation: f64,
49 pub settle: Settle,
52 pub limit_rate: bool,
56 pub realtime_priority: Option<i32>,
58 pub observer: Option<CartesianObserver>,
60}
61
62impl Default for TargetControlOptions {
63 fn default() -> Self {
64 TargetControlOptions {
65 limits: OtgLimits {
66 max_velocity: 0.3,
67 max_acceleration: 0.5,
68 max_jerk: 20.0,
69 },
70 rotation_limits: OtgLimits {
71 max_velocity: 0.5,
72 max_acceleration: 1.0,
73 max_jerk: 20.0,
74 },
75 backend: Backend::Impedance(ImpedanceOptions::cartesian()),
76 controller_mode: ControllerMode::CartesianImpedance,
77 max_deviation: 0.30,
78 max_angular_deviation: 0.5,
79 settle: Settle::default(),
80 limit_rate: true,
81 realtime_priority: None,
82 observer: None,
83 }
84 }
85}
86
87impl std::fmt::Debug for TargetControlOptions {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 f.debug_struct("TargetControlOptions")
90 .field("limits", &self.limits)
91 .field("rotation_limits", &self.rotation_limits)
92 .field("backend", &self.backend)
93 .field("controller_mode", &self.controller_mode)
94 .field("max_deviation", &self.max_deviation)
95 .field("max_angular_deviation", &self.max_angular_deviation)
96 .field("settle", &self.settle)
97 .field("limit_rate", &self.limit_rate)
98 .field("realtime_priority", &self.realtime_priority)
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_observer(
161 mut self,
162 observer: impl FnMut(&RobotState, &CartesianSent) + Send + 'static,
163 ) -> Self {
164 self.observer = Some(Box::new(observer));
165 self
166 }
167
168 pub fn validate(&self) -> FrankaResult<()> {
173 crate::otg::Otg::new(0.0, self.limits)?;
174 crate::otg::Otg::new(0.0, self.rotation_limits).map_err(|_| {
175 FrankaError::InvalidArgument(format!(
176 "target control: rotation_limits must be finite and positive, got {:?}",
177 self.rotation_limits
178 ))
179 })?;
180 if !(self.max_angular_deviation.is_finite() && self.max_angular_deviation > 0.0) {
181 return Err(FrankaError::InvalidArgument(format!(
182 "target control: max_angular_deviation must be finite and positive, got {}",
183 self.max_angular_deviation
184 )));
185 }
186 validate_common(
187 self.max_deviation,
188 self.settle,
189 self.realtime_priority,
190 &self.backend,
191 )
192 }
193}
194
195pub struct JointTargetControlOptions {
198 pub limits: Option<[OtgLimits; 7]>,
203 pub backend: Backend,
207 pub controller_mode: ControllerMode,
210 pub max_deviation: f64,
213 pub settle: Settle,
215 pub limit_rate: bool,
219 pub realtime_priority: Option<i32>,
221 pub observer: Option<JointObserver>,
223}
224
225impl Default for JointTargetControlOptions {
226 fn default() -> Self {
227 JointTargetControlOptions {
228 limits: None,
229 backend: Backend::Impedance(ImpedanceOptions::joint()),
230 controller_mode: ControllerMode::JointImpedance,
231 max_deviation: 1.0,
232 settle: Settle::default(),
233 limit_rate: true,
234 realtime_priority: None,
235 observer: None,
236 }
237 }
238}
239
240impl std::fmt::Debug for JointTargetControlOptions {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 f.debug_struct("JointTargetControlOptions")
243 .field("limits", &self.limits)
244 .field("backend", &self.backend)
245 .field("controller_mode", &self.controller_mode)
246 .field("max_deviation", &self.max_deviation)
247 .field("settle", &self.settle)
248 .field("limit_rate", &self.limit_rate)
249 .field("realtime_priority", &self.realtime_priority)
250 .field("observer", &self.observer.is_some())
251 .finish()
252 }
253}
254
255impl JointTargetControlOptions {
256 pub fn scaled_limits(version: FciVersion, fraction: f64) -> [OtgLimits; 7] {
260 let rate = rate_limits(version);
261 let velocity = match version {
262 FciVersion::V5 => rate_limiting::fer::MAX_JOINT_VELOCITY,
263 FciVersion::V10 => FR3_MAX_JOINT_VELOCITY,
264 };
265 std::array::from_fn(|i| OtgLimits {
266 max_velocity: velocity[i] * fraction,
267 max_acceleration: rate.max_joint_acceleration[i] * fraction,
268 max_jerk: rate.max_joint_jerk[i] * fraction,
269 })
270 }
271
272 pub fn with_limits(mut self, limits: [OtgLimits; 7]) -> Self {
274 self.limits = Some(limits);
275 self
276 }
277
278 pub fn with_backend(mut self, backend: Backend) -> Self {
280 self.backend = backend;
281 self
282 }
283
284 pub fn with_controller_mode(mut self, mode: ControllerMode) -> Self {
286 self.controller_mode = mode;
287 self
288 }
289
290 pub fn with_max_deviation(mut self, radians: f64) -> Self {
292 self.max_deviation = radians;
293 self
294 }
295
296 pub fn with_settle(mut self, settle: Settle) -> Self {
298 self.settle = settle;
299 self
300 }
301
302 pub fn with_limit_rate(mut self, limit_rate: bool) -> Self {
304 self.limit_rate = limit_rate;
305 self
306 }
307
308 pub fn with_realtime_priority(mut self, priority: Option<i32>) -> Self {
310 self.realtime_priority = priority;
311 self
312 }
313
314 pub fn with_observer(
316 mut self,
317 observer: impl FnMut(&RobotState, &JointSent) + Send + 'static,
318 ) -> Self {
319 self.observer = Some(Box::new(observer));
320 self
321 }
322
323 pub fn validate(&self) -> FrankaResult<()> {
328 if let Some(limits) = self.limits {
329 MultiOtg::with_limits([0.0; 7], limits, true)?;
330 }
331 validate_common(
332 self.max_deviation,
333 self.settle,
334 self.realtime_priority,
335 &self.backend,
336 )
337 }
338}