Add interactive slew mode and fix joystick coordinate mapping
- New `dwarfctl interactive` command: persistent WS connection with
real-time slew commands on a single session (no reconnect per command).
Decodes DeviceAttitude notifications (cmd 15295) when available.
- Fixed coordinate mapping: 90°=UP (toward sky), 270°=DOWN (toward ground),
confirmed by live testing on DWARF II in alt-az config.
- Monitor now decodes attitude notifications inline.
- Note: IMU attitude (15295) is NOT pushed during free slew — only during
calibration/EQ solving. Position feedback requires astro calibration.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
@ -9,7 +10,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/antitbone/dwarfctl/internal/api"
|
||||
pb "github.com/antitbone/dwarfctl/proto"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -39,6 +42,7 @@ func main() {
|
||||
cmdSystem(),
|
||||
cmdPower(),
|
||||
cmdMonitor(),
|
||||
cmdInteractive(),
|
||||
cmdPano(),
|
||||
)
|
||||
|
||||
@ -667,7 +671,8 @@ func cmdPano() *cobra.Command {
|
||||
|
||||
// --- monitor ---
|
||||
|
||||
func cmdMonitor() *cobra.Command { return &cobra.Command{
|
||||
func cmdMonitor() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "monitor",
|
||||
Short: "Listen for telescope notifications (Ctrl-C to stop)",
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
@ -676,8 +681,71 @@ func cmdMonitor() *cobra.Command { return &cobra.Command{
|
||||
ch := scope.Notifications()
|
||||
fmt.Println("Monitoring notifications (Ctrl-C to stop)...")
|
||||
for pkt := range ch {
|
||||
fmt.Printf("[NOTIFY] cmd=%d module=%d type=%d data_len=%d\n",
|
||||
pkt.GetCmd(), pkt.GetModuleId(), pkt.GetType(), len(pkt.GetData()))
|
||||
cmdID := pkt.GetCmd()
|
||||
extra := ""
|
||||
if cmdID == 15295 && len(pkt.GetData()) > 0 {
|
||||
att := &pb.DeviceAttitude{}
|
||||
if proto.Unmarshal(pkt.GetData(), att) == nil {
|
||||
extra = fmt.Sprintf(" pitch=%.1f yaw=%.1f roll=%.1f", att.GetPitch(), att.GetYaw(), att.GetRoll())
|
||||
}
|
||||
}
|
||||
fmt.Printf("[NOTIFY] cmd=%d module=%d type=%d data=%d%s\n",
|
||||
cmdID, pkt.GetModuleId(), pkt.GetType(), len(pkt.GetData()), extra)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func cmdInteractive() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "interactive",
|
||||
Short: "Interactive slew with real-time attitude (Ctrl-C to exit)",
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
scope, cleanup := dial()
|
||||
defer cleanup()
|
||||
ch := scope.Notifications()
|
||||
go func() {
|
||||
for pkt := range ch {
|
||||
if pkt.GetCmd() == 15295 && len(pkt.GetData()) > 0 {
|
||||
att := &pb.DeviceAttitude{}
|
||||
if proto.Unmarshal(pkt.GetData(), att) == nil {
|
||||
fmt.Printf("\r [ATTITUDE] pitch=%.1f yaw=%.1f roll=%.1f \n", att.GetPitch(), att.GetYaw(), att.GetRoll())
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
fmt.Println("Interactive slew. Commands: <angle> <speed> [duration_s], stop, photo, state, q")
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for {
|
||||
fmt.Print("> ")
|
||||
if !scanner.Scan() { break }
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" { continue }
|
||||
parts := strings.Fields(line)
|
||||
switch parts[0] {
|
||||
case "q", "quit", "exit":
|
||||
return
|
||||
case "stop":
|
||||
must(scope.MotorJoystickStop())
|
||||
fmt.Println("stopped")
|
||||
case "photo":
|
||||
must(scope.TakePhoto(api.CameraTele))
|
||||
fmt.Println("photo taken")
|
||||
case "state":
|
||||
st, err := scope.GetDeviceState()
|
||||
must(err)
|
||||
fmt.Printf("battery=%d%% focus=%d\n", st.GetDeviceStateInfo().GetBatteryInfo().GetPercentage(), st.GetFocusMotorStateInfo().GetFocusPosition().GetPos())
|
||||
default:
|
||||
if len(parts) < 2 { fmt.Println("usage: <angle> <speed> [duration]"); continue }
|
||||
angle := parseFloat(parts[0])
|
||||
speed := parseFloat(parts[1])
|
||||
dur := 1.0
|
||||
if len(parts) > 2 { dur = parseFloat(parts[2]) }
|
||||
must(scope.SlewJoystick(angle, speed))
|
||||
time.Sleep(time.Duration(dur * float64(time.Second)))
|
||||
must(scope.SlewJoystick(0, 0))
|
||||
fmt.Println("done")
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user