Skip to main content

nanonis_rs/client/motor/
mod.rs

1mod types;
2pub use types::*;
3
4use super::NanonisClient;
5use crate::error::NanonisError;
6use crate::types::NanonisValue;
7use std::time::Duration;
8
9impl NanonisClient {
10    /// Move the coarse positioning device (motor, piezo actuator)
11    pub fn motor_start_move(
12        &mut self,
13        direction: impl Into<MotorDirection>,
14        number_of_steps: impl Into<u16>,
15        group: impl Into<MotorGroup>,
16        wait_until_finished: bool,
17    ) -> Result<(), NanonisError> {
18        let wait_flag = if wait_until_finished { 1u32 } else { 0u32 };
19        self.quick_send(
20            "Motor.StartMove",
21            vec![
22                NanonisValue::U32(direction.into().into()),
23                NanonisValue::U16(number_of_steps.into()),
24                NanonisValue::U32(group.into().into()),
25                NanonisValue::U32(wait_flag),
26            ],
27            vec!["I", "H", "I", "I"],
28            vec![],
29        )?;
30        Ok(())
31    }
32
33    /// Move the coarse positioning device in closed loop
34    pub fn motor_start_closed_loop(
35        &mut self,
36        movement_mode: MovementMode,
37        target_position: Position3D,
38        wait_until_finished: bool,
39        group: MotorGroup,
40    ) -> Result<(), NanonisError> {
41        let wait_flag = if wait_until_finished { 1u32 } else { 0u32 };
42        self.quick_send(
43            "Motor.StartClosedLoop",
44            vec![
45                NanonisValue::U32(movement_mode.into()),
46                NanonisValue::F64(target_position.x),
47                NanonisValue::F64(target_position.y),
48                NanonisValue::F64(target_position.z),
49                NanonisValue::U32(wait_flag),
50                NanonisValue::U32(group.into()),
51            ],
52            vec!["I", "d", "d", "d", "I", "I"],
53            vec![],
54        )?;
55        Ok(())
56    }
57
58    /// Stop the motor motion
59    pub fn motor_stop_move(&mut self) -> Result<(), NanonisError> {
60        self.quick_send("Motor.StopMove", vec![], vec![], vec![])?;
61        Ok(())
62    }
63
64    /// Get the positions of the motor control module
65    pub fn motor_pos_get(
66        &mut self,
67        group: MotorGroup,
68        timeout: Duration,
69    ) -> Result<Position3D, NanonisError> {
70        let result = self.quick_send(
71            "Motor.PosGet",
72            vec![
73                NanonisValue::U32(group.into()),
74                NanonisValue::U32(timeout.as_millis() as u32),
75            ],
76            vec!["I", "I"],
77            vec!["d", "d", "d"],
78        )?;
79
80        if result.len() >= 3 {
81            let x = result[0].as_f64()?;
82            let y = result[1].as_f64()?;
83            let z = result[2].as_f64()?;
84            Ok(Position3D::new(x, y, z))
85        } else {
86            Err(NanonisError::Protocol(
87                "Invalid motor position response".to_string(),
88            ))
89        }
90    }
91
92    /// Get step counter values and optionally reset them
93    /// Available only on Attocube ANC150 devices
94    pub fn motor_step_counter_get(
95        &mut self,
96        reset_x: bool,
97        reset_y: bool,
98        reset_z: bool,
99    ) -> Result<(i32, i32, i32), NanonisError> {
100        let reset_x_flag = if reset_x { 1u32 } else { 0u32 };
101        let reset_y_flag = if reset_y { 1u32 } else { 0u32 };
102        let reset_z_flag = if reset_z { 1u32 } else { 0u32 };
103
104        let result = self.quick_send(
105            "Motor.StepCounterGet",
106            vec![
107                NanonisValue::U32(reset_x_flag),
108                NanonisValue::U32(reset_y_flag),
109                NanonisValue::U32(reset_z_flag),
110            ],
111            vec!["I", "I", "I"],
112            vec!["i", "i", "i"],
113        )?;
114
115        if result.len() >= 3 {
116            let step_x = result[0].as_i32()?;
117            let step_y = result[1].as_i32()?;
118            let step_z = result[2].as_i32()?;
119            Ok((step_x, step_y, step_z))
120        } else {
121            Err(NanonisError::Protocol(
122                "Invalid step counter response".to_string(),
123            ))
124        }
125    }
126
127    /// Get frequency and amplitude of the motor control module
128    /// Available only for PD5, PMD4, and Attocube ANC150 devices
129    pub fn motor_freq_amp_get(
130        &mut self,
131        axis: MotorAxis,
132    ) -> Result<(Frequency, Amplitude), NanonisError> {
133        let result = self.quick_send(
134            "Motor.FreqAmpGet",
135            vec![NanonisValue::U16(axis.into())],
136            vec!["H"],
137            vec!["f", "f"],
138        )?;
139
140        if result.len() >= 2 {
141            let frequency = Frequency::hz(result[0].as_f32()?);
142            let amplitude = Amplitude::volts(result[1].as_f32()?);
143            Ok((frequency, amplitude))
144        } else {
145            Err(NanonisError::Protocol(
146                "Invalid frequency/amplitude response".to_string(),
147            ))
148        }
149    }
150
151    /// Set frequency and amplitude of the motor control module
152    /// Available only for PD5, PMD4, and Attocube ANC150 devices
153    pub fn motor_freq_amp_set(
154        &mut self,
155        frequency: impl Into<Frequency>,
156        amplitude: impl Into<Amplitude>,
157        axis: impl Into<MotorAxis>,
158    ) -> Result<(), NanonisError> {
159        self.quick_send(
160            "Motor.FreqAmpSet",
161            vec![
162                NanonisValue::F32(frequency.into().into()),
163                NanonisValue::F32(amplitude.into().into()),
164                NanonisValue::U16(axis.into().into()),
165            ],
166            vec!["f", "f", "H"],
167            vec![],
168        )?;
169        Ok(())
170    }
171}