Skip to content

Feature/assisted threading#12

Open
Pawcu wants to merge 13 commits into
bartei:devfrom
Pawcu:feature/AssistedThreading
Open

Feature/assisted threading#12
Pawcu wants to merge 13 commits into
bartei:devfrom
Pawcu:feature/AssistedThreading

Conversation

@Pawcu
Copy link
Copy Markdown

@Pawcu Pawcu commented Mar 31, 2026

Summary
Add assisted threading support (also contains changes from main)

What changed

  • Introduced a new assistedThreadingData_t structure in Core/Inc/Ramps.h
  • Added assisted threading state into rampsSharedData_t
  • Implemented assisted threading logic in Core/Src/Ramps.c
    • getSpindlePhase() calculates spindle phase from encoder position
    • computeServoStepTolerance() defines safe completion tolerance per control cycle
    • applyAssistedThreading() handles host request / latch / wait / phase match / move completion
  • Integrated assisted threading into SynchroRefreshTimerIsr() when servoMode == 1
  • Added host-visible control fields:
    • threadRequest
    • threadReset
    • spindleScaleIndex
    • threadPhaseTolerance
    • threadRemainingSteps
    • threadStartSteps
    • spindleCountsPerRev
    • debug phase state fields

Behavior

  • Host can request an assisted thread move and wait for the spindle phase to match
  • Once phase match occurs, the firmware enables spindle sync motion
  • Motion completes when the requested threaded step count is reached within safe tolerance
  • Supports signed threadRemainingSteps for proper direction-aware step tracking

Benefits

  • Enables more deterministic threaded move starts by synchronizing to spindle phase
  • Keeps existing servoMode behavior intact while extending indexing mode
  • Adds a host-driven assisted threading primitive without disrupting current DRO/control logic

@Funkenjaeger
Copy link
Copy Markdown

It would be advantageous if you and I could converge on a common firmware approach to support your Automatic Threading wizard and my Advanced ELS mode features on the UI side, so that those features aren't mutually exclusive.

To that end, I'm currently working on a branch where I've merged both of our changes and updated the FW/HW emulator accordingly so that I can test out our respective firmware features side-by-side, compare and contrast, and determine whether one or the other (or some combination of the two) can support all of our use cases.

@Pawcu
Copy link
Copy Markdown
Author

Pawcu commented Apr 16, 2026

Happy to discuss further if need be. I also like the ui you did btw 😁
In the meantime I've also implemented (on a separate branch) the Compound cutting simulation but still need to test that properly. I didn't need to do firmware changes on that. But I've started looking into multi-start threads and will need to update it for that.
Not sure how you prefer to catchup on this?

@Funkenjaeger
Copy link
Copy Markdown

I'll offer some more specific thoughts/feedback/recommendations once I've had a chance to complete an initial assessment and we can discuss further from there.

@Pawcu
Copy link
Copy Markdown
Author

Pawcu commented Apr 17, 2026

I'll offer some more specific thoughts/feedback/recommendations once I've had a chance to complete an initial assessment and we can discuss further from there.

Sounds good ok :D

@Funkenjaeger
Copy link
Copy Markdown

I'm still working on more of a functional assessment, but got derailed with UI and state machine refactoring along the way. In the interest of time, here is my current impression of how our approaches compare based on code review:

