Scripting with GoQat - 3

As a final example of running a script from GoQat's task queue, here's a simple way of performing all-sky monitoring, perhaps with a fish-eye lens on a camera, that adjusts itself according to day or night.

Eye on the sky - the task queue

Click the 'Clear tasks' button on the Tasks tab, click the 'Load tasks from file...' button in the task editing window, navigate to /usr/local/share/GoQat/data/examples and pick tasks_eye_on_the_sky.txt. It looks like this:

SetParam 0 55000 SetParam 1 3000
SetParam 8 1
SetParam 9 0
While 1
SetParam 2 30
While %8 Expose TARGET - %2 1 1 1000 1000 1 1 0 Exec /usr/local/share/GoQat/data/examples/eye_on_the_sky.sh PauseFor 600 EndWhile
While %9 Expose TARGET - %2 1 1 1000 1000 1 1 0 Exec /usr/local/share/GoQat/data/examples/eye_on_the_sky.sh EndWhile
EndWhile

Parameter 0 is set to 55000 which is the maximum value that we'd like in the exposure. Parameter 1 is set to 3000 - this is a 'twilight' value. If the modal (most likely) pixel value is less than this, then it's nighttime - otherwise it's daytime. Parameter 8 is a flag that governs the operation of the first While loop shown in blue. Parameter 9 governs the operation of the second While loop shown in green. The blue loop is the daytime loop and the green loop is the nighttime loop. We start by setting parameter 8 to '1' and assume it's daytime. The eye_on_the_sky.sh script will work out whether it really is daytime or nighttime and set the values of parameters 8 and 9 accordingly. We would like the whole thing to run indefinitely so it can be left unattended as an all-sky monitor, so we wrap the daytime and nighttime While loops in an outer While...EndWhile loop shown in yellow. Since this loop begins with 'While 1' it will be executed perpetually. Just after this outer loop starts, we set parameter 2 to the desired initial exposure length of 30 seconds.

So what does it do? When the task queue first starts, parameter 8 is set to '1', so the daytime loop in blue will run with an exposure time of 30 seconds. The eye_on_the_sky.sh script tests to see if the modal value in the image is greater or less than the twilight value in parameter 1. If it's less than the twilight value for three successive exposures, then it's assumed to be nighttime and the script will set parameter 8 to '0' and parameter 9 to '1' to switch over to the nighttime loop in green. If the modal value is greater than the twilight value for three successive exposures the script will set parameters 8 and 9 to '1' and '0' respectively to switch back to the blue daytime loop. During daytime, the task queue pauses for 600 seconds between exposures but during nighttime the exposures are made with no intervening delay. In nighttime mode, the script will adjust the exposure time to give a maximum value close to the value given for parameter 0. If you choose to save each image, the script will automatically delete the daytime ones. It can do this because the name of the most recently saved image is always passed to any script by GoQat.

Eye on the sky - the script

Let's look at the script bit by bit to see what it does.

This first section is common to all script files and assigns the items that GoQat passes to the script to variables or arrays within the script. This section should be left as it is, apart from altering the variable names if you wish. This is a bash script, but you could write something functionally equivalent in the language of your choice.

#! /bin/sh # ------------------------------------------------------------------------ # | | # | An example shell script to read values from GoQat, and pass back | # | some parameters. | # | | # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ # | | # | START OF VARIABLE ASSIGNMENT SECTION | # | | # | Keep the following section in your scripts. This section obtains | # | values from GoQat and assigns them to named variables. (Of course, | # | you can change these variable names if you wish). | # | | # ------------------------------------------------------------------------ a=0 args=("$@") sync=${args[a++]} # 1 if synchronous, 0 if asynchronous results_file=${args[a++]} # If synchronous, name of file read by GoQat # when script finishes done_file=${args[a++]} # If synchronous, script must create this file # to indicate it has finished num_task_params=${args[a++]} # Number of task parameters (%0, %1... etc) for ((i=0;i<$num_task_params;i++)); do task_params[i]=${args[a++]} # Array containing task parameters done Expose_image_file=${args[a++]} # Name of most recently saved FITS file Expose_exposure_type=${args[a++]} # Exposure type Expose_filter=${args[a++]} # Exposure filter Expose_seconds=${args[a++]} # Exposure length Expose_H1=${args[a++]} # Exposure H1 coordinate Expose_V1=${args[a++]} # Exposure V1 coordinate Expose_H2=${args[a++]} # Exposure H2 coordinate Expose_V2=${args[a++]} # Exposure V2 coordinate Expose_Hbin=${args[a++]} # H-binning Expose_Vbin=${args[a++]} # V-binning Expose_degC=${args[a++]} # Chip temperature Expose_min_grey=${args[a++]} # Minimum pixel value in exposure (if monochrome) Expose_max_grey=${args[a++]} # Maximum pixel value in exposure (if monochrome) Expose_mean_grey=${args[a++]} # Mean pixel value in exposure (if monochrome) Expose_mode_grey=${args[a++]} # Modal pixel value in exposure (if monochrome) Coords_RA=${args[a++]} # Current RA position of telescope Coords_Dec=${args[a++]} # Current Dec position of telescope Focus_max_travel=${args[a++]} # Maximum travel of focuser Focus_cur_pos=${args[a++]} # Current focuser postion Focus_temp=${args[a++]} # Current focuser temperature Workspace=${args[a++]} # Workspace # ------------------------------------------------------------------------ # | | # | END OF VARIABLE ASSIGNMENT SECTION | # | | # ------------------------------------------------------------------------

