From 2737811e2e6b177ed3c45eccca087c34c1be399a Mon Sep 17 00:00:00 2001 From: pgdalmeida Date: Fri, 9 Oct 2026 14:25:51 +0200 Subject: [PATCH] Stop the gimbal where it is when switching from a scan to manual --- README.md | 2 +- src/core/Application.cpp | 17 +++++++++++++++++ src/core/HelpText.cpp | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aeb50c7..4325236 100644 --- a/README.md +++ b/README.md @@ -322,7 +322,7 @@ job. Details, payloads and safety rules: [docs/mqtt-api.md](docs/mqtt-api.md). | Command | Does | |---|---| -| `mode auto` / `mode manual` | sweep the scan grid / stop and take the gimbal by hand (it stays homed and powered) | +| `mode auto` / `mode manual` | sweep the scan grid / stop the gimbal where it is and take it by hand (it stays homed and powered) | | `mode pan []` | watch one direction: `mode pan 90 30` covers 75°-105°, a picture every 6° | | `gimbal home` | find the endstops and centre - needed after every power-up | | `gimbal move [,]` | point at a **true bearing** (0 = north) and an elevation, in degrees; without a pitch only yaw moves. A yaw-only tower ignores the pitch and refuses pitch-only commands | diff --git a/src/core/Application.cpp b/src/core/Application.cpp index ae15d13..be280f2 100644 --- a/src/core/Application.cpp +++ b/src/core/Application.cpp @@ -1849,6 +1849,7 @@ struct Application::Impl { if (m == Mode::Manual) camera->stop(); else camera->start(); scheduler->setMode(m, pan); + if (m == Mode::Manual && was != Mode::Manual) stopScanMove(); if (m == Mode::Pan) { const auto& h = scheduler->panHeadingsNow(); LOG_INFO << "mode pan: " << panText(pan) << " - " << h.size() @@ -1861,6 +1862,22 @@ struct Application::Impl { return true; } + // Leaving a scan: stop the move it last sent, which the firmware would + // otherwise finish - a slow return to the first waypoint can take many + // seconds the operator spends waiting for the gimbal to answer. The firmware + // ramps the axis down and holds where it comes to rest (it does not resume + // the move), and the next MOVE or jog supersedes a stop still ramping down. + // Sent whether or not telemetry shows motion, since a MOVE sent this tick + // is not in it yet. Never during a homing, which a STOP ends in ERROR. + void stopScanMove() { + const MotorTelemetry t = motor->telemetry(); + if (t.yaw.state == AxisState::Homing || + (t.pitch_present && t.pitch.state == AxisState::Homing)) + return; + if (anyLeftoverMove()) LOG_INFO << "stopping the gimbal where it is"; + motor->sendCommand("STOP ALL"); + } + // A pan the gimbal can actually do: its pitch inside the homed window (not // clamped to it - that would image an elevation nobody asked for), and at // least one of its headings inside the reachable yaw arc. diff --git a/src/core/HelpText.cpp b/src/core/HelpText.cpp index 02c1fb9..7ab5fce 100644 --- a/src/core/HelpText.cpp +++ b/src/core/HelpText.cpp @@ -35,7 +35,7 @@ const std::vector& helpCatalog() { "Pitch defaults to 0 (level); a yaw-only tower ignores it. Key p pans", "30 deg around the current aim.", "Example: mode pan 90 30"}}, - {"mode manual", "Stop scanning; aim by hand (key m). Cancels a running procedure.", {}}, + {"mode manual", "Stop scanning, and the gimbal where it is; aim by hand (key m). Cancels a running procedure.", {}}, }}, {"Capture", "Images and cameras. Manual mode, homed gimbal.", { {"snapshot", "Take one image now (key Space).", {