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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Motor interface definitions.
use crate::error::AsynResult;
use crate::user::AsynUser;
/// Motor axis status.
/// Fields match the C asynMotorController MotorStatus structure.
#[derive(Debug, Clone)]
pub struct MotorStatus {
/// Current position in user coordinates.
pub position: f64,
/// Encoder position (if available).
pub encoder_position: f64,
/// Current velocity.
pub velocity: f64,
/// True if the last move has completed.
pub done: bool,
/// True if the motor is currently moving.
pub moving: bool,
/// True if a positive (raw) limit switch is active.
pub high_limit: bool,
/// True if a negative (raw) limit switch is active.
pub low_limit: bool,
/// True if the home switch is active.
pub home: bool,
/// True if the motor is powered on / closed-loop is active.
pub powered: bool,
/// True if a problem was detected (driver stopped polling).
pub problem: bool,
/// Direction of last motion (true = positive).
pub direction: bool,
/// True if encoder slip is detected.
pub slip_stall: bool,
/// True if communication error was detected.
pub comms_error: bool,
/// True if the axis has been homed.
pub homed: bool,
/// True if the controller supports closed-loop gain.
pub gain_support: bool,
/// True if an encoder is present.
pub has_encoder: bool,
}
impl Default for MotorStatus {
fn default() -> Self {
Self {
position: 0.0,
encoder_position: 0.0,
velocity: 0.0,
done: true,
moving: false,
high_limit: false,
low_limit: false,
home: false,
powered: true,
problem: false,
direction: false,
slip_stall: false,
comms_error: false,
homed: false,
gain_support: false,
has_encoder: false,
}
}
}
/// Motor interface trait.
///
/// Provides motor axis control for motor-capable drivers.
pub trait AsynMotor: Send + Sync {
/// Move to an absolute position.
fn move_absolute(
&mut self,
user: &AsynUser,
position: f64,
velocity: f64,
acceleration: f64,
) -> AsynResult<()>;
/// Move a relative distance.
fn move_relative(
&mut self,
user: &AsynUser,
distance: f64,
velocity: f64,
acceleration: f64,
) -> AsynResult<()> {
// Default: convert to absolute using current position from poll
let status = self.poll(user)?;
self.move_absolute(user, status.position + distance, velocity, acceleration)
}
/// Move at a constant velocity (jog).
/// Default implementation uses move_absolute to a very large target.
fn move_velocity(
&mut self,
user: &AsynUser,
velocity: f64,
acceleration: f64,
) -> AsynResult<()> {
let target = if velocity >= 0.0 { 1e9 } else { -1e9 };
self.move_absolute(user, target, velocity.abs(), acceleration)
}
/// Start a homing sequence.
fn home(&mut self, user: &AsynUser, velocity: f64, forward: bool) -> AsynResult<()>;
/// Stop motion.
fn stop(&mut self, user: &AsynUser, acceleration: f64) -> AsynResult<()>;
/// Set the current position without moving.
fn set_position(&mut self, user: &AsynUser, position: f64) -> AsynResult<()>;
/// Enable or disable closed-loop control.
fn set_closed_loop(&mut self, _user: &AsynUser, _enable: bool) -> AsynResult<()> {
Ok(())
}
/// Enable or disable deferred moves for coordinated multi-axis motion.
fn set_deferred_moves(&mut self, _user: &AsynUser, _defer: bool) -> AsynResult<()> {
Ok(())
}
/// Poll the motor for current status.
fn poll(&mut self, user: &AsynUser) -> AsynResult<MotorStatus>;
/// Initialize profile move with maximum number of points.
fn initialize_profile(&mut self, _user: &AsynUser, _max_points: usize) -> AsynResult<()> {
Ok(())
}
/// Define profile positions for this axis.
fn define_profile(&mut self, _user: &AsynUser, _positions: &[f64]) -> AsynResult<()> {
Ok(())
}
/// Build the profile trajectory.
fn build_profile(&mut self, _user: &AsynUser) -> AsynResult<()> {
Ok(())
}
/// Execute the profile move.
fn execute_profile(&mut self, _user: &AsynUser) -> AsynResult<()> {
Ok(())
}
/// Abort the profile move.
fn abort_profile(&mut self, _user: &AsynUser) -> AsynResult<()> {
Ok(())
}
/// Read back actual positions after profile execution.
fn readback_profile(&mut self, _user: &AsynUser) -> AsynResult<Vec<f64>> {
Ok(vec![])
}
}