The second section is the interesting part - it's where you get to write your own commands. The first thing to do is assign the current values for parameters 0, 1, 2, 8 and 9 to named variables in the script - it makes it easier to understand.

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # > > # > START OF YOUR OWN COMMANDS > # > > # > Execute your own commands below. These can be anything that you > # > can do in a bash script. > # > > # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # Set some variables using the values that GoQat has passed for parameters # 0, 1, 2, 8 and 9. max_value=${task_params[0]} twilight_value=${task_params[1]} exposure_length=${task_params[2]} daytime_flag=${task_params[8]} nighttime_flag=${task_params[9]}

The script uses a couple of variables ('day_count' and 'night_count') to count the number of successive exposures for which the modal value has been greater or less than the twilight value, up to a maximum of three. These values are stored in the Workspace variable which is just a character string of up to 127 characters used for anything the script wants to remember between invocations. When the task queue starts, the Workspace variable contains nothing so we have to test for that and set the 'day_count' and 'night_count' variables to sensible initial values.

# day_count and night_count are working variables that need to be saved between one # invocation of the script and the next. Read these values from the Workspace # variable. # When the script is first called, these values will be blank, so test for this and # initialise them to something sensible. read day_count night_count <<<"$Workspace" if [ -z "$day_count" ]; then day_count=0 fi if [ -z "$night_count" ]; then night_count=0 fi

Now we can test to see if it's daytime or nighttime. Remember that we set the 'daytime_flag' variable equal to the value of parameter 8 above, so if this equals zero then it's nighttime. If so, we wait until there have been three sucessive exposures with the modal value greater than the twilight value before switching to the daytime settings.

# If it isn't daytime, test whether the modal value in the most recent exposure is # greater than the twilight value.
# If it is, increment the day_count variable up to a maximum of 3.
# If it isn't, decrement the day_count variable down to a minimum of 0.
# If there have been 3 consecutive exposures where the modal value is greater than # the twilight value, assume it's daytime. So set daytime_flag, unset # nighttime_flag and reset day_count to 0.
if [ $daytime_flag -eq 0 ]; then if [ $Expose_mode_grey -ge $twilight_value ]; then
let day_count=$day_count+1
if [ $day_count -eq 3 ]; then daytime_flag=1 day_count=0 nighttime_flag=0 fi
else
if [ $day_count -gt 0 ]; then let day_count=$day_count-1 fi
fi fi

If it is daytime, we can delete the image files (assuming we've set them to be autosaved on GoQat's Files tab).

# If it's daytime, we don't need to keep the image file, so let's delete it. # If the file doesn't exist, send any error messages to oblivion, a.k.a. /dev/null if [ $daytime_flag -eq 1 ]; then rm $Expose_image_file 2> /dev/null fi

Now we can check to see if it might be nighttime - this is just like the daytime test but the other way round!

# This is as for daytime above, but here we're testing to see if it's nighttime. if [ $nighttime_flag -eq 0 ]; then if [ $Expose_mode_grey -lt $twilight_value ]; then
let night_count=$night_count+1
if [ $night_count -eq 3 ]; then nighttime_flag=1 night_count=0 daytime_flag=0 fi
else
if [ $night_count -gt 0 ]; then let night_count=$night_count-1 fi
fi fi

If it is nighttime we can adjust the exposure length to make the maximum value not more than the requested value in parameter 0 (recall that we set the 'max_value' variable to the value of parameter 0 above). This is just a very simple reduction in the exposure length until the right value is reached. Note that when the task queue switches back to the daytime loop it resets parameter 2 (the exposure length) to 30 seconds.

This is the end of our task queue commands.

# If it's nighttime and the sky as a whole isn't getting brighter (i.e. if # day_count is 0), then adjust the exposure length for each successive exposure # until the maximum value is less than max_value. Note the use of the 'bc' # command to do non-integer arithmetic. if [ $nighttime_flag -eq 1 ] && [ $day_count -eq 0 ]; then if [ $Expose_max_grey -gt $max_value ]; then exposure_length=`bc<<<"$exposure_length * 0.75"` fi fi # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # < < # < END OF YOUR OWN COMMANDS < # < < # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Finally we want to return some values to GoQat. This following part of the script is common to all scripts and should not be altered. If the script is being executed synchronously, which this one is, GoQat will pass in a value of '1' for the 'sync' variable. The 'results_file' variable contains the name of the file that you write to in order to return values to GoQat. You don't need to know what this file name actually is.

