gmt_dos_clients_mount/
lib.rs

1/*!
2# GMT mount control model
3
4A [gmt_dos-actors] client for the GMT mount control system.
5
6## Example
7
8Commanding the elevation axis of the mount to a 1arcsec offset.
9
10```no_run
11// Dependencies:
12//  * tokio
13//  * gmt_dos_actors
14//  * gmt_dos_clients
15//  * gmt_dos_clients_io
16//  * gmt_dos_clients_arrow
17//  * gmt_dos_clients_fem
18//  * gmt-fem
19//  * gmt_dos_clients_mount
20//  * gmt-lom
21//  * skyangle
22// Environment variables:
23//  * FEM_REPO
24//  * LOM
25
26# tokio_test::block_on(async {
27use gmt_dos_actors::actorscript;
28use gmt_dos_clients::signals::{Signal, Signals};
29use gmt_dos_clients_fem::{fem_io::actors_outputs::*, DiscreteModalSolver, solvers::ExponentialMatrix};
30use gmt_dos_clients_io::{
31    gmt_m1::M1RigidBodyMotions,
32    gmt_m2::M2RigidBodyMotions,
33    mount::{MountEncoders, MountSetPoint, MountTorques},
34};
35use gmt_dos_clients_mount::Mount;
36use gmt_fem::FEM;
37use gmt_lom::{OpticalMetrics, LOM};
38use skyangle::Conversion;
39use serde::{Deserialize, Serialize};
40use gmt_mount_ctrl_controller::MountController;
41use gmt_mount_ctrl_driver::MountDriver;
42
43let sim_sampling_frequency = 1000; // Hz
44let sim_duration = 20_usize; // second
45let n_step = sim_sampling_frequency * sim_duration;
46// FEM MODEL
47let state_space = {
48    let fem = FEM::from_env()?;
49    println!("{fem}");
50    DiscreteModalSolver::<ExponentialMatrix>::from_fem(fem)
51        .sampling(sim_sampling_frequency as f64)
52        .proportional_damping(2. / 100.)
53        .including_mount()
54        .outs::<OSSM1Lcl>()
55        .outs::<MCM2Lcl6D>()
56        .use_static_gain_compensation()
57        .build()?
58};
59println!("{state_space}");
60// SET POINT
61let setpoint = Signals::new(3, n_step).channel(1, Signal::Constant(1f64.from_arcsec()));
62// MOUNT CONTROL
63let mount = Mount::new();
64actorscript! {
65    #[model(state = completed)]
66    1: setpoint[MountSetPoint]
67        -> mount[MountTorques]
68            -> state_space[MountEncoders]!
69                -> mount
70    1: state_space[M1RigidBodyMotions]$
71    1: state_space[M2RigidBodyMotions]$
72}
73// Linear optical sensitivities to derive segment tip and tilt
74let lom = LOM::builder()
75    .rigid_body_motions_record(
76        (*model_logging_1.lock().await).record()?,
77        Some("M1RigidBodyMotions"),
78        Some("M2RigidBodyMotions"),
79    )?
80    .build()?;
81let segment_tiptilt = lom.segment_tiptilt();
82let stt = segment_tiptilt.items().last().unwrap();
83println!("Segment TT: {:.3?}mas", stt.to_mas());
84# anyhow::Result::<()>::Ok(())
85# });
86```
87
88[gmt_dos-actors]: https://docs.rs/gmt_dos-actors
89*/
90
91use gmt_mount_ctrl_controller::MountController;
92use gmt_mount_ctrl_driver::MountDriver;
93use interface::filing::Codec;
94use serde::{Deserialize, Serialize};
95
96/// Discrete sampling frequency [Hz] of the mount controller
97pub fn sampling_frequency() -> usize {
98    match env!("MOUNT_MODEL") {
99        "MOUNT_PDR_8kHz" | "MOUNT_FDR_8kHz" => 8000,
100        "MOUNT_FDR_1kHz" | "MOUNT_FDR_1kHz-az17Hz" => 1000,
101        val => panic!("Unknown mount model: {val}"),
102    }
103}
104
105#[cfg(fem)]
106mod builder;
107#[cfg(fem)]
108pub use builder::Builder;
109
110mod actors_interface;
111
112/// GMT mount control model
113///
114// A [gmt_dos-actors] client for the GMT mount control system.
115#[derive(Debug, Default, Clone, Serialize, Deserialize)]
116pub struct Mount {
117    drive: MountDriver,
118    control: MountController,
119}
120impl Mount {
121    /// Returns the mount controller
122    pub fn new() -> Self {
123        Self {
124            drive: MountDriver::new(),
125            control: MountController::new(),
126        }
127    }
128}
129
130impl Codec for Mount {}