From 4d2480c248c2e36201916e647117e89cf6acf463 Mon Sep 17 00:00:00 2001 From: Jacquin Antoine Date: Sun, 12 Jul 2026 20:18:32 +0200 Subject: [PATCH] Implement working motor init command using limit-switch homing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added `motor init [up|down] [timeout]` that homes the altitude axis by slewing to a mechanical limit. The firmware detects the limit switch and performs an automatic home to position 0 (optics toward ground). Validated procedure: 1. Slew up briefly (90° 0.4 for 5s) to move away from the bottom limit 2. `motor init down 40` — slew 270° until bottom limit triggers auto-home 3. Axis remains fully operational after homing The firmware drops the WebSocket connection when the home sequence starts (normal behavior). After reconnecting, the axis works normally. Note: API still returns NEED_RESET (-14520) because absolute positioning requires astro calibration (plate solving). The mechanical home only provides physical position 0, not sky coordinates. 💘 Generated with Crush Assisted-by: Crush:glm-5.2 --- dwarfctl/TEST_RESULTS.md | 16 +++++++++++++--- dwarfctl/cmd/dwarfctl/main.go | 22 ++++++++++++++++++++++ dwarfctl/internal/api/client.go | 12 ++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/dwarfctl/TEST_RESULTS.md b/dwarfctl/TEST_RESULTS.md index b76177a..f61d915 100644 --- a/dwarfctl/TEST_RESULTS.md +++ b/dwarfctl/TEST_RESULTS.md @@ -101,9 +101,19 @@ Le `motor stop` interrompt un slew en cours instantanément. **Découverte clé — Home par butée** : slewing en 270° (descente) à vitesse modérée jusqu'à ce que le limit switch se déclenche provoque un **home automatique du firmware**. Le télescope revient à la position 0 physique (optique vers le sol). C'est la méthode d'initialisation manuelle des moteurs — pas besoin de `motor reset` (qui ne fait que rebooter). Procédure d'initialisation manuelle : -1. `motor slew 270 0.5` jusqu'à la butée (le firmware home tout seul) -2. Position 0 = optique vers le sol -3. L'API reste en `NEED_RESET` tant que la calibration astro n'est pas faite (le home mécanique ne donne pas la position absolue, seulement la position physique) +1. `motor slew 90 0.4` pendant 5s — monter ~45° pour décoller de la butée basse +2. `motor init down 40` — slew 270° jusqu'à la butée basse → home automatique +3. Position 0 = optique vers le sol +4. L'axe altitude reste **pleinement opérationnel** après le home +5. L'API reste en `NEED_RESET` tant que la calibration astro n'est pas faite (le home mécanique ne donne pas la position absolue, seulement la position physique) + +**IMPORTANT** : si le télescope démarre en butée basse, il faut d'abord monter (`motor slew 90`) avant de lancer `motor init down`, sinon le slew est ignoré car déjà en butée. + +**Commande `motor init`** : +- `motor init up [timeout]` — home via butée haute (90°) +- `motor init down [timeout]` — home via butée basse (270°, recommandé) +- Le firmware coupe la connexion WS quand le home se déclenche (normal) +- Après reconnexion, l'axe est opérationnel #### 4.5 Système de coordonnées joystick découvert (config alt-az, trépied vertical) diff --git a/dwarfctl/cmd/dwarfctl/main.go b/dwarfctl/cmd/dwarfctl/main.go index 5c131e5..8aa3829 100644 --- a/dwarfctl/cmd/dwarfctl/main.go +++ b/dwarfctl/cmd/dwarfctl/main.go @@ -397,6 +397,28 @@ func cmdMotor() *cobra.Command { fmt.Printf("motor %d: id=%d code=%d position=%.2f\n", id, pos.GetId(), pos.GetCode(), pos.GetPosition()) }, }, + &cobra.Command{ + Use: "init [up|down] [timeout]", + Short: "Home altitude axis by slewing to a mechanical limit (safe, daytime)", + Args: cobra.MaximumNArgs(2), + Run: func(_ *cobra.Command, args []string) { + dir := 90.0 // default: up + if len(args) > 0 && args[0] == "down" { + dir = 270.0 + } + timeout := 30 + if len(args) > 1 { + timeout = int(parseInt32(args[1])) + } + scope, cleanup := dial() + defer cleanup() + dirStr := "up (toward sky)" + if dir == 270 { dirStr = "down (toward ground)" } + fmt.Printf("Initializing: slewing %s at 0.5 until limit (max %ds)...\n", dirStr, timeout) + must(scope.MotorInit(dir, timeout)) + fmt.Println("Init complete.") + }, + }, ) return c } diff --git a/dwarfctl/internal/api/client.go b/dwarfctl/internal/api/client.go index b6d55ab..48ffc2c 100644 --- a/dwarfctl/internal/api/client.go +++ b/dwarfctl/internal/api/client.go @@ -210,6 +210,18 @@ func (t *Telescope) MotorGetPosition(id int32) (*pb.ResMotorPosition, error) { return resp, decodeResponse(pkt, resp) } +// MotorInit homes the altitude axis by slewing to a mechanical limit. +// The firmware detects the limit switch and resets position automatically. +// direction: 90 = up (toward sky), 270 = down (toward ground). +// timeoutSec is the maximum time to wait for the limit (typically 30-60s). +func (t *Telescope) MotorInit(direction float64, timeoutSec int) error { + if err := t.SlewJoystick(direction, 0.5); err != nil { + return fmt.Errorf("init slew: %w", err) + } + time.Sleep(time.Duration(timeoutSec) * time.Second) + return t.SlewJoystick(0, 0) +} + // MotorReset resets a motor (finds home via limit switch). // cmd 14003 is inferred. WARNING: causes telescope reboot — but may be // the only way to unblock an axis stuck at a mechanical limit.