Skip to main content

autocore_std/motion/
homing.rs

1//! Homing methods for CiA 402 servo drives.
2//!
3//! [`HomingMethod`] covers both hardware-delegated (drive-internal) homing
4//! and software-implemented homing where the [`Axis`](super::Axis) monitors
5//! [`AxisView`](super::AxisView) sensor signals.
6
7/// Homing methods for CiA 402 servo drives.
8///
9/// **Integrated** methods delegate to the drive's built-in CiA 402 homing
10/// mode (SDO 0x6098). The drive uses its own sensor inputs.
11///
12/// **Software** methods (no `Integrated` prefix) are implemented by the
13/// [`Axis`](super::Axis) struct, which monitors [`AxisView`](super::AxisView)
14/// sensor signals and captures the home position when triggered.
15///
16/// Limit switch variants use the sensor type convention:
17/// - **Pnp**: sensor reads `true` when object detected (normally open)
18/// - **Npn**: sensor reads `false` when object detected (normally closed)
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum HomingMethod {
21    // ── Hardware-delegated (drive handles it) ──
22
23    /// Hard stop in positive direction (torque foldback). CiA 402 code: -1.
24    HardStopPos,
25    /// Hard stop in negative direction (torque foldback). CiA 402 code: -2.
26    HardStopNeg,
27    /// Drive's integrated positive limit switch. CiA 402 code: 18.
28    IntegratedLimitSwitchPos,
29    /// Drive's integrated negative limit switch. CiA 402 code: 17.
30    IntegratedLimitSwitchNeg,
31    /// Drive's integrated home sensor, positive direction, rising edge. CiA 402 code: 19.
32    IntegratedHomeSensorPosRt,
33    /// Drive's integrated home sensor, negative direction, rising edge. CiA 402 code: 21.
34    IntegratedHomeSensorNegRt,
35    /// Drive's integrated home sensor, positive direction, falling edge. CiA 402 code: 22.
36    IntegratedHomeSensorPosFt,
37    /// Drive's integrated home sensor, negative direction, falling edge. CiA 402 code: 20.
38    IntegratedHomeSensorNegFt,
39    /// Set the present position as the reference (no motor movement) —
40    /// CiA 402 "homing on the current position", **method 35** (the original,
41    /// IEC 61800-7-201 Ed.1). The reference value is taken from the home offset
42    /// (0x607C). This is the **Kollmorgen AKD's only** current-position method
43    /// (the AKD lists codes 36–127 as reserved).
44    CurrentPosition35,
45    /// Set the present position as the reference (no motor movement) —
46    /// CiA 402 "homing on the current position", **method 37** (the Ed.2
47    /// replacement for 35, with standardized home-offset handling). Used by most
48    /// non-AKD drives. Same operation as 35, different code.
49    CurrentPosition37,
50    /// Arbitrary CiA 402 homing method code (vendor-specific or non-standard).
51    Integrated(i8),
52
53    // ── Software-implemented (Axis monitors AxisView sensors) ──
54
55    /// Move positive, home on positive limit switch (PNP: true = detected).
56    LimitSwitchPosPnp,
57    /// Move negative, home on negative limit switch (PNP: true = detected).
58    LimitSwitchNegPnp,
59    /// Move positive, home on positive limit switch (NPN: false = detected).
60    LimitSwitchPosNpn,
61    /// Move negative, home on negative limit switch (NPN: false = detected).
62    LimitSwitchNegNpn,
63    /// Move positive, home on home sensor (PNP: true = detected).
64    HomeSensorPosPnp,
65    /// Move negative, home on home sensor (PNP: true = detected).
66    HomeSensorNegPnp,
67    /// Move positive, home on home sensor (NPN: false = detected).
68    HomeSensorPosNpn,
69    /// Move negative, home on home sensor (NPN: false = detected).
70    HomeSensorNegNpn,
71}
72
73impl HomingMethod {
74    /// True if the drive handles this method internally (hardware-delegated).
75    pub fn is_integrated(&self) -> bool {
76        match self {
77            Self::HardStopPos
78            | Self::HardStopNeg
79            | Self::IntegratedLimitSwitchPos
80            | Self::IntegratedLimitSwitchNeg
81            | Self::IntegratedHomeSensorPosRt
82            | Self::IntegratedHomeSensorNegRt
83            | Self::IntegratedHomeSensorPosFt
84            | Self::IntegratedHomeSensorNegFt
85            | Self::CurrentPosition35
86            | Self::CurrentPosition37
87            | Self::Integrated(_) => true,
88
89            Self::LimitSwitchPosPnp
90            | Self::LimitSwitchNegPnp
91            | Self::LimitSwitchPosNpn
92            | Self::LimitSwitchNegNpn
93            | Self::HomeSensorPosPnp
94            | Self::HomeSensorNegPnp
95            | Self::HomeSensorPosNpn
96            | Self::HomeSensorNegNpn => false,
97        }
98    }
99
100    /// CiA 402 method code for hardware-delegated methods.
101    ///
102    /// # Panics
103    ///
104    /// Panics if called on a software-implemented method.
105    /// Check [`is_integrated()`](Self::is_integrated) first.
106    pub fn cia402_code(&self) -> i8 {
107        match self {
108            Self::HardStopPos => -1,
109            Self::HardStopNeg => -2,
110            Self::IntegratedLimitSwitchPos => 18,
111            Self::IntegratedLimitSwitchNeg => 17,
112            Self::IntegratedHomeSensorPosRt => 19,
113            Self::IntegratedHomeSensorNegRt => 21,
114            Self::IntegratedHomeSensorPosFt => 22,
115            Self::IntegratedHomeSensorNegFt => 20,
116            Self::CurrentPosition35 => 35,
117            Self::CurrentPosition37 => 37,
118            Self::Integrated(code) => *code,
119            _ => panic!("cia402_code() called on software homing method {:?}", self),
120        }
121    }
122
123    /// True if this method involves motor movement.
124    pub fn requires_motion(&self) -> bool {
125        !matches!(self, Self::CurrentPosition35 | Self::CurrentPosition37)
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn integrated_methods_are_integrated() {
135        assert!(HomingMethod::HardStopPos.is_integrated());
136        assert!(HomingMethod::HardStopNeg.is_integrated());
137        assert!(HomingMethod::IntegratedLimitSwitchPos.is_integrated());
138        assert!(HomingMethod::IntegratedLimitSwitchNeg.is_integrated());
139        assert!(HomingMethod::IntegratedHomeSensorPosRt.is_integrated());
140        assert!(HomingMethod::IntegratedHomeSensorNegRt.is_integrated());
141        assert!(HomingMethod::IntegratedHomeSensorPosFt.is_integrated());
142        assert!(HomingMethod::IntegratedHomeSensorNegFt.is_integrated());
143        assert!(HomingMethod::CurrentPosition35.is_integrated());
144        assert!(HomingMethod::CurrentPosition37.is_integrated());
145        assert!(HomingMethod::Integrated(35).is_integrated());
146    }
147
148    #[test]
149    fn software_methods_are_not_integrated() {
150        assert!(!HomingMethod::LimitSwitchPosPnp.is_integrated());
151        assert!(!HomingMethod::LimitSwitchNegPnp.is_integrated());
152        assert!(!HomingMethod::LimitSwitchPosNpn.is_integrated());
153        assert!(!HomingMethod::LimitSwitchNegNpn.is_integrated());
154        assert!(!HomingMethod::HomeSensorPosPnp.is_integrated());
155        assert!(!HomingMethod::HomeSensorNegPnp.is_integrated());
156        assert!(!HomingMethod::HomeSensorPosNpn.is_integrated());
157        assert!(!HomingMethod::HomeSensorNegNpn.is_integrated());
158    }
159
160    #[test]
161    fn cia402_codes_correct() {
162        assert_eq!(HomingMethod::HardStopPos.cia402_code(), -1);
163        assert_eq!(HomingMethod::HardStopNeg.cia402_code(), -2);
164        assert_eq!(HomingMethod::IntegratedLimitSwitchPos.cia402_code(), 18);
165        assert_eq!(HomingMethod::IntegratedLimitSwitchNeg.cia402_code(), 17);
166        assert_eq!(HomingMethod::IntegratedHomeSensorPosRt.cia402_code(), 19);
167        assert_eq!(HomingMethod::IntegratedHomeSensorNegRt.cia402_code(), 21);
168        assert_eq!(HomingMethod::IntegratedHomeSensorPosFt.cia402_code(), 22);
169        assert_eq!(HomingMethod::IntegratedHomeSensorNegFt.cia402_code(), 20);
170        assert_eq!(HomingMethod::CurrentPosition35.cia402_code(), 35);
171        assert_eq!(HomingMethod::CurrentPosition37.cia402_code(), 37);
172        assert_eq!(HomingMethod::Integrated(35).cia402_code(), 35);
173    }
174
175    #[test]
176    #[should_panic]
177    fn cia402_code_panics_on_software_method() {
178        HomingMethod::LimitSwitchPosPnp.cia402_code();
179    }
180
181    #[test]
182    fn requires_motion() {
183        assert!(HomingMethod::HardStopPos.requires_motion());
184        assert!(HomingMethod::IntegratedLimitSwitchPos.requires_motion());
185        assert!(HomingMethod::IntegratedHomeSensorPosRt.requires_motion());
186        assert!(!HomingMethod::CurrentPosition35.requires_motion());
187        assert!(!HomingMethod::CurrentPosition37.requires_motion());
188        assert!(HomingMethod::LimitSwitchPosPnp.requires_motion());
189        assert!(HomingMethod::HomeSensorPosPnp.requires_motion());
190        assert!(HomingMethod::Integrated(35).requires_motion());
191    }
192}