AimCamera and SpiralSearch

by Jeff Medkeff

These routines slew the telescope to the target, take a pointing exposure, solve it, and if necessary refine the pointing of the telescope. SpiralSolve is invoked if the pointing exposure can't be solved by assuming the telescope is properly pointed; SpiralSolve makes up a checkerboard pattern of places where the telescope might have slewed and attempts to find a match using these assumed locations (only one pointing exposure is ever taken).



Function AimCamera(RA, Dec, setNum)             ' Returns True/False

    ' Convert target J2000 coordinates to local topocentric 
    ' for scope. tjd = Terrestrial Julian Date for this instant 
    ujd = Util.SysJulianDate
    tjd = ujd + (Util.DeltaT(ujd) / 86400)
    objv.RightAscension = RA
    objv.Declination = Dec
    Set ovec = objv.GetTopocentricPosition(tjd, site, false)

    ' Slew the telescope, if needed. No slew done if already within pointing tolerance of target.
    If tools.AngSep(scope.RightAscension, scope.Declination, ovec.RightAscension, ovec.Declination) > (FieldTolerance/60) Then
      Scope.SlewToPosition ovec.RightAscension, ovec.Declination
    Else
      Log "Not slewing, because we are already aimed at this field."
    End If

    'This is a convenient point to put our slew-to RA and DEC in some variables
    'that we will use shortly to determine the pointing error of the telescope
    'for the slew we just did. SlewRA and SlewDEC are where we tried to go:
    SlewRA = ovec.RightAscension
    SlewDEC = ovec.Declination

    'wait for scope vibrations etc to damp out.
    For settle = 1 to regExpDelay
      Yield
      Util.WaitForMilliseconds 1000
      Yield
    Next

    ' Now take the exposure to be used for pointing. Save the pointing
    ' exposures for later analysis, in case some of them don't solve.
    ' The pointing image file names are formed similarly to the main
    ' ones. See the notes in main() about parenthesis removal.
    Log "taking pointing exposure"
    fn = pimageDir & "\p-" & tgtName & "-" & setNum & ".fts"
    Set rx = New RegExp
    rx.Pattern = "[()]"             ' Must remove parens
    rx.Global = True                ' (all of them)
    fn = rx.Replace(fn, "")         ' This removes them


    ' For pointing exposures, binning the camera and using a subframe can
    ' contribute to faster downloads and thus lower overhead. If you don't
    ' want to bin, just delete the cam.BinX and cam.BinY lines below. If you
    ' don't want to use a subframe, set UseSubFrame accordingly elsewhere.
    cam.SetFullFrame
    cam.BinX = 3
    cam.BinY = 3

    If UseSubFrame Then
      cam.StartX = StX
      cam.StartY = StY
      cam.NumX   = NmX
      cam.NumY   = NmY
    End If

    ' Ok, take the picture.
    TakePicture regExpInterval, fn

    ' Now we set camera back to proper binning for next exposure.
    cam.SetFullFrame
    cam.BinX = cambin
    cam.BinY = cambin

    ' Use PinPoint to plate-solve the image and get back the 
    ' real center point RA/Dec (J2000). 
    Logtext "Plate-solving image."
    plate.AttachFITS fn                         ' Attach the image
    plate.RightAscension = ovec.RightAscension  ' Set approx coordinates
    plate.Declination = ovec.Declination

    ' Set PointSolveScale to something approximately
    ' correct at beginning of script. Once the first
    ' pointing exposure is solved, the precise value
    ' will be put into this variable.
    plate.ArcsecPerPixelHoriz = PointSolveScale ' Set scale factors
    plate.ArcsecPerPixelVert = PointSolveScale
    plate.UpdateFITS()                          ' Write WCS for later analysis
    spiral = false
    On Error Resume Next                        ' Failure here should not be fatal
    If Not plate.Solve Then                     ' Get the real position
      spiral = True
      plate.DetachFITS                          ' Clean up
      Log Err.Description
    Else
      Log "ok! " & plate.MatchedStars.Count & " stars matched."
    End If 'if not plate.solve
    On Error Goto 0

    If spiral then 
      plate.AttachFITS fn                         ' Attach the image
      If Not SpiralSolve(ovec.RightAscension, ovec.Declination, 5) Then
        Log "SpiralSolve failed to solve the pointing exposure."
        plate.DetachFITS
        AimCamera = False
        Exit Function
      End If
    End If

    plate.UpdateFITS()                          ' Write WCS for later analysis
    On Error Goto 0                             ' Back to fatal errors

    ' Roll angle of image, for use in guide-star picking. Set
    ' Rotation to something approximately correct at the beginning
    ' of your script. The solved pointing exposure will put a
    ' precisely correct value into the variable.
    Rotation = plate.RollAngle / 57.29578
    PointSolveScale = plate.ArcsecPerPixelHoriz

    ' OK we now have the real J2000 RA/Dec of the center of the 
    ' picture we just took. Transform from J2000 to topocentric
    ' for the scope, plug those coordinates in, and then Sync
    ' the scope, updating its internal pointing data. Use the
    ' TJD we just calculated above. Plenty good!
    objv.RightAscension = plate.RightAscension
    objv.Declination = plate.Declination
    plate.DetachFits                            ' Done with this

    Set tvec = objv.GetTopocentricPosition(tjd, site, false)
    Scope.ObjectRightAscension = tvec.RightAscension
    Scope.ObjectDeclination = tvec.Declination
    Scope.SyncPosition

    'This is a good place to put our ACTUAL position into some variables
    'that can be used by the pointing error calculations coming up.
    ActRA  = tvec.RightAscension
    ActDEC = tvec.Declination

    ' Ok, now we find the angle between where we are pointed and where
    ' we are supposed to be pointed. If we are below the threshold, then
    ' we will do an update slew; otherwise we start astrometric exposure
    ' right away.
    ' NOTE: ovec still contains the topocentric coordinates of the target object.
    ' DoSecondSlew is a function that returns true or false based on a series
    ' of tests, the most significant of which is "are you pointed close enough?"

    If DoSecondSlew Then      'i.e., if DoSecondSlew = True Then....
      Scope.SlewToPosition ovec.RightAscension, ovec.Declination
      For delay = 1 to astExpDelay
        Yield
        Util.WaitForMilliseconds 1000
        Yield
      Next
      Log "Wait over."
    End If

    AimCamera = True                ' Hooray!
    
