New probing experience complete.
This commit is contained in:
@@ -11,13 +11,6 @@ script#settings-view-template(type="text/x-template")
|
|||||||
option(value="METRIC") METRIC
|
option(value="METRIC") METRIC
|
||||||
option(value="IMPERIAL") IMPERIAL
|
option(value="IMPERIAL") IMPERIAL
|
||||||
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
h2 Probing safety prompts
|
|
||||||
templated-input(name="probing-prompts",
|
|
||||||
:model.sync="config.settings['probing-prompts']",
|
|
||||||
:template="template.settings['probing-prompts']")
|
|
||||||
|
|
||||||
fieldset
|
fieldset
|
||||||
h2 Probe Dimensions
|
h2 Probe Dimensions
|
||||||
templated-input(v-for="templ in template.probe", :name="$key",
|
templated-input(v-for="templ in template.probe", :name="$key",
|
||||||
|
|||||||
@@ -22,11 +22,6 @@
|
|||||||
"max": 100000000,
|
"max": 100000000,
|
||||||
"unit": "mm/min²",
|
"unit": "mm/min²",
|
||||||
"default": 200000
|
"default": 200000
|
||||||
},
|
|
||||||
"probing-prompts": {
|
|
||||||
"help": "Enable or disable safety prompts during and after probing",
|
|
||||||
"type": "bool",
|
|
||||||
"default": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
93
src/svelte-components/src/components/DimensionInput.svelte
Normal file
93
src/svelte-components/src/components/DimensionInput.svelte
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import TextField from "@smui/textfield";
|
||||||
|
import Select, { Option } from "@smui/select";
|
||||||
|
import type { MenuComponentDev } from "@smui/menu";
|
||||||
|
import Menu from "@smui/menu";
|
||||||
|
import List, { Item, Text } from "@smui/list";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { set_input_value } from "svelte/internal";
|
||||||
|
|
||||||
|
let menu: MenuComponentDev;
|
||||||
|
|
||||||
|
type Option = {
|
||||||
|
value: number;
|
||||||
|
metric: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export let label: string;
|
||||||
|
export let value: number;
|
||||||
|
export let metric: boolean;
|
||||||
|
export let options: Option[];
|
||||||
|
|
||||||
|
let textValue = "";
|
||||||
|
|
||||||
|
$: if (textValue) {
|
||||||
|
value = Number(textValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
textValue = value?.toString() || "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function onOptionSelected(option: Option) {
|
||||||
|
textValue = option.value.toString();
|
||||||
|
metric = option.metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterKeys(event) {
|
||||||
|
const input = event.target;
|
||||||
|
|
||||||
|
if (input.value.match(/[^0-9.]/)) {
|
||||||
|
input.value = input.value.replace(/[^0-9.]/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.value.match(/\.[^.]*\./)) {
|
||||||
|
input.value = input.value.replace(/(\.[^.]*)\./g, "$1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="value-and-unit">
|
||||||
|
<TextField
|
||||||
|
{label}
|
||||||
|
on:keypress={filterKeys}
|
||||||
|
on:keyup={filterKeys}
|
||||||
|
bind:value={textValue}
|
||||||
|
on:click={() => menu.setOpen(true)}
|
||||||
|
/>
|
||||||
|
<Select bind:value={metric}>
|
||||||
|
<Option value={true}>mm</Option>
|
||||||
|
<Option value={false}>in</Option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<Menu bind:this={menu} anchorCorner="BOTTOM_LEFT">
|
||||||
|
<List>
|
||||||
|
{#each options as option}
|
||||||
|
<Item on:SMUI:action={() => onOptionSelected(option)}>
|
||||||
|
<Text>
|
||||||
|
{option.value}
|
||||||
|
{option.metric ? "mm" : "in"}
|
||||||
|
</Text>
|
||||||
|
</Item>
|
||||||
|
{/each}
|
||||||
|
</List>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.value-and-unit {
|
||||||
|
display: flex;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.mdc-select {
|
||||||
|
max-width: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smui-select--standard .mdc-select__dropdown-icon {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,18 +1,22 @@
|
|||||||
<script type="ts" context="module">
|
<script type="ts" context="module">
|
||||||
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
|
||||||
import Button, { Label } from "@smui/button";
|
|
||||||
import { get, writable, type Writable } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
import { Config } from "$lib/ConfigStore";
|
|
||||||
import { waitForChange } from "$lib/StoreHelpers";
|
|
||||||
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
|
||||||
|
|
||||||
type Step =
|
type Step =
|
||||||
| "None"
|
| "None"
|
||||||
| "TestingProbe"
|
| "CheckProbe"
|
||||||
| "GetToolDiameter"
|
| "BitDimensions"
|
||||||
| "Probing"
|
| "PlaceProbeBlock"
|
||||||
| "ProbingFailed"
|
| "Probe"
|
||||||
| "ProbingComplete";
|
| "Done";
|
||||||
|
|
||||||
|
const stepLabels: Record<Step, string> = {
|
||||||
|
None: "",
|
||||||
|
CheckProbe: "Check probe",
|
||||||
|
BitDimensions: "Bit dimensions",
|
||||||
|
PlaceProbeBlock: "Place probe block",
|
||||||
|
Probe: "Probe",
|
||||||
|
Done: "Done",
|
||||||
|
};
|
||||||
|
|
||||||
const cancelled = writable(false);
|
const cancelled = writable(false);
|
||||||
const probingActive = writable(false);
|
const probingActive = writable(false);
|
||||||
@@ -51,50 +55,86 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="ts">
|
<script type="ts">
|
||||||
|
import DimensionInput from "$components/DimensionInput.svelte";
|
||||||
|
import Dialog, { Title, Content, Actions } from "@smui/dialog";
|
||||||
|
import Button, { Label } from "@smui/button";
|
||||||
|
import { waitForChange } from "$lib/StoreHelpers";
|
||||||
|
import { ControllerMethods } from "$lib/RegisterControllerMethods";
|
||||||
|
import { Config } from "$lib/ConfigStore";
|
||||||
|
|
||||||
|
const cutterDiameterOptions = [
|
||||||
|
{ value: 0.5, metric: false },
|
||||||
|
{ value: 10, metric: true },
|
||||||
|
{ value: 0.25, metric: false },
|
||||||
|
{ value: 6, metric: true },
|
||||||
|
{ value: 0.125, metric: false },
|
||||||
|
{ value: 3, metric: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const cutterLengthOptions = [
|
||||||
|
{ value: 1, metric: false },
|
||||||
|
{ value: 20, metric: true },
|
||||||
|
{ value: 0.5, metric: false },
|
||||||
|
{ value: 10, metric: true },
|
||||||
|
{ value: 0.25, metric: false },
|
||||||
|
{ value: 6, metric: true },
|
||||||
|
];
|
||||||
|
|
||||||
export let open;
|
export let open;
|
||||||
export let probeType: "xyz" | "z";
|
export let probeType: "xyz" | "z";
|
||||||
let step: Step = "None";
|
let currentStep: Step = "None";
|
||||||
let toolDiameter;
|
let cutterDiameter;
|
||||||
|
let cutterLength;
|
||||||
let showCancelButton = true;
|
let showCancelButton = true;
|
||||||
|
let steps: Array<Step> = [];
|
||||||
let nextButton = {
|
let nextButton = {
|
||||||
label: "Next",
|
label: "Next",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
allowClose: false,
|
allowClose: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
$: showPrompts = $Config.settings?.["probing-prompts"];
|
$: metric = $Config.settings?.units === "METRIC";
|
||||||
|
|
||||||
$: if (open) {
|
$: if (open) {
|
||||||
toolDiameter = "";
|
cutterDiameter = null;
|
||||||
|
cutterLength = null;
|
||||||
|
|
||||||
// Svelte appears not to like it when you invoke
|
// Svelte appears not to like it when you invoke
|
||||||
// an async function from a reactive statement, so we
|
// an async function from a reactive statement, so we
|
||||||
// use requestAnimationFrame to call begin at a later moment.
|
// use requestAnimationFrame to call 'begin' at a later moment.
|
||||||
requestAnimationFrame(begin);
|
requestAnimationFrame(begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if (cutterDiameter && cutterLength) {
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSkippedSteps(steps: Step[]): Step[] {
|
||||||
|
return steps.filter((x) => x);
|
||||||
|
}
|
||||||
|
|
||||||
async function begin() {
|
async function begin() {
|
||||||
try {
|
try {
|
||||||
$probingActive = true;
|
$probingActive = true;
|
||||||
assertValidProbeType();
|
assertValidProbeType();
|
||||||
|
|
||||||
if (showPrompts) {
|
steps = removeSkippedSteps([
|
||||||
await stepCompleted("TestingProbe", probeContacted);
|
"CheckProbe",
|
||||||
}
|
probeType === "xyz" ? "BitDimensions" : undefined,
|
||||||
|
"PlaceProbeBlock",
|
||||||
|
"Probe",
|
||||||
|
"Done",
|
||||||
|
]);
|
||||||
|
|
||||||
|
await stepCompleted("CheckProbe", probeContacted);
|
||||||
|
|
||||||
if (probeType === "xyz") {
|
if (probeType === "xyz") {
|
||||||
await stepCompleted("GetToolDiameter", userAcknowledged);
|
await stepCompleted("BitDimensions", userAcknowledged);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
await stepCompleted("PlaceProbeBlock", userAcknowledged);
|
||||||
await stepCompleted("Probing", probingComplete, probingFailed);
|
await stepCompleted("Probe", probingComplete, probingFailed);
|
||||||
|
await stepCompleted("Done", userAcknowledged);
|
||||||
if ($probingFailed) {
|
|
||||||
await stepCompleted("ProbingFailed", userAcknowledged);
|
|
||||||
}
|
|
||||||
} while (!$probingComplete);
|
|
||||||
|
|
||||||
await stepCompleted("ProbingComplete", userAcknowledged);
|
|
||||||
|
|
||||||
if (probeType === "xyz") {
|
if (probeType === "xyz") {
|
||||||
ControllerMethods.goto_zero(1, 1, 0, 0);
|
ControllerMethods.goto_zero(1, 1, 0, 0);
|
||||||
@@ -105,7 +145,7 @@
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$probingActive = false;
|
$probingActive = false;
|
||||||
step = "None";
|
currentStep = "None";
|
||||||
|
|
||||||
if ($probingStarted) {
|
if ($probingStarted) {
|
||||||
ControllerMethods.stop();
|
ControllerMethods.stop();
|
||||||
@@ -130,12 +170,12 @@
|
|||||||
nextStep: Step,
|
nextStep: Step,
|
||||||
...writables: Array<Writable<any>>
|
...writables: Array<Writable<any>>
|
||||||
) {
|
) {
|
||||||
step = nextStep;
|
currentStep = nextStep;
|
||||||
|
|
||||||
clearFlags();
|
clearFlags();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
|
|
||||||
if (step === "Probing") {
|
if (currentStep === "Probe") {
|
||||||
executeProbe();
|
executeProbe();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,13 +207,24 @@
|
|||||||
allowClose: false,
|
allowClose: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (step) {
|
switch (currentStep) {
|
||||||
case "TestingProbe":
|
case "CheckProbe":
|
||||||
case "Probing":
|
case "Probe":
|
||||||
nextButton.disabled = true;
|
nextButton.disabled = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ProbingComplete":
|
case "BitDimensions":
|
||||||
|
nextButton.disabled = !(
|
||||||
|
cutterDiameter !== null &&
|
||||||
|
cutterDiameter !== 0 &&
|
||||||
|
isFinite(cutterDiameter) &&
|
||||||
|
cutterLength !== null &&
|
||||||
|
cutterLength !== 0 &&
|
||||||
|
isFinite(cutterLength)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Done":
|
||||||
showCancelButton = false;
|
showCancelButton = false;
|
||||||
nextButton = {
|
nextButton = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@@ -192,8 +243,8 @@
|
|||||||
const fastSeek = $Config.probe["probe-fast-seek"];
|
const fastSeek = $Config.probe["probe-fast-seek"];
|
||||||
|
|
||||||
const zLift = 1;
|
const zLift = 1;
|
||||||
const xOffset = probeBlockWidth + toolDiameter / 2.0;
|
const xOffset = probeBlockWidth + cutterDiameter / 2.0;
|
||||||
const yOffset = probeBlockLength + toolDiameter / 2.0;
|
const yOffset = probeBlockLength + cutterDiameter / 2.0;
|
||||||
const zOffset = probeBlockHeight;
|
const zOffset = probeBlockHeight;
|
||||||
|
|
||||||
if (probeType === "z") {
|
if (probeType === "z") {
|
||||||
@@ -213,9 +264,9 @@
|
|||||||
} else {
|
} else {
|
||||||
// After probing Z, we want to drop the bit down:
|
// After probing Z, we want to drop the bit down:
|
||||||
// Ideally, 12.7mm/0.5in
|
// Ideally, 12.7mm/0.5in
|
||||||
// And we don't want to be more than 75% down on the probe block
|
// And we don't want to be more than 90% down on the probe block
|
||||||
// Also, add zlift to compensate for the fact that we lift after probing Z
|
// Also, add zlift to compensate for the fact that we lift after probing Z
|
||||||
const plunge = Math.min(12.7, zOffset * 0.75) + zLift;
|
const plunge = Math.min(cutterLength, zOffset * 0.9) + zLift;
|
||||||
|
|
||||||
ControllerMethods.send(`
|
ControllerMethods.send(`
|
||||||
G21
|
G21
|
||||||
@@ -253,38 +304,71 @@
|
|||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
bind:open
|
bind:open
|
||||||
|
class="probe-dialog"
|
||||||
scrimClickAction=""
|
scrimClickAction=""
|
||||||
aria-labelledby="simple-title"
|
aria-labelledby="simple-title"
|
||||||
aria-describedby="simple-content"
|
aria-describedby="simple-content"
|
||||||
|
surface$style="width: 700px; height: 400px; max-width: calc(100vw - 32px); overflow: visible;"
|
||||||
>
|
>
|
||||||
<Title id="simple-title">Probe {probeType}</Title>
|
<Title id="simple-title">Probing {probeType?.toUpperCase()}</Title>
|
||||||
|
|
||||||
<Content id="simple-content">
|
<Content id="simple-content" style="overflow: visible;">
|
||||||
{#if step === "TestingProbe"}
|
<div class="steps">
|
||||||
<p>Attach the probe magnet to the collet.</p>
|
<p><b>Step {steps.indexOf(currentStep) + 1} of {steps.length}</b></p>
|
||||||
<p>Touch the probe block to the bit.</p>
|
<ul>
|
||||||
|
{#each steps as step}
|
||||||
{#if $probeContacted}
|
<li class:active={currentStep === step}>{stepLabels[step]}</li>
|
||||||
<p>Probe contact detected!</p>
|
{/each}
|
||||||
{:else}
|
</ul>
|
||||||
<p>Waiting for probe contact...</p>
|
</div>
|
||||||
{/if}
|
<div class="current-step">
|
||||||
{:else if step === "GetToolDiameter"}
|
|
||||||
<label for="tool-diameter">Tool Diameter (mm)</label>
|
|
||||||
<input id="tool-diameter" bind:value={toolDiameter} />
|
|
||||||
{:else if step === "Probing"}
|
|
||||||
<p>Probing in progress...</p>
|
|
||||||
{:else if step === "ProbingFailed"}
|
|
||||||
<p>Could not find the probe block during probing!</p>
|
|
||||||
<p>
|
<p>
|
||||||
Make sure the tip of the bit is about 1/4" (6mm) above the probe block,
|
{#if currentStep === "CheckProbe"}
|
||||||
and try again.
|
Attach the probe magnet to the collet, then touch the probe block to
|
||||||
|
the bit.
|
||||||
|
{:else if currentStep === "BitDimensions"}
|
||||||
|
<DimensionInput
|
||||||
|
label="Cutter diameter"
|
||||||
|
options={cutterDiameterOptions}
|
||||||
|
bind:value={cutterDiameter}
|
||||||
|
{metric}
|
||||||
|
/>
|
||||||
|
<DimensionInput
|
||||||
|
label="Cutter length"
|
||||||
|
options={cutterLengthOptions}
|
||||||
|
bind:value={cutterLength}
|
||||||
|
{metric}
|
||||||
|
/>
|
||||||
|
{:else if currentStep === "PlaceProbeBlock"}
|
||||||
|
{#if probeType === "xyz"}
|
||||||
|
Place the probe block face up, on the lower-left corner of your
|
||||||
|
workpiece.
|
||||||
|
{:else}
|
||||||
|
Place the probe block face down, with the bit above the recess.
|
||||||
|
{/if}
|
||||||
|
{:else if currentStep === "Probe"}
|
||||||
|
Probing in progress...
|
||||||
|
{:else if currentStep === "Done"}
|
||||||
|
{#if $probingFailed}
|
||||||
|
Could not find the probe block during probing!
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Make sure the tip of the bit is less than {metric
|
||||||
|
? "25mm"
|
||||||
|
: "1 in"} above the probe block, and try again.
|
||||||
|
</p>
|
||||||
|
{:else}
|
||||||
|
Don't forget to put away the probe!
|
||||||
|
|
||||||
|
{#if probeType === "xyz"}
|
||||||
|
<p>The machine will now move to the XY origin.</p>
|
||||||
|
|
||||||
|
<p>Watch your hands!</p>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
{:else if step === "ProbingComplete"}
|
</div>
|
||||||
<p>Don't forget to put away the probe!</p>
|
|
||||||
<p>The machine will now move to the XY origin.</p>
|
|
||||||
<p>Watch your hands!</p>
|
|
||||||
{/if}
|
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<Actions>
|
<Actions>
|
||||||
@@ -305,3 +389,87 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Actions>
|
</Actions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
$primary: #0078e7;
|
||||||
|
$very-dark: #555;
|
||||||
|
$text: #777;
|
||||||
|
$grey: #bbb;
|
||||||
|
$light: #ddd;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.mdc-dialog__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-step {
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
.mdc-text-field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps {
|
||||||
|
margin-right: 50px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0 auto;
|
||||||
|
list-style-type: none;
|
||||||
|
counter-reset: steps;
|
||||||
|
margin: 0;
|
||||||
|
font-family: sans-serif;
|
||||||
|
padding-inline-start: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
padding: 0 0 12px 30px;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: $text;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 0.5px;
|
||||||
|
content: "";
|
||||||
|
border: 2px solid $text;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
height: 11px;
|
||||||
|
width: 11px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 12px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
top: 22px;
|
||||||
|
bottom: 0;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
border-left: 2px solid $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type:before {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $primary;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
border: 3px solid $primary;
|
||||||
|
top: 2.5px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -28,4 +28,15 @@
|
|||||||
color: #777;
|
color: #777;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
input[type="number"] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user