Skip to content

Claude/buffer deferred motor drive p mp bi#13

Closed
adebuyss wants to merge 22 commits intoFly3DTeam:mainfrom
adebuyss:claude/buffer-deferred-motor-drive-pMPBi
Closed

Claude/buffer deferred motor drive p mp bi#13
adebuyss wants to merge 22 commits intoFly3DTeam:mainfrom
adebuyss:claude/buffer-deferred-motor-drive-pMPBi

Conversation

@adebuyss
Copy link
Copy Markdown

@adebuyss adebuyss commented Apr 4, 2026

No description provided.

adebuyss and others added 22 commits March 31, 2026 12:47
Replaces macro-based buffer control with a Klipper host plugin that
runs in the reactor loop. Uses TMC2209 VACTUAL for velocity control
and buttons callbacks for sensor monitoring, independent of the gcode
queue. Matches extruder velocity with sensor-based correction.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
When buffer hits the full sensor, instead of immediately retracting:
1. Slow feed to extruder_velocity * slowdown_factor (default 0.5)
2. Only retract after full_zone_timeout seconds (default 3.0s)
This lets the buffer naturally drain before forcing a retract.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
…nfigurable threshold

- Configurable min_extrusion_velocity (default 0.05 mm/s) replaces hard-coded 0.5
- Sensor callbacks now update extruder velocity before evaluating
- Cache GCONF register to eliminate UART read on direction change
- Detect extruder retraction (negative delta) and immediately stop motor
- Full zone timeout only counts active feeding time, not stopped time
- Burst feed: when empty while stopped, wait burst_delay then feed for burst_feed_time

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
- Add burst cycle counter (max 5) to prevent infinite feeding when
  buffer is stuck in empty zone (jammed motor, sensor failure)
- Full zone feed time now tracks actual elapsed time instead of adding
  a fixed control_interval increment, preventing double-counting when
  sensor callbacks trigger extra evaluations

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
buttons.register_buttons() expects pin description strings and does
its own parsing via ppins.lookup_pin(). We were pre-parsing into dicts
which caused 'dict has no attribute strip' on startup.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
Raw GCONF bit manipulation was not changing direction - both BUFFER_FEED
and BUFFER_RETRACT spun the same way. Switch to mcu_tmc.fields.set_field()
which uses Klipper's own register field definitions for correct bit layout.
Also removes the GCONF cache since the field helper maintains its own state.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
When the material switch detects filament insertion (absent → present),
the buffer auto-enables and immediately evaluates sensor state to start
feeding. The existing control loop handles the rest — feeds forward
until the middle sensor triggers, then stops.

Matches the original mellow-plus.cfg insert_gcode behavior.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
extruder.last_position returns [x, y, z, e] list, not a float.
Index [3] extracts the E axis position for velocity calculation.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
Skip shaft and vactual register writes when the values haven't changed.
Pressing the feed button while auto-control was running caused multiple
rapid UART writes that overwhelmed the STM32F072 MCU.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
With ^! pins, the buttons module reports state=0 when the sensor is
blocked (carriage present). Invert in the callback so sensor_states
reads True when the carriage is at that position.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
- Add debug config option (default False). When True, logs all three
  hall sensor states to console whenever any sensor changes.
- Fix sensor callback to use not bool(state) — with ^! pins, state=0
  means sensor is triggered (carriage present).

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
Debug output shows middle+full sensors trigger simultaneously in the
transition zone between those positions. Split the full branch:

- full only (deep full): existing slowdown + timeout + retract
- full+middle (overlap): slow down but no timeout/retract accumulation
- empty+middle overlap handled by empty branch (aggressive feed)
- all-false (between empty and middle) handled by between-sensors branch

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
manual_stepper.do_enable() triggers Klipper's TMC module to re-send
all configuration registers (~30 UART writes), which overwhelms the
STM32F072 MCU. Instead, enable the motor once at startup in
handle_ready and use VACTUAL=0 for stop. TMC2208 at VACTUAL=0
draws negligible power with the motor holding at zero velocity.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
extruder.last_position[3] wasn't updating during printing.
toolhead.get_position() returns the live gcode position [x,y,z,e]
which tracks E axis movement in real time.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
When print_stats.state != "printing", the buffer follows extruder
movement in both directions:
- Forward E movement: buffer feeds (same as before)
- Backward E movement: buffer retracts to follow

During active printing, short retractions (firmware retraction) still
just stop the buffer motor as before.

New config: follow_retract (default True)
New status fields: is_printing, extruder_retracting

This means SIMPLE_UNLOAD_FILAMENT and SIMPLE_LOAD_FILAMENT work
automatically with no macro changes needed.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt
)

* Switch from polling to event-driven E tracking via G0/G1/G2/G3 hooks

Replace the 100ms polling loop (toolhead.get_position()[3]) with direct
interception of G0/G1/G2/G3 gcode commands. The wrapper reads
gcode_move.last_position before/after the original handler to get exact
E deltas, accounting for M82/M83/G92/M221 automatically.

