1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate::control::{Moment, PositionController, Trajectory};
use crate::motors::{esc::ESC, MotorMatrix};
use crate::AHRS;
use embedded_time::{clock, duration::Seconds, Clock, Instant};
use nalgebra::Vector3;

mod builder;
pub use builder::Builder;

pub struct Copter<C: Clock, A, E, const N: usize> {
    pub controller: PositionController,
    pub motors: MotorMatrix<E, f32, N>,
    pub max_thrust: f32,
    pub max_radian_rate: f32,
    pub last_position: Vector3<f32>,
    pub last_time: f32,
    pub takeoff_time: Instant<C>,
    pub clock: C,
    pub ahrs: A,
}

impl<C, A, E, const N: usize> Copter<C, A, E, N>
where
    C: Clock<T = u32>,
    A: AHRS,
    E: ESC<Output = f32>,
{
    pub fn builder() -> Builder<C, A, E, N> {
        Builder::default()
    }

    pub fn take_off(&mut self, height: f32, time: f32) -> Result<(), clock::Error> {
        self.motors.arm();
        self.takeoff_time = self.clock.try_now()?;

        self.fly(Vector3::new(0., 0., height), time)
    }

    pub fn fly(&mut self, to: Vector3<f32>, time: f32) -> Result<(), clock::Error> {
        let now: u32 = Seconds::try_from(self.clock.try_now()? - self.takeoff_time)
            .unwrap()
            .0;
        let trajectory =
            Trajectory::calculate(self.last_position, self.last_time, to, time, now as f32);

        let motor_cmd = self.controller.trajectory_control(
            trajectory,
            self.ahrs.local_position(),
            self.ahrs.local_velocity(),
            self.ahrs.attitude(),
            self.ahrs.angle_rates(),
        );
        self.output_moment(motor_cmd);

        Ok(())
    }

    pub fn output_moment(&mut self, moment: Moment) {
        self.motors.output(
            moment.attitude / self.max_radian_rate,
            Vector3::new(0., 0., moment.thrust / self.max_thrust),
        );
    }
}