Skip to content

sim_encoder: fix negative velocity at the thread rate cap, raise sim spindle speed limits - #4583

Draft
grandixximo wants to merge 2 commits into
LinuxCNC:masterfrom
grandixximo:sim-encoder-4582
Draft

grandixximo wants to merge 2 commits into
LinuxCNC:masterfrom
grandixximo:sim-encoder-4582

Conversation

@grandixximo

Copy link
Copy Markdown
Contributor

Fixes #4582.

Root cause

sim_encoder runs its pulse generator in the base thread, so the quadrature count rate (rpm/60 × ppr × 4) cannot exceed the base thread frequency. update_speed() clamped the requested frequency at that limit (maxf), which makes the frequency-generator add value exactly +2^31. make_pulses() uses bit 31 of addval as the direction bit, so any positive speed at or above the cap was misread as negative rotation: the simulated counts ran backwards and encoder.N.velocity went negative (12500 rpm with the stock ppr 12 and a 100000 ns base period). spindle.0.at-speed then never asserts and a program dwells forever.

Verified with a halrun harness: 12000 rpm => +200 rps, 12500+ rpm => -208 rps before the fix.

Changes

  • sim_encoder: clamp the add value magnitude below 2^31 so capped speeds saturate in the correct direction instead of flipping sign; add a saturated output pin that is true while the cap is engaged (suggested by @rmu75); print a one-shot warning naming the maximum supported speed; document the pin and the cap formula in the man page.
  • configs: lower the sim spindle encoder count rate below the base thread cap.
    • Mills (gmoccapy, scara): ppr 12 => 2, position-scale 48 => 8, cap at 75000 rpm.
    • Lathes (gmoccapy lathe, lathe_multispindle): ppr => 6, position-scale => 24, cap at 25000 rpm, keeping 24 counts/rev for threading simulation. (No commercial lathe main spindle exceeds ~18000 rpm.)

Velocity precision is unaffected (actually slightly better at low ppr): the encoder component computes velocity from the time between edge timestamps, so fewer edges means a longer measurement window. The only real trade-off is coarser threading position quantization (1/8 vs 1/48 rev steps on spindle.0.revs) in the mill sims.

Testing

  • halrun harness: positive speeds saturate at the cap, negative speeds stay negative, saturated toggles correctly in both directions, warning fires once.
  • tests/module-loading/sim_encoder: 7/7 pass.

The frequency generator add value is freq * 2^31/maxf, and make_pulses()
uses bit 31 of addval as the direction bit.  The old freq clamp at
+/-maxf allowed addval to reach exactly +2^31, setting bit 31, so a
commanded speed at or above the cap was misread as negative rotation:
the simulated counts ran backwards and encoder.N.velocity went negative
(e.g. at >= 12500 rpm with ppr 12 and a 100000 ns base thread).  With a
spindle-at-speed interlock this makes a program dwell forever.

Clamp the add value magnitude to less than 2^31 instead, so the outputs
now keep turning in the commanded direction at the maximum rate.

Also add a 'saturated' output pin that is true while the cap is engaged,
and print a one-shot warning naming the maximum supported speed.
The software encoder is sampled in the base thread, so the quadrature
count rate (rpm/60 * ppr * 4) must stay below the base thread frequency
or the count saturates and spindle-at-speed never asserts.  With the
stock 100000 ns base period the old settings capped at 12500 rpm
(ppr 12), well below common spindle speeds.

Mill configs (gmoccapy, scara): ppr 12 -> 2, position-scale 48 -> 8,
cap at 75000 rpm.  Lathe configs (gmoccapy lathe, lathe_multispindle):
ppr -> 6, position-scale -> 24, cap at 25000 rpm, keeping 24 counts/rev
for threading simulation.

Fixes LinuxCNC#4582 together with the sim_encoder direction-bit fix.
@rmu75

rmu75 commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

didn't try it, but LGTM.

@grandixximo

Copy link
Copy Markdown
Contributor Author

@DauntlessAq could you give it a test?

@BsAtHome

Copy link
Copy Markdown
Contributor

On hold until 64-bit HAL merge. May need to change again.

@andypugh

Copy link
Copy Markdown
Collaborator

I think we should park this until after the 64-bit change.
(also, this component seems to mainly exist to disappoint people looking to simulate a spindle etc, when all it really is is a strangely limited stepgen)

@rmu75

rmu75 commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

remove and replace with stepgen in velocity mode?

@grandixximo
grandixximo marked this pull request as draft September 28, 2026 04:51
@grandixximo

Copy link
Copy Markdown
Contributor Author

Parked, agreed. I looked into sim_encoder against stepgen in velocity mode before answering.

stepgen can't replace it: its quadrature output has A and B but no index, and these sims need the index for index-enable and G33/G76. Its pulses also run in the base thread, so it would hit the same kind of speed limit.

The replacement that fits is sim_spindle, which most stock sims already get from basic_sim.tcl. I ran G33 and G76 headless on three chains from 1000 to 80000 rpm: master's sim_encoder values, this PR's lower ppr, and sim_spindle. sim_spindle threads with exact pitch and no jitter at every speed. Master's values never start a thread from 12500 rpm up, since at-speed never comes. This PR's values work to 60000 rpm but quantize 4 times coarser.

So after the 64-bit work I'd rework this PR: switch the six sims that use sim_encoder (gmoccapy mill, lathe and scara, lathe_multispindle, panelui-demo, gscreen spartan) to sim_spindle, and keep sim_encoder with its direction fix. It is the only source of a real quadrature signal with an index pulse in the tree, which is what you want for exercising the encoder component.

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.

SIM: negative spindle speed with simulated encoder

4 participants