# ------------------------------------------------------------------------ # | | # | START OF RESULTS SECTION FOR SYNCHRONOUS SCRIPTS | # | | # | If your script is being run synchronously, you must include both | # | sections below that are surrounded by '#' characters. You should | # | add any bash code between these two sections to return values to | # | GoQat. The name of the results file that GoQat will read is held in | # | the results_file variable. You don't need to know what the actual | # | file name is; just 'print' results to it as shown below. | # | | # | To return a parameter value, begin the line with '%Num' where 'Num' | # | is the parameter number. Each parameter must be returned on a | # | separate line. For example, to return the value of variable var1 | # | as parameter number 3: | # | | # | print (RESULTS "%3 $var1\n"); | # | | # | To return any temporary working variables to GoQat, begin the line | # | with '@' and return all the variables in one go. For example: | # | | # | print (RESULTS "@ $var1 $var2 $var3\n"); | # | | # | ...will return the values of variables var1, var2, and var3 to GoQat.| # | GoQat will pass these variables back again in the Workspace variable | # | for each subsequent execution of a script while the task queue is | # | running. Re-starting the task queue clears out the Workspace | # | variable. | # | | # | Any other line is treated as a comment and will be displayed in green| # | in GoQat's log window. For example: | # | | # | print (RESULTS "Focuser is now at position $Focus_cur_pos\n"); | # | | # ------------------------------------------------------------------------ ########################################################################## # # # RETURN ANY RESULTS OF SYNCHRONOUS SCRIPT EXECUTION BELOW # # # if [ $sync -eq 1 ]; then # touch $results_file # Create the results file # # # ##########################################################################

Here we return some comments (in green) for GoQat to display. Anything we write to 'results_file' is shown in the log window unless it begins with '%' or '@'. We also need to return values for some of the parameters so that the task queue knows whether to run the daytime or nighttime loop and what exposure length to use. To do that, we write the parameter number preceded by '%' and then the parameter value to the log file, with one parameter per line (in blue). Here we set parameter 2 to the current value of the exposure length, parameter 8 to the value of the daytime flag and parameter 9 to the value of the nighttime flag. We also want to save our counting variables containing the number of successive exposures with modal values above or below the twilight value. So we write these preceded by a '@' (in yellow). Any working variables that we want to save must be written in one go, not on separate lines. These values are passed back to us in the Workspace variable when the script is next called.

# Write some comments to the results file to keep the user informed echo "Maximum value in exposure is $Expose_max_grey" >> $results_file echo "Modal value in exposure is $Expose_mode_grey" >> $results_file if [ $daytime_flag -eq 1 ]; then echo "It's daytime" >> $results_file fi if [ $nighttime_flag -eq 1 ]; then echo "It's nighttime" >> $results_file echo "Using a nighttime exposure length" \ "of $exposure_length seconds" >> $results_file fi if [ $day_count -gt 0 ] && [ $nighttime_flag -eq 1 ]; then echo "$day_count exposure(s) with modal value greater" \ "than $twilight_value - it might be daytime!" >> $results_file fi if [ $night_count -gt 0 ] && [ $daytime_flag -eq 1 ]; then echo "$night_count exposure(s) with modal value less" \ "than $twilight_value - it might be nighttime!" >> $results_file fi # Write the parameter values to the results file. GoQat will use these values # when executing the task queue. echo "%2 $exposure_length" >> $results_file echo "%8 $daytime_flag" >> $results_file echo "%9 $nighttime_flag" >> $results_file # Save the working variables. GoQat will pass these back again in the Workspace # variable when the script is next called. echo "@ $day_count $night_count" >> $results_file

The script ends by creating a file whose name is held in the 'done_file' variable. GoQat passes the file name to the script - we don't need to know what it is. GoQat knows that the script has finished executing when this file is created and it then reads the 'results_file' to obtain any values that the script is passing back. Your scripts should always end with this section.

########################################################################## # # # IF THE SCRIPT IS BEING RUN SYNCHRONOUSLY, CREATE THE FILE THAT # # INDICATES TO GOQAT THAT THE SCRIPT HAS FINISHED # # # touch $done_file # fi # # # ########################################################################## exit 0

So that's it - it looks quite complicated but it isn't really. Have a look at demo1.sh, demo2.sh and demo3.sh supplied with GoQat for some simpler examples. There's also a Perl equivalent of demo1 - demo1.pl - if that's what you prefer.