Improve odometry with rotation estimation, daemon stability, and RTSP fixes

- Add rotation estimation via log-polar phase correlation (EstimateRotation,
  rotateGray) — de-rotate before translation to avoid aliasing
- Track cumulative field rotation in Tracker, reject low-confidence frames
- Extract RTSP grabber into internal/rtspgrab module
- Daemon: pause odometry during slew (motion blur), auto-resume after settle
  delay, add /pause and /resume HTTP endpoints, switch shooting mode before
  opening camera, use ReqOpenCamera with rtsp_encode_type=1
- WebSocket heartbeat (ping/pong every 10s) to prevent idle disconnects
- FFmpeg low-latency flags (-fflags nobuffer, -probesize, -analyzeduration)
- Add SendRaw API for custom payloads, increase daemon HTTP timeout to 60s

💘 Generated with Crush

Assisted-by: Crush:/models/Qwen3.6-27B-uncensored-heretic-v2-Native-MTP-Preserved-Q4_K_M.gguf
This commit is contained in:
Jacquin Antoine
2026-07-13 23:00:30 +02:00
parent 8daa9b4d58
commit d319ef6b4a
12 changed files with 522 additions and 143 deletions

View File

@ -60,10 +60,41 @@ func (c *Client) Connect(ip string) error {
return fmt.Errorf("ws dial %s: %w", url, err)
}
c.conn = conn
// Keep the connection alive — the telescope closes idle connections
// after ~30s. The PongHandler also resets the read deadline on each pong.
conn.SetPingHandler(func(string) error {
conn.WriteControl(websocket.PongMessage, nil, time.Now().Add(5*time.Second))
return nil
})
go c.readLoop()
go c.heartbeatLoop()
return nil
}
// heartbeatLoop sends periodic ping frames to keep the WebSocket alive.
// The telescope drops idle connections after ~30s.
func (c *Client) heartbeatLoop() {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for {
select {
case <-c.done:
return
case <-ticker.C:
c.mu.Lock()
if c.conn == nil {
c.mu.Unlock()
return
}
err := c.conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(5*time.Second))
c.mu.Unlock()
if err != nil && c.Debug {
log.Printf("[WS] heartbeat ping error: %v", err)
}
}
}
}
// Close shuts down the connection.
func (c *Client) Close() error {
close(c.done)