Compare commits
6 Commits
19e6cc6c93
...
549b69c234
| Author | SHA1 | Date | |
|---|---|---|---|
| 549b69c234 | |||
|
|
5376d23f8b | ||
|
|
ecf3191fcc | ||
|
|
3baa67360c | ||
|
|
b7bd7a1c9c | ||
|
|
6fe2e79bff |
@@ -369,6 +369,13 @@ module.exports = new Vue({
|
|||||||
ready: function() {
|
ready: function() {
|
||||||
window.onhashchange = () => this.parse_hash();
|
window.onhashchange = () => this.parse_hash();
|
||||||
|
|
||||||
|
// Embedded Svelte subviews (W axis settings, etc.) signal
|
||||||
|
// unsaved changes via this event. The master Save button
|
||||||
|
// highlights when modified is true.
|
||||||
|
window.addEventListener("onefin:dirty", () => {
|
||||||
|
this.modified = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Resolve the initial route before the websocket connects so
|
// Resolve the initial route before the websocket connects so
|
||||||
@@ -481,6 +488,12 @@ module.exports = new Vue({
|
|||||||
toggle_rotary: async function(isActive) {
|
toggle_rotary: async function(isActive) {
|
||||||
try {
|
try {
|
||||||
await api.put("rotary", {status: isActive});
|
await api.put("rotary", {status: isActive});
|
||||||
|
// The /api/rotary endpoint rewrites motors[1]/[2]
|
||||||
|
// in config.json on the server. Refetch so the UI
|
||||||
|
// reflects the new motor config (otherwise the
|
||||||
|
// motor settings page keeps showing pre-toggle
|
||||||
|
// values until the next page reload).
|
||||||
|
await this.update();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
alert("Error occured");
|
alert("Error occured");
|
||||||
@@ -673,9 +686,16 @@ module.exports = new Vue({
|
|||||||
|
|
||||||
this.config["selected-tool-settings"][selected_tool] = settings;
|
this.config["selected-tool-settings"][selected_tool] = settings;
|
||||||
this.display_units = this.config.settings["units"];
|
this.display_units = this.config.settings["units"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.put("config/save", this.config);
|
await api.put("config/save", this.config);
|
||||||
|
// Notify any embedded Svelte subviews that own their
|
||||||
|
// own persistence (W axis -> aux.json, etc.) that
|
||||||
|
// the user just hit the master Save button. They
|
||||||
|
// listen for `onefin:save-all` and PUT their state.
|
||||||
|
try {
|
||||||
|
window.dispatchEvent(new CustomEvent("onefin:save-all"));
|
||||||
|
} catch (_e) {}
|
||||||
this.modified = false;
|
this.modified = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Save failed:", error);
|
console.error("Save failed:", error);
|
||||||
|
|||||||
@@ -255,6 +255,21 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Home every enabled axis at once (legacy Onefinity behavior).
|
||||||
|
// The XYZ home is fired first via the standard /api/home endpoint,
|
||||||
|
// then the W axis is homed if it is enabled. The two cycles run
|
||||||
|
// in parallel — W is on the auxcnc ESP and doesn't share motors
|
||||||
|
// with the AVR — so the user sees one click homing everything.
|
||||||
|
home_all: function () {
|
||||||
|
this.ask_home = false;
|
||||||
|
api.put("home");
|
||||||
|
if (this.w && this.w.enabled) {
|
||||||
|
api.put("aux/home").catch(function (err) {
|
||||||
|
console.error("W home failed:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
aux_jog: function (delta_mm) {
|
aux_jog: function (delta_mm) {
|
||||||
api.put("aux/jog", { mm: delta_mm }).catch(function (err) {
|
api.put("aux/jog", { mm: delta_mm }).catch(function (err) {
|
||||||
console.error("W jog failed:", err);
|
console.error("W jog failed:", err);
|
||||||
|
|||||||
@@ -87,100 +87,16 @@ module.exports = {
|
|||||||
return this.stallRPM * this.stepsPerRev * ustep / 60;
|
return this.stallRPM * this.stepsPerRev * ustep / 60;
|
||||||
},
|
},
|
||||||
|
|
||||||
current_axis: function() {
|
// NOTE: do not add `current_xxx` computed props that mirror
|
||||||
return this.state[this.index + 'an'];
|
// controller state vars (`<idx>vm`, `<idx>am`, …) and pair
|
||||||
},
|
// them with watchers that copy state -> motor config. The
|
||||||
|
// controller streams those vars continuously over the WS;
|
||||||
current_max_velocity: function() {
|
// any watcher that writes them back into
|
||||||
return this.state[this.index + 'vm'];
|
// `config.motors[index]` will clobber whatever the user is
|
||||||
},
|
// typing into the form between websocket ticks. The form
|
||||||
|
// edits config directly; Save (app.js) PUTs it to the
|
||||||
current_max_soft_limit: function() {
|
// server. The server-side rotary toggle is handled by
|
||||||
return this.state[this.index + 'tm'];
|
// refetching config after the PUT, not by watching state.
|
||||||
},
|
|
||||||
|
|
||||||
current_min_soft_limit: function() {
|
|
||||||
return this.state[this.index + 'tn'];
|
|
||||||
},
|
|
||||||
current_max_accel: function() {
|
|
||||||
return this.state[this.index + 'am'];
|
|
||||||
},
|
|
||||||
current_max_jerk: function() {
|
|
||||||
return this.state[this.index + 'jm'];
|
|
||||||
},
|
|
||||||
current_step_angle: function() {
|
|
||||||
return this.state[this.index + 'sa'];
|
|
||||||
},
|
|
||||||
current_travel_per_rev: function() {
|
|
||||||
return this.state[this.index + 'tr'];
|
|
||||||
},
|
|
||||||
current_microsteps: function() {
|
|
||||||
return this.state[this.index + 'mi'];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
attached: function() {
|
|
||||||
// Sync all state values with motor config when component is ready
|
|
||||||
// This ensures UI shows correct values when component is first loaded
|
|
||||||
console.log("Syncing state to motor config for motor index ",this.index);
|
|
||||||
this.syncStateToConfig();
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
current_axis(new_value) {
|
|
||||||
const motor_axes = ["X", "Y", "Z", "A", "B", "C"]
|
|
||||||
if(motor_axes[new_value] != this.motor['axis']){
|
|
||||||
this.motor['axis'] = motor_axes[new_value];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_max_velocity(new_value) {
|
|
||||||
if(new_value != this.motor['max-velocity']) {
|
|
||||||
this.motor['max-velocity'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_max_soft_limit(new_value) {
|
|
||||||
if(new_value != this.motor['max-soft-limit']) {
|
|
||||||
this.motor['max-soft-limit'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_min_soft_limit(new_value) {
|
|
||||||
if(new_value != this.motor['min-soft-limit']) {
|
|
||||||
this.motor['min-soft-limit'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_max_accel(new_value) {
|
|
||||||
if(new_value != this.motor['max-accel']) {
|
|
||||||
this.motor['max-accel'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_max_jerk(new_value) {
|
|
||||||
if(new_value != this.motor['max-jerk']) {
|
|
||||||
this.motor['max-jerk'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_step_angle(new_value) {
|
|
||||||
if(new_value != this.motor['step-angle']) {
|
|
||||||
this.motor['step-angle'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_travel_per_rev(new_value) {
|
|
||||||
if(new_value != this.motor['travel-per-rev']) {
|
|
||||||
this.motor['travel-per-rev'] = new_value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
current_microsteps(new_value) {
|
|
||||||
if(new_value != this.motor['microsteps']) {
|
|
||||||
this.motor['microsteps'] = new_value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
@@ -210,45 +126,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return templ.hmodes.indexOf(this.motor["homing-mode"]) != -1;
|
return templ.hmodes.indexOf(this.motor["homing-mode"]) != -1;
|
||||||
},
|
|
||||||
|
|
||||||
syncStateToConfig: function() {
|
|
||||||
// Force sync all state values to motor config
|
|
||||||
// This ensures the UI reflects the current state even if changes happened while component was unmounted
|
|
||||||
|
|
||||||
if(this.state == undefined) {
|
|
||||||
console.log("State is undefined");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state[this.index + 'an'] != this.motor['axis']) {
|
|
||||||
const motor_axes = ["X", "Y", "Z", "A", "B", "C"];
|
|
||||||
this.$set('motor["axis"]', motor_axes[this.state[this.index + 'an']]);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'vm'] != this.motor['max-velocity']) {
|
|
||||||
this.$set('motor["max-velocity"]', this.state[this.index + 'vm']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'tm'] != this.motor['max-soft-limit']) {
|
|
||||||
this.$set('motor["max-soft-limit"]', this.state[this.index + 'tm']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'tn'] != this.motor['min-soft-limit']) {
|
|
||||||
this.$set('motor["min-soft-limit"]', this.state[this.index + 'tn']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'am'] != this.motor['max-accel']) {
|
|
||||||
this.$set('motor["max-accel"]', this.state[this.index + 'am']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'jm'] != this.motor['max-jerk']) {
|
|
||||||
this.$set('motor["max-jerk"]', this.state[this.index + 'jm']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'sa'] != this.motor['step-angle']) {
|
|
||||||
this.$set('motor["step-angle"]', this.state[this.index + 'sa']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'tr'] != this.motor['travel-per-rev']) {
|
|
||||||
this.$set('motor["travel-per-rev"]', this.state[this.index + 'tr']);
|
|
||||||
}
|
|
||||||
if (this.state[this.index + 'mi'] != this.motor['microsteps']) {
|
|
||||||
this.$set('motor["microsteps"]', this.state[this.index + 'mi']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ script#control-view-template(type="text/x-template")
|
|||||||
|
|
||||||
// Row 2
|
// Row 2
|
||||||
button.jbtn(@click="jog_fn(-1, 0, 0, 0)") X−
|
button.jbtn(@click="jog_fn(-1, 0, 0, 0)") X−
|
||||||
button.jbtn.ghost(@click="showMoveToZeroDialog('xy')")
|
button.jbtn(@click="showMoveToZeroDialog('xy')")
|
||||||
span.lbl XY
|
span.lbl XY
|
||||||
span Origin
|
span Origin
|
||||||
button.jbtn(@click="jog_fn(1, 0, 0, 0)") X+
|
button.jbtn(@click="jog_fn(1, 0, 0, 0)") X+
|
||||||
button.jbtn.ghost(@click="showMoveToZeroDialog('z')")
|
button.jbtn(@click="showMoveToZeroDialog('z')")
|
||||||
span.lbl Z
|
span.lbl Z
|
||||||
span Origin
|
span Origin
|
||||||
|
|
||||||
@@ -213,7 +213,14 @@ script#control-view-template(type="text/x-template")
|
|||||||
div Offset
|
div Offset
|
||||||
div State
|
div State
|
||||||
div Toolpath
|
div Toolpath
|
||||||
div(style="text-align:right") Actions
|
.actions-cell
|
||||||
|
// Master Home All. Each row's Actions cell has a per-axis
|
||||||
|
// home button; this header-level button homes every
|
||||||
|
// enabled axis (legacy Onefinity behavior). Auto-includes
|
||||||
|
// the W axis when it is enabled.
|
||||||
|
button.icon-btn(:disabled="!is_idle",
|
||||||
|
title="Home all axes.", @click="home_all()")
|
||||||
|
.fa.fa-house-chimney
|
||||||
|
|
||||||
// Per-axis rows — keep unit-value + bindings from axis-vars
|
// Per-axis rows — keep unit-value + bindings from axis-vars
|
||||||
each axis in 'xyzabc'
|
each axis in 'xyzabc'
|
||||||
|
|||||||
@@ -41,12 +41,17 @@ DEFAULTS = {
|
|||||||
'home_dir': '-', # which direction is "toward limit" (host's view)
|
'home_dir': '-', # which direction is "toward limit" (host's view)
|
||||||
'home_position_mm': 0.0, # mm value to assign at home
|
'home_position_mm': 0.0, # mm value to assign at home
|
||||||
# ESP-side homing rates (steps/sec). Pushed via HOMECFG on connect.
|
# ESP-side homing rates (steps/sec). Pushed via HOMECFG on connect.
|
||||||
'home_fast_sps': 4000,
|
# Speeds tuned for a typical 25 steps/mm aux drive (so 1 step =
|
||||||
'home_slow_sps': 400,
|
# 0.04 mm). With the limit-aware ESP firmware these values give
|
||||||
'home_backoff_steps': 200,
|
# a brisk seek (100 mm/s), enough backoff to clear the switch
|
||||||
|
# hysteresis (16 mm), and a slow re-engage (10 mm/s) that's
|
||||||
|
# accurate without being painfully slow on a longer axis.
|
||||||
|
'home_fast_sps': 2500, # ≈ 100 mm/s @ 25 steps/mm
|
||||||
|
'home_slow_sps': 250, # ≈ 10 mm/s
|
||||||
|
'home_backoff_steps': 400, # ≈ 16 mm
|
||||||
'home_maxtravel_steps': 200000,
|
'home_maxtravel_steps': 200000,
|
||||||
'step_max_sps': 4000,
|
'step_max_sps': 4000, # ≈ 160 mm/s normal-move cap
|
||||||
'step_accel_sps2': 16000,
|
'step_accel_sps2': 12000,
|
||||||
'step_start_sps': 200,
|
'step_start_sps': 200,
|
||||||
'limit_low': True,
|
'limit_low': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1410,6 +1410,15 @@ tt.save
|
|||||||
letter-spacing 0.1em
|
letter-spacing 0.1em
|
||||||
color $muted-2
|
color $muted-2
|
||||||
|
|
||||||
|
// Master Home All sits in the header's Actions cell. Make it
|
||||||
|
// visually subordinate to the per-axis home buttons in the rows
|
||||||
|
// below — same family, smaller scale.
|
||||||
|
.icon-btn
|
||||||
|
width 44px
|
||||||
|
height 44px
|
||||||
|
font-size 0.95rem
|
||||||
|
border-radius 9px
|
||||||
|
|
||||||
.control-page .dro-row
|
.control-page .dro-row
|
||||||
border-bottom 1px solid $line-soft
|
border-bottom 1px solid $line-soft
|
||||||
flex 1
|
flex 1
|
||||||
|
|||||||
@@ -31,10 +31,19 @@
|
|||||||
let cfg: AuxConfig | null = null;
|
let cfg: AuxConfig | null = null;
|
||||||
let status: { enabled: boolean; present: boolean; homed: boolean; pos_mm: number } | null = null;
|
let status: { enabled: boolean; present: boolean; homed: boolean; pos_mm: number } | null = null;
|
||||||
let busy = false;
|
let busy = false;
|
||||||
let saveMessage = "";
|
|
||||||
|
// Listen for the global "save-all" event the Vue root dispatches
|
||||||
|
// when the user clicks the master Save button. We persist our
|
||||||
|
// current cfg the same way the in-form button used to. This way
|
||||||
|
// the user only ever needs one Save button.
|
||||||
|
function onGlobalSave() {
|
||||||
|
save().catch(e => console.error("aux save failed:", e));
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await refresh();
|
await refresh();
|
||||||
|
window.addEventListener("onefin:save-all", onGlobalSave);
|
||||||
|
return () => window.removeEventListener("onefin:save-all", onGlobalSave);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
@@ -49,19 +58,28 @@
|
|||||||
async function save() {
|
async function save() {
|
||||||
if (!cfg) return;
|
if (!cfg) return;
|
||||||
busy = true;
|
busy = true;
|
||||||
saveMessage = "";
|
|
||||||
try {
|
try {
|
||||||
await api.PUT("aux/config/save", cfg);
|
await api.PUT("aux/config/save", cfg);
|
||||||
saveMessage = "Saved.";
|
|
||||||
await refresh();
|
await refresh();
|
||||||
setTimeout(() => (saveMessage = ""), 3000);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to save aux config:", e);
|
console.error("Failed to save aux config:", e);
|
||||||
saveMessage = "Save failed - see console.";
|
throw e;
|
||||||
} finally {
|
} finally {
|
||||||
busy = false;
|
busy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the root config as modified whenever a W axis field is
|
||||||
|
// edited, so the master Save button highlights and the user knows
|
||||||
|
// there are unsaved changes.
|
||||||
|
function markDirty() {
|
||||||
|
try {
|
||||||
|
const root = (window as any).$root || (window as any).Vue?.root;
|
||||||
|
if (root && "modified" in root) root.modified = true;
|
||||||
|
} catch (_e) {}
|
||||||
|
// Also dispatch a generic event the Vue root listens for.
|
||||||
|
window.dispatchEvent(new CustomEvent("onefin:dirty"));
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-axis-settings">
|
<div class="w-axis-settings">
|
||||||
@@ -85,7 +103,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pure-form pure-form-aligned">
|
<div class="pure-form pure-form-aligned" on:input={markDirty} on:change={markDirty}>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="pure-control-group" title="Enable the auxcnc W axis. Edit aux.json to toggle.">
|
<div class="pure-control-group" title="Enable the auxcnc W axis. Edit aux.json to toggle.">
|
||||||
<label for="enabled">enabled</label>
|
<label for="enabled">enabled</label>
|
||||||
@@ -206,25 +224,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="actions">
|
|
||||||
<Button
|
|
||||||
touch
|
|
||||||
variant="raised"
|
|
||||||
on:click={save}
|
|
||||||
disabled={busy}
|
|
||||||
>
|
|
||||||
<Label>Save W Axis Settings</Label>
|
|
||||||
</Button>
|
|
||||||
{#if saveMessage}
|
|
||||||
<span class="save-msg">{saveMessage}</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tip">
|
<div class="tip">
|
||||||
Changes are written to aux.json. Homing rates and the
|
Changes are written to aux.json when you click the
|
||||||
limit polarity are pushed to the ESP immediately; any
|
master <strong>Save</strong> button at the bottom of the
|
||||||
running motion is unaffected. Re-home the W axis after
|
settings rail. Homing rates and the limit polarity are
|
||||||
changing direction, sign, or step settings.
|
pushed to the ESP immediately; any running motion is
|
||||||
|
unaffected. Re-home the W axis after changing direction,
|
||||||
|
sign, or step settings.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user