FCC 静态编译与有限状态机 (FSM) 架构重构蓝图
1. 背景与核心动机
当前 FCC (run_fcc_step) 在 10ms 级别的热点循环中存在巨大的性能瓶颈,其根本原因是动态构建抽象语法树 (AST):
- 每一帧都在动态构造 Free Monad 和 RWS Monad 流水线。
- 每一帧都在遍历
FccEnv的配置,并通过std::map::find(字符串哈希) 实时查找 GNC 算法的函数指针。 这种“解释器放进热点循环”的反模式导致极高的堆分配与寻址开销。本重构蓝图旨在将这套动态系统拆分为初始化期 (编译) 和 循环期 (极速路由),同时恪守函数式纯粹性与系统解耦原则。
2. 核心机制:Fcc_Clock 与跨域解耦
为了解决物理仿真与控制逻辑之间的变步长、整脉冲对齐问题,同时避免 FCC 与 Dynamics 引擎互相耦合(越权调用),我们引入了 Fcc_Clock。
Fcc_Clock 的本质:RTOS 与总线控制 (BC) 晶振
在真实物理总线(如 MIL-STD-1553B)架构中,FCC 作为总线控制器 (BC),其晶振定义了全系统的调度时间。Fcc_Clock 是此物理硬件晶振的数字孪生。
- 定时与中断:FCC 内部的关机算法(如发现达到目标轨道)计算出精确剩余时间 $\Delta t$,调用
Fcc_Clock注册一个未来的硬件中断时间点。 - 输出语义指令:FCC 将这个“预期事件时间”写入
FccOutFrame.sequencing.next_critical_event_time,并扔给总线,随后 FCC 自身进入盲目等待状态,直至其自身的晶振到达该时间。 - 动力学侧的自主响应:在
closed_loop_10s.cpp主循环中,Dynamics / ICU 作为硬件设备 (RT) 收到总线消息,发现未来有精确事件。是动力学自己决定截断 ODE 积分步长,对齐该时间点,完成级间分离或物理模型重组,进而计算精确的 IMU 脉冲增量返回给总线。FCC 全程不调用任何 Dynamics API。
3. FCC 三层极速架构 (The Ground Truth)
重构后的 FCC 将被严格划分为三个层次,各司其职:
Layer 1: 宏观外壳 (The Shell) - Free Monad
- 职责:抽象 IO / Effect。
- 形态:它仅仅作为整个 FCC 的最外层包装。从总线抓取
FccInFrame,把内层计算得出的FccOutFrame推给总线执行。 - 意义:实现“SITL(软件在环普通电脑)”与“真实 RTOS 硬件”环境的无缝移植。它不参与具体的姿态、导航运算流的构建。
Layer 2: 状态机中枢 (The Router) - FSM
- 职责:宏观生命周期管理与阶段 (Stage) 路由。
- 形态:一个依赖于
FccState.clock的有限状态机。 - 运作:
- 每帧入口,滴答
Fcc_Clock,检查是否有已预订的硬件中断被触发。 - 若触发(如 MECO 发动机关机中断),则切换
FccState.current_stage到下一阶段。 - 执行一次
O(1)的std::map查找,获取当前阶段对应的静态闭包(见 Layer 3),喂入输入帧。
- 每帧入口,滴答
Layer 3: 微观内核 (The Core) - 独立预编译的 FccRWS Pipelines
- 职责:纯粹的数学、导航、制导与控制逻辑计算。
- 编译时行为:在系统初始化 (0时刻) 时,
FccCompiler遍历 YAML 配置,将每个 Stage 内部的所有 GNC 任务(如SINS_Nav >>= PitchProgram >>= PID)预先绑定,生成一条极致优化的纯粹FccRWS<FccOutFrame>实例。 - 极致性能保障:
- 绝不混杂:不同的飞行阶段(例如
Stage1_Ascent和TargetOrbit)被编译为各自独立的 Pipeline。 - 最小化类型擦除:只在放入路由
std::map<std::string, FccRWS<FccOutFrame>>的边界处发生唯一一次类型擦除。 - 零开销运行:一旦进入 RWS 内部,所有 Task 的执行都是由编译器极致内联的指针调用,没有任何字符串查找或动态内存分配。
- 绝不混杂:不同的飞行阶段(例如
4. 总结
这套架构融合了 Free Monad 的环境隔离能力、RWS Monad 的函数式单向数据流能力,以及硬件孪生 (Fcc_Clock) 的实时调度能力。它成功将动态语言级别的灵活性(YAML 配置阶段控制律)与 C++ 系统级的极速性能结合,为高精度、变步长的闭环仿真扫清了性能障碍。