From 946fb4b141678dd3cbb6c890b562dafe3ecd4a10 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 2 Jun 2020 23:52:25 +0100 Subject: [PATCH] Implementation of backlash compensation feature --- .../FocuserUnitTests.cs | 41 ++- .../SharedResourcesUnitTests.cs | 4 + Meade.net.focuser/Focuser.cs | 84 ++++--- Meade.net/ProfileProperties.cs | 1 + Meade.net/SetupDialogForm.cs | 4 +- Meade.net/SetupDialogForm.designer.cs | 48 ++++ Meade.net/SetupDialogForm.resx | 236 +++++++++++++++--- Meade.net/SharedResources.cs | 7 +- 8 files changed, 352 insertions(+), 73 deletions(-) diff --git a/Meade.net.Focuser.UnitTests/FocuserUnitTests.cs b/Meade.net.Focuser.UnitTests/FocuserUnitTests.cs index 4fab074..e326b64 100644 --- a/Meade.net.Focuser.UnitTests/FocuserUnitTests.cs +++ b/Meade.net.Focuser.UnitTests/FocuserUnitTests.cs @@ -313,7 +313,6 @@ namespace Meade.net.Focuser.UnitTests _focuser.Halt(); _sharedResourcesWrapperMock.Verify( x => x.SendBlind(":FQ#"), Times.AtLeastOnce); - _utilMock.Verify( x => x.WaitForMilliseconds(250), Times.AtLeastOnce); } [Test] @@ -395,29 +394,61 @@ namespace Meade.net.Focuser.UnitTests [TestCase(-200)] public void Move_WhenIncrementIsNot0_ThenMovesFocuserAndStopsFocuser( int position) { + _profileProperties.BacklashCompensation = 0; + ConnectFocuser(); _focuser.Move(position); if (position < 0) { - _sharedResourcesWrapperMock.Verify( x => x.SendBlind("#:F-#"), Times.AtLeastOnce); + _sharedResourcesWrapperMock.Verify( x => x.SendBlind("#:F-#"), Times.Once); _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F+#"), Times.Never); } else { _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F-#"), Times.Never); - _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F+#"), Times.AtLeastOnce); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F+#"), Times.Once); } _sharedResourcesWrapperMock.Verify( x => x.Lock(It.IsAny()), Times.Once); - _utilMock.Verify(x => x.WaitForMilliseconds(250), Times.AtLeastOnce); - + _utilMock.Verify(x => x.WaitForMilliseconds(Math.Abs(position)), Times.Once); + _utilMock.Verify(x => x.WaitForMilliseconds(Math.Abs(_profileProperties.BacklashCompensation)), Times.Never); _utilMock.Verify(x => x.WaitForMilliseconds(100), Times.Once()); _utilMock.Verify(x => x.WaitForMilliseconds(1000), Times.Once()); } + [TestCase(200, 3, 3)] + [TestCase(-200, 1, 0)] + public void Move_WhenIncrementIsNot0_ThenMovesFocuserAndStopsFocuserWithBacklashCompensation(int position, int hundredMsWaitCount, int backlashCompensaionCount) + { + _profileProperties.BacklashCompensation = 3000; + + ConnectFocuser(); + + _focuser.Move(position); + + if (position < 0) + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F-#"), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F+#"), Times.Never); + } + else + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F-#"), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind("#:F+#"), Times.Exactly(2)); + } + + _sharedResourcesWrapperMock.Verify(x => x.Lock(It.IsAny()), Times.Once); + + _utilMock.Verify(x => x.WaitForMilliseconds(Math.Abs(position)), Times.Once); + _utilMock.Verify(x => x.WaitForMilliseconds(Math.Abs(_profileProperties.BacklashCompensation)), Times.Exactly(backlashCompensaionCount)); + + _utilMock.Verify(x => x.WaitForMilliseconds(100), Times.Exactly(hundredMsWaitCount)); + _utilMock.Verify(x => x.WaitForMilliseconds(1000), Times.Once); + } + [Test] public void Position_WhenCalled_ThenThrowsException() { diff --git a/Meade.net.UnitTests/SharedResourcesUnitTests.cs b/Meade.net.UnitTests/SharedResourcesUnitTests.cs index 6eada17..d70d163 100644 --- a/Meade.net.UnitTests/SharedResourcesUnitTests.cs +++ b/Meade.net.UnitTests/SharedResourcesUnitTests.cs @@ -140,6 +140,7 @@ namespace Meade.net.UnitTests string GuideRateProfileNameDefault = "10.077939"; //67% of sidereal rate string PrecisionDefault = "Unchanged"; string GuidingStyleDefault = "Auto"; + string BacklashCompensationDefault = "3000"; Mock profileWrapperMock = new Mock(); profileWrapperMock.SetupAllProperties(); @@ -155,6 +156,8 @@ namespace Meade.net.UnitTests .Returns(PrecisionDefault); profileWrapperMock.Setup(x => x.GetValue(DriverId, "Guiding Style", string.Empty, GuidingStyleDefault)) .Returns(GuidingStyleDefault); + profileWrapperMock.Setup(x => x.GetValue(DriverId, "Backlash Compensation", string.Empty, BacklashCompensationDefault)) + .Returns(BacklashCompensationDefault); IProfileWrapper profeWrapper = profileWrapperMock.Object; @@ -172,6 +175,7 @@ namespace Meade.net.UnitTests Assert.That(profileProperties.TraceLogger, Is.EqualTo(bool.Parse(TraceStateDefault))); Assert.That(profileProperties.Precision, Is.EqualTo(PrecisionDefault)); Assert.That(profileProperties.GuidingStyle, Is.EqualTo(GuidingStyleDefault)); + Assert.That(profileProperties.BacklashCompensation, Is.EqualTo(int.Parse(BacklashCompensationDefault))); } [TestCase("TCP")] diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 33ac3e4..f00ee64 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -47,6 +47,7 @@ namespace ASCOM.Meade.net private static string _comPort; // Variables to hold the currrent device configuration + private static int _backlashCompensation; /// /// Private variable to hold an ASCOM Utilities object /// @@ -286,17 +287,11 @@ namespace ASCOM.Meade.net CheckConnected("Halt"); - //A single halt command is sometimes missed by the #909 apm, so let's do it a few times to be safe. - //todo make this mockable - Stopwatch stopwatch = Stopwatch.StartNew(); - while (stopwatch.ElapsedMilliseconds < 1000) - { - _sharedResourcesWrapper.SendBlind(":FQ#"); - //:FQ# Halt Focuser Motion - //Returns: Nothing + //todo fix this issue: A single halt command is sometimes missed by the #909 apm, so let's do it a few times to be safe. - _utilities.WaitForMilliseconds(250); - } + _sharedResourcesWrapper.SendBlind(":FQ#"); + //:FQ# Halt Focuser Motion + //Returns: Nothing } public bool IsMoving @@ -359,45 +354,56 @@ namespace ASCOM.Meade.net if (position == 0) return; - MoveFocuser(position > 0, Math.Abs(position)); + _sharedResourcesWrapper.Lock(() => + { + MoveFocuser(position > 0, Math.Abs(position)); + ApplyBacklashCompensation(position > 0); + //This gives the focuser time to physically stop. + _utilities.WaitForMilliseconds(1000); + }); + } + + private void ApplyBacklashCompensation(bool directionOut) + { + if (_backlashCompensation == 0) + return; + + _tl.LogMessage("Move", "Applying backlash compensation"); + + if (directionOut) + { + MoveFocuser(directionOut, Math.Abs(_backlashCompensation)); + _utilities.WaitForMilliseconds(Math.Abs(_backlashCompensation)); + MoveFocuser(!directionOut, Math.Abs(_backlashCompensation)); + } } private void MoveFocuser(bool directionOut, int steps) { - _sharedResourcesWrapper.Lock(() => - { - //_sharedResourcesWrapper.SendBlind("#:FF#"); - //:FF# Set Focus speed to fastest setting - //Returns: Nothing + //_sharedResourcesWrapper.SendBlind("#:FF#"); + //:FF# Set Focus speed to fastest setting + //Returns: Nothing - //:FS# Set Focus speed to slowest setting - //Returns: Nothing + //:FS# Set Focus speed to slowest setting + //Returns: Nothing - //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 - //Returns: Nothing - //All others – Not Supported - _utilities.WaitForMilliseconds(100); + //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 + //Returns: Nothing + //All others – Not Supported + _utilities.WaitForMilliseconds(100); - //A Single focus command sometimes gets lost on the #909, so sending lots of them solves the issue. - //todo make this mockable - Stopwatch stopwatch = Stopwatch.StartNew(); - while (stopwatch.ElapsedMilliseconds < steps) - { - _sharedResourcesWrapper.SendBlind(directionOut ? "#:F+#" : "#:F-#"); - //:F+# Start Focuser moving inward (toward objective) - //Returns: None + //Todo fix this issue. A Single focus command sometimes gets lost on the #909, so sending lots of them solves the issue. - //:F-# Start Focuser moving outward (away from objective) - //Returns: None + _sharedResourcesWrapper.SendBlind(directionOut ? "#:F+#" : "#:F-#"); + //:F+# Start Focuser moving inward (toward objective) + //Returns: None - _utilities.WaitForMilliseconds(250); - } + //:F-# Start Focuser moving outward (away from objective) + //Returns: None - Halt(); + _utilities.WaitForMilliseconds(steps); - //This gives the focuser time to physically stop. - _utilities.WaitForMilliseconds(1000); - }); + Halt(); } public int Position => throw new PropertyNotImplementedException("Position", false); @@ -556,9 +562,11 @@ namespace ASCOM.Meade.net var profileProperties = _sharedResourcesWrapper.ReadProfile(); _tl.Enabled = profileProperties.TraceLogger; _comPort = profileProperties.ComPort; + _backlashCompensation = profileProperties.BacklashCompensation; LogMessage("ReadProfile", $"Trace logger enabled: {_tl.Enabled}"); LogMessage("ReadProfile", $"Com Port: {_comPort}"); + LogMessage("ReadProfile", $"Backlash Steps: {_backlashCompensation}"); } /// diff --git a/Meade.net/ProfileProperties.cs b/Meade.net/ProfileProperties.cs index 56ee4a5..a469d6f 100644 --- a/Meade.net/ProfileProperties.cs +++ b/Meade.net/ProfileProperties.cs @@ -8,5 +8,6 @@ namespace ASCOM.Meade.net public double GuideRateArcSecondsPerSecond { get; set; } public string Precision { get; set; } public string GuidingStyle { get; set; } + public int BacklashCompensation { get; set; } } } \ No newline at end of file diff --git a/Meade.net/SetupDialogForm.cs b/Meade.net/SetupDialogForm.cs index 851b048..2366268 100644 --- a/Meade.net/SetupDialogForm.cs +++ b/Meade.net/SetupDialogForm.cs @@ -81,6 +81,7 @@ namespace ASCOM.Meade.net cboGuidingStyle.SelectedItem = "Auto"; } + txtBacklashSteps.Text = profileProperties.BacklashCompensation.ToString(CultureInfo.CurrentCulture); } public ProfileProperties GetProfile() @@ -91,7 +92,8 @@ namespace ASCOM.Meade.net ComPort = comboBoxComPort.SelectedItem.ToString(), GuideRateArcSecondsPerSecond = double.Parse(txtGuideRate.Text.Trim()), Precision = cboPrecision.SelectedItem.ToString(), - GuidingStyle = cboGuidingStyle.SelectedItem.ToString() + GuidingStyle = cboGuidingStyle.SelectedItem.ToString(), + BacklashCompensation = int.Parse(txtBacklashSteps.Text) }; return profileProperties; diff --git a/Meade.net/SetupDialogForm.designer.cs b/Meade.net/SetupDialogForm.designer.cs index 4b40bb9..38678e2 100644 --- a/Meade.net/SetupDialogForm.designer.cs +++ b/Meade.net/SetupDialogForm.designer.cs @@ -47,6 +47,12 @@ namespace ASCOM.Meade.net this.cboPrecision = new System.Windows.Forms.ComboBox(); this.label6 = new System.Windows.Forms.Label(); this.cboGuidingStyle = new System.Windows.Forms.ComboBox(); + this.label7 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.txtBacklashSteps = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.picASCOM)).BeginInit(); this.SuspendLayout(); // @@ -151,10 +157,46 @@ namespace ASCOM.Meade.net resources.ApplyResources(this.cboGuidingStyle, "cboGuidingStyle"); this.cboGuidingStyle.Name = "cboGuidingStyle"; // + // label7 + // + resources.ApplyResources(this.label7, "label7"); + this.label7.Name = "label7"; + // + // label8 + // + resources.ApplyResources(this.label8, "label8"); + this.label8.Name = "label8"; + // + // txtBacklashSteps + // + resources.ApplyResources(this.txtBacklashSteps, "txtBacklashSteps"); + this.txtBacklashSteps.Name = "txtBacklashSteps"; + // + // label9 + // + resources.ApplyResources(this.label9, "label9"); + this.label9.Name = "label9"; + // + // label10 + // + resources.ApplyResources(this.label10, "label10"); + this.label10.Name = "label10"; + // + // label11 + // + resources.ApplyResources(this.label11, "label11"); + this.label11.Name = "label11"; + // // SetupDialogForm // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.label11); + this.Controls.Add(this.label10); + this.Controls.Add(this.txtBacklashSteps); + this.Controls.Add(this.label9); + this.Controls.Add(this.label8); + this.Controls.Add(this.label7); this.Controls.Add(this.cboGuidingStyle); this.Controls.Add(this.label6); this.Controls.Add(this.cboPrecision); @@ -200,5 +242,11 @@ namespace ASCOM.Meade.net private ComboBox cboPrecision; private Label label6; private ComboBox cboGuidingStyle; + private Label label7; + private Label label8; + private TextBox txtBacklashSteps; + private Label label9; + private Label label10; + private Label label11; } } \ No newline at end of file diff --git a/Meade.net/SetupDialogForm.resx b/Meade.net/SetupDialogForm.resx index 4bb64fd..40dc2b0 100644 --- a/Meade.net/SetupDialogForm.resx +++ b/Meade.net/SetupDialogForm.resx @@ -123,7 +123,7 @@ - 281, 250 + 281, 387 59, 24 @@ -145,13 +145,13 @@ $this - 14 + 20 Bottom, Right - 281, 280 + 281, 417 59, 25 @@ -172,7 +172,7 @@ $this - 13 + 19 12, 9 @@ -196,7 +196,7 @@ $this - 12 + 18 Top, Right @@ -223,13 +223,13 @@ $this - 11 + 17 True - 13, 90 + 12, 90 58, 13 @@ -250,13 +250,13 @@ $this - 10 + 16 True - 86, 136 + 97, 114 69, 17 @@ -277,10 +277,10 @@ $this - 9 + 15 - 86, 87 + 97, 87 90, 21 @@ -298,13 +298,13 @@ $this - 8 + 14 True - 10, 162 + 12, 202 61, 13 @@ -325,10 +325,10 @@ $this - 7 + 13 - 86, 159 + 97, 199 46, 20 @@ -349,13 +349,13 @@ $this - 6 + 12 True - 138, 162 + 149, 202 122, 13 @@ -376,13 +376,13 @@ $this - 5 + 11 True - 138, 175 + 149, 215 105, 13 @@ -403,13 +403,13 @@ $this - 4 + 10 True - 13, 194 + 12, 234 50, 13 @@ -430,7 +430,7 @@ $this - 3 + 9 Unchanged @@ -442,7 +442,7 @@ High - 86, 191 + 97, 231 90, 21 @@ -460,7 +460,7 @@ $this - 2 + 8 True @@ -469,7 +469,7 @@ NoControl - 13, 221 + 12, 261 67, 13 @@ -490,7 +490,7 @@ $this - 1 + 7 Auto @@ -502,7 +502,7 @@ Pulse guiding - 86, 218 + 97, 258 90, 21 @@ -520,6 +520,186 @@ $this + 6 + + + True + + + Microsoft Sans Serif, 8.25pt, style=Bold + + + 12, 176 + + + 66, 13 + + + 16 + + + Telescope + + + label7 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + True + + + Microsoft Sans Serif, 8.25pt, style=Bold + + + NoControl + + + 12, 317 + + + 52, 13 + + + 17 + + + Focuser + + + label8 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + 97, 335 + + + 46, 20 + + + 19 + + + 3000 + + + txtBacklashSteps + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + NoControl + + + 12, 338 + + + 79, 13 + + + 18 + + + Backlash steps + + + label9 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + True + + + NoControl + + + 149, 338 + + + 20, 13 + + + 20 + + + ms + + + label10 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + Microsoft Sans Serif, 8.25pt, style=Bold + + + NoControl + + + 12, 67 + + + 71, 13 + + + 21 + + + Connection + + + label11 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + 0 @@ -529,7 +709,7 @@ 6, 13 - 350, 313 + 350, 450 CenterScreen diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index b6b60d8..9089ce2 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -140,6 +140,7 @@ namespace ASCOM.Meade.net private const string GuideRateProfileName = "Guide Rate Arc Seconds Per Second"; private const string PrecisionProfileName = "Precision"; private const string GuidingStyleProfileName = "Guiding Style"; + private const string BacklashCompensationName = "Backlash Compensation"; public static void WriteProfile(ProfileProperties profileProperties) { @@ -153,6 +154,7 @@ namespace ASCOM.Meade.net driverProfile.WriteValue(DriverId, GuideRateProfileName, profileProperties.GuideRateArcSecondsPerSecond.ToString(CultureInfo.InvariantCulture)); driverProfile.WriteValue(DriverId, PrecisionProfileName, profileProperties.Precision); driverProfile.WriteValue(DriverId, GuidingStyleProfileName, profileProperties.GuidingStyle); + driverProfile.WriteValue(DriverId, BacklashCompensationName, profileProperties.BacklashCompensation.ToString()); } } } @@ -162,7 +164,9 @@ namespace ASCOM.Meade.net private const string GuideRateProfileNameDefault = "10.077939"; //67% of sidereal rate private const string PrecisionDefault = "Unchanged"; private const string GuidingStyleDefault = "Auto"; - + private const string BacklashCompensationDefault = "3000"; + + public static ProfileProperties ReadProfile() { @@ -177,6 +181,7 @@ namespace ASCOM.Meade.net profileProperties.GuideRateArcSecondsPerSecond = double.Parse(driverProfile.GetValue(DriverId, GuideRateProfileName, string.Empty, GuideRateProfileNameDefault), NumberFormatInfo.InvariantInfo); profileProperties.Precision = driverProfile.GetValue(DriverId, PrecisionProfileName, string.Empty, PrecisionDefault); profileProperties.GuidingStyle = driverProfile.GetValue(DriverId, GuidingStyleProfileName, string.Empty, GuidingStyleDefault); + profileProperties.BacklashCompensation = Convert.ToInt32(driverProfile.GetValue(DriverId, BacklashCompensationName, string.Empty, BacklashCompensationDefault)); } return profileProperties;