Add bg park postitions. Closes #18

This commit is contained in:
osiu97
2026-07-08 22:03:59 +02:00
parent 4924e1b4e3
commit 40ff0ca913
5 changed files with 99 additions and 19 deletions
@@ -1,5 +1,6 @@
{
"hasAlphabet": true,
"parkPosition": { "x": 0, "y": 80 },
"bounds": { "xMin": -150, "xMax": 150, "yMin": -30, "yMax": 145 },
"spots": [
{ "id": "YES", "label": "YES", "x": -70, "y": 90 },
+16 -4
View File
@@ -46,6 +46,7 @@ This file tells the web UI where your letters/targets are located in **physical
```json
{
"hasAlphabet": true,
"parkPosition": { "x": 0, "y": 80 },
"bounds": {
"xMin": -150,
"xMax": 150,
@@ -60,9 +61,20 @@ This file tells the web UI where your letters/targets are located in **physical
}
```
- **hasAlphabet**: (Optional, boolean) If `true`, this background is used for the "Input Text" feature. The letters in `spots` are used to spell out typed input.
- **parkPosition**: (Optional, object) Defines a background-specific "Park Position" or resting spot where the arm can go when not actively in use. If omitted, defaults to `{ "x": 0, "y": 0 }`.
- **bounds**: Defines the physical bounding box (in mm) that your background image represents. This automatically adjusts the UI's aspect ratio and coordinate mapping!
- **spots**: Array of target objects.
- **id**: Unique identifier for the dropdown list.
- **label**: Human-readable text shown on the UI.
- **x**: The X coordinate in physical mm (`-150` to `+150`).
- **y**: The Y coordinate in physical mm (`-30` to `+145`).
- **id**: Unique identifier for the dropdown list.
- **label**: Human-readable text shown on the UI.
- **x**: The X coordinate in physical mm (`-150` to `+150`).
- **y**: The Y coordinate in physical mm (`-30` to `+145`).
## 5. Excluded Zones (No-Go Zones)
When defining spots or the `parkPosition`, you **must avoid** the central mechanism housing. The SCARA arm will reject commands that enter this region to prevent mechanical collisions.
The exact exclusion box (the "No-Go Zone") is:
- **X Range:** `-30` mm to `+30` mm
- **Y Range:** `-10` mm to `+40` mm
Make sure that your `parkPosition` and all clickable spots lie outside this rectangle.
+24 -5
View File
@@ -96,9 +96,14 @@ function buildHTML() {
<div id="homing-banner" class="homing-banner ${isHomed ? 'homed' : 'not-homed'}">
${isHomed ? '✓ HOMED' : '⚠ NOT HOMED! Movement Locked.'}
</div>
<button id="btn-force-home" class="btn btn-danger btn-full" style="padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<div style="display:flex; gap: 8px;">
<button id="btn-force-home" class="btn btn-danger" style="flex:1; padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<button id="btn-park" class="btn btn-secondary" style="flex:1; padding: 10px; font-weight:bold;">
GO TO PARK
</button>
</div>
</div>
<!-- Controls Card -->
@@ -191,12 +196,21 @@ async function loadSpots() {
try {
const res = await fetch(`web/assets/backgrounds/${currentBg}/spots.json?v=${Date.now()}`);
const data = await res.json();
let parsedSpots = [];
let parkPosition = { x: 0, y: 0 };
if (Array.isArray(data)) {
spots = data;
parsedSpots = data;
} else {
spots = data.spots || [];
parsedSpots = data.spots || [];
if (data.bounds) bounds = data.bounds;
if (data.parkPosition) parkPosition = data.parkPosition;
}
if (!parsedSpots.find(s => s.id === 'PARK')) {
parsedSpots.push({ id: 'PARK', label: 'Park Position', x: parkPosition.x, y: parkPosition.y });
}
spots = parsedSpots;
document.getElementById('bg-image').src = `web/assets/backgrounds/${currentBg}/bg.svg?v=${Date.now()}`;
renderSpots();
} catch(e) {
@@ -335,6 +349,11 @@ export default {
}
});
document.getElementById('btn-park').addEventListener('click', () => {
const parkSpot = spots.find(s => s.id === 'PARK');
if (parkSpot) executeMove(parkSpot);
});
// ── List Selection ────────────────────────────────────────
const listEl = document.getElementById('spot-list');
const goBtn = document.getElementById('btn-go');
+24 -5
View File
@@ -112,9 +112,14 @@ function buildHTML() {
<div id="homing-banner" class="homing-banner ${isHomed ? 'homed' : 'not-homed'}">
${isHomed ? '✓ HOMED' : '⚠ NOT HOMED! Movement Locked.'}
</div>
<button id="btn-force-home" class="btn btn-danger btn-full" style="padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<div style="display:flex; gap: 8px;">
<button id="btn-force-home" class="btn btn-danger" style="flex:1; padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<button id="btn-park" class="btn btn-secondary" style="flex:1; padding: 10px; font-weight:bold;">
GO TO PARK
</button>
</div>
</div>
<!-- Controls Card -->
@@ -245,12 +250,21 @@ async function loadSpots() {
UI.log(`Background '${currentBg}' does not support an alphabet.`, 'warn');
}
let parsedSpots = [];
let parkPosition = { x: 0, y: 0 };
if (Array.isArray(data)) {
spots = data;
parsedSpots = data;
} else {
spots = data.spots || [];
parsedSpots = data.spots || [];
if (data.bounds) bounds = data.bounds;
if (data.parkPosition) parkPosition = data.parkPosition;
}
if (!parsedSpots.find(s => s.id === 'PARK')) {
parsedSpots.push({ id: 'PARK', label: 'Park Position', x: parkPosition.x, y: parkPosition.y });
}
spots = parsedSpots;
document.getElementById('bg-image').src = `web/assets/backgrounds/${currentBg}/bg.svg?v=${Date.now()}`;
@@ -404,6 +418,11 @@ export default {
}
});
document.getElementById('btn-park').addEventListener('click', () => {
const parkSpot = spots.find(s => s.id === 'PARK');
if (parkSpot) executeMove(parkSpot);
});
// ── Spelling Logic ────────────────────────────────────────
const btnSpell = document.getElementById('btn-spell');
const btnStop = document.getElementById('btn-stop');
+34 -5
View File
@@ -3,6 +3,7 @@ import UI from '../ui.js';
import IK from '../kinematics.js';
import Settings from '../settings.js';
import SequenceRunner from '../sequence-runner.js';
import Motion from '../motion.js';
let eventCleanup = [];
let isHomed = false;
@@ -244,9 +245,14 @@ function buildHTML() {
<div id="homing-banner" class="homing-banner ${isHomed ? 'homed' : 'not-homed'}">
${isHomed ? '✓ HOMED' : '⚠ NOT HOMED! Movement Locked.'}
</div>
<button id="btn-force-home" class="btn btn-danger btn-full" style="padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<div style="display:flex; gap: 8px;">
<button id="btn-force-home" class="btn btn-danger" style="flex:1; padding: 10px; font-weight:bold;">
${isHomed ? 'FORCE HOME ALL' : 'HOME ALL MOTORS'}
</button>
<button id="btn-park" class="btn btn-secondary" style="flex:1; padding: 10px; font-weight:bold;">
GO TO PARK
</button>
</div>
</div>
<!-- Settings Card -->
@@ -409,14 +415,23 @@ async function loadSpots() {
try {
const res = await fetch(`web/assets/backgrounds/${currentBg}/spots.json?v=${Date.now()}`);
const data = await res.json();
let parsedSpots = [];
let parkPosition = { x: 0, y: 0 };
if (Array.isArray(data)) {
spots = data;
parsedSpots = data;
hasAlphabet = false;
} else {
spots = data.spots || [];
parsedSpots = data.spots || [];
if (data.bounds) bounds = data.bounds;
if (data.parkPosition) parkPosition = data.parkPosition;
hasAlphabet = !!data.hasAlphabet;
}
if (!parsedSpots.find(s => s.id === 'PARK')) {
parsedSpots.push({ id: 'PARK', label: 'Park Position', x: parkPosition.x, y: parkPosition.y });
}
spots = parsedSpots;
document.getElementById('text-input-row').style.display = hasAlphabet ? 'grid' : 'none';
document.getElementById('text-input-divider').style.display = hasAlphabet ? 'block' : 'none';
@@ -723,6 +738,20 @@ export default {
}
});
document.getElementById('btn-park').addEventListener('click', async () => {
const parkSpot = spots.find(s => s.id === 'PARK');
if (parkSpot) {
if (!isHomed) {
UI.log('Cannot move: System is not homed!', 'error');
return;
}
const modeEl = document.getElementById('seq-mode-select');
const mode = modeEl ? modeEl.value : 'direct';
UI.log(`Moving to Park Position (${parkSpot.x}, ${parkSpot.y})`, 'info');
await Motion.goto(parkSpot.x, parkSpot.y, mode);
}
});
// ── Sync Steps from BLE ───────────────────────────────────
const onBLEStatus = (e) => {
const msg = e.detail;