End Function







Function SpiralSolve (ra, dec, gridlimit)
' careful - don't make 'gridlimit' too high a number. If you
' use ten here, then 440 possible fields will be searched. It
' can get out of hand pretty quickly.

  Log "Doing a spiral search to solve this pointing exposure."

  dim RAstep
  dim Decstep
  dim top
  dim x
  dim y

  RAstep = ((PointSolveScale * plate.Columns) / (3600 * 15)) / Cos(dec * PI / 180)
  Decstep = (PointSolveScale * plate.Rows) / 3600

  plate.ArcsecPerPixelHoriz = PointSolveScale ' Set scale factors
  plate.ArcsecPerPixelVert = PointSolveScale

  ' we assume plate is the PinPoint Plate object, and
  ' that you have already attached an image.
  plate.FindImageStars            ' Scan the image only once

  ' counts rows/columns outward from middle
  For top = 1 to gridlimit

    ' counts out the x,y positions of a box of "radius" equal to top
    For x = -top to top
      For y = -top to top

        If abs(x) = top Or abs(y) = top then

          plate.RightAscension = ra + (RAstep * x)
          plate.Declination = dec + (Decstep * y)
          plate.FindCatalogStars

          On Error Resume Next 
          If Not plate.Solve Then
            Logtext "Solution failed at " & x & "," & y
            On Error Goto 0
          Else
            Log "Plate solved at " & x & "," & y
            plate.UpdateFITS
            SpiralSolve = True
            On Error Goto 0
            Exit Function
          End If
          On Error Goto 0

        End If  ' abs(x) = top Or abs(y) = top
  
      next 'y
    next 'x
  next 'top

  SpiralSolve = false

End Function