Saturday, May 28, 2011

Automated Astrophotography with Python - Part 1d

AUTOGUIDING
The last major functionality to add to the 'cCamera' class is the ability to perform autoguiding during long exposures. Instead of showing the complete 'cCamera' class listing as I have in previous posts, here I show the new attributes and methods that must be added to the 'cCamera' class that I've built up so far. The first listing shows the new class attributes.
self.__guideStarXPos = 0 # x-coordinate of guide star
self.__guideStarYPos = 0 # y-coordinate of guide star
self.__guideExposure = 1.0 # default guide exposure in seconds
self.__guideSettleLimit = 0.40 # max pixel error before imaging can occur
self.__guideSettleMaxTime = 120 # max time for autoguider to settle
The first two attributes contain the x- and y-coordinates of the guide star that will be used for autoguiding and the attribute '__guideExposure' specifies the length of exposure for each guide image. The attribute '__guideSettleLimit' sets the limit which the guide errors must fall under before an image exposure will start. (ex. In this case, guide errors for both axes must settle under 0.40 pixels before an image exposure will begin.) The '__guideSettleMaxTime' attribute holds the maximum number of seconds allowed for the guide errors to settle under '__guideSettleLimit'.

The next listing shows the new methods added to the 'cCamera' class.
def autoGuide(self,autoGuideStar,exposure):
    if autoGuideStar:
        self.__CAMERA.GuiderAutoSelectStar = True
        if self.__guideStarYPos == 0 or self.__guideStarYPos == 0:
            self.__guideExposure = exposure
            if self.exposeGuider(self.__guideExposure):
                return ERROR
            self.__guideStarXPos = self.__CAMERA.GuiderXStarPosition
            self.__guideStarYPos = self.__CAMERA.GuiderYStarPosition
            print
            print "Guider Setup:"
            print "Guider:                %s" % self.__CAMERA.GuiderName
            print "Guide star selection:  Auto"
            print "Guide star exposure:   %0.2f" % self.__guideExposure
            print "Aggressiveness X-Axis: %0.2f" % \
                   self.__CAMERA.GuiderAggressivenessX
            print "Aggressiveness Y-Axis: %0.2f" % \
                   self.__CAMERA.GuiderAggressivenessY
            print "Max Move X-Axis:       %0.2f" % self.__CAMERA.GuiderMaxMoveX
            print "Max Move Y-Axis:       %0.2f" % self.__CAMERA.GuiderMaxMoveY
            print "Min Move X-Axis:       %0.2f" % self.__CAMERA.GuiderMinMoveX
            print "Min Move Y-Axis:       %0.2f" % self.__CAMERA.GuiderMinMoveY
    else:
        self.__CAMERA.GuiderAutoSelectStar = False
        ## if necessary, set up the guider for autoguiding
        if self.__guideStarXPos == 0 or self.__guideStarYPos == 0:
            # prompt operator to manually select a guide star
            print
            print " *** INPUT NEEDED ***"
            print " 1. In MaxIm, manually expose the guide camera."
            print " 2. Click on a guide star and enter a guide exposure value."
            print " 3. Verify that MaxIm correctly tracks on the guide star."
            raw_input(" 4. Press ENTER key when ready to proceed: ")
            self.__guideStarXPos = self.__CAMERA.GuiderXStarPosition
            self.__guideStarYPos = self.__CAMERA.GuiderYStarPosition
            print
            exposure = raw_input(" Enter Guide Star Exposure (sec): ")
            try:
                self.__guideExposure = float(exposure)
            except:
                print " ERROR: Invalid input. Expecting float value...try again"
                exposure = raw_input(" Enter Guide Star Exposure: ")
                try:
                    self.__guideExposure = float(exposure)
                except:
                    print "ERROR: Invalid input for guide star exposure"
                    return ERROR
            print
            print "Guider Setup:"
            print "Guider:                %s" % self.__CAMERA.GuiderName
            print "Guide star selection:  Manual"
            print "Guide star exposure:   %0.2f" % self.__guideExposure
            print "Aggressiveness X-Axis: %0.2f" % \
                   self.__CAMERA.GuiderAggressivenessX
            print "Aggressiveness Y-Axis: %0.2f" % \
                   self.__CAMERA.GuiderAggressivenessY
            print "Max Move X-Axis:       %0.2f" % self.__CAMERA.GuiderMaxMoveX
            print "Max Move Y-Axis:       %0.2f" % self.__CAMERA.GuiderMaxMoveY
            print "Min Move X-Axis:       %0.2f" % self.__CAMERA.GuiderMinMoveX
            print "Min Move Y-Axis:       %0.2f" % self.__CAMERA.GuiderMinMoveY

    self.__CAMERA.GuiderBinning = 1
    self.__CAMERA.GuiderSetStarPosition(self.__guideStarXPos,
                                        self.__guideStarYPos)
    print "Guider Declination = %d" % self.__CAMERA.GuiderDeclination
    print "Tracking on guide star at X = %d, Y = %d" % \
           (self.__guideStarXPos,self.__guideStarYPos)
    # start autoguiding
    try:
        guideStatus = self.__CAMERA.GuiderTrack(self.__guideExposure)
    except:
        print "ERROR: While attempting to start the autoguider"
        return ERROR
    else:
        if guideStatus:
            print "Start autoguiding..."
        else:
            print "ERROR: Autoguider did not start successfully"
            return ERROR
    print "Waiting for guider to settle below %0.2f px (max wait %d sec)" % \
           (self.__guideSettleLimit,self.__guideSettleMaxTime)
    started = time.time()
    cnt = 0
    while True:
        if (time.time() - started) > self.__guideSettleMaxTime:
            print "ERROR: Guider not settled within the max allowable time"
            return ERROR
        if self.__CAMERA.GuiderNewMeasurement:
            recentErrorX = self.__CAMERA.GuiderXError
            recentErrorY = self.__CAMERA.GuiderYError
            # ignore the first reading
            if cnt != 0:
                print "X-Error: %7.3f  Y-Error: %7.3f" % \
                       (recentErrorX,recentErrorY)
                if (abs(recentErrorX) < self.__guideSettleLimit and
                    abs(recentErrorY) < self.__guideSettleLimit):
                    break
        cnt += 1
        time.sleep(0.5)
    return NOERROR

