ZwoController
An Elixir library for controlling ZWO AM5 telescope mounts via serial communication.
Features
- GoTo/Slewing: Command the mount to slew to any celestial coordinates
- Manual Motion: Control axis motion at various speeds (guide to max slew)
- Tracking: Enable/disable tracking with sidereal, lunar, or solar rates
- Alt-Az & Equatorial Modes: Switch between altitude-azimuth and equatorial tracking
- Autoguiding: Send guide pulses for autoguiding applications
- Mock Mount: Test your application without physical hardware
Installation
Add zwo_controller to your list of dependencies in mix.exs:
def deps do
[
{:zwo_controller, "~> 0.1.0"}
]
endOr for the latest development version from GitHub:
def deps do
[
{:zwo_controller, github: "jmcguigs/zwo_controller"}
]
endThen fetch dependencies:
mix deps.getQuick Start
Connect to a Real Mount
# Connect via serial port (typical on Linux/Mac)
{:ok, mount} = ZwoController.start_mount(port: "/dev/ttyUSB0")
# On Windows
{:ok, mount} = ZwoController.start_mount(port: "COM3")Use the Mock for Testing
{:ok, mount} = ZwoController.start_mock()Basic Operations
# Get current position (RA in decimal hours, DEC in decimal degrees)
{:ok, pos} = ZwoController.position(mount)
IO.puts("RA: #{pos.ra}h, DEC: #{pos.dec}°")
# Slew to coordinates
ZwoController.goto(mount, 12.5, 45.0)
# Slew to Vega using HMS/DMS
ra = ZwoController.ra(18, 36, 56) # 18h 36m 56s
dec = ZwoController.dec(38, 47, 1) # +38° 47' 01"
ZwoController.goto(mount, ra, dec)
# Enable sidereal tracking
ZwoController.track(mount, :sidereal)
# Manual motion
ZwoController.set_rate(mount, 5) # Set medium speed
ZwoController.move(mount, :north) # Start moving north
Process.sleep(1000)
ZwoController.stop(mount) # Emergency stopAutoguiding
# Set guide rate to 0.5x sidereal
ZwoController.set_guide_rate(mount, 0.5)
# Send guide pulses (direction, duration in ms)
ZwoController.guide(mount, :north, 200)
ZwoController.guide(mount, :east, 150)Tracking Modes
ZwoController.track(mount, :sidereal) # For stars
ZwoController.track(mount, :lunar) # For the Moon
ZwoController.track(mount, :solar) # For the Sun
ZwoController.track_off(mount) # Disable trackingMount Mode (Alt-Az vs Equatorial)
The ZWO AM5 can operate in two modes depending on physical installation:
# Alt-Az mode - for mount on tripod (no wedge)
# Use for azimuth/altitude tracking (satellites, terrestrial objects)
ZwoController.set_altaz_mode(mount)
# Equatorial mode - for mount on wedge (polar aligned)
# Use for tracking celestial objects that move with Earth's rotation
ZwoController.set_polar_mode(mount)
# Check current mount type
{:ok, status} = ZwoController.status(mount)
IO.inspect(status.mount_type) # => :altaz or :equatorialImportant: The mount mode must match your physical setup:
- Alt-Az mode: Mount on tripod, no wedge. Tracks by moving in azimuth and altitude.
- Equatorial mode: Mount on equatorial wedge, polar aligned. Tracks by rotating around polar axis.
For satellite tracking or azimuth/altitude control, you must set Alt-Az mode first:
ZwoController.set_altaz_mode(mount)
Process.sleep(1000) # Wait for mode change
{:ok, pos} = ZwoController.altaz(mount) # Now returns Az/Alt coordinatesHome and Park
ZwoController.home(mount) # Go to home position
ZwoController.park(mount) # Go to park positionCoordinate System
The mount supports two coordinate systems depending on its mode:
Equatorial Coordinates (RA/Dec)
Used when mount is in equatorial mode (on wedge, polar aligned):
- Right Ascension (RA): Decimal hours (0-24)
- Declination (DEC): Decimal degrees (-90 to +90)
# Get current RA/Dec position
{:ok, pos} = ZwoController.position(mount)
IO.puts("RA: #{pos.ra}h, DEC: #{pos.dec}°")Horizontal Coordinates (Az/Alt)
Used when mount is in Alt-Az mode (on tripod, no wedge):
- Azimuth (Az): Degrees from North (0-360°, clockwise)
- Altitude (Alt): Degrees above horizon (0-90°)
# Get current Az/Alt position
{:ok, pos} = ZwoController.altaz(mount)
IO.puts("Az: #{pos.az}°, Alt: #{pos.alt}°")Converting Coordinates
alias ZwoController.Coordinates
# HMS to decimal hours
ra = Coordinates.hms_to_ra(12, 30, 45) # 12h 30m 45s → 12.5125
# DMS to decimal degrees
dec = Coordinates.dms_to_dec(-23, 26, 21) # -23° 26' 21" → -23.439...
# Decimal to HMS/DMS
Coordinates.ra_to_hms(12.5) # → %{hours: 12, minutes: 30, seconds: 0.0}
Coordinates.dec_to_dms(-23.5) # → %{degrees: -23, minutes: 30, seconds: 0.0}Module Overview
| Module | Description |
|---|---|
ZwoController | High-level convenience API |
ZwoController.Mount | GenServer-based mount controller |
ZwoController.Mock | Simulated mount for testing |
ZwoController.Protocol |
Serial command definitions (includes :AA# for Alt-Az mode, :AP# for Polar mode) |
ZwoController.Coordinates | Coordinate conversion utilities |
ZwoController.SatelliteTracker | Satellite tracking with TLE propagation |
Low-Level Access
For advanced usage, you can send raw commands:
alias ZwoController.Protocol
# Send any command
{:ok, response} = ZwoController.raw(mount, Protocol.get_version())
# Or construct custom commands
{:ok, response} = ZwoController.raw(mount, ":GVP#") # Get mount modelHardware Requirements
- ZWO AM5 mount (or compatible)
- USB-serial connection to the mount
-
Serial port permissions (on Linux, add user to
dialoutgroup)
# Linux: Add user to dialout group for serial access
sudo usermod -a -G dialout $USER
# Log out and back in for changes to take effectLicense
MIT