New probing experience complete.

This commit is contained in:
David Carley
2022-07-12 18:08:20 -07:00
parent dd34b1e988
commit c710d124a0
5 changed files with 336 additions and 76 deletions

View File

@@ -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",

View File

@@ -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
} }
}, },

View 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>

View File

@@ -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>

View File

@@ -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;
}
} }