def stopAutoGuide(self):
    try:
        self.__CAMERA.GuiderStop()
    except TypeError:
        print "Stop Autoguiding..."
        time.sleep(2)
    except:
        print "ERROR: Unexpected error while attempting to stop autoguider"

def checkGuiderRunning(self):
    return self.__CAMERA.GuiderRunning
    
def resetGuideStar(self):
    self.__guideStarXPos = 0
    self.__guideStarYPos = 0
Not surprisingly, 'autoGuide' is the new method that initiates all autoguiding operations. This method takes a boolean argument called 'autoGuideStar' to determine if autoguiding will use automatic or manual guide star selection. Additionally, the 'exposure' argument specifies the guide exposure length to use when automatic guide star selection is chosen and is not relevant when manual guide star selection is specified. If 'True' is passed in to the 'autoGuideStar' argument, the MaxIm DL attribute 'GuiderAutoSelectStar' is set to 'True', and, if a guide star has not been previously selected, a guide image is taken, and class attributes are populated with the position of the brightest guide star that MaxIm DL finds. All guide settings are then printed to the screen. If the 'autoGuideStar' argument is passed in as 'False', the MaxIm DL attribute 'GuiderAutoSelectStar' is set to 'False', and if a guide star has not previously been identified, the user is prompted to manually take a guide exposure, click on a potential guide star, then test tracking to make sure it is suitable. After pressing the 'ENTER' key, the user is then prompted to enter a length of exposure for all guide images and then all guide settings are printed to the screen.

After the guide star has been identified and set up, the guider binning is set then messages are printed to screen that show the current declination of the guider and the x- and y-coordinates of the chosen guide star. At this point, the autoguider is started with the MaxIm DL 'GuiderTrack' method inside a 'try', 'except', 'else' construct. The 'autoGuide' method then enters a loop that repeats until the guide errors fall under the pixel value defined by the class attribute '__guideSettleLimit'. If the errors do not settle within '__guideSettleMaxTime' seconds an error is returned to the calling routine. Assuming autoguiding starts okay and guide errors settle out, imaging can now begin.

