mecha10_behavior_runtime/actions/
navigation.rs1use crate::{BehaviorNode, Context, NodeStatus, TreeStatusSnapshot};
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8macro_rules! stub_tick_success {
9 ($msg:literal) => {{
10 tracing::debug!($msg);
11 Ok(NodeStatus::Success)
12 }};
13}
14
15#[derive(Debug)]
16pub struct PlanPathNode {
17 #[allow(dead_code)]
18 target_position: Vec<f64>,
19 #[allow(dead_code)]
20 algorithm: String,
21 last_status: Option<NodeStatus>,
22}
23
24#[derive(Debug, Serialize, Deserialize)]
25struct PlanPathConfig {
26 target_position: Vec<f64>,
27 #[serde(default = "default_algorithm")]
28 path_planning_algorithm: String,
29}
30
31fn default_algorithm() -> String {
32 "a_star".to_string()
33}
34
35impl PlanPathNode {
36 pub fn from_json(config: Value) -> anyhow::Result<Self> {
38 let cfg: PlanPathConfig = serde_json::from_value(config)?;
39 Ok(Self {
40 target_position: cfg.target_position,
41 algorithm: cfg.path_planning_algorithm,
42 last_status: None,
43 })
44 }
45}
46
47#[async_trait]
48impl BehaviorNode for PlanPathNode {
49 async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
50 tracing::debug!("PlanPathNode: planning path to {:?} (stub)", self.target_position);
51 self.last_status = Some(NodeStatus::Success);
52 Ok(NodeStatus::Success)
53 }
54
55 fn name(&self) -> &str {
56 "PlanPathNode"
57 }
58
59 fn status_snapshot(&self) -> TreeStatusSnapshot {
60 TreeStatusSnapshot {
61 name: self.name().to_string(),
62 status: self.last_status,
63 active_capability: self.active_capability().map(String::from),
64 children: Vec::new(),
65 }
66 }
67}
68
69#[derive(Debug)]
70pub struct FollowPathNode {
71 #[allow(dead_code)]
72 topic: String,
73 #[allow(dead_code)]
74 max_speed: f64,
75 #[allow(dead_code)]
76 turn_rate: f64,
77 last_status: Option<NodeStatus>,
78}
79
80#[derive(Debug, Serialize, Deserialize)]
81struct FollowPathConfig {
82 #[serde(default = "default_motor_topic")]
83 topic: String,
84 #[serde(default = "default_max_speed")]
85 max_speed: f64,
86 #[serde(default = "default_turn_rate")]
87 turn_rate: f64,
88}
89
90fn default_motor_topic() -> String {
91 "/motor/cmd_vel".to_string()
92}
93
94fn default_max_speed() -> f64 {
95 1.0
96}
97
98fn default_turn_rate() -> f64 {
99 0.5
100}
101
102impl FollowPathNode {
103 pub fn from_json(config: Value) -> anyhow::Result<Self> {
105 let cfg: FollowPathConfig = serde_json::from_value(config)?;
106 Ok(Self {
107 topic: cfg.topic,
108 max_speed: cfg.max_speed,
109 turn_rate: cfg.turn_rate,
110 last_status: None,
111 })
112 }
113}
114
115#[async_trait]
116impl BehaviorNode for FollowPathNode {
117 async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
118 self.last_status = Some(NodeStatus::Success);
119 stub_tick_success!("FollowPathNode: following path (stub)")
120 }
121
122 fn name(&self) -> &str {
123 "FollowPathNode"
124 }
125
126 fn status_snapshot(&self) -> TreeStatusSnapshot {
127 TreeStatusSnapshot {
128 name: self.name().to_string(),
129 status: self.last_status,
130 active_capability: self.active_capability().map(String::from),
131 children: Vec::new(),
132 }
133 }
134}
135
136#[derive(Debug)]
137pub struct CheckArrivalNode {
138 #[allow(dead_code)]
139 position_tolerance: f64,
140 #[allow(dead_code)]
141 angular_tolerance: f64,
142 last_status: Option<NodeStatus>,
143}
144
145#[derive(Debug, Serialize, Deserialize)]
146struct CheckArrivalConfig {
147 position_tolerance: f64,
148 angular_tolerance: f64,
149}
150
151impl CheckArrivalNode {
152 pub fn from_json(config: Value) -> anyhow::Result<Self> {
154 let cfg: CheckArrivalConfig = serde_json::from_value(config)?;
155 Ok(Self {
156 position_tolerance: cfg.position_tolerance,
157 angular_tolerance: cfg.angular_tolerance,
158 last_status: None,
159 })
160 }
161}
162
163#[async_trait]
164impl BehaviorNode for CheckArrivalNode {
165 async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
166 self.last_status = Some(NodeStatus::Success);
167 stub_tick_success!("CheckArrivalNode: checking arrival (stub)")
168 }
169
170 fn name(&self) -> &str {
171 "CheckArrivalNode"
172 }
173
174 fn status_snapshot(&self) -> TreeStatusSnapshot {
175 TreeStatusSnapshot {
176 name: self.name().to_string(),
177 status: self.last_status,
178 active_capability: self.active_capability().map(String::from),
179 children: Vec::new(),
180 }
181 }
182}