Pawcu approach: (please correct me if I've misinterpreted any of this from the code)

  • Phase sync between carriage and spindle is achieved by always starting the cutting pass at a specific Z position and spindle angle (phase)
  • Starting Z position is achieved by the servo moving the carriage to the target location based on the Z scale, including a small back-and-forth to take up the backlash
  • Spindle phase reference is latched on first activation, and on subsequent passes the firmware just waits to start until the spindle rotates into alignment with the latched reference phase
  • Stopping at the end of the cut is premeditated, moving a calculated number of steps relative to the reference (start) position

Pros:

  • Technically no requirement to keep the half nut closed between cutting passes since it re-syncs based on the Z scale

Cons:

  • Some added motion control complexity due to need for precise starting position w/ backlash management
  • Even in simpler turning use cases (phase doesn't matter), would require a start position since stop position is always relative to start

Funkenjaeger approach:

  • Phase sync between carriage and spindle is achieved by tracking the leadscrew phase relative to the spindle phase at all times (whether synced, stopped or jogging)
  • During the synchronized cutting move, the regular ELS behavior keeps them in phase (leadscrew slaved to spindle)
  • When not in a synchronized cutting move (stopped, jogging/retracting to prep for next pass, etc.) the phase delta (leadscrew actual phase vs. desired phase) is continuously accumulated
  • To start a synchronized cut, the firmware just waits for the accumulated phase delta (using modulo arithmetic) to reach 0
  • Stopping at the end of the cut is simply triggered by the Z scale reaching the target position

Pros:

  • Less motion control complexity; start from any Z position, no backlash management required
  • Keeps simple use cases simple (e.g. turning up to a shoulder - no start position needs to be defined)

Cons:

  • Must keep half nut closed throughout threading cycle. Not required for turning cycles.

Comments

I think both have their pros and cons, but I also think it may be possible to merge the positive aspects of each. For instance:

  • Your approach of re-syncing using scale position & spindle angle (opens the door to allowing relatively free use of the half nut)
  • My approach of stopping the cut based only on Z scale position, rather than counting steps from start position (simplifies some of the logic, and facilitates simple turn-to-shoulder use case)
  • Hybrid approach of allowing re-sync at any Z position rather than requiring a specific start position (given a reference phase at a particular Z position, you can easily calculate the correct phase at any other Z position since they're related by the thread pitch)

I don't completely love the added complexity of having to manage backlash in order to re-sync off of the scale, but IMO the option to allow free use of the half nut may make it worth the trade. I think I can envision a workflow where once the operator configures and starts the cycle, the whole threading cycle can be done using the mechanical controls on the lathe without needing to touch the touchscreen at all between passes.
I am also formulating some thoughts about how we might be able to make the backlash compensation a little more seamless, but more to come on that.

Thoughts? Concerns?

@Pawcu
Copy link
Copy Markdown
Author

Pawcu commented Apr 28, 2026

I'd love to discuss this further with you as to be honest I never considered my approach to be used for turning, only for thread cutting.
I still have a couple of questions as to how your approach will work - but i think they should be considered as separate operations and thus potentially also the logic should be different (i'm obviously biased on my approach for thread cutting :P )

If we start thinking about the cutting to a shoulder, maybe we could also consider adding logic for a 2nd servo? Just thinking out loud.

@Funkenjaeger
Copy link
Copy Markdown

I'd love to discuss this further with you as to be honest I never considered my approach to be used for turning, only for thread cutting. I still have a couple of questions as to how your approach will work - but i think they should be considered as separate operations and thus potentially also the logic should be different (i'm obviously biased on my approach for thread cutting :P )

The leadscrew/power feed on a lathe supports two main operations - turning and threading. Turning is functionally the same as threading, except the phase doesn't matter. It doesn't seem efficient to me to ignore one of the two, or to implement entirely separate logic, when one is just a simpler version of the other and both can be accommodated with a common implementation. I think that applies both in FW and in the UI.

If we start thinking about the cutting to a shoulder, maybe we could also consider adding logic for a 2nd servo? Just thinking out loud.

To be clear, when I say 'turning up to a shoulder' I am only talking about the turning operation, i.e. cutting moves electronically stopping at the configured Stop Z position - just the same as you do in your threading cycle, just ignoring phase sync. I'm not suggesting that facing off the shoulder would be automated as part of this. That's very easy for the operator to do manually at the end of the cycle by releasing the half nut, manually advancing the carriage just slightly, and retracting the cross-slide. I'm not suggesting bringing a 2nd simultaneous electronically controlled axis into the equation, which would start down the slippery slope toward a full CNC conversion.

@Pawcu
Copy link
Copy Markdown
Author

Pawcu commented Apr 29, 2026

The leadscrew/power feed on a lathe supports two main operations - turning and threading. Turning is functionally the same as threading, except the phase doesn't matter. It doesn't seem efficient to me to ignore one of the two, or to implement entirely separate logic, when one is just a simpler version of the other and both can be accommodated with a common implementation. I think that applies both in FW and in the UI.

Maybe - like i said i still need to find some time to understand a bit more how your approach will work. I didnt have a lot of time to think about it yet but would it potentially overflow some of the variables if you try to keep track of phase between spindle and servo (especially if servo is using a lot of steps for each turn?) - just thinking out loud at the moment and like I said haven't given it a lot of thought.

To be clear, when I say 'turning up to a shoulder' I am only talking about the turning operation, i.e. cutting moves electronically stopping at the configured Stop Z position - just the same as you do in your threading cycle, just ignoring phase sync. I'm not suggesting that facing off the shoulder would be automated as part of this. That's very easy for the operator to do manually at the end of the cycle by releasing the half nut, manually advancing the carriage just slightly, and retracting the cross-slide. I'm not suggesting bringing a 2nd simultaneous electronically controlled axis into the equation, which would start down the slippery slope toward a full CNC conversion.

Yeah i do get what you mean - i guess i've already started thinking of a cnc conversion😅

@Funkenjaeger
Copy link
Copy Markdown

Maybe - like i said i still need to find some time to understand a bit more how your approach will work. I didnt have a lot of time to think about it yet but would it potentially overflow some of the variables if you try to keep track of phase between spindle and servo (especially if servo is using a lot of steps for each turn?) - just thinking out loud at the moment and like I said haven't given it a lot of thought.

Just using napkin math, the max step rate that most stepper/servo drivers can even handle is in the ballpark of 200 kHz. At that rate it would take just shy of 3 hours to overflow an int32 accumulator. That's a highly unrealistic corner case, and anyway it's quite trivial to detect and mitigate such an overflow condition. Not a problem.

Yeah i do get what you mean - i guess i've already started thinking of a cnc conversion😅

I get it... like I said, slippery slope. This is currently nowhere near to what a CNC-ready implementation would look like, since that's not what it was designed for. Trying to make it so would be a huge effort to reinvent a wheel that's been done quite well in many other places, while making it worse for its original intended purpose (especially in terms of overcomplication).

@Funkenjaeger
Copy link
Copy Markdown

I have an initial version of this experimental new automated ELS firmware variant on this branch. As indicated above, my intention here was to merge what I see as the best attributes of your and my original firmware approaches.

ELS Stop behavior summary:

  • Electronic stop from SYNC mode based simply on Z axis scale position reaching the configured stop point
  • Reference phase relationship between spindle & carriage is latched once during the first pass - similar to your approach, but done at the end, when it stops (where we choose to latch this is fairly arbitrary, but doing it at the end is an easy way to guarantee we're on the correct side of the backlash when it happens)
  • Re-sync to the thread pitch at the start of each cutting pass is based on Z scale position (and spindle phase) - sort of like your approach, but the carriage doesn't have to be at a specific position, it can be anywhere and the phase will be corrected based on the actual position at the start
  • Backlash is taken up with a short move in the cutting direction at the start of a cutting pass. The moment that's done, it re-syncs ELS phase to the spindle, and for the rest of the cut it's just doing standard ELS SYNC mode behavior.

Benefits, in my opinion:

  • Simple stop mechanism has no dependence on where the cutting pass starts or really any other factors. I think this is as robust & reliable as it can be, which is important since a failure to stop correctly could be catastrophic
  • No pre-calculation required for cutting moves. Just re-sync and let it rip
  • Operator is free to open and close the half-nut, since it'll re-sync at the start of any cutting pass regardless of where the carriage starts from and how it got there (electronic retract, manual retract, or a combination of both)
  • The re-sync logic is inherently bypassed if turning rather than threading so it seamlessly handles both use cases
  • By latching reference Z and spindle phase at the stop position, the values can be compared at the end of each pass; they should stay consistent to within a fairly tight tolerance, and if they're not then it's a red flag that something's wrong (such as a mis-configured axis encoder resolution or servo steps/rev setting, lathe leadscrew gearbox not in the intended gear, etc) which I think could be a useful self-check

There's a writeup here with more information:
https://github.com/Funkenjaeger/rotary-controller-f4/blob/els-stop-scale-sync/ARCHITECTURE.md#els-shoulder-stop

I've got more work to do with general cleanup, removing temporary debugging instrumentation, testing etc., but so far it seems to be working for me in the full wizard-based automated threading cycle based on your UI work.

@bartei
Copy link
Copy Markdown
Owner

bartei commented May 14, 2026

Thanks for your contributions folks! I will take some time to review and test the changes as soon as i have a minute!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants