franka/robot/target_control/
position.rs1pub(super) use super::envelope::VelocityLimit;
5use super::velocity::fade_start;
6use crate::rate_limiting::DELTA_T;
7
8pub(super) const DEFAULT_JOINT_POSITION_MARGIN: f64 = 0.05;
10
11#[derive(Debug, Clone, Copy, PartialEq)]
13pub(super) struct JointLimits {
14 pub position: ([f64; 7], [f64; 7]),
16 pub margin: f64,
18 pub fraction: f64,
20 pub velocity: VelocityLimit,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq)]
25pub(super) struct CycleBox {
26 pub lower: [f64; 7],
27 pub upper: [f64; 7],
28 pub position_lower: [bool; 7],
30 pub position_upper: [bool; 7],
31 pub velocity_lower: [f64; 7],
33 pub velocity_upper: [f64; 7],
34}
35
36impl CycleBox {
37 pub(super) fn pin(&self, i: usize, side: i8) -> i8 {
40 let position = if side < 0 {
41 self.position_lower[i]
42 } else {
43 self.position_upper[i]
44 };
45 side.signum() * if position { 1 } else { 2 }
46 }
47}
48
49const REST_BAND: f64 = 1e-5;
54
55pub const POSITION_FADE_BAND: f64 = 0.02;
59
60pub const POSITION_BARRIER_STIFFNESS: f64 = 12.5;
63
64const SPRING_RAMP_CYCLES: u32 = 500;
67
68pub(super) fn spring_ramp(cycles: u32) -> f64 {
70 f64::from(cycles.min(SPRING_RAMP_CYCLES)) / f64::from(SPRING_RAMP_CYCLES)
71}
72
73impl JointLimits {
74 pub(super) fn cycle_box(&self, from: &[f64; 7], dt: f64) -> CycleBox {
82 let flat = self.velocity.flat();
83 let (lower, upper) = self.position;
84 let f = self.fraction;
85 let start = self.velocity.at(from);
86 let end = self.velocity.position_dependent().then(|| {
88 let toward = |sign: f64, speed: &[f64; 7]| {
89 std::array::from_fn(|i| from[i] + sign * f * speed[i] * dt)
90 };
91 (
92 self.velocity.at(&toward(-1.0, &start.0)).0,
93 self.velocity.at(&toward(1.0, &start.1)).1,
94 )
95 });
96 let (toward_lower, toward_upper) = end.unwrap_or(start);
97 let side = |i: usize, distance: f64, speed: f64| {
98 let x = distance - self.margin;
99 let velocity = f * speed * dt;
100 let braking = f * self.velocity.braking(i, x, flat[i]) * dt;
101 let braking = f * self.velocity.braking(i, x - braking, flat[i]) * dt;
102 let bound = velocity.min(x.min(braking).max(0.0));
103 (bound, velocity, braking < velocity - 1e-12)
104 };
105 let mut b = CycleBox {
106 lower: [0.0; 7],
107 upper: [0.0; 7],
108 position_lower: [false; 7],
109 position_upper: [false; 7],
110 velocity_lower: [0.0; 7],
111 velocity_upper: [0.0; 7],
112 };
113 for i in 0..7 {
114 let (bound, velocity, position) = side(i, from[i] - lower[i], toward_lower[i]);
115 (b.lower[i], b.velocity_lower[i], b.position_lower[i]) = (-bound, -velocity, position);
116 let (bound, velocity, position) = side(i, upper[i] - from[i], toward_upper[i]);
117 (b.upper[i], b.velocity_upper[i], b.position_upper[i]) = (bound, velocity, position);
118 }
119 b
120 }
121
122 pub(super) fn rest(&self, q: &[f64; 7], joints: &[i8; 7]) -> f64 {
125 let (lower, upper) = self.position;
126 (0..7)
127 .map(|i| match joints[i] {
128 -1 => q[i] - lower[i] - self.margin,
129 1 => upper[i] - q[i] - self.margin,
130 _ => f64::INFINITY,
131 })
132 .map(|x| (1.0 - x / REST_BAND).clamp(0.0, 1.0))
133 .fold(0.0, f64::max)
134 }
135
136 fn distances(&self, i: usize, q: f64) -> (f64, f64) {
138 (q - self.position.0[i], self.position.1[i] - q)
139 }
140
141 fn onset_distance(&self) -> f64 {
143 self.margin - POSITION_FADE_BAND
144 }
145
146 pub(super) fn envelope(
154 &self,
155 q: &[f64; 7],
156 dq: &[f64; 7],
157 barrier_fraction: f64,
158 ) -> ([f64; 7], [f64; 7]) {
159 let now = self.envelope_at(q, dq, barrier_fraction);
160 let next = std::array::from_fn(|i| q[i] + dq[i] * DELTA_T);
161 let (start, onset) = self.envelope_at(&next, dq, barrier_fraction);
162 (
163 std::array::from_fn(|i| now.0[i].min(start[i])),
164 std::array::from_fn(|i| now.1[i].min(onset[i])),
165 )
166 }
167
168 fn envelope_at(
169 &self,
170 q: &[f64; 7],
171 dq: &[f64; 7],
172 barrier_fraction: f64,
173 ) -> ([f64; 7], [f64; 7]) {
174 let flat = self.velocity.flat();
175 let (toward_lower, toward_upper) = self.velocity.at(q);
176 let (mut start, mut onset) = ([0.0; 7], [0.0; 7]);
177 for i in 0..7 {
178 let (lower, upper) = self.distances(i, q[i]);
179 let (s, v) = if dq[i] < 0.0 {
180 (lower, toward_lower[i])
181 } else {
182 (upper, toward_upper[i])
183 };
184 let braking = |x: f64| v.min(self.velocity.braking(i, x, flat[i]));
185 onset[i] = barrier_fraction * braking(s - self.onset_distance());
186 start[i] = fade_start(v, self.fraction * braking(s - self.margin), onset[i]);
187 }
188 (start, onset)
189 }
190
191 pub(super) fn fade_toward(&self, torque: &[f64; 7], q: &[f64; 7]) -> [f64; 7] {
194 let b = self.onset_distance();
195 std::array::from_fn(|i| {
196 let (lower, upper) = self.distances(i, q[i]);
197 let s = if torque[i] < 0.0 { lower } else { upper };
198 torque[i] * ((s - b) / (self.margin - b)).clamp(0.0, 1.0)
199 })
200 }
201
202 pub(super) fn spring(&self, q: &[f64; 7], torque_limits: &[f64; 7], ramp: f64) -> [f64; 7] {
205 let b = self.onset_distance();
206 std::array::from_fn(|i| {
207 let push = |s: f64| {
208 let depth = (b - s).max(0.0);
209 (ramp * POSITION_BARRIER_STIFFNESS * torque_limits[i] * depth).min(torque_limits[i])
210 };
211 let (lower, upper) = self.distances(i, q[i]);
212 push(lower) - push(upper)
213 })
214 }
215}