diff --git a/NINA.Core/Enum/MountTypeEnum.cs b/NINA.Core/Enum/MountTypeEnum.cs index 2508d7504..62d3d3106 100644 --- a/NINA.Core/Enum/MountTypeEnum.cs +++ b/NINA.Core/Enum/MountTypeEnum.cs @@ -30,5 +30,8 @@ public enum MountTypeEnum { [Description("LblForkOnWedge")] FORK_ON_WEDGE, + + [Description("LblAltitudeAzimuth")] + ALT_AZ, } } \ No newline at end of file diff --git a/NINA.Core/Locale/Locale.resx b/NINA.Core/Locale/Locale.resx index 2ff24033e..8e295b273 100644 --- a/NINA.Core/Locale/Locale.resx +++ b/NINA.Core/Locale/Locale.resx @@ -3899,7 +3899,7 @@ In case a longer duration is needed, a duration can be specified and the applica GEM Axis Length - If Alt/Az, this should be 0. For an EQ mount, slew RA to +/- 90 degrees, and measure the lateral distance (in mm) from the axis to center of the telescope aperture + On an EQ mount, slew RA to +/- 90 degrees, and measure the lateral distance (in mm) from the axis to center of the telescope aperture Lateral Axis Length @@ -7185,6 +7185,15 @@ Additionally, it is essential that the ASCOM driver used also supports this 32-b Civil dawn + + Altitude-Azimuth + + + Vertical axis length + + + For piggy-backed OTAs on an Alt-Az mounted telescope. This should be the distance between the center of the main OTA and the piggy-backed OTA + Refuse mount unpark if shutter is not open diff --git a/NINA.Equipment/Equipment/MyDome/DomeSynchronization.cs b/NINA.Equipment/Equipment/MyDome/DomeSynchronization.cs index b176c8744..6531bd9a9 100644 --- a/NINA.Equipment/Equipment/MyDome/DomeSynchronization.cs +++ b/NINA.Equipment/Equipment/MyDome/DomeSynchronization.cs @@ -24,8 +24,8 @@ This Source Code Form is subject to the terms of the Mozilla Public namespace NINA.Equipment.Equipment.MyDome { public class DomeSynchronization : IDomeSynchronization { - private static double TWO_PI = 2.0 * Math.PI; - private static double HALF_PI = Math.PI / 2.0; + private const double TWO_PI = 2.0 * Math.PI; + private const double HALF_PI = Math.PI / 2.0; private readonly IProfileService profileService; @@ -43,7 +43,6 @@ public TopocentricCoordinates TargetDomeCoordinates( return TargetDomeCoordinates(scopeCoordinates: scopeCoordinates, localSiderealTime: localSiderealTime, siteLatitude: siteLatitude, siteLongitude: siteLongitude, siteElevation: 0, sideOfPier: sideOfPier); } - /// /// Gets the dome coordinates required so the scope points directly out of the shutter. This works for Alt-Az, EQ mounts, and fork mounts on a wedge /// and depends on careful user measurements including: @@ -77,16 +76,17 @@ public TopocentricCoordinates TargetDomeCoordinates( PierSide sideOfPier) { scopeCoordinates = scopeCoordinates.Transform(Epoch.JNOW); var domeSettings = profileService.ActiveProfile.DomeSettings; + // To calculate the effect of rotations in the southern hemisphere we augment a few of the rotations to pretend as if it were the northern hemisphere, // and then add 180 degrees to the final result - var origin = new Vector4(0, 0, 0, 1); - Matrix4x4 scopeOriginTranslation; - if (domeSettings.MountType == MountTypeEnum.EQUATORIAL) { - scopeOriginTranslation = CalculateGEM(scopeCoordinates, localSiderealTime, siteLatitude, sideOfPier); - } else { - scopeOriginTranslation = CalculateForkOnWedge(scopeCoordinates, localSiderealTime, siteLatitude); - } + + var scopeOriginTranslation = domeSettings.MountType switch { + MountTypeEnum.EQUATORIAL => CalculateGEM(scopeCoordinates, localSiderealTime, siteLatitude, sideOfPier), + MountTypeEnum.FORK_ON_WEDGE => CalculateForkOnWedge(scopeCoordinates, localSiderealTime, siteLatitude), + MountTypeEnum.ALT_AZ => CalculateAltAz(scopeCoordinates, siteLatitude, siteLongitude), + _ => throw new NotSupportedException($"Unsupported mount type: {domeSettings.MountType}"), + }; var scopeApertureOrigin = scopeOriginTranslation * origin; @@ -207,5 +207,43 @@ private Matrix4x4 CalculateGEM( return mountOffset * latitudeAdjustment * raRotationAdjustment * decRotationAdjustment * gemAdjustment; } + + private Matrix4x4 CalculateAltAz( + Coordinates scopeCoordinates, + Angle siteLatitude, + Angle siteLongitude) { + var domeSettings = profileService.ActiveProfile.DomeSettings; + + // Alt-Az mounts rotate in altitude (around the y-axis) and azimuth (around the z-axis) + // Altitude is Dec, Azimuth is Azimuth derived from RA/Dec + LST + + // Convert scope RA/Dec to horizontal coordinates (Alt/Az) + var topocentric = scopeCoordinates.Transform(siteLatitude, siteLongitude, 0d); // elevation not critical here + + // Altitude rotation: scope tilts up from horizontal + var altitudeRotation = Matrix4x4.CreateRotationY((float)(topocentric.Altitude.Radians)); + + // Azimuth rotation: scope rotates around the dome's vertical axis (z-axis) + var azimuthRotation = Matrix4x4.CreateRotationZ((float)(-topocentric.Azimuth.Radians)); + + // Determine hemisphere direction + var latitudeFactor = siteLatitude.Radians >= 0 ? 1.0 : -1.0; + + // Mount offset from dome center + var mountOffset = Matrix4x4.CreateTranslation(new Vector3( + (float)(domeSettings.ScopePositionNorthSouth_mm * latitudeFactor), // X: North + (float)(-domeSettings.ScopePositionEastWest_mm * latitudeFactor), // Y: East + (float)domeSettings.ScopePositionUpDown_mm // Z: Up + )); + + // Account for any lateral axis and vertical axis offsets to accomodate side-by-side or piggyback telescopes + var offsets = Matrix4x4.CreateTranslation(new Vector3( + 0.0f, + -(float)domeSettings.LateralAxis_mm, + (float)domeSettings.GemAxis_mm // Reusing GemAxis_mm for vertical offset in Alt-Az mounts since the basic meaning is the same + )); + + return mountOffset * (azimuthRotation * altitudeRotation * offsets); + } } } \ No newline at end of file diff --git a/NINA.Profile/DomeSettings.cs b/NINA.Profile/DomeSettings.cs index 41a5c0a91..3e0a88822 100644 --- a/NINA.Profile/DomeSettings.cs +++ b/NINA.Profile/DomeSettings.cs @@ -30,12 +30,13 @@ public void OnDeserializing(StreamingContext context) { protected override void SetDefaultValues() { Id = "No_Device"; - LastDeviceName = ""; + LastDeviceName = string.Empty; ScopePositionEastWest_mm = 0.0; ScopePositionNorthSouth_mm = 0.0; ScopePositionUpDown_mm = 0.0; DomeRadius_mm = 0.0; GemAxis_mm = 0.0; + LateralAxis_mm = 0.0; AzimuthTolerance_degrees = 2.0; FindHomeBeforePark = false; DomeSyncTimeoutSeconds = 120; diff --git a/NINA/View/Options/DomeView.xaml b/NINA/View/Options/DomeView.xaml index 79c922b07..35ffbd5f2 100644 --- a/NINA/View/Options/DomeView.xaml +++ b/NINA/View/Options/DomeView.xaml @@ -152,6 +152,9 @@ + + + @@ -182,6 +185,9 @@ + + + @@ -202,6 +208,39 @@ Text="{Binding DecOffsetHorizontal_mm, UpdateSourceTrigger=LostFocus}" Unit="mm" /> + + + + + + + + + + + n - N.I.N.A. now queries the ASCOM device name after connecting to the driver. - **ASCOM Device State** - For drivers that implement the new ASCOM 7 Device State the application will now use the state when possible instead of polling individual fields +- **Domes with Alt-Az mounts** + - Alt-Az mounts are a new mount configuration that is supported under Options > Dome. This permits one to define mount and OTA offsets that result in proper dome azimuthal rotation for an alt-az mount, or any side-by-side or piggy-backed telescopes mounted on a main telescope. - ** Dome/Roof safety ** - Optionally disallow the mount to be unparked if the dome or roof controller reports a shutter state other than Open. - ** Switch Polling**