Proposed Redesign
Context
Path Manager is a state machine in ZeroPilot that determines how we get our plane from point A to B. Over the past few months, Path Manager’s complexity has increased grealty with the introduction of landing and takeoff states. In the future, it will only get more complex. To make Path Manager more modular and expandable, it will need to be redesigned. This document contains one such proposal, which will introduce sub-state machines (dubbed Modes) with their own states (dubbed Stages).
States, Modes, and Stages
Before we go forward, we must define these three words:
State - Lives in Path Manager and is a child class to pathManagerState
Mode - Is a type of flight exhibited by our aircraft. It includes, but is not limited to: landing, takeoff, cruising, and taxiing. Each mode is a sub-state machine to Path Manager (meaning its execution methods are called exclusively by Path Manager)
Stage - Is a specific function executed by an aircraft in a mode of flight. Stages are the states for the Modes (sub-state machines). Each mode has at least one stage.
For example, takeoff has two stages: rolling and climb.
Another example is landing, which has five stages: transition, slope, flare, decrab, and touchdown.
Intended Final Result
Path Manager (that is,
pathManager
,pathManagerState
, and their children) should not know which mode of flight we are in.Each mode needs to be an independent unit, ensuring expandibility
Modes must be able to switch between each other without the help of Path Manager states.
The modes must all be called via one singular
execute()
method call in a Path Manager state.
In the end, Path Manager will look like the following flowchart
The Enums
We will need to introduce a few new enums to represent different modes and stages within each mode:
Modes
enum ModeEnum {MODE_TAKEOFF = 0, MODE_CRUISING, MODE_LANDING, MODE_TAXIING};
Stages
Takeoff
enum TakeoffStages {
TAKEOFF_ROLL = 0,
TAKEOFF_CLIMB
};
Cruising
enum CruisingStages {
CRUISING = 0
};
Landing
Taxiing
tbd…
The Classes
ModeSelector
An abstraction layer that Path Manager interacts with directly. It ensures that Path Manager never knows what mode of flight we are in.
In the code, this class is PathModeSelector
.
ModeSelector (Singleton) |
- current_mode : ModeParent* - current_mode_enum : ModeEnum - is_error : bool - static singleton : PathModeSelector*
// The following are all output data - altitude_airspeed_input : AltitudeAirspeedInput_t - altitude_airspeed_input : AltitudeAirspeedInput_t - Individual member variables that will need to be used/sent down by telemetry |
- ModeSelector() + static getInstance() → ModeSelector* + execute(Telemetry_PIGO_t, SFOutput_t, …) → void // Input data sent in via parameters + getCurrentMode() → ModeParent* + getCurrentModeEnum() → ModeEnum + setCurrentMode(ModeParent&) → void + setCurrentModeEnum(ModeEnum) → Void + getters and setters for all output data |
Mode
Is akin to the pathManager
class in ZeroPilot. One of these classes will exist for each mode of flight: Crusing, Landing, Takeoff, Taxiing, etc.
Examples in the code of this class include CruisingMode
and LandingMode
.
Mode (Singleton) |
- current_stage : ModeStage* - stage_status : STAGE_ENUM - mode_selector : ModeSelector* - current_status : PathMan::_Path_Manager_Cycle_Status |
- Mode() + static getInstance() → ModeParent + execute() → void + getCurrentStage() → ModeStage* + setCurrentStage(ModeStage&) → void + getCurrentStageEnum() → STAGE_ENUM + setCurrentStageEnum(STAGE_ENUM) → void + getModeSelector() → ModeSelector& + Gettes and setters to access data in ModeSelector and ModeParent |
* STAGE_ENUM is a substitute for TakeoffStages, LandingStages, etc.
WAIT! POLYMORPHISM
With many different Mode
Classes , we need some way of storing them all within the same pointer current_mode
in the ModeSelector
class. To accomplish this, we will declare an abstract base class, ModeParent
(or PathMode
in the code) which will be the parent to all Mode
classes.
ModeParent |
# current_status : PathMan::_Path_Manager_Cycle_Status # telemetry_data : Telemetry_PIGO_t # sf_data : SFOutput_t # imu_data : IMU_Data_t
+ bool operator==(const ModeParent&) |
+ execute(Telemetry_PIGO_t, SFOutput_t, IMU_Data_t) = 0 → void + getTelemetryData() → Telemetry_PIGO_t + getSensorFusionData() → SFOutput_t + getImuData() → IMU_Data_t |
ModeStage
Is akin to the pathManagerState
class in ZeroPilot. Each of these classes will represent a stage in a mode of flight (ex. landingFlareStage
in landing or takeoffClimbStage
in takeoff). This will be an abstract base class (ABC).
An example of this class in the code is LandingModeStageManager
and CruisingModeStageManager
.
ModeStage (ABC) |
+ operator ==(const ModeStage&) const → bool |
+ enter(Mode*) = 0 → void + execute(Mode*) = 0 → void + exit(Mode*) = 0 → void + ~ModeStage() → void |
Stage
Each individual stage class is like the state classes (ex. commsWithTelemetry
) in Path Manager.
Examples of this class include CruisingFlight
and LandingTransitionStage
.
Stage (Singleton) |
- Stage(const Stage&) - Stage& operator =(const Stage&) - any additional parameters |
- Stage() + enter(Mode*) → void + execute(Mode*) → void + exit(Mode*) → void + static getInstance() → Stage& + getters for private data |
Flow of Code
Here is the flow of code when Path Manager’s ModeExecuter
state calls ModeSelector::execute(params)
: