mecha10_nodes_object_detector/
config.rs

1//! Configuration for Object Detector Node
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Object detector node configuration
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ObjectDetectorConfig {
9    /// Path to ONNX model file
10    #[serde(default = "default_model_path")]
11    pub model_path: String,
12
13    /// Model name for identification
14    #[serde(default = "default_model_name")]
15    pub model_name: String,
16
17    /// Input size for YOLO model (usually 640)
18    #[serde(default = "default_input_size")]
19    pub input_size: u32,
20
21    /// Confidence threshold for detections (0-1)
22    #[serde(default = "default_confidence_threshold")]
23    pub confidence_threshold: f32,
24
25    /// IoU threshold for Non-Maximum Suppression (0-1)
26    #[serde(default = "default_iou_threshold")]
27    pub iou_threshold: f32,
28
29    /// Maximum number of detections to return
30    #[serde(default = "default_max_detections")]
31    pub max_detections: usize,
32
33    /// Frame skip - process every Nth frame (1 = process all)
34    #[serde(default = "default_frame_skip")]
35    pub frame_skip: u32,
36
37    /// Start enabled by default
38    #[serde(default = "default_enabled")]
39    pub default_enabled: bool,
40
41    /// Use INT8 quantization (requires quantized ONNX model)
42    #[serde(default = "default_use_int8")]
43    pub use_int8: bool,
44
45    /// Max concurrent async preprocessing tasks (1 = serialize, prevents threading delay)
46    #[serde(default = "default_max_async_frames")]
47    pub max_async_frames: usize,
48
49    /// Topics configuration (for framework topology)
50    #[serde(default)]
51    pub topics: Topics,
52}
53
54/// Topics configuration for object detector
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct Topics {
57    /// Topics this node publishes to
58    /// Format: [{ "output": "/vision/object/detections" }]
59    #[serde(default)]
60    pub publishes: Vec<HashMap<String, String>>,
61
62    /// Topics this node subscribes to
63    /// Format: [{ "input": "/camera/rgb" }, { "control": "/vision/object/control" }]
64    #[serde(default)]
65    pub subscribes: Vec<HashMap<String, String>>,
66}
67
68impl Default for Topics {
69    fn default() -> Self {
70        let mut publishes = Vec::new();
71        let mut subscribes = Vec::new();
72
73        // Default publish topic
74        let mut pub_map = HashMap::new();
75        pub_map.insert("output".to_string(), "/vision/object/detections".to_string());
76        publishes.push(pub_map);
77
78        // Default subscribe topics
79        let mut input_map = HashMap::new();
80        input_map.insert("input".to_string(), "/camera/rgb".to_string());
81        subscribes.push(input_map);
82
83        let mut control_map = HashMap::new();
84        control_map.insert("control".to_string(), "/vision/object/control".to_string());
85        subscribes.push(control_map);
86
87        Self { publishes, subscribes }
88    }
89}
90
91impl ObjectDetectorConfig {
92    /// Get input topic path from topics config
93    pub fn input_topic(&self) -> String {
94        self.topics
95            .subscribes
96            .iter()
97            .find_map(|t| t.get("input"))
98            .cloned()
99            .unwrap_or_else(|| "/camera/rgb".to_string())
100    }
101
102    /// Get output topic path from topics config
103    pub fn output_topic(&self) -> String {
104        self.topics
105            .publishes
106            .iter()
107            .find_map(|t| t.get("output"))
108            .cloned()
109            .unwrap_or_else(|| "/vision/object/detections".to_string())
110    }
111
112    /// Get control topic path from topics config
113    pub fn control_topic(&self) -> String {
114        self.topics
115            .subscribes
116            .iter()
117            .find_map(|t| t.get("control"))
118            .cloned()
119            .unwrap_or_else(|| "/vision/object/control".to_string())
120    }
121}
122
123fn default_model_path() -> String {
124    "models/yolov8n/model.onnx".to_string()
125}
126
127fn default_model_name() -> String {
128    "yolov8n".to_string()
129}
130
131fn default_input_size() -> u32 {
132    640
133}
134
135fn default_confidence_threshold() -> f32 {
136    0.5
137}
138
139fn default_iou_threshold() -> f32 {
140    0.45
141}
142
143fn default_max_detections() -> usize {
144    100
145}
146
147fn default_frame_skip() -> u32 {
148    1
149}
150
151fn default_enabled() -> bool {
152    false
153}
154
155fn default_use_int8() -> bool {
156    false
157}
158
159fn default_max_async_frames() -> usize {
160    1
161}
162
163impl Default for ObjectDetectorConfig {
164    fn default() -> Self {
165        Self {
166            model_path: default_model_path(),
167            model_name: default_model_name(),
168            input_size: default_input_size(),
169            confidence_threshold: default_confidence_threshold(),
170            iou_threshold: default_iou_threshold(),
171            max_detections: default_max_detections(),
172            frame_skip: default_frame_skip(),
173            default_enabled: default_enabled(),
174            use_int8: default_use_int8(),
175            max_async_frames: default_max_async_frames(),
176            topics: Topics::default(),
177        }
178    }
179}