The other two new methods added to this class are a procedure to stop the autoguider and a procedure to check to see if the autoguider is running. The 'checkGuiderRunning' method simply returns the result of MaxIm DL's 'GuiderRunning' attribute to the calling routine. The 'stopAutoGuide' method is complicated by a minor bug in MaxIm DL that causes a call to MaxIm's 'GuiderStop' method to always throw a 'TypeError' exception even though the autoguider is successfully stopped. This expected error is trapped in a 'except TypeError' block and any other exception generates an error statement to the screen.

cCAMERA UNIT TEST
The following listing shows the unit test code for this version of the 'cCamera' class. The script sets the simulator imaging camera up for full-frame mode with 1x1 binning then sets a CCD temperature and waits for the temperature to stabilize. As a first test, the script initiates autoguiding with automatic guide star selection and uses 1-second exposures for guide images. After making sure that autoguiding is in progress, it begins taking three 10-second images through the blue filter. When all images are complete, autoguiding is stopped. After resetting the guide star's x- and y-coordinates to zero, the process is started again with auto guide star selection and with 2.5-second guide images. This time, three 20-second images through the blue filter are taken before autoguiding is stopped. As a last test, the guide star cooridinates are zeroed out and autoguiding is started with manual guide star selection. After the user switches to MaxIm DL, takes a guide exposure, clicks on a guide star, and tests tracking for that star, autoguiding is started and three 15-second images through the blue filter are initiated. After all images are finished, autoguiding is stopped and the CCD is warmed to ambient temperature.
if __name__ == "__main__":

    # Create an instance of the cCamera class
    testCamera = cCamera()

    # Setup Maxim DL to take a full frame image 
    testCamera.setFullFrame()
    # Setup binning for 1x1
    testCamera.setBinning(1)

    # Set CCD Temperature
    testCamera.setCCDTemp('-15C')
    # Goto CCD Temperature
    testCamera.gotoCCDTemp()
    
    # Start camera autoguiding with auto guide star select
    # Guide exposure = 1.0 second
    if testCamera.autoGuide(True,1.0):
        testCamera.stopAutoGuide()
    # Make sure autoguider is running
    if testCamera.checkGuiderRunning():
        # Take 3 images
        for i in range(3):
            # Expose filter slot 2 (Blue) for 10 seconds
            testCamera.exposeLight(10,2,'m51_B')
        # Stop autoguider after all images complete
        testCamera.stopAutoGuide()    
    else:
        print "ERROR - Autoguider not running as expected"

    # Reset guide star positions for next test
    testCamera.resetGuideStar()
    # Start camera autoguiding with auto guide star select
    # Guide exposure = 2.5 seconds
    if testCamera.autoGuide(True,2.5):
        testCamera.stopAutoGuide()
    # Make sure autoguider is running 
    if testCamera.checkGuiderRunning():
        # Take 3 images
        for i in range(3):
            # Expose filter slot 2 (Blue) for 20 seconds
            testCamera.exposeLight(20,2,'m51_B')
        # Stop autoguider after all images complete
        testCamera.stopAutoGuide()    
    else:
        print "ERROR - Autoguider not running as expected"
    
    # Reset guide star positions for next test
    testCamera.resetGuideStar()
    # Start camera autoguiding with manual guide star select
    if testCamera.autoGuide(False,0):
        testCamera.stopAutoGuide()
    if testCamera.checkGuiderRunning():
        # Take 3 images
        for i in range(3):
            # Expose filter slot 2 (Blue) for 15 seconds
            testCamera.exposeLight(15,2,'m51_B')
        # Stop autoguider after all images complete
        testCamera.stopAutoGuide()    
    else:
        print "ERROR - Autoguider not running as expected"

    # Warm the CCD to ambient
    testCamera.warmCCD()
RUNNING THE SCRIPT
Testing this version of the 'cCamera' class using the camera simulator follows the same procedure described in Part 1a of this series. The new listing for 'cCamera' can be downloaded from cCamera_1d.zip. Experiment with the script by changing guide star selection mode (automatic or manual) and/or guide image exposure time to verify the script operates as expected.

WHAT'S NEXT?
This is the final post that will cover the 'cCamera' class (although occasionally new attributes or methods may be added to the class, as needed). In the next post I will begin building the 'cMount' class. This class will interface with methods and attributes provided by the Sky's telescope control and planetarium classes.

CLICK HERE FOR NEXT POST IN THIS SERIES

No comments:

Post a Comment