1use arci::{
2 gamepad::{Axis, Button, GamepadEvent},
3 BaseVelocity, MoveBase,
4};
5use async_trait::async_trait;
6use parking_lot::Mutex;
7
8use super::control_mode::ControlMode;
9
10const BASE_LINEAR_VEL_AXIS_GAIN: f64 = 0.5;
11const BASE_ANGULAR_VEL_AXIS_GAIN: f64 = 1.5;
12const BASE_TURBO_GAIN: f64 = 2.0;
13
14struct MoveBaseModeInner {
15 vel: BaseVelocity,
16 is_enabled: bool,
17 is_turbo: bool,
18}
19
20impl MoveBaseModeInner {
21 fn new() -> Self {
22 Self {
23 vel: BaseVelocity::default(),
24 is_enabled: false,
25 is_turbo: false,
26 }
27 }
28
29 fn handle_event(&mut self, ev: GamepadEvent) -> bool {
30 let mut should_stop = false;
31 match ev {
32 GamepadEvent::AxisChanged(Axis::LeftStickX, v) => {
33 self.vel.y = v * BASE_LINEAR_VEL_AXIS_GAIN
34 }
35 GamepadEvent::AxisChanged(Axis::LeftStickY, v) => {
36 self.vel.x = v * BASE_LINEAR_VEL_AXIS_GAIN
37 }
38 GamepadEvent::AxisChanged(Axis::RightStickX, v) => {
39 self.vel.theta = v * BASE_ANGULAR_VEL_AXIS_GAIN
40 }
41 GamepadEvent::ButtonPressed(Button::RightTrigger2) => {
42 self.is_enabled = true;
43 }
44 GamepadEvent::ButtonReleased(Button::RightTrigger2) => {
45 self.is_enabled = false;
46 self.vel = BaseVelocity::default();
47 should_stop = true;
48 }
49 GamepadEvent::ButtonPressed(Button::LeftTrigger2) => {
50 self.is_turbo = true;
51 }
52 GamepadEvent::ButtonReleased(Button::LeftTrigger2) => {
53 self.is_turbo = false;
54 }
55 GamepadEvent::Disconnected => {
56 self.is_enabled = false;
57 self.is_turbo = false;
58 self.vel = BaseVelocity::default();
59 should_stop = true;
60 }
61 _ => {}
62 }
63 should_stop
64 }
65
66 fn get_target_velocity(&self) -> Option<BaseVelocity> {
67 if self.is_enabled {
68 if self.is_turbo {
69 let turbo_vel = self.vel * BASE_TURBO_GAIN;
70 Some(turbo_vel)
71 } else {
72 Some(self.vel)
73 }
74 } else {
75 None
76 }
77 }
78}
79
80pub struct MoveBaseMode<T: MoveBase> {
81 move_base: T,
82 mode: String,
83 submode: String,
84 inner: Mutex<MoveBaseModeInner>,
85}
86
87impl<T> MoveBaseMode<T>
88where
89 T: MoveBase,
90{
91 pub fn new(mode: String, move_base: T) -> Self {
92 Self {
93 move_base,
94 mode,
95 submode: "".to_string(),
96 inner: Mutex::new(MoveBaseModeInner::new()),
97 }
98 }
99}
100
101#[async_trait]
102impl<T> ControlMode for MoveBaseMode<T>
103where
104 T: MoveBase,
105{
106 fn handle_event(&self, ev: GamepadEvent) {
107 if self.inner.lock().handle_event(ev) {
108 self.move_base
110 .send_velocity(&BaseVelocity::default())
111 .unwrap();
112 }
113 }
114
115 async fn proc(&self) {
116 if let Some(v) = self.inner.lock().get_target_velocity() {
117 self.move_base.send_velocity(&v).unwrap();
118 }
119 }
120
121 fn mode(&self) -> &str {
122 &self.mode
123 }
124
125 fn submode(&self) -> String {
126 self.submode.to_owned()
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use arci::DummyMoveBase;
133 use assert_approx_eq::*;
134
135 use super::*;
136
137 #[test]
138 fn test_move_mode_new() {
139 let mode_name = String::from("tested");
140 let base = DummyMoveBase::new();
141 let mode = MoveBaseMode::new(mode_name.clone(), base);
142
143 assert_eq!(
144 format!("{:?}", mode.move_base),
145 format!("{:?}", DummyMoveBase::new())
146 );
147 assert_eq!(mode.mode, mode_name);
148 assert_eq!(mode.submode, String::from(""));
149 assert_eq!(
150 format!("{:?}", mode.inner.lock().vel),
151 format!("{:?}", BaseVelocity::default())
152 );
153 assert!(!mode.inner.lock().is_enabled);
154 assert!(!mode.inner.lock().is_turbo);
155 }
156
157 #[test]
158 fn test_move_mode_get() {
159 let mode_name = String::from("tested");
160 let base = DummyMoveBase::new();
161 let mode = MoveBaseMode::new(mode_name.clone(), base);
162
163 let base_mode = mode.mode();
164 assert_eq!(base_mode, mode_name);
165 let base_sub_mode = mode.submode();
166 assert_eq!(base_sub_mode, String::from(""));
167 }
168
169 #[tokio::test]
170 async fn test_move_mode_proc() {
171 let mode_name = String::from("tested");
172 const X: f64 = 1.2;
173 const Y: f64 = 3.5;
174 const THETA: f64 = 1.8;
175 let mode = MoveBaseMode {
176 move_base: DummyMoveBase::new(),
177 mode: mode_name.clone(),
178 submode: "".to_string(),
179 inner: Mutex::new(MoveBaseModeInner {
180 vel: BaseVelocity {
181 x: X,
182 y: Y,
183 theta: THETA,
184 },
185 is_enabled: false,
186 is_turbo: false,
187 }),
188 };
189 mode.proc().await;
190 let current = mode.move_base.current_velocity().unwrap();
191 assert_approx_eq!(current.x, 0.0);
192 assert_approx_eq!(current.y, 0.0);
193 assert_approx_eq!(current.theta, 0.0);
194 println!("{:?} {current:?}", mode.inner.lock().vel);
195
196 let mode = MoveBaseMode {
197 move_base: DummyMoveBase::new(),
198 mode: mode_name.clone(),
199 submode: "".to_string(),
200 inner: Mutex::new(MoveBaseModeInner {
201 vel: BaseVelocity {
202 x: 1.2,
203 y: 3.5,
204 theta: 1.8,
205 },
206 is_enabled: false,
207 is_turbo: true,
208 }),
209 };
210 mode.proc().await;
211 let current = mode.move_base.current_velocity().unwrap();
212 assert_approx_eq!(current.x, 0.0);
213 assert_approx_eq!(current.y, 0.0);
214 assert_approx_eq!(current.theta, 0.0);
215 println!("{:?} {current:?}", mode.inner.lock().vel);
216
217 let mode = MoveBaseMode {
218 move_base: DummyMoveBase::new(),
219 mode: mode_name.clone(),
220 submode: "".to_string(),
221 inner: Mutex::new(MoveBaseModeInner {
222 vel: BaseVelocity {
223 x: 1.2,
224 y: 3.5,
225 theta: 1.8,
226 },
227 is_enabled: true,
228 is_turbo: false,
229 }),
230 };
231 mode.proc().await;
232 let current = mode.move_base.current_velocity().unwrap();
233 assert_approx_eq!(current.x, X);
234 assert_approx_eq!(current.y, Y);
235 assert_approx_eq!(current.theta, THETA);
236 println!("{:?} {current:?}", mode.inner.lock().vel);
237
238 let mode = MoveBaseMode {
239 move_base: DummyMoveBase::new(),
240 mode: mode_name.clone(),
241 submode: "".to_string(),
242 inner: Mutex::new(MoveBaseModeInner {
243 vel: BaseVelocity {
244 x: 1.2_f64,
245 y: 3.5,
246 theta: 1.8,
247 },
248 is_enabled: true,
249 is_turbo: true,
250 }),
251 };
252 mode.proc().await;
253 let current = mode.move_base.current_velocity().unwrap();
254 assert_approx_eq!(current.x, X * 2.0);
255 assert_approx_eq!(current.y, Y * 2.0);
256 assert_approx_eq!(current.theta, THETA * 2.0);
257 println!("{:?} {current:?}", mode.inner.lock().vel);
258 }
259}