diff --git a/CHANGELOG.md b/CHANGELOG.md index 2196102d4..829937d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +### [FIX] `AxoCmmtAs` loses axis position while in torque control + +**Note:** PLC bug fix in `src/components.festo.drives` (`AxoCmmtAs`, `PROFIdriveTelegram_111`) and `src/components.drives` (`AxoDrive_Config`). No public-API removal. Branch: `1152-bug-cmmt-as-while-in-torque-control-loses-axis-position`. Issue #1152, PR #1166. + +- fix: `AxoCmmtAs` positioning no longer advances past the target-reached step on the `Telegram111_In.ZSW1.targetPosReached` (X10) bit alone. It now additionally requires the actual position to be within the in-position window — `ABS(Position - ActualPosition) <= _AxisReference^.Config.InPositionWindow` — before transitioning, so a drive that asserts `targetPosReached` while still off target (e.g. after a torque-control phase) no longer "loses" its position. +- fix: Removed an unstable torque-control guard that raised programming error `1542` (`eAxoMessageCategory#ProgrammingError`, `MC_TorqueControlErrorID := 1542`) whenever `targetPosReached` became true during torque-control states `126`/`127`. The check proved unreliable and is disabled pending further investigation. +- feat: `AxoDrive_Config` (in `src/components.drives`) gains an `InPositionWindow` parameter (`LREAL`, default `0.05`) supplying the tolerance above. +- chore: Annotated the `PROFIdriveTelegram_111_ZSW1` status signals with their hardware bit positions (X0–X15) in the attribute labels, and added matching bit-position comments to the ZSW1 mapping in `AxoCmmtAs`. +- chore: Disabled an unfinished dynamic-torque-boost parameter write (PNU `13073`). +- docs: Updated `components.festo.drives` docs (CHANGELOG `0.61.1`, TROUBLES, `AxoCmmtAs.md`) to document the in-position window, the ZSW1 bit map, and the torque-control behaviour. + +**Impact:** +- Absolute positioning moves on Festo CMMT-AS drives complete only when the axis is genuinely within `InPositionWindow` of the commanded target, fixing the position loss observed after torque control. +- The spurious `1542` programming error during torque control no longer fires. + +**Risks/Review:** +- `InPositionWindow` defaults to `0.05` (axis position units). Too small a value can stall a move just before completion; too large lets it complete while still off target — tune per axis. +- The torque-control `1542` guard is disabled rather than fixed; the underlying condition is still under investigation. + +**Testing:** +- Delivered and reviewed via PR #1166 (issue #1152). No automated AxUnit test was added for the in-position gate. ### [FIX] `AxoKrc5` no longer throws spurious task-timeout errors **Note:** PLC bug fix in `src/components.kuka.robotics/ctrl/src/AxoKrc5/v_5_x_x/AxoKrc5.st`. KRC5-only — `AxoKrc4` is unchanged. No public-API change. Branch: `1165-bug-kuka-issue-with-robot-reset` ([#1167](https://github.com/Inxton/AXOpen/pull/1167)). diff --git a/src/components.drives/ctrl/src/AxoDrives/AxoDrive_Config.st b/src/components.drives/ctrl/src/AxoDrives/AxoDrive_Config.st index 7786cefea..8a490c5b0 100644 --- a/src/components.drives/ctrl/src/AxoDrives/AxoDrive_Config.st +++ b/src/components.drives/ctrl/src/AxoDrives/AxoDrive_Config.st @@ -13,6 +13,8 @@ NAMESPACE AXOpen.Components.Drives InTorqueWindowPerCent : LREAL := LREAL#5.0; {#ix-set:AttributeName = "<#InTorque window time#>"} InTorqueWindowTime : LTIME := LT#100ms; + {#ix-set:AttributeName = "<#InPosition window#>"} + InPositionWindow : LREAL := LREAL#0.05; END_VAR END_CLASS END_NAMESPACE diff --git a/src/components.festo.drives/ctrl/src/AxoCmmtAs/AxoCmmtAs.st b/src/components.festo.drives/ctrl/src/AxoCmmtAs/AxoCmmtAs.st index 06bcc41f2..53c8698e5 100644 --- a/src/components.festo.drives/ctrl/src/AxoCmmtAs/AxoCmmtAs.st +++ b/src/components.festo.drives/ctrl/src/AxoCmmtAs/AxoCmmtAs.st @@ -952,22 +952,22 @@ NAMESPACE AXOpen.Components.Festo.Drives END_IF; // ZSW1 - _AxisReference^.Telegram111_In.ZSW1.followingErrorInTolerance := _Telegram111[0].%X0; - _AxisReference^.Telegram111_In.ZSW1.controlRequest := _Telegram111[0].%X1; - _AxisReference^.Telegram111_In.ZSW1.targetPosReached := _Telegram111[0].%X2; - _AxisReference^.Telegram111_In.ZSW1.homePosSet := _Telegram111[0].%X3; - _AxisReference^.Telegram111_In.ZSW1.acknowledgeTraversingBlockActivated := _Telegram111[0].%X4; - _AxisReference^.Telegram111_In.ZSW1.driveStopped := _Telegram111[0].%X5; - _AxisReference^.Telegram111_In.ZSW1.axisAccelerates := _Telegram111[0].%X6; - _AxisReference^.Telegram111_In.ZSW1.axisDecelerates := _Telegram111[0].%X7; - _AxisReference^.Telegram111_In.ZSW1.readyForSwitchOn := _Telegram111[1].%X0; - _AxisReference^.Telegram111_In.ZSW1.ready := _Telegram111[1].%X1; - _AxisReference^.Telegram111_In.ZSW1.operationEnabled := _Telegram111[1].%X2; - _AxisReference^.Telegram111_In.ZSW1.faultPresent := _Telegram111[1].%X3; - _AxisReference^.Telegram111_In.ZSW1.noCoastingActive := _Telegram111[1].%X4; - _AxisReference^.Telegram111_In.ZSW1.noQuickStopActive := _Telegram111[1].%X5; - _AxisReference^.Telegram111_In.ZSW1.switchingOnInhibitedActive := _Telegram111[1].%X6; - _AxisReference^.Telegram111_In.ZSW1.warningActive := _Telegram111[1].%X7; + _AxisReference^.Telegram111_In.ZSW1.followingErrorInTolerance := _Telegram111[0].%X0; //.8 + _AxisReference^.Telegram111_In.ZSW1.controlRequest := _Telegram111[0].%X1; //.9 + _AxisReference^.Telegram111_In.ZSW1.targetPosReached := _Telegram111[0].%X2; //.10 + _AxisReference^.Telegram111_In.ZSW1.homePosSet := _Telegram111[0].%X3; //.11 + _AxisReference^.Telegram111_In.ZSW1.acknowledgeTraversingBlockActivated := _Telegram111[0].%X4; //.12 + _AxisReference^.Telegram111_In.ZSW1.driveStopped := _Telegram111[0].%X5; //.13 + _AxisReference^.Telegram111_In.ZSW1.axisAccelerates := _Telegram111[0].%X6; //.14 + _AxisReference^.Telegram111_In.ZSW1.axisDecelerates := _Telegram111[0].%X7; //.15 + _AxisReference^.Telegram111_In.ZSW1.readyForSwitchOn := _Telegram111[1].%X0; //.0 + _AxisReference^.Telegram111_In.ZSW1.ready := _Telegram111[1].%X1; //.1 + _AxisReference^.Telegram111_In.ZSW1.operationEnabled := _Telegram111[1].%X2; //.2 + _AxisReference^.Telegram111_In.ZSW1.faultPresent := _Telegram111[1].%X3; //.3 + _AxisReference^.Telegram111_In.ZSW1.noCoastingActive := _Telegram111[1].%X4; //.4 + _AxisReference^.Telegram111_In.ZSW1.noQuickStopActive := _Telegram111[1].%X5; //.5 + _AxisReference^.Telegram111_In.ZSW1.switchingOnInhibitedActive := _Telegram111[1].%X6; //.6 + _AxisReference^.Telegram111_In.ZSW1.warningActive := _Telegram111[1].%X7; //.7 //POS_ZSW1 _AxisReference^.Telegram111_In.POS_ZSW1.%B1 := _Telegram111[2]; _AxisReference^.Telegram111_In.POS_ZSW1.%B0 := _Telegram111[3]; @@ -2416,8 +2416,9 @@ NAMESPACE AXOpen.Components.Festo.Drives END_IF; IF State = UINT#84 THEN _AxisReference^.Telegram111_Out.STW1.activateTraversing := FALSE; - IF _AxisReference^.Telegram111_In.ZSW1.targetPosReached THEN - State := UINT#85; + IF _AxisReference^.Telegram111_In.ZSW1.targetPosReached + AND ABS( Position - THIS.ActualPosition) <= _AxisReference^.Config.InPositionWindow THEN + State := UINT#85; END_IF; END_IF; IF State = UINT#85 THEN @@ -3462,6 +3463,32 @@ NAMESPACE AXOpen.Components.Festo.Drives State := UINT#129; END_IF; END_IF; + + // //Writing P1.102223.0.0 – Selection of dynamic torque boost → [0] None + // // PNU 13073.0 - USINT + // IF State = UINT#1123 THEN + // Busy := TRUE; + // Active := TRUE; + // Parametrization.Inputs.Enable := TRUE; + // Parametrization.Inputs.ReadWrite := TRUE; + // Parametrization.Inputs.ParameterNo := 13073; + // Parametrization.Inputs.Subindex := 0; + // Parametrization.Inputs.AxisNo := BYTE#1; + // Parametrization.Inputs.HardwareId := _AxisReference^.HWIDs.HW_ModuleAccessPoint; + // Parametrization.Inputs.ValueWriteLINT := LINT#0; + // IF Parametrization.Outputs.Done AND NOT Parametrization.Outputs.Error THEN + // Parametrization.Inputs.Enable := FALSE; + // Parametrization.Inputs.ReadWrite := FALSE; + // State := UINT#124; + // RETURN; + // END_IF; + // IF Parametrization.Outputs.Error THEN + // Messenger.Activate( UINT#1543, eAxoMessageCategory#Error); + // MC_TorqueControlErrorID := DINT#1543; + // State := UINT#129; + // END_IF; + // END_IF; + IF State = UINT#124 THEN Busy := TRUE; Active := TRUE; @@ -3513,11 +3540,12 @@ NAMESPACE AXOpen.Components.Festo.Drives Error := TRUE; END_IF; - IF (State=UINT#126 OR State =UINT#127) AND _AxisReference^.Telegram111_In.ZSW1.targetPosReached THEN - Messenger.Activate( UINT#1542, eAxoMessageCategory#ProgrammingError); - MC_TorqueControlErrorID := DINT#1542; - State := UINT#129; - END_IF; + // ! IT IS NOT STABLE ! + // IF (State=UINT#126 OR State =UINT#127) AND _AxisReference^.Telegram111_In.ZSW1.targetPosReached THEN + // Messenger.Activate( UINT#1542, eAxoMessageCategory#ProgrammingError); + // MC_TorqueControlErrorID := DINT#1542; + // State := UINT#129; + // END_IF; IF State>=UINT#120 AND State +### 0.61.1 + +**Bug fixes:** +- Fixed `AxoCmmtAs` move-absolute task to verify `InPositionWindow` tolerance (`ABS(Position - ActualPosition) <= Config.InPositionWindow`) at the end of movement before completing the move. +- Removed aborting torque-control task with error `1542`, when `targetPosReached` was raised. + +**Other:** +- Annotated the `PROFIdriveTelegram_111_ZSW1` status signals with their hardware bit positions (X0–X15) in the attribute labels, and added matching bit-position comments to the ZSW1 mapping in `AxoCmmtAs`, clarifying which telegram bit drives each status signal. +- Documented the `InPositionWindow` positioning-tolerance parameter (provided by `AxoDrive_Config`) consumed by `AxoCmmtAs` move completion. + ### 0.43.0 **Other:** diff --git a/src/components.festo.drives/docs/TROUBLES.md b/src/components.festo.drives/docs/TROUBLES.md index 5cdc2ba7d..fc7979268 100644 --- a/src/components.festo.drives/docs/TROUBLES.md +++ b/src/components.festo.drives/docs/TROUBLES.md @@ -1,5 +1,56 @@ # Troubleshooting +## Common issues + +### A positioning move reports complete while the axis is not at the commanded target + +**What you observe** — After a torque-control phase, a subsequent absolute positioning move advances as "in position", but `ActualPosition` differs noticeably from the commanded `Position` (the axis appears to have "lost" its position). + +**Why it happens** — The Festo CMMT-AS drive can assert the `Telegram111_In.ZSW1.targetPosReached` (bit X10) status signal while the mechanical position is still outside an acceptable band — for example when the preceding torque-control phase disturbed the axis. Acting on that bit alone lets the move sequence advance prematurely. + +**What to check** — `AxoCmmtAs` gates the target-reached transition on both the `targetPosReached` bit *and* `ABS(Position - ActualPosition) <= _AxisReference^.Config.InPositionWindow`. Tune `InPositionWindow` (see [Diagnostics](#diagnostics)): +- Too **small** → the move never satisfies the window and the sequence stalls just before completing. +- Too **large** → the move completes while the axis is still off target (the original symptom). + +### Programming error `1542` raised during torque control + +**What you observe** — Message `1542` (`eAxoMessageCategory#ProgrammingError`) is activated and `MC_TorqueControlErrorID` is set to `1542` while the axis is in a torque-control state. + +**Why it happens** — A guard previously flagged `targetPosReached` becoming true during torque-control states (`126`/`127`) as a programming error. That guard proved unreliable and is disabled in this release. + +**What to check** — If you still hit `1542` during torque control, you are running an older build; update to a build that includes this fix. The guard is intentionally removed pending further investigation, so it should no longer fire. + +## Diagnostics + +Read the drive's status from the cyclic PROFIdrive telegram 111 input word `Telegram111_In.ZSW1`. As of this release each signal carries its hardware bit position in the attribute label: + +| Signal (`ZSW1.…`) | Bit | Meaning | +|---|---|---| +| `targetPosReached` | X10 | Drive reports the commanded target position has been reached | +| `operationEnabled` | X2 | Power stage enabled, drive following commands | +| `readyForSwitchOn` | X0 | Drive ready to be switched on | +| `ready` | X1 | Drive ready | +| `faultPresent` | X3 | A drive fault is active | +| `warningActive` | X7 | A drive warning is active | +| `switchingOnInhibitedActive` | X6 | Switch-on inhibit active | +| `noQuickStopActive` | X5 | Quick-stop *not* active (TRUE = normal operation) | +| `noCoastingActive` | X4 | Coast-stop *not* active (TRUE = normal operation) | +| `followingErrorInTolerance` | X8 | Following error within tolerance | +| `driveStopped` | X13 | Drive is stopped | + +For positioning precision, the relevant tuning parameter lives in the drive's `AxoDrive_Config` (from the `components.drives` base library): + +| Parameter | Type | Default | Purpose | +|---|---|---|---| +| `InPositionWindow` | `LREAL` | `0.05` | Maximum allowed `ABS(Position - ActualPosition)` (in axis position units) for a positioning move to count as complete, in addition to the drive's `targetPosReached` bit. | + +## Known limitations + +- The dynamic torque-boost parameter write (PNU `13073`, "Selection of dynamic torque boost") is not implemented — the code path is present but disabled. +- The torque-control "target reached during torque control" safety guard (programming error `1542`) is currently disabled and under investigation. + +## Support + Unfortunately, we don't have a direct solution to your problem at the moment. If you encounter any issues, please [file a report on our GitHub](https://github.com/inxton/AXOpen/issues/new/choose). We appreciate your feedback and patience. ---