STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
state_machine.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <map>
3#include <memory>
4#include <string>
5#include <vector>
6
7// ============================================================================
8// DATA STRUCTURES
9// ============================================================================
10
11// Sensor readings and system state parameters
13 // Pressures (psi)
14 float PT_HP = 0.0f;
15 float PT_LP = 0.0f;
16 float PT_F = 0.0f;
17 float PT_O = 0.0f;
18
19 float RTD_O1 = 0.0f;
20 float RTD_O2 = 0.0f;
21 float RTD_O3 = 0.0f;
22
23 float PT_I = 0.0f;
24 float TC_I = 0.0f;
25 float PT_C1 = 0.0f;
26 float TC_C1 = 0.0f;
27 float TC_C3 = 0.0f;
28 float TC_C2 = 0.0f;
29 float PT_C2 = 0.0f;
30 float TC_C4 = 0.0f;
31
32 // Solenoid states (true = open/energized, false = closed/de-energized)
33 bool SOL_PV = false;
34 bool SOL_FUP = false;
35 bool SOL_FV = false;
36 bool SOL_OUP = false;
37 bool SOL_OV = false;
38 bool SOL_FDP = false;
39 bool MOT_ODP = false;
40
41 bool ROT_MF = false;
42 bool ROT_MO = false;
43
44 // Valve states (true = open, false = closed)
45};
46
47// ============================================================================
48// STATE MACHINE BASE CLASS
49// ============================================================================
50
52public:
53 virtual ~EngineState() = default;
54 virtual void on_enter(
55 SystemParameters& params) = 0; // Called when entering the state
56 virtual bool update(
58 params) = 0; // Called repeatedly while in the state// Returns true
59 // if state should automatically transition to next
60 // state
61 virtual void on_exit(
62 SystemParameters& params) = 0; // Called when exiting the state
63 virtual std::string get_name() const = 0; // Get human-readable state name
64 virtual bool validate_entry(const SystemParameters& params)
65 const = 0; // Define what conditions must be met to enter this state//
66 // Each state checks the current SystemParameters and
67 // returns whether entry is valid
68 virtual std::vector<std::string> get_allowed_transitions()
69 const // Return an empty vector if no manual transitions are allowed //
70 // Define which states can be transitioned to FROM this state
71 {
72 return {};
73 }
74 virtual std::string get_next_state_name() const {
75 return "";
76 }
77 virtual bool is_automatic()
78 const // If true, this state automatically checks transition
79 // requirements for get_next_state_name()
80 {
81 return false;
82 }
83};
84
85// ============================================================================
86// STATE MACHINE MANAGER
87// ============================================================================
88
89class EngineFSM {
90public:
91 EngineFSM();
92
93 void register_state(const std::string& state_name,
94 std::shared_ptr<EngineState> state);
95 bool request_transition(const std::string& target_state,
96 SystemParameters& params); // manual transition
97 void update(SystemParameters& params);
98 std::string get_current_state() const;
99 std::vector<std::string> get_available_transitions(
100 const SystemParameters& params)
101 const; // Get all states that can be transitioned to from the current
102 // state// Includes only states whose validation criteria are
103 // currently met
104
105private:
106 void transition_to_state(const std::string& state_name,
107 SystemParameters& params);
108 bool can_enter_state(const std::string& state_name,
109 const SystemParameters& params) const;
110
111 std::map<std::string, std::shared_ptr<EngineState>> states;
112 std::string current_state;
113};
114
115// ============================================================================
116// IMPLEMENTATION
117// ============================================================================
118
121
122void EngineFSM::register_state(const std::string& state_name,
123 std::shared_ptr<EngineState> state) {
124 if (states.find(state_name) != states.end()) {
125 std::cerr << "Warning: State '" << state_name
126 << "' already registered\n";
127 return;
128 }
129 states[state_name] = state;
130
131 // Initialize to first registered state
132 if (current_state.empty()) {
133 current_state = state_name;
134 }
135}
136
138 if (states.find(current_state) == states.end()) {
139 return;
140 }
141
142 auto current = states[current_state];
143
144 // Update the current state
145 current->update(params);
146
147 // If this is an automatic state, check if we should transition
148 if (current->is_automatic()) {
149 std::string next_state_name = current->get_next_state_name();
150
151 if (!next_state_name.empty() &&
152 states.find(next_state_name) != states.end()) {
153 // Check if the next state's validation criteria are met
154 if (can_enter_state(next_state_name, params)) {
155 transition_to_state(next_state_name, params);
156 }
157 }
158 }
159}
160
161bool EngineFSM::request_transition(const std::string& target_state,
162 SystemParameters& params) {
163 // Check if target state exists
164 if (states.find(target_state) == states.end()) {
165 std::cerr << "Error: Target state '" << target_state
166 << "' not registered\n";
167 return false;
168 }
169
170 // Check if target state's validation criteria are met
171 if (!can_enter_state(target_state, params)) {
172 std::cerr << "Error: Cannot enter state '" << target_state
173 << "' - validation criteria not met\n";
174 return false;
175 }
176
177 transition_to_state(target_state, params);
178 return true;
179}
180
181void EngineFSM::transition_to_state(const std::string& state_name,
182 SystemParameters& params) {
183 // Exit current state
184 if (states.find(current_state) != states.end()) {
185 states[current_state]->on_exit(params);
186 std::cout << "Exiting state: " << states[current_state]->get_name()
187 << "\n";
188 }
189
190 // Enter new state
191 current_state = state_name;
192 states[current_state]->on_enter(params);
193 std::cout << "Entering state: " << states[current_state]->get_name()
194 << "\n";
195}
196
197std::string EngineFSM::get_current_state() const {
198 return current_state;
199}
200
201bool EngineFSM::can_enter_state(const std::string& state_name,
202 const SystemParameters& params) const {
203 if (states.find(state_name) == states.end()) {
204 return false;
205 }
206 auto allowed = states.at(current_state)->get_allowed_transitions();
207 if (std::find(allowed.begin(), allowed.end(), state_name) ==
208 allowed.end()) {
209 return false; // Not an allowed transition from current state
210 }
211 return states.at(state_name)->validate_entry(params);
212}
213
215 const SystemParameters& params) const {
216 std::vector<std::string> available;
217
218 // Get the list of allowed transitions from the current state
219 if (states.find(current_state) == states.end()) {
220 return available;
221 }
222
223 auto allowed = states.at(current_state)->get_allowed_transitions();
224
225 // Filter to only those whose validation criteria are met
226 for (const auto& target_state : allowed) {
227 if (can_enter_state(target_state, params)) {
228 available.push_back(target_state);
229 }
230 }
231
232 return available;
233}
234
235// ============================================================================
236// EXAMPLE USAGE (SKELETON - ADD YOUR STATES HERE)
237// ============================================================================
238
239/*
240// Example: Manual state (requires user command to transition)
241class IdleState : public EngineState {
242public:
243 void on_enter(const SystemParameters& params) override {
244 std::cout << " Idle: All systems standing by\n";
245 }
246
247 bool update(const SystemParameters& params) override {
248 return false; // No automatic behavior
249 }
250
251 void on_exit(const SystemParameters& params) override {
252 std::cout << " Idle: Leaving idle state\n";
253 }
254
255 std::string get_name() const override {
256 return "Idle";
257 }
258
259 bool validate_entry(const SystemParameters& params) const override {
260 // Idle can always be entered (e.g., abort state)
261 return true;
262 }
263
264 std::vector<std::string> get_allowed_transitions() const override {
265 return {"Pressurize", "Abort"};
266 }
267};
268
269// Example: Automatic state (transitions automatically when next state's
270conditions are met) class PressurizeState : public EngineState { private:
271 // Track state duration or progress
272 int iteration_count = 0;
273
274public:
275 void on_enter(const SystemParameters& params) override {
276 std::cout << " Pressurize: Starting pressurization sequence\n";
277 iteration_count = 0;
278 // In real code: open GN2 solenoid, monitor pressures, etc.
279 }
280
281 bool update(const SystemParameters& params) override {
282 iteration_count++;
283 // Simulate pressure building
284 if (iteration_count % 10 == 0) {
285 std::cout << " Pressurize: Pressurizing tanks...\n";
286 }
287 return false; // Don't return true; let is_automatic() handle
288transitions
289 }
290
291 void on_exit(const SystemParameters& params) override {
292 std::cout << " Pressurize: Pressurization complete\n";
293 }
294
295 std::string get_name() const override {
296 return "Pressurize";
297 }
298
299 bool validate_entry(const SystemParameters& params) const override {
300 // Can only enter if initial state is acceptable
301 return true; // Define real conditions based on your system
302 }
303
304 std::vector<std::string> get_allowed_transitions() const override {
305 return {"Idle", "Abort"};
306 }
307
308 bool is_automatic() const override {
309 return true;
310 }
311
312 std::string get_next_state_name() const override {
313 return "ReadyToFire";
314 }
315};
316
317// Example: Target state for automatic transition
318class ReadyToFireState : public EngineState {
319public:
320 void on_enter(const SystemParameters& params) override {
321 std::cout << " ReadyToFire: All systems pressurized and ready\n";
322 }
323
324 bool update(const SystemParameters& params) override {
325 return false;
326 }
327
328 void on_exit(const SystemParameters& params) override {
329 std::cout << " ReadyToFire: Leaving ready state\n";
330 }
331
332 std::string get_name() const override {
333 return "ReadyToFire";
334 }
335
336 bool validate_entry(const SystemParameters& params) const override {
337 // Define conditions that must be met to enter ready state
338 // For example: all pressures in acceptable range
339 return params.fuel_pressure > 100.0f &&
340 params.ox_pressure > 100.0f &&
341 params.gn2_pressure > 50.0f;
342 }
343
344 std::vector<std::string> get_allowed_transitions() const override {
345 return {"Fire", "Abort"};
346 }
347};
348
349// In main():
350EngineFSM fsm;
351fsm.register_state("Idle", std::make_shared<IdleState>());
352fsm.register_state("Pressurize", std::make_shared<PressurizeState>());
353fsm.register_state("ReadyToFire", std::make_shared<ReadyToFireState>());
354// Register more states...
355
356SystemParameters params;
357
358// Main loop
359while (true) {
360 // Read sensor data into params...
361 // params.fuel_pressure = read_fuel_pressure();
362 // params.ox_pressure = read_ox_pressure();
363 // etc.
364
365 // Display available transitions to user
366 auto available = fsm.get_available_transitions(params);
367 std::cout << "Available transitions from " << fsm.get_current_state() <<
368":\n"; for (const auto& state : available) { std::cout << " - " << state <<
369"\n";
370 }
371
372 // Update state machine (handles automatic transitions)
373 fsm.update(params);
374
375 // User can request manual transitions
376 // if (user_wants_pressurize) {
377 // fsm.request_transition("Pressurize", params);
378 // }
379}
380*/
std::string get_current_state() const
std::vector< std::string > get_available_transitions(const SystemParameters &params) const
std::map< std::string, std::shared_ptr< EngineState > > states
void register_state(const std::string &state_name, std::shared_ptr< EngineState > state)
bool request_transition(const std::string &target_state, SystemParameters &params)
bool can_enter_state(const std::string &state_name, const SystemParameters &params) const
std::string current_state
void transition_to_state(const std::string &state_name, SystemParameters &params)
void update(SystemParameters &params)
virtual bool is_automatic() const
virtual bool validate_entry(const SystemParameters &params) const =0
virtual std::string get_name() const =0
virtual std::string get_next_state_name() const
virtual std::vector< std::string > get_allowed_transitions() const
virtual void on_exit(SystemParameters &params)=0
virtual void on_enter(SystemParameters &params)=0
virtual bool update(SystemParameters &params)=0
virtual ~EngineState()=default
static ActuatorControllerState state
Definition main.cpp:57