1use crate::motor::*;
82use crate::{Controller, ControllerCapabilities, ControllerError, ControllerHealth, ControllerState};
83use async_trait::async_trait;
84use mecha10_core::actuator::MotorStatus;
85use mecha10_drivers_motor::l298n::{L298NConfig, L298NDriver, L298NMotorPins as DriverMotorPins};
86use mecha10_drivers_motor::{ControlMode, MotorCommand, MotorDriver};
87use serde::{Deserialize, Serialize};
88use std::collections::HashMap;
89use std::time::{SystemTime, UNIX_EPOCH};
90use tracing::{debug, info, warn};
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct L298nControllerConfig {
95 pub gpio_chip: String,
97
98 pub motor_a: L298nMotorPins,
100
101 pub motor_b: L298nMotorPins,
103
104 #[serde(default = "default_pwm_frequency")]
106 pub pwm_frequency_hz: u32,
107
108 #[serde(default = "default_wheel_base")]
110 pub wheel_base: f32,
111
112 #[serde(default = "default_max_velocity")]
114 pub max_velocity: f32,
115
116 #[serde(default = "default_max_duty_cycle")]
118 pub max_duty_cycle: f32,
119
120 #[serde(default = "default_init_high_pins")]
123 pub init_high_pins: Vec<u32>,
124}
125
126fn default_init_high_pins() -> Vec<u32> {
127 vec![4, 11, 12, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27]
128}
129
130fn default_pwm_frequency() -> u32 {
131 1000
132}
133
134fn default_wheel_base() -> f32 {
135 0.3
136}
137
138fn default_max_velocity() -> f32 {
139 1.0
140}
141
142fn default_max_duty_cycle() -> f32 {
143 1.0
144}
145
146impl Default for L298nControllerConfig {
147 fn default() -> Self {
148 Self {
149 gpio_chip: "gpiochip0".to_string(),
150 motor_a: L298nMotorPins::default_motor_a(),
151 motor_b: L298nMotorPins::default_motor_b(),
152 pwm_frequency_hz: default_pwm_frequency(),
153 wheel_base: default_wheel_base(),
154 max_velocity: default_max_velocity(),
155 max_duty_cycle: default_max_duty_cycle(),
156 init_high_pins: default_init_high_pins(),
157 }
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct L298nMotorPins {
164 pub in1: u32,
166
167 pub in2: u32,
169
170 #[serde(default)]
172 pub enable: Option<u32>,
173
174 #[serde(default)]
176 pub invert: bool,
177
178 #[serde(default = "default_active_low")]
182 pub active_low: bool,
183}
184
185fn default_active_low() -> bool {
186 true
187}
188
189impl L298nMotorPins {
190 pub fn default_motor_a() -> Self {
195 Self {
196 in1: 19, in2: 13, enable: None,
199 invert: true, active_low: true,
201 }
202 }
203
204 pub fn default_motor_b() -> Self {
209 Self {
210 in1: 6, in2: 5, enable: None,
213 invert: true, active_low: true,
215 }
216 }
217}
218
219impl From<L298nMotorPins> for DriverMotorPins {
220 fn from(pins: L298nMotorPins) -> Self {
221 DriverMotorPins {
222 in1: pins.in1,
223 in2: pins.in2,
224 enable: pins.enable,
225 invert: pins.invert,
226 active_low: pins.active_low,
227 }
228 }
229}
230
231pub struct L298nMotorController {
235 config: L298nControllerConfig,
236 driver: L298NDriver,
237 state: ControllerState,
238 left_velocity: f32,
239 right_velocity: f32,
240 left_encoder: i32,
242 right_encoder: i32,
243 last_update_us: u64,
244}
245
246#[async_trait]
247impl Controller for L298nMotorController {
248 type Config = L298nControllerConfig;
249 type Error = ControllerError;
250
251 async fn init(config: Self::Config) -> Result<Self, Self::Error> {
252 info!("Initializing L298N motor controller");
253 info!("Wheel base: {} m", config.wheel_base);
254 info!("Max velocity: {}", config.max_velocity);
255 info!("Max duty cycle: {}%", config.max_duty_cycle * 100.0);
256
257 let driver_config = L298NConfig {
259 gpio_chip: config.gpio_chip.clone(),
260 motor_a: config.motor_a.clone().into(),
261 motor_b: config.motor_b.clone().into(),
262 pwm_frequency_hz: config.pwm_frequency_hz,
263 max_duty_cycle: config.max_duty_cycle,
264 update_rate_hz: 50.0,
265 init_high_pins: config.init_high_pins.clone(),
266 };
267
268 let mut driver = L298NDriver::new(driver_config);
269 driver
270 .init()
271 .await
272 .map_err(|e| ControllerError::InitializationFailed(e.to_string()))?;
273
274 Ok(Self {
275 config,
276 driver,
277 state: ControllerState::Initialized,
278 left_velocity: 0.0,
279 right_velocity: 0.0,
280 left_encoder: 0,
281 right_encoder: 0,
282 last_update_us: now_us(),
283 })
284 }
285
286 async fn start(&mut self) -> Result<(), Self::Error> {
287 info!("Starting L298N motor controller");
288
289 self.driver
291 .enable(0)
292 .await
293 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
294 self.driver
295 .enable(1)
296 .await
297 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
298
299 self.state = ControllerState::Running;
300 self.last_update_us = now_us();
301 info!("L298N motor controller started");
302
303 Ok(())
304 }
305
306 async fn stop(&mut self) -> Result<(), Self::Error> {
307 info!("Stopping L298N motor controller");
308
309 self.set_velocity(0.0, 0.0).await?;
311
312 self.driver
314 .disable(0)
315 .await
316 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
317 self.driver
318 .disable(1)
319 .await
320 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
321
322 self.state = ControllerState::Stopped;
323 info!("L298N motor controller stopped");
324
325 Ok(())
326 }
327
328 async fn health_check(&self) -> ControllerHealth {
329 match self.state {
330 ControllerState::Running => ControllerHealth::Healthy,
331 ControllerState::Initialized => ControllerHealth::Degraded {
332 reason: "Controller initialized but not started".to_string(),
333 },
334 ControllerState::Stopped => ControllerHealth::Degraded {
335 reason: "Controller stopped".to_string(),
336 },
337 ControllerState::Error => ControllerHealth::Unhealthy {
338 reason: "Controller in error state".to_string(),
339 },
340 ControllerState::Uninitialized => ControllerHealth::Unknown,
341 }
342 }
343
344 fn capabilities(&self) -> ControllerCapabilities {
345 ControllerCapabilities::new("motor", "l298n")
346 .with_vendor("STMicroelectronics")
347 .with_model("L298N Dual H-Bridge")
348 .with_feature("velocity_control", true)
349 .with_feature("encoders", false) .with_feature("position_control", false)
351 .with_feature("torque_control", false)
352 .with_feature("current_sensing", false)
353 .with_feature("temperature_sensing", false)
354 .with_metadata("wheel_base", format!("{} m", self.config.wheel_base))
355 .with_metadata("max_duty_cycle", format!("{}%", self.config.max_duty_cycle * 100.0))
356 }
357
358 async fn diagnostics(&self) -> HashMap<String, String> {
359 let mut diag = HashMap::new();
360 diag.insert("state".to_string(), format!("{:?}", self.state));
361 diag.insert("left_velocity".to_string(), format!("{:.2}", self.left_velocity));
362 diag.insert("right_velocity".to_string(), format!("{:.2}", self.right_velocity));
363 diag.insert("left_encoder_est".to_string(), self.left_encoder.to_string());
364 diag.insert("right_encoder_est".to_string(), self.right_encoder.to_string());
365 diag.insert("gpio_chip".to_string(), self.config.gpio_chip.clone());
366 diag
367 }
368}
369
370#[async_trait]
371impl MotorController for L298nMotorController {
372 async fn set_velocity(&mut self, left: f32, right: f32) -> Result<(), Self::Error> {
373 if self.state != ControllerState::Running {
374 return Err(ControllerError::InvalidState("Controller not running".to_string()));
375 }
376
377 let max_vel = self.config.max_velocity;
379 let left_clamped = left.clamp(-max_vel, max_vel);
380 let right_clamped = right.clamp(-max_vel, max_vel);
381
382 let left_norm = left_clamped / max_vel;
384 let right_norm = right_clamped / max_vel;
385
386 self.update_encoder_estimates(left_norm, right_norm);
388
389 self.left_velocity = left_clamped;
391 self.right_velocity = right_clamped;
392
393 let left_cmd = MotorCommand {
396 motor_id: 0,
397 mode: ControlMode::PWM,
398 target: left_norm as f64,
399 velocity_limit: None,
400 torque_limit: None,
401 profile_velocity: None,
402 profile_acceleration: None,
403 };
404
405 let right_cmd = MotorCommand {
406 motor_id: 1,
407 mode: ControlMode::PWM,
408 target: right_norm as f64,
409 velocity_limit: None,
410 torque_limit: None,
411 profile_velocity: None,
412 profile_acceleration: None,
413 };
414
415 self.driver
416 .send_command(&left_cmd)
417 .await
418 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
419
420 self.driver
421 .send_command(&right_cmd)
422 .await
423 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
424
425 debug!(
426 "Set velocity: left={:.2}, right={:.2} (norm: {:.2}, {:.2})",
427 left_clamped, right_clamped, left_norm, right_norm
428 );
429
430 Ok(())
431 }
432
433 async fn get_encoders(&mut self) -> Result<(i32, i32), Self::Error> {
434 warn!("L298N has no encoders - returning estimated values");
436 Ok((self.left_encoder, self.right_encoder))
437 }
438
439 async fn get_status(&mut self) -> Result<MotorStatus, Self::Error> {
440 let wheel_radius = 0.05; let vel_to_rpm = 60.0 / (2.0 * std::f32::consts::PI * wheel_radius);
443
444 Ok(MotorStatus {
445 timestamp: now_us(),
446 left_motor_rpm: self.left_velocity * vel_to_rpm,
447 right_motor_rpm: self.right_velocity * vel_to_rpm,
448 battery_voltage: 0.0, temperature_c: 0.0, })
451 }
452
453 async fn emergency_stop(&mut self) -> Result<(), Self::Error> {
454 info!("Emergency stop triggered!");
455
456 self.left_velocity = 0.0;
458 self.right_velocity = 0.0;
459
460 let stop_cmd = MotorCommand {
462 motor_id: 0,
463 mode: ControlMode::PWM,
464 target: 0.0,
465 velocity_limit: None,
466 torque_limit: None,
467 profile_velocity: None,
468 profile_acceleration: None,
469 };
470
471 let _ = self.driver.send_command(&stop_cmd).await;
473 let mut stop_cmd_b = stop_cmd;
474 stop_cmd_b.motor_id = 1;
475 let _ = self.driver.send_command(&stop_cmd_b).await;
476
477 let _ = self.driver.disable(0).await;
479 let _ = self.driver.disable(1).await;
480
481 self.state = ControllerState::Stopped;
482 Ok(())
483 }
484
485 async fn enable(&mut self) -> Result<(), Self::Error> {
486 self.driver
487 .enable(0)
488 .await
489 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
490 self.driver
491 .enable(1)
492 .await
493 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
494 Ok(())
495 }
496
497 async fn disable(&mut self) -> Result<(), Self::Error> {
498 self.set_velocity(0.0, 0.0).await?;
500
501 self.driver
502 .disable(0)
503 .await
504 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
505 self.driver
506 .disable(1)
507 .await
508 .map_err(|e| ControllerError::CommunicationError(e.to_string()))?;
509 Ok(())
510 }
511
512 async fn reset_encoders(&mut self) -> Result<(), Self::Error> {
513 self.left_encoder = 0;
514 self.right_encoder = 0;
515 info!("Reset estimated encoder counts");
516 Ok(())
517 }
518}
519
520impl L298nMotorController {
521 fn update_encoder_estimates(&mut self, left_norm: f32, right_norm: f32) {
523 let now = now_us();
524 let dt_us = now.saturating_sub(self.last_update_us);
525 let dt_s = dt_us as f32 / 1_000_000.0;
526
527 let counts_per_second = 1000.0;
529
530 self.left_encoder += (left_norm * counts_per_second * dt_s) as i32;
531 self.right_encoder += (right_norm * counts_per_second * dt_s) as i32;
532
533 self.last_update_us = now;
534 }
535
536 pub fn state(&self) -> ControllerState {
538 self.state
539 }
540
541 pub fn config(&self) -> &L298nControllerConfig {
543 &self.config
544 }
545}
546
547fn now_us() -> u64 {
549 SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros() as u64
550}
551
552#[cfg(test)]
553mod tests {
554 use super::*;
555
556 #[tokio::test]
557 async fn test_controller_init() {
558 let config = L298nControllerConfig::default();
559 let controller = L298nMotorController::init(config).await;
560 assert!(controller.is_ok());
561 }
562
563 #[tokio::test]
564 async fn test_controller_start_stop() {
565 let config = L298nControllerConfig::default();
566 let mut controller = L298nMotorController::init(config).await.unwrap();
567
568 controller.start().await.unwrap();
569 assert_eq!(controller.state(), ControllerState::Running);
570
571 controller.stop().await.unwrap();
572 assert_eq!(controller.state(), ControllerState::Stopped);
573 }
574
575 #[tokio::test]
576 async fn test_set_velocity() {
577 let config = L298nControllerConfig::default();
578 let mut controller = L298nMotorController::init(config).await.unwrap();
579 controller.start().await.unwrap();
580
581 let result = controller.set_velocity(0.5, 0.5).await;
582 assert!(result.is_ok());
583 }
584
585 #[tokio::test]
586 async fn test_emergency_stop() {
587 let config = L298nControllerConfig::default();
588 let mut controller = L298nMotorController::init(config).await.unwrap();
589 controller.start().await.unwrap();
590
591 controller.set_velocity(1.0, 1.0).await.unwrap();
592 controller.emergency_stop().await.unwrap();
593
594 assert_eq!(controller.state(), ControllerState::Stopped);
595 }
596
597 #[tokio::test]
598 async fn test_capabilities() {
599 let config = L298nControllerConfig::default();
600 let controller = L298nMotorController::init(config).await.unwrap();
601
602 let caps = controller.capabilities();
603 assert_eq!(caps.controller_type, "motor");
604 assert_eq!(caps.implementation, "l298n");
605 assert!(!caps.supports("encoders"));
606 assert!(caps.supports("velocity_control"));
607 }
608}