Skip to main content

nyx_space/dynamics/guidance/
finiteburns.rs

1use anise::prelude::Almanac;
2/*
3    Nyx, blazing fast astrodynamics
4    Copyright (C) 2018-onwards Christopher Rabotin <christopher.rabotin@gmail.com>
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU Affero General Public License as published
8    by the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU Affero General Public License for more details.
15
16    You should have received a copy of the GNU Affero General Public License
17    along with this program.  If not, see <https://www.gnu.org/licenses/>.
18*/
19use hifitime::Epoch;
20
21use super::{GuidanceError, GuidanceLaw, Maneuver};
22use crate::cosmic::{GuidanceMode, Spacecraft};
23use crate::linalg::Vector3;
24use crate::State;
25use std::fmt;
26use std::sync::Arc;
27
28/// A guidance law for a set of pre-determined maneuvers.
29#[derive(Clone, Debug)]
30pub struct FiniteBurns {
31    /// Maneuvers should be provided in chronological order and non-overlapping, first maneuver first in the list
32    pub mnvrs: Vec<Maneuver>,
33}
34
35impl FiniteBurns {
36    /// Builds a schedule from the vector of maneuvers, must be provided in chronological order.
37    pub fn from_mnvrs(mnvrs: Vec<Maneuver>) -> Arc<Self> {
38        Arc::new(Self { mnvrs })
39    }
40
41    /// Find the maneuver with the closest start epoch that is less than or equal to the current epoch
42    /// and return it if its end epoch is after the current epoch
43    fn maneuver_at(&self, epoch: Epoch) -> Option<&Maneuver> {
44        let index = self.mnvrs.binary_search_by_key(&epoch, |mnvr| mnvr.start);
45        let mnvr = match index {
46            Err(0) => None, // No maneuvers start before the current epoch
47            Ok(index) => Some(&self.mnvrs[index]),
48            Err(index) => Some(&self.mnvrs[index - 1]), // Return the maneuver with the closest start epoch
49        }?;
50
51        (epoch <= mnvr.end).then_some(mnvr)
52    }
53}
54
55impl fmt::Display for FiniteBurns {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(f, "FiniteBurns with {} maneuvers", self.mnvrs.len())
58    }
59}
60
61impl GuidanceLaw for FiniteBurns {
62    fn direction(&self, osc: &Spacecraft) -> Result<Vector3<f64>, GuidanceError> {
63        // NOTE: We do not increment the mnvr number here. The power function is called first,
64        // so we let that function handle starting and stopping of the maneuver.
65        match osc.mode() {
66            GuidanceMode::Thrust => {
67                if let Some(next_mnvr) = self.maneuver_at(osc.epoch()) {
68                    <Maneuver as GuidanceLaw>::direction(next_mnvr, osc)
69                } else {
70                    Ok(Vector3::zeros())
71                }
72            }
73            _ => Ok(Vector3::zeros()),
74        }
75    }
76
77    fn throttle(&self, osc: &Spacecraft) -> Result<f64, GuidanceError> {
78        match osc.mode() {
79            GuidanceMode::Thrust => {
80                if let Some(next_mnvr) = self.maneuver_at(osc.epoch()) {
81                    Ok(next_mnvr.thrust_prct)
82                } else {
83                    Ok(0.0)
84                }
85            }
86            _ => {
87                // We aren't in maneuver mode, so return 0% throttle
88                Ok(0.0)
89            }
90        }
91    }
92
93    fn next(&self, sc: &mut Spacecraft, _almanac: Arc<Almanac>) {
94        // check if there is a current maneuver and put into Thrust mode otherwise Coast
95        if self.maneuver_at(sc.epoch()).is_some() {
96            sc.mut_mode(GuidanceMode::Thrust)
97        } else {
98            // There aren't any maneuvers
99            sc.mut_mode(GuidanceMode::Coast)
100        }
101    }
102}