AYAB user @doo reported on Discord that multiple end-of-line beeps could be generated without moving the K carriage by more than a few needles. Here’s a video demonstration of the issue:
Similarly, another Discord user testing garter carriage support reported extra end-of-row beeps (with the corresponding increase in the row number displayed in the AYAB app) randomly but frequently occurring after the end of a row of knitting.
I have a theory on how these cases managed to get past the protections added back then. Note that reading the conversation in https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 may be a prerequisite to understand the following explanation.
The fix to https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 involved making the « is the carriage inside » test stricter by not applying the margin in that case, introducing hysteresis in the process so that a small movement of the carriage back and forth over the edge of the working area would no longer trigger an end-of-row detection. Currently, the safety margin that is added to the working area is 12 needles wide on each side for a KH-910.
Looking carefully at the code, one can see that it is not directly the position of the carriage that is tested to be inside or outside the working area. Indeed, given the significant width of a carriage, a simple position number would be insufficient to describe exactly how it relates to the working area.
Instead, what is compared to the bounds of the working area is the value of the variable m_pixelToSet, which refers to the next needle (and therefore the pixel column in a 200-wide pattern) that should be “programmed” (i.e. whose associated solenoid needs to be energized or not according to the pattern) given the current position of the carriage and the direction it is travelling (for reference, the calculatePixelAndSolenoid does that computation).
Why does the travel direction need to be taken into account when determining which needle to “program” next (a.k.a. m_pixelToSet)? The K carriage (as does the L carriage) possesses two “needle selector” mechanisms, symmetrically disposed near the left and right edges of the carriage. Whichever selector is active is the one on the trailing edge of the carriage’s movement, so that needles are correctly positioned as they “exit” the carriage on that edge. The firmware needs to “program” needles slightly ahead of the active needle selector, so that they are ready when the selector visits them. And because the two selectors are on opposite sides of the carriage, for a given position of the carriage their points of entry are at different locations.
In practice, the AYAB source contains a set of constants (the START_OFFSET array) describing how to adjust the carriage’s position to obtain the next needle number to set, depending on machine type, carriage type, and of course travel direction. For the K carriage on a KH-910, these offsets — to be subtracted from the carriage’s position —are respectively 40 (for a carriage traveling to the right) and 16 (for a carriage traveling to the left).
Getting back to our end-of-row detection issue: what is not taken into account by the current code is that when a carriage that was knitting a row traveling right, suddenly does a small, possibly involuntary, movement to the left, not only does its position decrease slightly — which is easily covered by the margin introduced to fix #244 — but its direction temporarily switches from rightward to leftward, causing the computation of m_pixelToSet to return a very different result. In the case of a K carriage on a KH-910 again, switching from m_position - 40 to m_position - 16 results in an apparent rightward jump of 24 needles, easily bypassing the safety margin of 12 needles if the carriage had been within the last few needles of the working area.
When this happens, the carriage temporarily appears to be outside of the working area, triggering an end-of-row event with the following negative consequences:
The remaining stitches on the current row will be knit according to the next row in the pattern, since the pattern buffer will have been overwritten within milliseconds of the next row being requested by the firmware;
As rightward travel is resumed, the working position will first jump back into the working area, causing the worked on row flag to be set again; then when the carriage finally passes the stop needle, another end-of-row event will occur, discarding the row that had just been started.
The situation is slightly different with the garter carriage, since its selector offsets are in an opposite relation compared to the other carriages — there is a single selector at the center of the carriage, so the needle to be programmed will be to the right of the center when traveling right, and left of the center when traveling left. Which in turn means that for a garter carriage traveling to the right, a small move to the left will make the apparent position jump 24 needles to the left. But this just means that for the problem to occur, the carriage has to be a few needles outside of the working area. Which matches perfectly the reports of the user who had problems with the garter carriage triggering extra row changes just after normally completing a row.
With all of that in mind, I have started to work on an alternative, hopefully more robust test for end-of-row detection which will be submitted in a upcoming PR.
AYAB user @doo reported on Discord that multiple end-of-line beeps could be generated without moving the K carriage by more than a few needles. Here’s a video demonstration of the issue:
https://github.com/user-attachments/assets/8229e8e8-3b1b-4ec9-823e-0fe635e7c674
Similarly, another Discord user testing garter carriage support reported extra end-of-row beeps (with the corresponding increase in the row number displayed in the AYAB app) randomly but frequently occurring after the end of a row of knitting.
These seem to be corner cases of an issue first reported and fixed in 2018: https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244
I have a theory on how these cases managed to get past the protections added back then. Note that reading the conversation in https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 may be a prerequisite to understand the following explanation.
Even before https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 was fixed in https://github.com/AllYarnsAreBeautiful/ayab-firmware/commit/4abd6cf4bf02baaa9627a8b69edcae6914d3b4c0 , the AYAB logic for determining when knitting a row was complete was already the following: a row is complete, i.e. turnaround is allowed, as soon as the carriage is observed outside of the working area (start needle to stop needle), plus some “safety margin”, after having been observed at least once inside the working area (plus the margin) since the last turnaround.
The fix to https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 involved making the « is the carriage inside » test stricter by not applying the margin in that case, introducing hysteresis in the process so that a small movement of the carriage back and forth over the edge of the working area would no longer trigger an end-of-row detection. Currently, the safety margin that is added to the working area is 12 needles wide on each side for a KH-910.
How is it then that the same issue can still be observed, albeit probably in more restricted circumstances since it was not immediately reproduced after the fix to https://github.com/AllYarnsAreBeautiful/ayab-desktop/issues/244 was deployed?
Looking carefully at the code, one can see that it is not directly the position of the carriage that is tested to be inside or outside the working area. Indeed, given the significant width of a carriage, a simple position number would be insufficient to describe exactly how it relates to the working area.
https://github.com/AllYarnsAreBeautiful/ayab-firmware/blob/f69d0e7d94e19afbc1530bf5bbc1f1a1e40398e3/src/ayab/knitter.cpp#L289-L291
Instead, what is compared to the bounds of the working area is the value of the variable
m_pixelToSet
, which refers to the next needle (and therefore the pixel column in a 200-wide pattern) that should be “programmed” (i.e. whose associated solenoid needs to be energized or not according to the pattern) given the current position of the carriage and the direction it is travelling (for reference, thecalculatePixelAndSolenoid
does that computation).Why does the travel direction need to be taken into account when determining which needle to “program” next (a.k.a.
m_pixelToSet
)? The K carriage (as does the L carriage) possesses two “needle selector” mechanisms, symmetrically disposed near the left and right edges of the carriage. Whichever selector is active is the one on the trailing edge of the carriage’s movement, so that needles are correctly positioned as they “exit” the carriage on that edge. The firmware needs to “program” needles slightly ahead of the active needle selector, so that they are ready when the selector visits them. And because the two selectors are on opposite sides of the carriage, for a given position of the carriage their points of entry are at different locations.In practice, the AYAB source contains a set of constants (the
START_OFFSET
array) describing how to adjust the carriage’s position to obtain the next needle number to set, depending on machine type, carriage type, and of course travel direction. For the K carriage on a KH-910, these offsets — to be subtracted from the carriage’s position —are respectively 40 (for a carriage traveling to the right) and 16 (for a carriage traveling to the left).Getting back to our end-of-row detection issue: what is not taken into account by the current code is that when a carriage that was knitting a row traveling right, suddenly does a small, possibly involuntary, movement to the left, not only does its position decrease slightly — which is easily covered by the margin introduced to fix #244 — but its direction temporarily switches from rightward to leftward, causing the computation of
m_pixelToSet
to return a very different result. In the case of a K carriage on a KH-910 again, switching fromm_position - 40
tom_position - 16
results in an apparent rightward jump of 24 needles, easily bypassing the safety margin of 12 needles if the carriage had been within the last few needles of the working area.When this happens, the carriage temporarily appears to be outside of the working area, triggering an end-of-row event with the following negative consequences:
The situation is slightly different with the garter carriage, since its selector offsets are in an opposite relation compared to the other carriages — there is a single selector at the center of the carriage, so the needle to be programmed will be to the right of the center when traveling right, and left of the center when traveling left. Which in turn means that for a garter carriage traveling to the right, a small move to the left will make the apparent position jump 24 needles to the left. But this just means that for the problem to occur, the carriage has to be a few needles outside of the working area. Which matches perfectly the reports of the user who had problems with the garter carriage triggering extra row changes just after normally completing a row.
With all of that in mind, I have started to work on an alternative, hopefully more robust test for end-of-row detection which will be submitted in a upcoming PR.