{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pyscope.observatory import Observatory\n", "from astropy import coordinates as coord\n", "import logging\n", "import time\n", "import numpy as np\n", "import pathlib\n", "from IPython.display import display, clear_output\n", "\n", "# Set up logging\n", "logging.basicConfig(level=logging.DEBUG)\n", "\n", "# Set up after cell logging at debug level\n", "logger = logging.getLogger('pyscope')\n", "logger.setLevel(logging.DEBUG)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "logger.setLevel(logging.INFO)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using this config file to initialize the observatory: ./config/observatory.cfg\n", "INFO:pyscope.observatory.observatory:Using MaxIm DL as the camera driver\n", "INFO:pyscope.observatory.observatory:CCD Temp Set to -10.0\n", "INFO:pyscope.observatory.observatory:Checking passed kwargs and overriding config file values\n", "INFO:pyscope.observatory.observatory:CCD Temp Set to -10.0\n", "INFO:pyscope.observatory.observatory:Camera connected\n", "INFO:pyscope.observatory.observatory:Turning cooler on\n", "INFO:pyscope.observatory.observatory:Cover calibrator connected\n", "INFO:pyscope.observatory.observatory:Filter wheel connected\n", "INFO:pyscope.observatory.observatory:Initial filter: r (position 2)\n", "INFO:pyscope.observatory.observatory:Initial focus offset: 0\n", "INFO:pyscope.observatory.observatory:Focuser connected\n", "INFO:pyscope.observatory.observatory:Telescope connected\n", "INFO:pyscope.observatory.observatory:Unparking telescope...\n", "INFO:pyscope.observatory.observatory:Telescope unparked\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rlmt = Observatory(config_path=\"./config/observatory.cfg\")\n", "rlmt.connect_all()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "save_dir = r\"D:\\scratch\\2025-01-23\"\n", "# Make the save directory if it doesn't exist\n", "pathlib.Path(save_dir).mkdir(parents=True, exist_ok=True)\n", "\n", "def capture_image(filter_name, object_name, exp_time=5, filename_prefix=\"focus\", binning=1):\n", " # # Set binning\n", " rlmt.camera.BinX = binning\n", " rlmt.camera.BinY = binning\n", "\n", " # # Start exposure\n", " print(f\"Starting {int(exp_time)}s exposure...\")\n", " # Set readout mode to 0\n", " rlmt.camera.ReadoutMode = 0\n", " rlmt.camera.StartExposure(exp_time, True)\n", " \n", " # Set up image base filename\n", " exp_time_str = str(exp_time).replace(\".\", \"p\")\n", " filename_base = f\"{filename_prefix}_{object_name}_{exp_time_str}s_{filter_name}\"\n", " # Remove spaces from filename\n", " filename_base = filename_base.replace(\" \", \"_\")\n", " # Check if file exists in save_dir\n", " i = 0\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", " # print(f\"filename.exists() is {filename.exists()}\")\n", " while filename.exists():\n", " # If file exists, add a number to the end of the filename\n", " i += 1\n", " # print(f\"{filename} does exist\")\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", "\n", " # Save latest image\n", " while not rlmt.camera.ImageReady:\n", " time.sleep(0.1)\n", " time.sleep(0.1)\n", " rlmt.save_last_image(filename, \"Light\", overwrite=True)\n", "\n", " return filename" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def change_filter(filter_name):\n", " # Filter key\n", "# 0 - Low res grism; 1 - u; 2 - g; 3 - r; 4 - Ha grism; 5 - i; 6 - z;\n", "# 7 - OIII; 8 - y; 9 - SII; 10 - Ha; 11 - empty\n", " filter_positions = {\"g\": 0, \"low_res_grism\": 1, \"r\": 2, \"i\": 3, \"Ha_grism\": 4, \"ha\": 5, \"dark\": 6}\n", " rlmt.filter_wheel.Position = filter_positions[filter_name] \n", " while rlmt.filter_wheel.is_moving:\n", " time.sleep(0.01) " ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "change_filter(\"r\")" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Filter g found at index 0\n", "INFO:pyscope.observatory.observatory:Setting filter wheel to filter 0\n", "INFO:pyscope.observatory.observatory:Filter wheel set\n", "INFO:pyscope.observatory.observatory:Current focus offset: 0\n", "INFO:pyscope.observatory.observatory:Target focus offset: 0\n", "INFO:pyscope.observatory.observatory:No focuser adjustment needed\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rlmt.set_filter_offset_focuser(filter_index=0)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rlmt.filter_wheel.Unidirectional = True\n", "rlmt.filter_wheel.Unidirectional" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using observatory autofocus routine...\n", "INFO:pyscope.observatory.observatory:Starting autofocus routine...\n", "INFO:pyscope.observatory.observatory:Moving focuser to 8000...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 8500...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 9000...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 9500...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 10000...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 10500...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Moving focuser to 11000...\n", "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Taking 3.0 second exposure...\n", "INFO:pyscope.observatory.observatory:Exposure complete.\n", "INFO:pyscope.observatory.observatory:Calculating mean star fwhm...\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Running PlateSolve2...\n", "INFO:pyscope.observatory.observatory:Best focus position is 10221.0 +/- 272.7\n", "INFO:pyscope.observatory.observatory:Moving focuser to best focus position...\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Results path: C:\\Users\\MACRO\\AppData\\Local\\Temp\\2025-01-24T04-39-03.162\\results.txt\n", "10221, 10.79,272.7\n", "\n", "\n", "['10221', '10.79', '272.7']\n", "Best focus: 10221.0\n", "FWHM: 10.79\n", "Focus error: 272.7\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Focuser moved.\n", "INFO:pyscope.observatory.observatory:Autofocus routine complete.\n" ] }, { "data": { "text/plain": [ "10221.0" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# turn on tracking\n", "rlmt.telescope.Tracking = True\n", "# Start autofocus\n", "rlmt.run_autofocus(exposure=3.0, midpoint=9500, nsteps=7, step_size=500, use_current_pointing=True, binning=2)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Attempt 1\n", "Moving to g filter\n", "Starting 5s exposure...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "WARNING: VerifyWarning: Card is too long, comment will be truncated. [astropy.io.fits.card]\n", "WARNING:astroquery:VerifyWarning: Card is too long, comment will be truncated.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Moving to r filter\n", "Starting 5s exposure...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Moving to Ha filter\n", "Starting 5s exposure...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Moving to low res grism\n", "Starting 5s exposure...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Moving to Ha grism\n", "Starting 5s exposure...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Attempt 2\n", "Moving to g filter\n", "Starting 5s exposure...\n" ] }, { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[33], line 6\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMoving to g filter\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 5\u001b[0m change_filter(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mg\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m----> 6\u001b[0m filename \u001b[38;5;241m=\u001b[39m \u001b[43mcapture_image\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mg\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mnorth\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexp_time\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfilename_prefix\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdriver_test\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbinning\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 7\u001b[0m \u001b[38;5;66;03m# Move to r filter\u001b[39;00m\n\u001b[0;32m 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMoving to r filter\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", "Cell \u001b[1;32mIn[22], line 35\u001b[0m, in \u001b[0;36mcapture_image\u001b[1;34m(filter_name, object_name, exp_time, filename_prefix, binning)\u001b[0m\n\u001b[0;32m 31\u001b[0m \u001b[38;5;66;03m# print(f\"Checking if {filename} exists...\")\u001b[39;00m\n\u001b[0;32m 32\u001b[0m \n\u001b[0;32m 33\u001b[0m \u001b[38;5;66;03m# Save latest image\u001b[39;00m\n\u001b[0;32m 34\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m rlmt\u001b[38;5;241m.\u001b[39mcamera\u001b[38;5;241m.\u001b[39mImageReady:\n\u001b[1;32m---> 35\u001b[0m \u001b[43mtime\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msleep\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m0.1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 36\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m0.1\u001b[39m)\n\u001b[0;32m 37\u001b[0m rlmt\u001b[38;5;241m.\u001b[39msave_last_image(filename, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mLight\u001b[39m\u001b[38;5;124m\"\u001b[39m, overwrite\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", "\u001b[1;31mKeyboardInterrupt\u001b[0m: " ] } ], "source": [ "for i in range(1):\n", " print(f\"Attempt {i+1}\")\n", " # Move to g filter\n", " print(\"Moving to g filter\")\n", " change_filter(\"g\")\n", " filename = capture_image(\"g\", \"north\", exp_time=5, filename_prefix=\"driver_test\", binning=2)\n", " # Move to r filter\n", " print(\"Moving to r filter\")\n", " change_filter(\"r\")\n", " filename = capture_image(\"r\", \"north\", exp_time=5, filename_prefix=\"driver_test\", binning=2)\n", " # Move to Ha filter\n", " print(\"Moving to Ha filter\")\n", " change_filter(\"ha\")\n", " filename = capture_image(\"Ha\", \"north\", exp_time=5, filename_prefix=\"driver_test\", binning=2)\n", " # Move to low res grism\n", " print(\"Moving to low res grism\")\n", " change_filter(\"low_res_grism\")\n", " filename = capture_image(\"low_res_grism\", \"north\", exp_time=5, filename_prefix=\"driver_test\", binning=2)\n", " # Move to Ha grism\n", " print(\"Moving to Ha grism\")\n", " change_filter(\"Ha_grism\")\n", " filename = capture_image(\"Ha_grism\", \"north\", exp_time=5, filename_prefix=\"driver_test\", binning=2)\n", " clear_output" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Center on object (run both cells below)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "save_dir = \"grism_images_2024-01-23\"\n", "# Make the save directory if it doesn't exist\n", "pathlib.Path(save_dir).mkdir(parents=True, exist_ok=True)\n", "\n", "def capture_grism_image(filter_name, object_name, exp_time=5, filename_prefix=\"focus\", binning=1):\n", " # # Set binning\n", " rlmt.camera.BinX = binning\n", " rlmt.camera.BinY = binning\n", "\n", " # # Start exposure\n", " print(f\"Starting {int(exp_time)}s exposure...\")\n", " rlmt.camera.StartExposure(exp_time, True)\n", " \n", " # Set up image base filename\n", " exp_time_str = str(exp_time).replace(\".\", \"p\")\n", " filename_base = f\"{filename_prefix}_{object_name}_{exp_time_str}s_{filter_name}\"\n", " # Remove spaces from filename\n", " filename_base = filename_base.replace(\" \", \"_\")\n", " # Check if file exists in save_dir\n", " i = 0\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", " # print(f\"filename.exists() is {filename.exists()}\")\n", " while filename.exists():\n", " # If file exists, add a number to the end of the filename\n", " i += 1\n", " # print(f\"{filename} does exist\")\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", "\n", " # Save latest image\n", " while not rlmt.camera.ImageReady:\n", " time.sleep(0.1)\n", " time.sleep(0.1)\n", " rlmt.save_last_image(filename, \"Light\", overwrite=True)\n", "\n", " return filename" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "RA: hms_tuple(h=5.0, m=14.0, s=32.272096080005355),\n", "Dec: dms_tuple(d=-8.0, m=-12.0, s=-5.898114000003147)\n", "\n", "Elevation: 49.87, Azimuth: 187.77\n", "Elevation dms: dms_tuple(d=49.0, m=52.0, s=6.963279416651176), \n", "Azimuth dms: dms_tuple(d=187.0, m=46.0, s=23.184752042973287)\n" ] } ], "source": [ "# Get more on NGC4151 (120s in Ha grism)\n", "object_name = \"Rigel\" # Change name here\n", "#src = coord.SkyCoord(\"19h21m09.2835s -03d44m26.2962s\", frame='icrs')\n", "src = coord.SkyCoord.from_name(object_name)\n", "print(f\"RA: {src.ra.hms},\\nDec: {src.dec.dms}\")\n", "print(src)\n", "# Print alt az of source\n", "src_altaz = rlmt.get_object_altaz(src)\n", "print(f\"Elevation: {src_altaz.alt.deg:.2f}, Azimuth: {src_altaz.az.deg:.2f}\")\n", "print(f\"Elevation dms: {src_altaz.alt.dms}, \\nAzimuth dms: {src_altaz.az.dms}\")\n", "if src_altaz.alt.deg < 30:\n", " raise Exception(\"Source is too low to observe.\")\n", " \n", "# tete_coords = src.transform_to(coord.TETE(obstime = rlmt.observatory_time, location=rlmt.observatory_location))\n", "# print(tete_coords)\n", "# print(f\"RA: {tete_coords.ra.hms},\\nDec: {tete_coords.dec.dms}\")" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pyscope.observatory.observatory:Attempting to put 05h14m32.27209608s -08d12m05.898114s on pixel (2394.00, 1597.00)\n", "INFO:pyscope.observatory.observatory:Attempt 1 of 5\n", "INFO:pyscope.observatory.observatory:Slewing to RA hms_tuple(h=5.0, m=14.0, s=32.27209608000855) and Dec dms_tuple(d=-8.0, m=-12.0, s=-5.898114000003147)\n", "INFO:pyscope.observatory.observatory:Turning on sidereal tracking...\n", "INFO:pyscope.observatory.observatory:Sidereal tracking is on.\n", "INFO:pyscope.observatory.observatory:Attempting to slew to coordinates...\n", "INFO:pyscope.observatory.observatory:Slewing to RA 5.26270 and Dec -8.17389\n", "INFO:pyscope.observatory.observatory:Settling for 3.00 seconds...\n", "INFO:pyscope.observatory.observatory:Settling for 3.00 seconds\n", "INFO:pyscope.observatory.observatory:Taking 5.00 second exposure\n", "INFO:pyscope.observatory.observatory:Exposure complete\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Searching for a WCS solution\n", "INFO:pyscope.observatory.observatory:Pixel scale is 0.22 arcseconds per pixel\n", "INFO:pyscope.reduction.maxim_pinpoint_wcs:Attempting to solve C:\\Users\\MACRO\\AppData\\Local\\Temp2025-01-24T04-43-58.073.fts\n", "INFO:pyscope.reduction.maxim_pinpoint_wcs:Solve successful\n", "ERROR:pyscope.reduction.maxim_pinpoint_wcs:Solve failed: 'bool' object is not callable, saving unsolved image\n", "INFO:pyscope.observatory.observatory:Saving the centering image to recenter_images\\Temp2025-01-24T04-43-58.073.fts\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:WCS solution found, solving for the pixel location of the target\n", "WARNING: FITSFixedWarning: RADECSYS= 'FK5 ' / Equatorial coordinate system \n", "the RADECSYS keyword is deprecated, use RADESYSa. [astropy.wcs.wcs]\n", "WARNING:astroquery:FITSFixedWarning: RADECSYS= 'FK5 ' / Equatorial coordinate system \n", "the RADECSYS keyword is deprecated, use RADESYSa.\n", "WARNING: FITSFixedWarning: 'datfix' made the change 'Set MJD-OBS to 60699.196971 from DATE-OBS'. [astropy.wcs.wcs]\n", "WARNING:astroquery:FITSFixedWarning: 'datfix' made the change 'Set MJD-OBS to 60699.196971 from DATE-OBS'.\n", "INFO:pyscope.observatory.observatory:Error in RA is -33.85 arcseconds\n", "INFO:pyscope.observatory.observatory:Error in Dec is -28.24 arcseconds\n", "INFO:pyscope.observatory.observatory:Error in x pixels is -74.84\n", "INFO:pyscope.observatory.observatory:Error in y pixels is -61.79\n", "INFO:pyscope.observatory.observatory:Offsetting next slew coordinates\n", "INFO:pyscope.observatory.observatory:\n", "INFO:pyscope.observatory.observatory:Attempt 2 of 5\n", "INFO:pyscope.observatory.observatory:Slewing to RA hms_tuple(h=5.0, m=14.0, s=30.01565326854866) and Dec dms_tuple(d=-8.0, m=-12.0, s=-34.13637460266614)\n", "INFO:pyscope.observatory.observatory:Turning on sidereal tracking...\n", "INFO:pyscope.observatory.observatory:Sidereal tracking is on.\n", "INFO:pyscope.observatory.observatory:Attempting to slew to coordinates...\n", "INFO:pyscope.observatory.observatory:Slewing to RA 5.26207 and Dec -8.18172\n", "INFO:pyscope.observatory.observatory:Settling for 3.00 seconds...\n", "INFO:pyscope.observatory.observatory:Settling for 3.00 seconds\n", "INFO:pyscope.observatory.observatory:Taking 5.00 second exposure\n", "INFO:pyscope.observatory.observatory:Exposure complete\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:Searching for a WCS solution\n", "INFO:pyscope.observatory.observatory:Pixel scale is 0.22 arcseconds per pixel\n", "INFO:pyscope.reduction.maxim_pinpoint_wcs:Attempting to solve C:\\Users\\MACRO\\AppData\\Local\\Temp2025-01-24T04-44-34.721.fts\n", "INFO:pyscope.reduction.maxim_pinpoint_wcs:Solve successful\n", "ERROR:pyscope.reduction.maxim_pinpoint_wcs:Solve failed: 'bool' object is not callable, saving unsolved image\n", "INFO:pyscope.observatory.observatory:Saving the centering image to recenter_images\\Temp2025-01-24T04-44-34.721.fts\n", "INFO:pyscope.observatory.observatory:Using Maxim to save image\n", "INFO:pyscope.observatory.observatory:Overwrite allowed for header keys ['AIRMASS', 'OBJECT', 'TELESCOP', 'INSTRUME', 'OBSERVER']\n", "INFO:pyscope.observatory.observatory:Getting header from MaxIm image\n", "WARNING: NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation. [astropy.coordinates.baseframe]\n", "WARNING:astroquery:NonRotationTransformationWarning: transforming other coordinates from to . Angular separation can depend on the direction of the transformation.\n", "INFO:pyscope.observatory.observatory:WCS solution found, solving for the pixel location of the target\n", "WARNING: FITSFixedWarning: 'datfix' made the change 'Set MJD-OBS to 60699.197387 from DATE-OBS'. [astropy.wcs.wcs]\n", "WARNING:astroquery:FITSFixedWarning: 'datfix' made the change 'Set MJD-OBS to 60699.197387 from DATE-OBS'.\n", "INFO:pyscope.observatory.observatory:Error in RA is -0.13 arcseconds\n", "INFO:pyscope.observatory.observatory:Error in Dec is 0.75 arcseconds\n", "INFO:pyscope.observatory.observatory:Error in x pixels is -0.22\n", "INFO:pyscope.observatory.observatory:Error in y pixels is 1.62\n", "INFO:pyscope.observatory.observatory:Target is now in position after 2 attempts\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Set to g filter\n", "rlmt.filter_wheel.Position = 0\n", "time.sleep(3)\n", "while rlmt.focuser.IsMoving:\n", " time.sleep(0.5)\n", "\n", "# Run recentering algorithm\n", "if src_altaz.alt.deg < 30:\n", " raise Exception(\"Source is too low to observe.\")\n", "rlmt.repositioning(src, \n", " target_x_pixel=2394, # TODO: make default center of sensor in each axis\n", " target_y_pixel=1597,\n", " exposure=5, \n", " save_images=True,\n", " save_path=\"./recenter_images/\",\n", " readout=0,\n", " binning=2,\n", " solver=\"maxim_pinpoint_wcs\"\n", ")" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "# Change filter to Ha grism\n", "# change_filter(\"Ha_grism\")\n", "change_filter(\"low_res_grism\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Setup for Focus position movement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Change values in cell below" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Focus positions are [ 6721 6921 7121 7321 7521 7721 7921 8121 8321 8521 8721 8921\n", " 9121 9321 9521 9721 9921 10121 10321 10521 10721 10921 11121 11321\n", " 11521 11721 11921 12121 12321 12521 12721 12921 13121 13321 13521 13721], there are 36 positions\n", "Filter wheel is at (or moving to) position 1\n" ] } ], "source": [ "# Image save directory\n", "save_dir = \"focus_images_ZWO_2025-01-23\"\n", "# Make the save directory if it doesn't exist\n", "pathlib.Path(save_dir).mkdir(parents=True, exist_ok=True)\n", "\n", "# Set up focuser position list\n", "# Start at min, end at max, step by focus_step\n", "min_focus = 6721 # Minimum focus position\n", "max_focus = 13921 # Maximum focus position\n", "focus_step = 200\n", "\n", "# Filter positions DO NOT CHANGE\n", "filter_positions = {\n", " \"LowRes\": 1,\n", " \"HighRes\": 4,\n", " \"g\": 0,\n", "}\n", "\n", "# Camera and filter wheel settings (use filter names from above)\n", "num_images = 3 # Images at each focus position\n", "exp_time = 0.6\n", "filter_name = \"LowRes\" # This is the filter that will be used\n", "\n", "# Move filter wheel to position\n", "rlmt.filter_wheel.Position = filter_positions[filter_name]\n", "\n", "# Print for verification\n", "focus_positions = np.arange(min_focus, max_focus, focus_step)\n", "print(f\"Focus positions are {focus_positions}, there are {len(focus_positions)} positions\")\n", "print(f\"Filter wheel is at (or moving to) position {rlmt.filter_wheel.Position}\")" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "def capture_focus_image(focus_position, filter_name, exp_time=5, filename_prefix=\"focus\", binning=1):\n", " # # Set binning\n", " rlmt.camera.BinX = binning\n", " rlmt.camera.BinY = binning\n", "\n", " # # Start exposure\n", " print(f\"Starting {int(exp_time)}s exposure...\")\n", " rlmt.camera.StartExposure(int(exp_time), True)\n", " \n", " # Set up image base filename\n", " exp_time_str = str(exp_time).replace(\".\", \"p\")\n", " filename_base = f\"{filename_prefix}_{focus_position}_{exp_time_str}s_{filter_name}\"\n", " # Check if file exists in save_dir\n", " i = 0\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", " # print(f\"filename.exists() is {filename.exists()}\")\n", " while filename.exists():\n", " # If file exists, add a number to the end of the filename\n", " i += 1\n", " # print(f\"{filename} does exist\")\n", " filename = pathlib.Path(save_dir) / f\"{filename_base}_{i}.fts\"\n", " # print(f\"Checking if {filename} exists...\")\n", "\n", " # Save latest image\n", " while not rlmt.camera.ImageReady:\n", " time.sleep(0.1)\n", " time.sleep(0.1)\n", " rlmt.save_last_image(filename, \"Light\", overwrite=True)\n", "\n", " return filename" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "# Focus at each position\n", "focus_move_time = 10\n", "img_download_time = 16\n", "focus_image_time = exp_time + img_download_time\n", "\n", "# Estimate total time required\n", "total_time = (\n", " focus_move_time * len(focus_positions)\n", ") + focus_image_time * num_images * len(focus_positions)\n", "print(f\"Estimated total time required is {total_time/60} minutes\")\n", "\n", "time_per_cycle = []\n", "\n", "for focus_position in focus_positions:\n", " if time_per_cycle:\n", " print(f\"Average time per cycle is {np.mean(time_per_cycle):.2f} seconds\")\n", " est_time_remaining = np.mean(time_per_cycle) * (\n", " len(focus_positions) - np.where(focus_positions == focus_position)[0][0]\n", " )\n", " # Print time remaining in minutes and seconds\n", " print(\n", " f\"Estimated time remaining is {est_time_remaining//60:.0f} min {est_time_remaining%60:.0f} sec\"\n", " )\n", " start_time = time.time()\n", " print(f\"Moving to focus position {focus_position}\")\n", "\n", " print(\n", " f\"This is position {np.where(focus_positions == focus_position)[0][0]+1} of {len(focus_positions)}\"\n", " )\n", " rlmt.focuser.Move(focus_position)\n", " while rlmt.focuser.IsMoving:\n", " #print(f\"Focuser is moving to {focus_positions[0]}\")\n", " time.sleep(0.1)\n", " #current_focus = int(rlmt.focuser.Position)\n", " current_focus = focus_position\n", " print(f\"Focus position is {current_focus}\")\n", " print(\"========================================\")\n", "\n", " current_exp_time = exp_time\n", " print(f\"current_exp_time={current_exp_time}\")\n", "\n", " for i in range(num_images):\n", " img_file = capture_focus_image(current_focus, filter_name, exp_time=current_exp_time, filename_prefix=\"focus\", binning=2)\n", " print(f\"Saved image {i} at focus position {current_focus}\")\n", "\n", " end_time = time.time()\n", " time_per_cycle.append(end_time - start_time)\n", "\n", " # Clear cell output for next loop\n", " clear_output()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "pyscope-dev", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 2 }