openrr_base/
robot_velocity_status.rs

1use std::sync::Mutex;
2
3use arci::BaseVelocity;
4
5use crate::*;
6
7#[derive(Debug, Default)]
8pub struct RobotVelocityStatus {
9    velocity: Mutex<BaseVelocity>,
10    velocity_state: Mutex<BaseVelocity>,
11    max_velocity: BaseVelocity,
12    min_velocity: BaseVelocity,
13    max_acceleration: BaseAcceleration,
14    min_acceleration: BaseAcceleration,
15    last_sent_log: Mutex<BaseVelocityTimestamped>,
16}
17
18impl RobotVelocityStatus {
19    pub fn new(max_velocity: BaseVelocity, max_acceleration: BaseAcceleration) -> Self {
20        Self::new_as_asymmetric(
21            max_velocity,
22            max_velocity * (-1.),
23            max_acceleration,
24            max_acceleration * (-1.),
25        )
26    }
27
28    pub fn new_as_asymmetric(
29        max_velocity: BaseVelocity,
30        min_velocity: BaseVelocity,
31        max_acceleration: BaseAcceleration,
32        min_acceleration: BaseAcceleration,
33    ) -> Self {
34        Self {
35            velocity: Mutex::new(BaseVelocity::default()),
36            velocity_state: Mutex::new(BaseVelocity::default()),
37            max_velocity,
38            min_velocity,
39            max_acceleration,
40            min_acceleration,
41            last_sent_log: Mutex::new(BaseVelocityTimestamped::default()),
42        }
43    }
44
45    pub fn velocity(&self) -> BaseVelocity {
46        self.velocity.lock().unwrap().to_owned()
47    }
48
49    pub fn set_velocity(&self, velocity: &BaseVelocity) {
50        let mut vel = self.velocity.lock().unwrap();
51        *vel = *velocity;
52    }
53
54    pub fn time_since_last_sent(&self) -> f64 {
55        self.last_sent_log
56            .lock()
57            .unwrap()
58            .to_owned()
59            .timestamp
60            .elapsed()
61            .as_secs_f64()
62    }
63
64    pub fn set_log(&self, velocity_log: &BaseVelocity) {
65        let mut log = self.last_sent_log.lock().unwrap();
66        *log = BaseVelocityTimestamped {
67            base_velocity: *velocity_log,
68            timestamp: std::time::Instant::now(),
69        }
70    }
71
72    pub fn set_velocity_state(&self, velocity: BaseVelocity) {
73        let mut velocity_state = self.velocity_state.lock().unwrap();
74        *velocity_state = velocity;
75    }
76
77    pub fn get_limited_velocity(&self, velocity: &BaseVelocity) -> BaseVelocity {
78        let vel = self.limit_acceleration(velocity);
79        self.limit_velocity(&vel)
80    }
81
82    fn limit_velocity(&self, velocity: &BaseVelocity) -> BaseVelocity {
83        BaseVelocity {
84            x: velocity.x.clamp(self.min_velocity.x, self.max_velocity.x),
85            y: velocity.y.clamp(self.min_velocity.y, self.max_velocity.y),
86            theta: velocity
87                .theta
88                .clamp(self.min_velocity.theta, self.max_velocity.theta),
89        }
90    }
91
92    fn limit_acceleration(&self, velocity: &BaseVelocity) -> BaseVelocity {
93        let dt = self.time_since_last_sent();
94        let vel = self.velocity.lock().unwrap().to_owned();
95        BaseVelocity {
96            x: velocity.x.clamp(
97                vel.x + self.min_acceleration.x * dt,
98                vel.x + self.max_acceleration.x * dt,
99            ),
100            y: velocity.y.clamp(
101                vel.y + self.min_acceleration.y * dt,
102                vel.y + self.max_acceleration.y * dt,
103            ),
104            theta: velocity.theta.clamp(
105                vel.theta + self.min_acceleration.theta * dt,
106                vel.theta + self.max_acceleration.theta * dt,
107            ),
108        }
109    }
110}
111
112#[cfg(test)]
113mod test {
114    use assert_approx_eq::assert_approx_eq;
115
116    use super::*;
117
118    const LIMIT_VEL_X: f64 = 10.0;
119    const LIMIT_VEL_THETA: f64 = 10.0;
120    const LIMIT_ACC_X: f64 = 1000.0;
121    const LIMIT_ACC_THETA: f64 = 1000.0;
122    const DUMMY_VELOCITY_STATE_X: f64 = 1.23;
123
124    #[test]
125    fn test_robot_velocity_status() {
126        let limit_velocity = BaseVelocity::new(LIMIT_VEL_X, 0.0, LIMIT_VEL_THETA);
127        let limit_acceleration = BaseAcceleration::new(LIMIT_ACC_X, 0.0, LIMIT_ACC_THETA);
128
129        let status = RobotVelocityStatus::new(limit_velocity, limit_acceleration);
130
131        status.set_velocity(&BaseVelocity {
132            x: LIMIT_VEL_X,
133            y: 0.,
134            theta: -LIMIT_VEL_THETA,
135        });
136
137        let vel = status.velocity();
138        assert_approx_eq!(vel.x, LIMIT_VEL_X);
139
140        std::thread::sleep(std::time::Duration::from_millis(100));
141        let cmd_vel = BaseVelocity {
142            x: -20.,
143            y: 0.,
144            theta: 20.,
145        };
146        let limited = status.get_limited_velocity(&cmd_vel);
147
148        assert_approx_eq!(limited.x, -LIMIT_VEL_X);
149        assert_approx_eq!(limited.theta, LIMIT_VEL_THETA);
150
151        let velocity_state = BaseVelocity {
152            x: DUMMY_VELOCITY_STATE_X,
153            y: 0.,
154            theta: 0.,
155        };
156
157        status.set_velocity_state(velocity_state);
158
159        let velocity_state_x = status.velocity_state.lock().unwrap().x;
160        assert_approx_eq!(velocity_state_x, DUMMY_VELOCITY_STATE_X);
161    }
162}