Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NINA.Core/Enum/MountTypeEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,8 @@ public enum MountTypeEnum {

[Description("LblForkOnWedge")]
FORK_ON_WEDGE,

[Description("LblAltitudeAzimuth")]
ALT_AZ,
}
}
11 changes: 10 additions & 1 deletion NINA.Core/Locale/Locale.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3899,7 +3899,7 @@ In case a longer duration is needed, a duration can be specified and the applica
<value>GEM Axis Length</value>
</data>
<data name="LblDomeGemAxisLengthTooltip" xml:space="preserve">
<value>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</value>
<value>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</value>
</data>
<data name="LblDomeLateralAxisLength" xml:space="preserve">
<value>Lateral Axis Length</value>
Expand Down Expand Up @@ -7185,6 +7185,15 @@ Additionally, it is essential that the ASCOM driver used also supports this 32-b
<data name="LblCivilDawn" xml:space="preserve">
<value>Civil dawn</value>
</data>
<data name="LblAltitudeAzimuth" xml:space="preserve">
<value>Altitude-Azimuth</value>
</data>
<data name="LblDomeVerticalAxisLength" xml:space="preserve">
<value>Vertical axis length</value>
</data>
<data name="LblDomeVerticalAxisLengthTooltip" xml:space="preserve">
<value>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</value>
</data>
<data name="LblRefuseUnparkWithoutShutterOpen" xml:space="preserve">
<value>Refuse mount unpark if shutter is not open</value>
</data>
Expand Down
58 changes: 48 additions & 10 deletions NINA.Equipment/Equipment/MyDome/DomeSynchronization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -43,7 +43,6 @@ public TopocentricCoordinates TargetDomeCoordinates(
return TargetDomeCoordinates(scopeCoordinates: scopeCoordinates, localSiderealTime: localSiderealTime, siteLatitude: siteLatitude, siteLongitude: siteLongitude, siteElevation: 0, sideOfPier: sideOfPier);
}


/// <summary>
/// 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:
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
}
}
3 changes: 2 additions & 1 deletion NINA.Profile/DomeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions NINA/View/Options/DomeView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="1">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="2">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</UniformGrid.Style>
Expand Down Expand Up @@ -182,6 +185,9 @@
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="2">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</UniformGrid.Style>
Expand All @@ -202,6 +208,39 @@
Text="{Binding DecOffsetHorizontal_mm, UpdateSourceTrigger=LostFocus}"
Unit="mm" />
</UniformGrid>
<UniformGrid
Margin="0,5,0,0"
VerticalAlignment="Center"
Columns="2">
<UniformGrid.Style>
<Style TargetType="{x:Type UniformGrid}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=PART_MountTypeList, Path=SelectedItem}" Value="1">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</UniformGrid.Style>
<TextBlock
Width="250"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{ns:Loc LblDomeVerticalAxisLength}">
<TextBlock.ToolTip>
<TextBlock Text="{ns:Loc LblDomeVerticalAxisLengthTooltip}" />
</TextBlock.ToolTip>
</TextBlock>
<ninactrl:UnitTextBox
MinWidth="80"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Text="{Binding GemAxis_mm, UpdateSourceTrigger=LostFocus}"
Unit="mm" />
</UniformGrid>
<UniformGrid
Margin="0,5,0,0"
VerticalAlignment="Center"
Expand Down
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ More details at <a href="https://nighttime-imaging.eu/donate/" target="_blank">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**
Expand Down