Job freezes after MoveZ – race condition between XY completion and Z command

18 views
Skip to first unread message

Andreas Petter

unread,
May 14, 2026, 5:35:56 AM (4 days ago) May 14
to OpenPnP
Hi,

I am running OpenPnP 2.6 on a Neoden4 and have a reproducible issue where a placement job freezes after a few parts. The machine and OpenPnP both end up in a deadlock exchanging 0x02 bytes indefinitely until the job times out.

After analysing the TRACE log and the current NeoDen4Driver.java (main branch), I believe I have found the bug:

- `moveStep()` (XY move) correctly calls `waitForStatusReady(100, 30000)` at the end and blocks until the machine reports ready.
- `moveZ()` (Z move) only does a fixed `Thread.sleep(300)` and then returns — no `waitForStatusReady()` call.

The result: if the Z move takes longer than 300 ms (which happens regularly depending on distance and speed), the next command arrives while the machine is still busy. The machine then responds with an error packet (all four nozzle axes reporting `0x11` = not ready) instead of the expected single-byte ACK. The driver's `pollFor()` cannot handle this response in context, the machine falls into a loop answering only `0x02`, and `flushInput()` on retry blocks indefinitely because the serial timeout does not fire.

Below is a representative section of the TRACE log showing the failure sequence after a Z-Move and before Job died:

```
2026-05-13 16:29:35.709 NeoDen4Driver TRACE: > 42
2026-05-13 16:29:35.715 NeoDen4Driver TRACE: < 0e
2026-05-13 16:29:35.716 NeoDen4Driver TRACE: > c2
2026-05-13 16:29:35.767 NeoDen4Driver TRACE: < 06
2026-05-13 16:29:35.768 NeoDen4Driver TRACE: > 2e2264010000000084
2026-05-13 16:29:35.773 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.779 NeoDen4Driver TRACE: < 09
2026-05-13 16:29:35.780 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.781 NeoDen4Driver TRACE: < 04
2026-05-13 16:29:35.782 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.784 NeoDen4Driver TRACE: < 0e
2026-05-13 16:29:35.784 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.785 NeoDen4Driver TRACE: < 11
2026-05-13 16:29:35.785 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.786 NeoDen4Driver TRACE: < 11
2026-05-13 16:29:35.786 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.786 NeoDen4Driver TRACE: < 11
2026-05-13 16:29:35.787 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.787 NeoDen4Driver TRACE: < 11
2026-05-13 16:29:35.787 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.787 NeoDen4Driver TRACE: < 48
2026-05-13 16:29:35.787 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.788 NeoDen4Driver TRACE: < 03
2026-05-13 16:29:35.788 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.788 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.788 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.789 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.789 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.790 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.790 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.791 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.791 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.794 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.794 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.795 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.795 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.795 NeoDen4Driver TRACE: < 00
2026-05-13 16:29:35.795 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.796 NeoDen4Driver TRACE: < 75
2026-05-13 16:29:35.796 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.798 NeoDen4Driver TRACE: < 02
2026-05-13 16:29:35.799 NeoDen4Driver TRACE: > 02
2026-05-13 16:29:35.800 NeoDen4Driver TRACE: < 02
2026-05-13 16:29:35.801 NeoDen4Driver TRACE: > 02
```
This looks like the machine respond with an error status 0x11 for all 4 nozzles, instead of the expected ready signal.

**Proposed fix**

Add a `waitForStatusReady()` call after each `moveZ()`, mirroring the existing pattern in `moveStep()`:

```java
// In moveZ(), after writeWithChecksum(b) and pollFor(...):
if (!waitForStatusReady(100, 10000)) {
    throw new Exception("moveZ timeout waiting for status==ready");
}
```

I have not yet submitted a PR — I wanted to check here first whether anyone else has seen this, or whether there is a known reason `waitForStatusReady()` was intentionally omitted from `moveZ()`.

**Questions**

1. Can anyone with a Neoden4 confirm this behaviour?
2. Is there a known workaround (e.g. configuring a dwell time somewhere in the UI)?
3. Would a PR with the above fix be welcome?

Thanks, Andreas
Reply all
Reply to author
Forward
0 new messages