E velocity is computed from the commanded path speed (F parameter):
- Mixed XYZ+E moves: e_vel = speed * |de| / xyz_distance
- Pure E moves: e_vel = speed (feedrate applies to E directly)
- Fallback: delta/time between commands

The control timer is demoted to a watchdog (default 500ms):
- Forward timeout checking
- Velocity decay (move-time-aware, won't cut mid-move)
- Burst feed and full-zone timeout timing

Sensor callbacks remain unchanged (immediate via buttons module).
G10/G11 firmware retraction is caught automatically since it
internally generates G1 commands via run_script_from_command.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt

* Add pytest test framework for buffer plugin (99 tests)

Pure-mock test infrastructure inspired by Kalico's PrinterShim pattern.
Mocks all Klipper interfaces (reactor, gcode, TMC driver, buttons,
gcode_move, print_stats) with controllable time for deterministic
testing of burst cycles, full zone timeouts, and velocity decay.

Covers: BufferMotor register writes/caching, state machine transitions,
burst feed cycles, full zone timeout/retract, E velocity tracking,
retraction following, error conditions, manual button control, all
BUFFER_* gcode commands, and material insertion/removal.

Also fixes latent bug: _update_extruder_velocity() was called but
never defined (would raise AttributeError on sensor callbacks).

https://claude.ai/code/session_0142Jm124CYMHMjo13dCNgwp

* Add __pycache__ and .pytest_cache to gitignore

https://claude.ai/code/session_0142Jm124CYMHMjo13dCNgwp

---------

Co-authored-by: Claude <noreply@anthropic.com>
Klipper's register_command rejects duplicate registrations.
Must pass None first to unregister the existing handler.

https://claude.ai/code/session_01CATwsdMwumQvPKVz4AjkFt

Co-authored-by: Claude <noreply@anthropic.com>
Separate velocity state updates (fast, arithmetic-only) from TMC2208
UART register writes (slow, blocking) in the G-code move path. The
_on_e_movement hook now updates state variables immediately, then
schedules a rate-limited reactor callback for the actual motor write.

Key changes:
- Add _request_drive_update/_deferred_drive for coalesced UART writes
- Rate-limit motor writes to ~10/s via _min_drive_interval (100ms)
- Tighten control_interval default from 0.5s to 0.25s for faster
  catch-up of rate-limited updates
- Expose drive_interval as configurable (default 0.1s, range 0.02-1.0)
- Add register_callback/flush_callbacks to MockReactor for testing
- Add test_deferred_drive.py with 11 tests for the new behavior

This eliminates per-move UART latency on dense G-code streams, reducing
risk of "Timer too close" MCU errors and print stutter.

https://claude.ai/code/session_01YEx9rspTQ2wVUJkrAqLphm
@adebuyss adebuyss closed this Apr 4, 2026
@adebuyss adebuyss deleted the claude/buffer-deferred-motor-drive-pMPBi branch April 4, 2026 03:38
Avatarsia pushed a commit to Avatarsia/BufferPLUS-klipper that referenced this pull request Apr 22, 2026
12 Verbesserungen aus der parallelen LLL_Plus-Variante integriert.
Unser Refactor (Helpers, Parametrisierung, Raw-State) bleibt.

Kategorie A - Sensor- und Event-Filterung:
 ss1gohan13#1 Sensor disable waehrend Erstbefuellung, reaktivieren in
    _initial_follow_end, STOP_BUFFER_FILL, BUFFER_AUTO_ON
 ss1gohan13#2 runout_gcode ignoriert Events wenn manual_operation==1
 Fly3DTeam#3 HALL2/HALL3 Guards erweitert um manual_operation-Check
 Fly3DTeam#4 HALL1 selektiv: nur _MANUAL_FEED stoppen, LOAD/UNLOAD
    weiterlaufen lassen. action_respond_info() statt M118 mit
    Emoji. Guard zusaetzlich.

Kategorie B - Toggle-Features:
 Fly3DTeam#6 variable_feed_burst_enabled (default 0): Triple-Feed-Burst
    nur aktiv wenn =1. Default = sicher (Dauerlauf-Neustart).
 Fly3DTeam#8 variable_auto_load_after_follow (default 0): nach Follow-Phase
    automatisch LOAD_FILAMENT wenn Hotend warm, nur wenn =1.

Kategorie C - UNLOAD-Praezision:
 Fly3DTeam#9 Phase 3a Distanz = load_fast_distance + Follow-Strecke
    (initial_follow_speed * initial_follow_duration).
 Fly3DTeam#10 sync_locked=0 und sync_state=0 explizit am UNLOAD-Ende.

Kategorie D - Diagnose:
 Fly3DTeam#11 _STATE_DUMP zeigt sync_locked und sync_state.
 Fly3DTeam#12 _boot_autostart ueberspringt BUFFER_AUTO_ON wenn
     initial_lockout==1 (Stromausfall-Edge-Case).
 Fly3DTeam#13 ENABLE/DISABLE_RUNOUT_SENSOR description nennt
     runout_pause=1-Abhaengigkeit explizit.

Punkt Fly3DTeam#5 (M118 -> action_respond_info flaechig) bewusst uebersprungen -
nur HALL1 bekommt das, Rest bleibt M118.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants