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    /// Current position as home (no motor movement). CiA 402 code: 37.
40    CurrentPosition,
41    /// Arbitrary CiA 402 homing method code (vendor-specific or non-standard).
42    Integrated(i8),
43
44    // ── Software-implemented (Axis monitors AxisView sensors) ──
45
46    /// Move positive, home on positive limit switch (PNP: true = detected).
47    LimitSwitchPosPnp,
48    /// Move negative, home on negative limit switch (PNP: true = detected).
49    LimitSwitchNegPnp,
50    /// Move positive, home on positive limit switch (NPN: false = detected).
51    LimitSwitchPosNpn,
52    /// Move negative, home on negative limit switch (NPN: false = detected).
53    LimitSwitchNegNpn,
54    /// Move positive, home on home sensor (PNP: true = detected).
55    HomeSensorPosPnp,
56    /// Move negative, home on home sensor (PNP: true = detected).
57    HomeSensorNegPnp,
58    /// Move positive, home on home sensor (NPN: false = detected).
59    HomeSensorPosNpn,
60    /// Move negative, home on home sensor (NPN: false = detected).
61    HomeSensorNegNpn,
62}
63
64impl HomingMethod {
65    /// True if the drive handles this method internally (hardware-delegated).
66    pub fn is_integrated(&self) -> bool {
67        match self {
68            Self::HardStopPos
69            | Self::HardStopNeg
70            | Self::IntegratedLimitSwitchPos
71            | Self::IntegratedLimitSwitchNeg
72            | Self::IntegratedHomeSensorPosRt
73            | Self::IntegratedHomeSensorNegRt
74            | Self::IntegratedHomeSensorPosFt
75            | Self::IntegratedHomeSensorNegFt
76            | Self::CurrentPosition
77            | Self::Integrated(_) => true,
78
79            Self::LimitSwitchPosPnp
80            | Self::LimitSwitchNegPnp
81            | Self::LimitSwitchPosNpn
82            | Self::LimitSwitchNegNpn
83            | Self::HomeSensorPosPnp
84            | Self::HomeSensorNegPnp
85            | Self::HomeSensorPosNpn
86            | Self::HomeSensorNegNpn => false,
87        }
88    }
89
90    /// CiA 402 method code for hardware-delegated methods.
91    ///
92    /// # Panics
93    ///
94    /// Panics if called on a software-implemented method.
95    /// Check [`is_integrated()`](Self::is_integrated) first.
96    pub fn cia402_code(&self) -> i8 {
97        match self {
98            Self::HardStopPos => -1,
99            Self::HardStopNeg => -2,
100            Self::IntegratedLimitSwitchPos => 18,
101            Self::IntegratedLimitSwitchNeg => 17,
102            Self::IntegratedHomeSensorPosRt => 19,
103            Self::IntegratedHomeSensorNegRt => 21,
104            Self::IntegratedHomeSensorPosFt => 22,
105            Self::IntegratedHomeSensorNegFt => 20,
106            Self::CurrentPosition => 37,
107            Self::Integrated(code) => *code,
108            _ => panic!("cia402_code() called on software homing method {:?}", self),
109        }
110    }
111
112    /// True if this method involves motor movement.
113    pub fn requires_motion(&self) -> bool {
114        !matches!(self, Self::CurrentPosition)
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn integrated_methods_are_integrated() {
124        assert!(HomingMethod::HardStopPos.is_integrated());
125        assert!(HomingMethod::HardStopNeg.is_integrated());
126        assert!(HomingMethod::IntegratedLimitSwitchPos.is_integrated());
127        assert!(HomingMethod::IntegratedLimitSwitchNeg.is_integrated());
128        assert!(HomingMethod::IntegratedHomeSensorPosRt.is_integrated());
129        assert!(HomingMethod::IntegratedHomeSensorNegRt.is_integrated());
130        assert!(HomingMethod::IntegratedHomeSensorPosFt.is_integrated());
131        assert!(HomingMethod::IntegratedHomeSensorNegFt.is_integrated());
132        assert!(HomingMethod::CurrentPosition.is_integrated());
133        assert!(HomingMethod::Integrated(35).is_integrated());
134    }
135
136    #[test]
137    fn software_methods_are_not_integrated() {
138        assert!(!HomingMethod::LimitSwitchPosPnp.is_integrated());
139        assert!(!HomingMethod::LimitSwitchNegPnp.is_integrated());
140        assert!(!HomingMethod::LimitSwitchPosNpn.is_integrated());
141        assert!(!HomingMethod::LimitSwitchNegNpn.is_integrated());
142        assert!(!HomingMethod::HomeSensorPosPnp.is_integrated());
143        assert!(!HomingMethod::HomeSensorNegPnp.is_integrated());
144        assert!(!HomingMethod::HomeSensorPosNpn.is_integrated());
145        assert!(!HomingMethod::HomeSensorNegNpn.is_integrated());
146    }
147
148    #[test]
149    fn cia402_codes_correct() {
150        assert_eq!(HomingMethod::HardStopPos.cia402_code(), -1);
151        assert_eq!(HomingMethod::HardStopNeg.cia402_code(), -2);
152        assert_eq!(HomingMethod::IntegratedLimitSwitchPos.cia402_code(), 18);
153        assert_eq!(HomingMethod::IntegratedLimitSwitchNeg.cia402_code(), 17);
154        assert_eq!(HomingMethod::IntegratedHomeSensorPosRt.cia402_code(), 19);
155        assert_eq!(HomingMethod::IntegratedHomeSensorNegRt.cia402_code(), 21);
156        assert_eq!(HomingMethod::IntegratedHomeSensorPosFt.cia402_code(), 22);
157        assert_eq!(HomingMethod::IntegratedHomeSensorNegFt.cia402_code(), 20);
158        assert_eq!(HomingMethod::CurrentPosition.cia402_code(), 37);
159        assert_eq!(HomingMethod::Integrated(35).cia402_code(), 35);
160    }
161
162    #[test]
163    #[should_panic]
164    fn cia402_code_panics_on_software_method() {
165        HomingMethod::LimitSwitchPosPnp.cia402_code();
166    }
167
168    #[test]
169    fn requires_motion() {
170        assert!(HomingMethod::HardStopPos.requires_motion());
171        assert!(HomingMethod::IntegratedLimitSwitchPos.requires_motion());
172        assert!(HomingMethod::IntegratedHomeSensorPosRt.requires_motion());
173        assert!(!HomingMethod::CurrentPosition.requires_motion());
174        assert!(HomingMethod::LimitSwitchPosPnp.requires_motion());
175        assert!(HomingMethod::HomeSensorPosPnp.requires_motion());
176        assert!(HomingMethod::Integrated(35).requires_motion());
177    }
178}