From f652b741ae89c2edb461342e02884c2cf6ca40a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?PROFERIS=20-=20Mi=C2=B3osz=20Stocki?= Date: Mon, 6 Jul 2026 15:40:15 +0200 Subject: [PATCH] delete homing. Have to redo --- TODO.md | 2 +- src/main.cpp | 97 +-------------------------------- web/js/kinematics.js | 52 +++++++++--------- web/js/sections/stepper-test.js | 87 +---------------------------- wiring_diagram.md | 89 ++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 208 deletions(-) create mode 100644 wiring_diagram.md diff --git a/TODO.md b/TODO.md index 65dc642..b859b57 100644 --- a/TODO.md +++ b/TODO.md @@ -1 +1 @@ -You didn't finish writing home for web. Analyse it properly as it was quota reached. I can see that there is definitely wron position on map at the start. I do not know what else but you should properly finish homing sequence it was done for mcu already \ No newline at end of file +Implement mechanical stall homing \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d70a522..5a691da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,20 +50,6 @@ #define DEFAULT_SPEED 600.0f // steps/sec #define DEFAULT_ACCEL 100.0f // steps/sec² -// ─── Homing configuration ───────────────────────────────────────── -// TUNE these after first hardware test. -// SEEK_DIR: +1 = CW (positive steps), -1 = CCW toward stop -// SEEK_STEPS: must exceed maximum arm travel (~240° = 1365 steps) -// OP_OFFSET: steps from the mechanical stop to the operating home -// (derived from original PositionControl.cpp homing offsets) -#define M1_HOME_DIR (-1) // ← TUNE: flip to +1 if M1 moves wrong way -#define M2_HOME_DIR (+1) // ← TUNE: flip to -1 if M2 moves wrong way -#define HOME_SEEK_STEPS 1600 // ← TUNE: > max travel; 1600 ≈ 281° of a rev -#define HOME_SPEED 180.0f // ← TUNE: slow seek to avoid missing steps -#define HOME_ACCEL 50.0f // ← TUNE: gentle accel during seek -#define M1_OP_OFFSET 550 // ← TUNE: steps from M1 stop → operating home -#define M2_OP_OFFSET -530 // ← TUNE: steps from M2 stop → operating home - // ─── BLE UUIDs ──────────────────────────────────────────────────── #define SERVICE_UUID "a0b1c2d3-e4f5-6789-abcd-ef0123456700" #define CMD_UUID "a0b1c2d3-e4f5-6789-abcd-ef0123456701" @@ -87,7 +73,6 @@ const unsigned long NOTIFY_INTERVAL_MS = 200; // ─── Forward declarations ───────────────────────────────────────── void parseCommand(const String& cmd); void sendPosition(); -void runHoming(); // ─── BLE Server Callbacks ───────────────────────────────────────── class ServerCallbacks : public BLEServerCallbacks { @@ -145,13 +130,7 @@ void parseCommand(const String& cmd) { Serial.printf("[CFG] Acceleration → %.0f steps/sec²\n", acc); return; } - // HOME – full stall-seek homing sequence - if (cmd == "HOME") { - Serial.println("[HOME] Received HOME command"); - runHoming(); - return; - } - // HOME1 / HOME2 – manual zero (soft zero, no motion) + // HOME1 if (cmd == "HOME1") { stepper1.setCurrentPosition(0); Serial.println("[S1] Zeroed"); @@ -173,80 +152,6 @@ void parseCommand(const String& cmd) { Serial.printf("[CMD] Unknown command: '%s'\n", cmd.c_str()); } -// ─── Stall-based homing sequence ───────────────────────────────── -/** - * Drives each motor slowly into its mechanical hard stop (the arm - * folds against the motor housing). The 28BYJ-48 stalls harmlessly - * for a fraction of a second at the stop. After both stops are - * found, the arm backs off to the operating home position and both - * step counters are zeroed. - * - * This is a BLOCKING call — BLE is not serviced during homing - * (~15-20 s total). The browser shows "Homing…" until the - * HOMED notify arrives. - * - * Tune M1_HOME_DIR, M2_HOME_DIR, HOME_SEEK_STEPS, and OP_OFFSETs - * after the first hardware test. - */ -void runHoming() { - Serial.println("[HOME] Starting homing sequence…"); - - // Reduce speed for the seek phase - stepper1.setMaxSpeed(HOME_SPEED); - stepper1.setAcceleration(HOME_ACCEL); - stepper2.setMaxSpeed(HOME_SPEED); - stepper2.setAcceleration(HOME_ACCEL); - - // ── Seek M1 to its mechanical stop ─────────────────────────── - Serial.println("[HOME] Seeking M1 stop…"); - stepper1.move(M1_HOME_DIR * HOME_SEEK_STEPS); - while (stepper1.isRunning()) { - stepper1.run(); - stepper2.run(); // keep M2 coils energised during M1 seek - } - stepper1.setCurrentPosition(0); - Serial.println("[HOME] M1 stop found → zeroed"); - delay(200); // brief pause before M2 seek - - // ── Seek M2 to its mechanical stop ─────────────────────────── - Serial.println("[HOME] Seeking M2 stop…"); - stepper2.move(M2_HOME_DIR * HOME_SEEK_STEPS); - while (stepper2.isRunning()) { - stepper1.run(); - stepper2.run(); - } - stepper2.setCurrentPosition(0); - Serial.println("[HOME] M2 stop found → zeroed"); - delay(200); - - // ── Move to operating home (restore normal speed) ───────────── - stepper1.setMaxSpeed(DEFAULT_SPEED); - stepper1.setAcceleration(DEFAULT_ACCEL); - stepper2.setMaxSpeed(DEFAULT_SPEED); - stepper2.setAcceleration(DEFAULT_ACCEL); - - Serial.println("[HOME] Moving to operating home…"); - stepper1.moveTo(M1_OP_OFFSET); - stepper2.moveTo(M2_OP_OFFSET); - while (stepper1.isRunning() || stepper2.isRunning()) { - stepper1.run(); - stepper2.run(); - } - - // Declare operating home as the new step zero - stepper1.setCurrentPosition(0); - stepper2.setCurrentPosition(0); - Serial.println("[HOME] Homing complete — at operating home (0, 0)"); - - // Notify the browser so it can sync its step counters - if (bleConnected && pStatusChar) { - pStatusChar->setValue("HOMED"); - pStatusChar->notify(); - } - delay(50); - sendPosition(); // immediately follow with P:0,0 -} - // ─── Send current positions via BLE NOTIFY ──────────────────────── void sendPosition() { if (!bleConnected || !pStatusChar) return; diff --git a/web/js/kinematics.js b/web/js/kinematics.js index b2fcb98..ab5b8c1 100644 --- a/web/js/kinematics.js +++ b/web/js/kinematics.js @@ -33,11 +33,11 @@ // ── Exact constants from PositionControl.cpp ───────────────────── const ARM = { - d: 25.8, // full motor separation (mm) + d: 25.8, // full motor separation (mm) d2: 12.9, // half separation; M1 at (+d2, 0), M2 at (-d2, 0) - l1: 85.0, // proximal link length (mm) + l1: 85.0, // proximal link length (mm) l2: 110.0, // distal link length (mm) - STEPS_PER_REV: 2048, + STEPS_PER_REV: 2048, STEP_ANGLE_DEG: 360 / 2048, // ≈ 0.17578125 °/step }; @@ -48,16 +48,16 @@ const LIMITS = { // ── Outer board boundary ─────────────────────────────────────── // The EE cannot be requested outside this rectangle. X_MIN: -150, // ← TUNE: left edge of board - X_MAX: 150, // ← TUNE: right edge of board - Y_MIN: -30, // ← TUNE: bottom (numbers reach ~44 mm; sign coords go lower) - Y_MAX: 145, // ← TUNE: top (highest letter is ~128 mm) + X_MAX: 150, // ← TUNE: right edge of board + Y_MIN: -30, // ← TUNE: bottom (numbers reach ~44 mm; sign coords go lower) + Y_MAX: 145, // ← TUNE: top (highest letter is ~128 mm) // ── Centre mechanism exclusion box ──────────────────────────── // Rectangular zone centred on (0, 0) where the motor housing sits. // The EE and both elbows must stay outside this area. BOX_HALF_W: 30, // ← TUNE: half-width in X (motors at ±12.9, housing wider) BOX_Y_MIN: -10, // ← TUNE: bottom of housing - BOX_Y_MAX: 40, // ← TUNE: top of housing + BOX_Y_MAX: 40, // ← TUNE: top of housing // ── Elbow exclusion zone (prevents arm crossing near the box) ─ // Each elbow has a separate rectangular exclusion box. @@ -66,7 +66,7 @@ const LIMITS = { // If ELBOW_BOX_X_INNER is 5, the left elbow's X must be > +5 mm // (can never cross to the other side of the box mid-point). ELBOW_BOX_X_INNER: 5, // ← TUNE: inner X margin from centre for each elbow - ELBOW_BOX_Y_MAX: 50, // ← TUNE: Y below which elbow crossing is forbidden + ELBOW_BOX_Y_MAX: 50, // ← TUNE: Y below which elbow crossing is forbidden }; // ── Letter / number position lookup table ──────────────────────── @@ -132,23 +132,23 @@ function solve(x, y) { // ── Motor 1 (pivot at +d2, 0 = +12.9 mm) ───────────────────── // xmd = x - d2 is the X component of (target – M1_pivot). 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 }; const cosW1 = (l2 * l2 - s * s - l1 * l1) / (-2 * l1 * s); if (cosW1 < -1 || cosW1 > 1) return { theta1: 0, theta2: 0, reachable: false }; - const q = Math.atan2(y, xmd); - const w1 = Math.acos(cosW1); + const q = Math.atan2(y, xmd); + const w1 = Math.acos(cosW1); const theta1 = q - w1; // ── Motor 2 (pivot at -d2, 0 = -12.9 mm) ───────────────────── // xpd = x + d2 is the X component of (target – M2_pivot). const xpd = x + d2; - const t = Math.sqrt(xpd * xpd + y * y); + const t = Math.sqrt(xpd * xpd + y * y); if (t < 1e-6) return { theta1: 0, theta2: 0, reachable: false }; const cosW2 = (l2 * l2 - t * t - l1 * l1) / (-2 * l1 * t); if (cosW2 < -1 || cosW2 > 1) return { theta1: 0, theta2: 0, reachable: false }; - const r = Math.atan2(y, xpd); - const w2 = Math.acos(cosW2); + const r = Math.atan2(y, xpd); + const w2 = Math.acos(cosW2); const theta2 = r + w2; return { theta1, theta2, reachable: true }; @@ -180,16 +180,16 @@ function forward(theta1, theta2) { // Elbow 1 — tip of Motor 1 proximal link (motor at +d2) const e1x = +d2 + l1 * Math.cos(theta1); - const e1y = l1 * Math.sin(theta1); + const e1y = l1 * Math.sin(theta1); // Elbow 2 — tip of Motor 2 proximal link (motor at -d2) const e2x = -d2 + l1 * Math.cos(theta2); - const e2y = l1 * Math.sin(theta2); + const e2y = l1 * Math.sin(theta2); // End-effector: intersection of the two distal-link circles // (radius l2, centred on each elbow). Pick the "upward" solution. - const dx = e2x - e1x; - const dy = e2y - e1y; + const dx = e2x - e1x; + const dy = e2y - e1y; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < 1e-6 || dist > 2 * l2) { @@ -203,15 +203,15 @@ function forward(theta1, theta2) { }; } - const a = dist / 2; - const h = Math.sqrt(Math.max(0, l2 * l2 - a * a)); + const a = dist / 2; + const h = Math.sqrt(Math.max(0, l2 * l2 - a * a)); const mx = (e1x + e2x) / 2; const my = (e1y + e2y) / 2; // Two intersection candidates - const px1 = mx + h * ( dy / dist); + const px1 = mx + h * (dy / dist); const py1 = my + h * (-dx / dist); - const px2 = mx - h * ( dy / dist); + const px2 = mx - h * (dy / dist); const py2 = my - h * (-dx / dist); // Always pick the candidate with higher Y (EE above the elbow line) @@ -247,15 +247,15 @@ function armsCrossed(theta1, theta2) { // Elbow positions (same formula as forward()) const e1x = +d2 + l1 * Math.cos(theta1); - const e1y = l1 * Math.sin(theta1); + const e1y = l1 * Math.sin(theta1); const e2x = -d2 + l1 * Math.cos(theta2); - const e2y = l1 * Math.sin(theta2); + const e2y = l1 * Math.sin(theta2); // Elbow1 (from M1 on the RIGHT) must not appear far to the LEFT at low height // Elbow2 (from M2 on the LEFT) must not appear far to the RIGHT at low height // Both conditions together catch the "arms have swapped sides" scenario. const e1_crossed = e1x < -XI && e1y < YM; // M1's elbow went too far left - const e2_crossed = e2x > XI && e2y < YM; // M2's elbow went too far right + const e2_crossed = e2x > XI && e2y < YM; // M2's elbow went too far right return e1_crossed || e2_crossed; } @@ -285,7 +285,7 @@ function checkWorkspace(x, y) { // 2. Centre mechanism exclusion box if (x > -L.BOX_HALF_W && x < L.BOX_HALF_W && - y > L.BOX_Y_MIN && y < L.BOX_Y_MAX) + y > L.BOX_Y_MIN && y < L.BOX_Y_MAX) return { ok: false, reason: `(${x.toFixed(1)}, ${y.toFixed(1)}) is inside the mechanism housing` }; // 3. IK geometric reachability diff --git a/web/js/sections/stepper-test.js b/web/js/sections/stepper-test.js index 2e7372a..6f6ce96 100644 --- a/web/js/sections/stepper-test.js +++ b/web/js/sections/stepper-test.js @@ -47,7 +47,6 @@ const PX_D2 = IK.ARM.d2 * SV.SCALE; // ── Section state ───────────────────────────────────────────────── let steps1 = 0; let steps2 = 0; -let isHoming = false; // blocks all controls during homing sequence let eventCleanup = []; // ── SVG element refs ────────────────────────────────────────────── @@ -226,58 +225,9 @@ async function zeroMotor(motor) { } // ───────────────────────────────────────────────────────────────── -// Homing +// Manual jog // ───────────────────────────────────────────────────────────────── -/** Block / unblock all interactive controls while homing is running. */ -function setHomingActive(active) { - isHoming = active; - const root = document.querySelector('.section-page'); - if (!root) return; - if (active) { - root.classList.add('homing-active'); - } else { - root.classList.remove('homing-active'); - } - // Update the button label - const btn = document.getElementById('btn-find-home'); - const spin = document.getElementById('home-spinner'); - const lbl = document.getElementById('home-label'); - if (!btn) return; - btn.disabled = active; - if (spin) spin.style.display = active ? '' : 'none'; - if (lbl) lbl.textContent = active ? 'Homing…' : 'Find Home'; -} - -/** Called when the firmware sends HOMED or when simulating. */ -function onHomingComplete() { - steps1 = 0; - steps2 = 0; - setHomingActive(false); - renderArmFromSteps(); - UI.log('✓ Homing complete — step counters reset to zero.', 'success'); -} - -async function startHoming() { - if (isHoming) return; - setHomingActive(true); - UI.log('⧐ Homing started — arm moving to mechanical stops…', 'warn'); - - if (BLE.isConnected()) { - try { - await BLE.write('HOME'); - // onHomingComplete() will be called when HOMED notify arrives - } catch (e) { - UI.log(`BLE error during home: ${e.message}`, 'error'); - setHomingActive(false); - } - } else { - // Simulation: instant reset - UI.log('[sim] HOME command sent — simulating instant home', 'info'); - setTimeout(onHomingComplete, 600); - } -} - // ───────────────────────────────────────────────────────────────── // SVG workspace zones (pre-computed) // ───────────────────────────────────────────────────────────────── @@ -401,19 +351,7 @@ function buildHTML() { .quick-steps button { flex:1; min-width:30px; padding:4px 2px; font-size:0.68rem; border-radius:var(--radius-xs); } - /* Disable all interactive elements during homing */ - .homing-active button:not(#btn-find-home), - .homing-active input, - .homing-active #scara-svg { - pointer-events: none; - opacity: 0.4; - } - /* Spinner animation for homing button */ - @keyframes spin { to { transform: rotate(360deg); } } - .home-spin { display:inline-block; width:13px; height:13px; - border:2px solid currentColor; border-top-color:transparent; - border-radius:50%; animation:spin 0.7s linear infinite; - vertical-align:middle; margin-right:5px; } +
@@ -614,19 +552,6 @@ function buildHTML() { Incremental step control — bypasses IK
- -
-
- ⚠️ Drives each arm slowly into its mechanical stop then backs off to - operating home. Takes ~15–20 s. All controls are locked during homing. -
- -
@@ -818,11 +743,6 @@ const StepperTestSection = { // ── BLE NOTIFY position feedback ────────────────────────────── function onBLEStatus(e) { const msg = e.detail; - if (msg === 'HOMED') { - // Firmware completed homing — sync browser counters - onHomingComplete(); - return; - } if (msg.startsWith('P:')) { const [s1, s2] = msg.slice(2).split(',').map(Number); steps1 = s1; steps2 = s2; @@ -831,9 +751,6 @@ const StepperTestSection = { } document.addEventListener('ble:status', onBLEStatus); - // ── Find Home button ────────────────────────────────────── - document.getElementById('btn-find-home').addEventListener('click', startHoming); - eventCleanup = [ () => BLE.off('connected', updateBadge), () => BLE.off('disconnected', updateBadge), diff --git a/wiring_diagram.md b/wiring_diagram.md new file mode 100644 index 0000000..35c7c0d --- /dev/null +++ b/wiring_diagram.md @@ -0,0 +1,89 @@ +# WijiBoard Wiring Diagram + +This document outlines the hardware connections for the WijiBoard. + +## Hardware Components +- **Microcontroller**: Waveshare ESP32-S3-Zero +- **Motors**: 2× 28BYJ-48 (5V Stepper Motors) +- **Motor Drivers**: 2× ULN2003 Driver Boards +- **Power System**: + - 4S LiPo Battery + - XH-M609 Battery Low-Voltage Disconnect Module + - 2× Buck Regulators (step-down converters tuned to 5V) + +--- + +## Power Connections +The system is powered by a 4S LiPo battery. To protect the battery from over-discharge, it is connected to an **XH-M609** module. The output of the XH-M609 is split into two separate **Buck Regulators**, both tuned to output 5V. + +1. **Buck Regulator 1 (MCU Power)**: Dedicated to powering the ESP32-S3-Zero. +2. **Buck Regulator 2 (Motor Power)**: Dedicated to powering both ULN2003 driver boards to prevent voltage drops or electrical noise from affecting the MCU. + +> [!IMPORTANT] +> **Common Ground**: You MUST connect the Ground (GND) from the ESP32 to the Ground (GND) of the ULN2003 drivers. Even though they have separate 5V power supplies, they need a common ground reference for the GPIO logic signals to work correctly. + +| Component | Connection | Destination | +| :--- | :--- | :--- | +| **4S LiPo** | `BAT+` / `BAT-` | XH-M609 `VIN+` / `VIN-` | +| **XH-M609** | `VOUT+` / `VOUT-` | Split to **IN+** and **IN-** on both Buck Regulators | +| **Buck 1 (MCU)** | `OUT+ (5V)` | ESP32-S3-Zero `5V` (used as power input) | +| **Buck 1 (MCU)** | `OUT- (GND)` | ESP32-S3-Zero `GND` | +| **Buck 2 (Motors)**| `OUT+ (5V)` | ULN2003 (M1) `+ / 5V` and ULN2003 (M2) `+ / 5V` | +| **Buck 2 (Motors)**| `OUT- (GND)` | ULN2003 (M1) `- / GND` and ULN2003 (M2) `- / GND` | +| **ESP32-S3-Zero** | `GND` | Tie to the motor ground network (Common Ground) | + +--- + +## Motor 1 (Right Motor) Logic +**Physical Location**: Right side (pivot at +12.9mm) + +| ESP32-S3-Zero Pin | ULN2003 (Motor 1) Pin | +| :--- | :--- | +| **GPIO 4** | `IN1` | +| **GPIO 5** | `IN2` | +| **GPIO 6** | `IN3` | +| **GPIO 7** | `IN4` | + +--- + +## Motor 2 (Left Motor) Logic +**Physical Location**: Left side (pivot at -12.9mm) + +| ESP32-S3-Zero Pin | ULN2003 (Motor 2) Pin | +| :--- | :--- | +| **GPIO 8** | `IN1` | +| **GPIO 9** | `IN2` | +| **GPIO 10** | `IN3` | +| **GPIO 11** | `IN4` | + +--- + +## Stepper to Driver Connections +Simply plug the white 5-pin JST connectors from the 28BYJ-48 motors into the corresponding white sockets on their respective ULN2003 driver boards. The connector is keyed and only fits one way. + +## Schematic Overview + +```mermaid +flowchart LR + subgraph Power Delivery + BATT[4S LiPo Battery] -->|14.8V| XHM609[XH-M609 Protector] + XHM609 -->|14.8V| BUCK1[Buck Regulator 1] + XHM609 -->|14.8V| BUCK2[Buck Regulator 2] + end + + BUCK1 -->|5V Power| ESP[ESP32-S3-Zero] + BUCK2 -->|5V Power| M1_Driver[ULN2003 M1] + BUCK2 -->|5V Power| M2_Driver[ULN2003 M2] + + %% Common Ground + ESP -. Common Ground .- M1_Driver + ESP -. Common Ground .- M2_Driver + + %% Logic Signals + ESP -- Pins 4,5,6,7 --> M1_Driver + ESP -- Pins 8,9,10,11 --> M2_Driver + + %% Motors + M1_Driver == 5-wire cable ==> M1[Motor 1 - Right] + M2_Driver == 5-wire cable ==> M2[Motor 2 - Left] +```