-
Notifications
You must be signed in to change notification settings - Fork 38
Winder
The Winder V2 winds filament onto a spool: a puller draws the filament at a set speed, a tension arm measures the slack between puller and spool, the spool speed follows the tension arm, and a traverse lays the filament across the spool.
| Winder V2 | Winder V2 (EL7031-0030 spool) | |
|---|---|---|
| Machine ID | 2 | 98 |
| Spool stepper | EL7041-0052 | EL7031-0030 |
| Schema | winder_v1.yaml |
winder_v1_7031_0030_spool.yaml |
Both variants run the same code in winder_v2/. The XL Winder is a Winder V2 with Settings → Traverse Size → XL, which raises the outer traverse limit in the UI from 180 mm to 385 mm. Operating instructions: Winder-Manual.
| Role | Terminal | Purpose |
|---|---|---|
| 0 | EK1100 | Bus coupler |
| 1 | EL2002 | Laser pointer (output 1) |
| 2 | EL7041-0052 or EL7031-0030 | Spool motor |
| 3 | EL7031 | Traverse motor and end stop |
| 4 | EL7031-0030 | Puller motor; its analog input reads the tension arm |
Wiring is in the Winder-Manual; assigning roles in Identification.
flowchart TB
subgraph CTRL["Winder V2 control"]
direction LR
LA["<a href='https://github.com/qitechgmbh/control/blob/jse-control-v2/qitech_control/src/machines/laser_v1.rs'>Laser V1</a>, optional<br/>via <a href='https://github.com/qitechgmbh/qitech_framework/blob/main/qitech_framework/src/machine/subscribe.rs'>RemoteProperty</a>"]:::framework
PSC["<a href='https://github.com/qitechgmbh/control/blob/jse-control-v2/qitech_control/src/machines/winder_v2/puller/speed_controller.rs'>Puller speed controller</a><br/>direct or adaptive, jerk-limited"]:::control
TA["<a href='https://github.com/qitechgmbh/control/blob/jse-control-v2/qitech_control/src/machines/winder_v2/tension_arm.rs'>Tension arm</a><br/>angle"]:::control
SSC["<a href='https://github.com/qitechgmbh/control/blob/jse-control-v2/qitech_control/src/machines/winder_v2/spool/speed_controller.rs'>Spool speed controller</a><br/>min/max or adaptive"]:::control
TR["<a href='https://github.com/qitechgmbh/control/blob/jse-control-v2/qitech_control/src/machines/winder_v2/traverse/mod.rs'>Traverse</a><br/>homing and traversing"]:::control
LA -. "diameter" .-> PSC
PSC -- "puller speed" --> SSC
TA -- "arm angle" --> SSC
SSC -- "spool rpm" --> TR
end
classDef frontend fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef control fill:#dcfce7,stroke:#15803d,color:#14532d
classDef framework fill:#fef3c7,stroke:#b45309,color:#78350f
classDef lib fill:#ede9fe,stroke:#6d28d9,color:#4c1d95
classDef hardware fill:#f1f5f9,stroke:#475569,color:#0f172a
tension_arm.rs turns the voltage of the arm's angle sensor into an angle. The operating manual calls the arm the load arm.
- Input: the analog input of the puller terminal EL7031-0030, in volts. 0–5 V maps to 0–1 revolution (modulo one revolution).
-
Zero:
tension_arm.set_zero(UI: Set Zero Point) stores the current raw angle as the zero point,tension_arm.zero(revolutions,nulluntil the arm is zeroed). -
Output:
tension_arm.angle= raw angle − zero, wrapped into 0°–360°. Values from 270° up are reported as negative, so the range is −90° to 270°.
Winding requires a zeroed arm. The zero point lives in memory only and is lost when the server restarts. The tension arm has no config parameters.
spool/speed_controller.rs sets the spool speed from the tension arm.
Filament tension. utils/filament_tension.rs converts the arm angle into a normalised tension, spool.speed_controller.filament_tension. It computes the filament path length puller → arm tip → traverse from fixed geometry and scales it so that 20° = 0.0 (slack, spool speeds up) and 90° = 1.0 (tight, spool slows down). Outside 20°–90° the tension is null and both algorithms target 0 rpm.
Algorithms (spool.speed_controller.algorithm):
-
Min/max (
speed_algorithm_min_max.rs): target =speed_min + f(1 − tension) × (speed_max − speed_min)with the exponential curvef(x) = (e^(2x) − 1) / (e^2 − 1), which makes the speed more sensitive at low tension. AnAngularAccelerationSpeedControllerlimits the acceleration to 0.5/s × the higher of the target speed and the highest output speed of the last 5 s. -
Adaptive (
speed_algorithm_adaptive.rs): learns an effective spool radius,spool.speed_controller.adaptive.speed_factor(starts at 4.25 cm, limited to 4.25–20 cm). Whenever the tension is valid, also outside Wind mode, the factor changes by(tension − tension_target) × radius_learning_rate × Δt(cm, Δt in s): too much tension makes it larger and the spool slower. The adaptive maximum speed ispuller.speed / speed_factor × max_speed_multiplier, and the target isspeed_min + (1 − tension) × (adaptive maximum − speed_min). The acceleration limit isadaptive maximum × acceleration_factor; below a target of 0.1 rad/s it is multiplied bydeacceleration_urgency_multiplier / (|target| + 0.01). It is never lower than 0.5 rad/s².
Output. The controller is enabled only in Wind mode; otherwise both algorithms ramp towards 0. The result is always clamped to speed_min…speed_max, stored as spool.speed_controller.speed, multiplied by the direction sign, converted to steps (200 steps/rev) and written to the spool stepper. spool.rpm is its absolute value.
Progress. Every cycle spool.progress changes by puller.speed × Δt, so it counts down while the puller runs in reverse. spool.reset_progress sets it to 0.
| Parameter | Unit | Default | Description |
|---|---|---|---|
spool.direction |
forward / reverse
|
forward |
Sign of the spool speed |
spool.speed_controller.algorithm |
adaptive / min_max
|
adaptive |
Speed algorithm |
spool.speed_controller.speed_min |
rpm | 0 | Lower clamp for both algorithms. Min/max: speed at tension 1.0 |
spool.speed_controller.speed_max |
rpm | 150 (max. 600) | Upper clamp for both algorithms. Min/max: speed at tension 0.0 |
spool.speed_controller.adaptive.tension_target |
0–1 | 0.7 | Tension the adaptive algorithm steers to |
spool.speed_controller.adaptive.radius_learning_rate |
– | 0.5 | Gain of the speed-factor learning |
spool.speed_controller.adaptive.max_speed_multiplier |
– | 4.0 | Multiplier for the adaptive maximum speed |
spool.speed_controller.adaptive.acceleration_factor |
1/s | 0.2 | Base acceleration as a fraction of the adaptive maximum speed |
spool.speed_controller.adaptive.deacceleration_urgency_multiplier |
– | 15 | Raises the acceleration limit when the target is close to 0 |
State: spool.mode (standby / hold / wind), spool.speed_controller.enabled. Measurements: spool.rpm, spool.progress (m), spool.speed_controller.speed (rpm), spool.speed_controller.filament_tension (0–1 or null), spool.speed_controller.adaptive.speed_factor (m). Command: spool.reset_progress.
puller/mod.rs and puller/speed_controller.rs drive the puller wheel.
Speed controller (puller.speed_controller.algorithm, UI: Speed Regulation with the options Fixed and Adaptive):
-
Direct: target =
speed_desired. -
Adaptive: target =
speed_desired × (1 + modulation × speed_delta_max), never below 0. The laser diameter drivesmodulation(−1…1), see below.
Output chain. The target is used only while the puller is in Pull mode (winder Pull or Wind); otherwise it is 0. It is multiplied by the gear ratio (1, 5 or 10) and the direction sign, then a LinearJerkSpeedControllerDT limits it to ±50 m/min, ±5 m/min/s and ±10 m/min/s². The limited value is puller.speed. It is converted to steps (8 cm wheel, 200 steps/rev) and written to the puller stepper. The motor is enabled in Hold and Pull and disabled in Standby. The UI caps the target speed at 50 m/min divided by the gear ratio.
Laser-adaptive mode. When the winder is subscribed to a Laser V1, subscribe() in mod.rs binds two RemoteProperty values of the laser: the measurement diameter and the config diameter.target. While the subscription exists, the modulation is updated every cycle, whichever algorithm is selected:
- If
|diameter − target| ≤ tolerance_limit: reset the distance counter and change nothing. - Otherwise add the pulled distance (
|puller.speed| × Δt) topuller.speed_controller.adaptive.distance_since_adjustment. - Once the counter reaches
adjustment_distance: change the modulation byincrease_per_step(diameter too large: faster; too small: slower), clamp it to −1…1 and reset the counter.
Writing puller.speed_controller.algorithm through the API resets the modulation and the counter to 0. In the UI, turn on Settings → Puller → Adaptive Speed (Experimental) and pick the laser as Reference Machine. Only then does Adaptive appear under Speed Regulation.
| Parameter | Unit | Default | Description |
|---|---|---|---|
puller.direction |
forward / reverse
|
forward |
Sign of the puller speed |
puller.gear_ratio |
one_to_one / one_to_five / one_to_ten
|
one_to_one |
Multiplies the target speed by 1, 5 or 10 before the limits |
puller.speed_controller.algorithm |
direct / adaptive
|
direct |
Speed algorithm |
puller.speed_controller.speed_desired |
m/min | 0 | Target speed; base speed in adaptive mode |
puller.speed_controller.adaptive.speed_delta_max |
fraction | 0 | Relative speed change at modulation ±1 (UI: Max Speed Deviation, %) |
puller.speed_controller.adaptive.increase_per_step |
fraction | 0 | Modulation change per step (UI: Change Per Step, %) |
puller.speed_controller.adaptive.tolerance_limit |
mm | 0 | Dead band around the diameter target (UI: Allowed Diameter Deviation) |
puller.speed_controller.adaptive.adjustment_distance |
m | 0 | Pulled length between two steps (UI: Distance Between Steps) |
The speed, acceleration and jerk limits and the wheel size are constants in puller/mod.rs, not config. State: puller.mode (standby / hold / pull). Measurements: puller.speed (m/min, after gear ratio, direction and limits), puller.speed_controller.speed_target (m/min, before them), puller.speed_controller.adaptive.modulation, puller.speed_controller.adaptive.distance_since_adjustment (m).
traverse/mod.rs moves the filament guide between the inner and the outer limit. Position 0 is the end stop; positive is outward.
-
Inputs: the end stop (first digital input of the EL7031), the EL7031 step counter (
traverse.position, mm) and the spool rpm. -
Homing (UI: Go to Home): moves to the end stop fast, backs off, approaches it again slowly, sets the counter to 0 and checks after 100 ms that the position is still 0 (±0.01 mm). Then
traverse.homedis true. -
Traversing (Wind mode): first moves out at 100 mm/s, then runs back and forth between
limit_inner + paddingandlimit_outer − paddingatspool rev/s × step_size, so every spool revolution moves the guide by one step size. -
Manual moves (
goto_limit_inner,goto_limit_outer): 100 mm/s, 10 mm/s for the last 1 mm, stop within 0.01 mm. - Mode side effects: entering Hold (winder Hold or Pull, coming from Standby or Wind) starts homing, entering Traverse (winder Wind) starts traversing, and Standby switches the motor off.
| Parameter | Unit | Default | Description |
|---|---|---|---|
traverse.limit_inner |
mm | 22 | Inner turning point. Range 0 … limit_outer − 0.9 |
traverse.limit_outer |
mm | 92 | Outer turning point. Range limit_inner + 0.9 … 385 |
traverse.step_size |
mm | 1.75 | Traverse travel per spool revolution (winding pitch) |
traverse.padding |
mm | 0.88 | Distance from each limit at which the traverse turns |
When one limit is written through the API, the bound of the other limit moves with it (minimum gap 0.9 mm) and its value is clamped if needed.
| Command | Allowed when |
|---|---|
traverse.goto_home |
Traverse in Hold mode (winder Hold or Pull), not homing, not traversing |
traverse.goto_limit_inner |
Hold mode, homed, not homing, not traversing, not already moving in |
traverse.goto_limit_outer |
Hold mode, homed, not homing, not traversing, not already moving out |
State: traverse.mode (standby / hold / traverse), traverse.state, traverse.homed, traverse.endstop_triggered. Measurement: traverse.position (mm).
laser_pointer.rs switches output 1 of the EL2002 with laser_pointer.enable / laser_pointer.disable and reports laser_pointer.enabled. It is independent of the mode.
check_spool_automatic_action in mod.rs stops or pulls after a set length. Every cycle, if the action isn't no_action and spool.progress ≥ required_meters, it sets the winder mode to Hold or Pull, the same way the mode commands do. In the UI this is the Spool Autostop card on the control page.
| Parameter | Unit | Default | Description |
|---|---|---|---|
spool_automatic.required_meters |
m | 250 | Length after which the action runs (UI: Target Length) |
spool_automatic.action |
no_action / pull / hold
|
no_action |
Mode to switch to |
QiTech Control · GitHub · Framework wiki · Lib wiki · Report a docs problem
Getting Started
Guides
Machines
Developers
Related