This commit is contained in:
PROFERIS - Mi³osz Stocki
2026-07-08 16:12:27 +02:00
parent 9cd29cd5d4
commit ab5dc7b678
+13 -49
View File
@@ -139,65 +139,29 @@ function solve(x, y) {
if (t < 1e-6) return { theta1: 0, theta2: 0, reachable: false }; if (t < 1e-6) return { theta1: 0, theta2: 0, reachable: false };
const cosW2 = (l2 * l2 - t * t - l1 * l1) / (-2 * l1 * t); const cosW2 = (l2 * l2 - t * t - l1 * l1) / (-2 * l1 * t);
if (cosW2 < -1 || cosW2 > 1) return { theta1: 0, theta2: 0, reachable: false }; if (cosW2 < -1 || cosW2 > 1) return { theta1: 0, theta2: 0, reachable: false };
const r = Math.atan2(y, xpd); let r = Math.atan2(y, xpd);
// Fix atan2 wrap-around: shift the cut from -180° (which crosses our left workspace)
// to -90° (straight down, which is safely outside our workspace).
if (r < -Math.PI / 2) r += 2 * Math.PI;
const w2 = Math.acos(cosW2); const w2 = Math.acos(cosW2);
const t1A = r + w2; // Outward const theta1 = r + w2; // Outward elbow
const t1B = r - w2; // Inward
// ── Motor 2 (Right, pivot at +d2, 0 = +12.9 mm) ────────────── // ── Motor 2 (Right, pivot at +d2, 0 = +12.9 mm) ──────────────
// xmd = x - d2 is the X component of (target M2_pivot).
const xmd = x - d2; const xmd = x - d2;
const s = Math.sqrt(xmd * xmd + y * y); const s = Math.sqrt(xmd * xmd + y * y);
if (s < 1e-6) return { theta1: 0, theta2: 0, reachable: false }; if (s < 1e-6) return { theta1: 0, theta2: 0, reachable: false };
const cosW1 = (l2 * l2 - s * s - l1 * l1) / (-2 * l1 * s); const cosW1 = (l2 * l2 - s * s - l1 * l1) / (-2 * l1 * s);
if (cosW1 < -1 || cosW1 > 1) return { theta1: 0, theta2: 0, reachable: false }; if (cosW1 < -1 || cosW1 > 1) return { theta1: 0, theta2: 0, reachable: false };
const q = Math.atan2(y, xmd);
let q = Math.atan2(y, xmd);
// Fix atan2 wrap-around for the right motor as well
if (q < -Math.PI / 2) q += 2 * Math.PI;
const w1 = Math.acos(cosW1); const w1 = Math.acos(cosW1);
const t2A = q - w1; // Outward const theta2 = q - w1; // Outward elbow
const t2B = q + w1; // Inward
// Evaluate all 4 possible elbow configurations return { theta1, theta2, reachable: true };
const combos = [
{ t1: t1A, t2: t2A }, // Out/Out
{ t1: t1B, t2: t2A }, // In/Out
{ t1: t1A, t2: t2B }, // Out/In
{ t1: t1B, t2: t2B }, // In/In
];
let bestCombo = null;
for (const c of combos) {
if (armsCrossed(c.t1, c.t2)) continue; // Rejected by physical constraints (housing/bottom)
// Calculate distance between elbows to avoid physical joint collision
const e1x = -d2 + l1 * Math.cos(c.t1);
const e1y = l1 * Math.sin(c.t1);
const e2x = +d2 + l1 * Math.cos(c.t2);
const e2y = l1 * Math.sin(c.t2);
const edist = Math.sqrt((e2x - e1x)**2 + (e2y - e1y)**2);
// If elbows are absurdly close (< 10mm), the physical joints will collide
// and the FK will glitch (since intersections become highly sensitive).
if (edist < 10) continue;
// We prefer the combination where elbows point UP (y > 0)
// Score based on how far above the bottom housing they are
c.score = e1y + e2y;
// Penalize configurations that point downwards heavily
if (e1y < 0) c.score -= 1000;
if (e2y < 0) c.score -= 1000;
if (!bestCombo || c.score > bestCombo.score) {
bestCombo = c;
}
}
if (!bestCombo) {
return { theta1: t1A, theta2: t2A, reachable: false };
}
return { theta1: bestCombo.t1, theta2: bestCombo.t2, reachable: true };
} }
// ── Forward kinematics ─────────────────────────────────────────── // ── Forward kinematics ───────────────────────────────────────────