Research
DICS: The DAzLE Instrument Control System
changelogThis page contains instructions for the normal operation of the DAzLE instrument using the DICS command line interface. Some commands only used during software development are not documented here.
It would be helpful (though not necessarily essential) for the user to have some experience with Python. The best way to quickly get an idea of the basics is to run through the excellent (and not too long) official tutorial.
A local copy is here: [ html ] [ pdf ]
Contents
INI File and LoggingStartup/Shutdown
Cortex Interface
'Linear' Mechanisms
Detector Focus
Filter Wheels
Rotator Control
Detector Control
Temperature Logging
Extending DICS
INI File and Logging
DICS used a INI style config file, much like that used by the CIRPASS control software, CirICS. This is used both for adjustable parameters (such as motor speeds and accelerations) and for storing status information (such as mechanism positions) when DICS is shutdown.
The config file, dics.ini, consists of sections (marked with [section name]) which have a list of entries in the form of item = value lines. The format for most of these sections are described later in this document when discussing particular types of mechanisms, however there are two system level entries that the user may want to adjust which relate to the DICS logging system.
[handler_console] class = StreamHandler level = INFO formatter = basic args = () [handler_file] class = FileHandler level = DEBUG formatter = basic args = ('dics.log', 'w')
During operation the various components of DICS generate a number of time-stamped messages with one of four priorities, DEBUG, INFO, WARNING and CRITICAL. Messages of a certain priotity and above are displayed on the terminal from which DICS is being run and also saved as a dics.log log file which serves as a record of the most recent DICS session. The threshold priorities for the terminal and the log file are set by the level entries of the [handler_console] and [handler_file] sections in the dics.ini file. For normal use the terminal should be set to display messages of INFO priority and above, however if problems are encountered then the DEBUG messages will give much more information about what is happening.
Startup/Shutdown
First login to the DAzLE instrument control computer (optics25 while DAzLE is in the IoA lab) and change to the DICS directory (currently /home/optics/dazle/dics/dics).
[horton@optics01 ~]$ ssh -X optics@optics25 optics@optics25's password: Last login: Wed Aug 24 14:09:35 2005 from optics01.ast.cam.ac.uk [optics@optics25 ~]$ cd dazle/dics/dics
Start up the Python interpreter, import the dics module and create the dics.instrument object.
[optics@optics25 dics]$ python Python 2.3.4 (#1, Feb 22 2005, 04:09:37) [GCC 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import dics >>> dazle = dics.instrument() 2005-08-25 15:46:28,593 dazle INFO Creating cortex object cortex_1 2005-08-25 15:46:28,594 cortex_1 INFO Connected to serial port /dev/ttyS0 2005-08-25 15:46:28,714 dazle INFO Creating linear object coll_focus 2005-08-25 15:46:28,715 coll_focus INFO Assigned to ICU 1, axis 3 of cortex_1 2005-08-25 15:46:28,715 dazle INFO Creating filterwheel object mask_wheel 2005-08-25 15:46:28,716 mask_wheel INFO Assigned to ICU 1, axis 1 of cortex_1 2005-08-25 15:46:28,716 dazle INFO Creating filterwheel object nb_wheel 2005-08-25 15:46:28,717 nb_wheel INFO Assigned to ICU 1, axis 2 of cortex_1 >>>
This will cause DICS to parse the dics.ini file then create and initialise all the sub-systems described. In the example above the INI file had entries for the cortex interface, the collimator focus and both of the coldroom filter/mask wheels.
In order to shut down DICS simply press control-D in the Python interpreter window. This will prompt DICS to save all current status information to the dics.ini file before the interpreter exits.
>>> 2005-08-25 16:08:34,299 dazle INFO Opening config file dics.ini... 2005-08-25 16:08:34,301 dazle INFO Config saved. [optics@optics25 dics]$
Cortex Interface
This module provides a low level engineering interface to the cortex stepper motor control card which forms part of the DAzLE ICUs, and the higher level modules use it to access the hardware. There should be no reason for the user to use the functions of this module directly, however they will need to ensure that its settings in the INI file are correct for DICS to function correctly.
Further information about this part of DICS can be obtained from the extensive comments in the file cortex.py [see also the pydoc generated cortex.html file].
INI file entries
[cortex] instances = cortex_1
Each ICU directly connected to a serial port should be named in a comma seperated (no spaces) list in the instances entry of the cortex section. In this example there is only one, named cortex_1.
[cortex_1] portname = /dev/ttyS0 units = 2
The correspondingly named section needs two entries, portname and units. DICS correctly handles daisy-chained ICUs, however it needs to know how many ICUs there are in the chain, and this should entered into the units entry. portname is the linux device name of the serial port that the ICU is connected to.
'Linear' Mechanisms
The collimator focus, fold mirror tilt & turn and the three individual detector focus mechanisms are controlled using the 'linear' mechanism interface.
Additional information about this module can be found in the extensive comments in the files linear.py , mechanism.py [see also the pydoc generated linear.html and mechanism.html files].
INI file entries
[linear] instances = coll_focus,det1,det2,det3
The mechanisms are listed in a comma seperated list (no spaces) in the linear section. In order to temporarily disable a mechanism (e.g. one that isn't currently connected) simply remove its name from the list.
[coll_focus] cortex = cortex_1 icu_num = 1 axis_num = 3 base_speed = 62.0 max_speed = 100.0 acceleration = 62.0 deceleration = 62.0 position = 0.0 lower_limit = -110.0 upper_limit = 110.0 units = 1.0
The sections describing each mechanism need the following entries:
- cortex
The name of the cortex interface corresponding to the daisy chain of ICUs that the mechanism is connected to.
- icu_num
The position of the ICU that the mechanism is connected to in the daisy chain.
- axis_num
Which axis of the ICU that the mechanism is connected to.
- base_speed
The starting speed for the motor, in units/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- max_speed
The top speed for the motor, in units/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- acceleration
The acceleration for the motor, in units/s/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- deceleration
The deceleration for the motor, in units/s/s Must be at least 62 half-steps/s otherwise the ICU will reject it.
- position
The current position of the mechanism, in units.
- lower_limit
The position of the lower software limit on the range of movement, in units.
- upper_limit
The position of the upper software limit on the range of movement, in units.
- units
The number of half-steps of the motor corresponding to one 'unit', as used by all the motion parameters.
Commands
- setupLinear()
Performs an automatic setup procedure. This finds the position of the upper and lower limit switches, defines the position zero-point to be the midpoint between the two, sets the software limits at 90 percent of the distance to the limit switchs and moves the mechanism to the zero position. If the default software limits are not acceptable then they can be queried with getLimits() and changed using setLimits(). In order to avoid possible damage (and an infinite loop) it's important that the limit switches are working properly when using this function. Also, this procedure will generate a warning, however this is expected and harmless.
>>> dazle.coll_focus.setupLinear() 2005-08-25 17:43:36,801 coll_focus WARNING Moving away from a made limit
- moveTo(new_pos)
Moves the mechanism to position new_pos, given in units.
>>> dazle.coll_focus.moveTo(-10)
- moveBy(distance)
Moves the mechanism by distance units.
>>> dazle.coll_focus.moveBy(30)
- getPosition()
Retrieves the current position of the mechanism, in units.
>>> dazle.coll_focus.getPosition() 0.0
- setPosition(new_pos)
Sets the current position of the mechanism to new_pos units. Note that this will not adjust the software limit positions so setLimits() will probably also be needed. In general setupLinear() should be used for setting the zero point instead of setPosition().
>>> dazle.coll_focus.setPosition(-5) >>> dazle.coll_focus.getPosition() -5.0
- getLimits()
Retrieves the upper and lower software limits, in units.
>>> dazle.coll_focus.getLimits() (-110.0, 110.0)
- setLimits(lower, upper)
Sets the software lower and upper limits, in units.
>>> dazle.coll_focus.setLimits(-100, 100) >>> dazle.coll_focus.getLimits() (-100.0, 100.0)
- getMotorParams()
Retrieves the current values of the motor motion parameters, base_speed, max_speed, acceleration and deceleration in units/s or units/s/s.
>>> dazle.coll_focus.getMotorParams() (62.0, 100.0, 62.0, 62.0)
- setMotorParams(base_speed, max_speed, acceleration, deceleration)
Sets the values of the motor motion parameters, base_speed, max_speed, acceleration and deceleration in units/s or units/s/s.
>>> dazle.coll_focus.setMotorParams(62, 80, 62, 62) >>> dazle.coll_focus.getMotorParams() (62.0, 80.0, 62.0, 62.0)
- getUnits()
Retrieves the current value of units, the number of motor half-steps per unit used for all the other parameters.
>>> dazle.coll_focus.getUnits() 1.0
- setUnits(units)
Sets the value of units, the number of motor half-steps per unit used for all the other parameters.
>>> dazle.coll_focus.setUnits(4) >>> dazle.coll_focus.getUnits() 4
Detector Focus
While the three motors of the DAzLE/CIRPASS detector focus/tilt mechanism can be controlled individually using the linear interface there is a specific detector focus interface enabling overall control of the detector's focus position and tilts.
Additional information about this module can be found in the extensive comments in the detmech.py [see also the pydocgenerated detmech.html file].
INI file entries
[detmech] instances = detmech_1
Detector focus mechanisms (though there is going to be only one) are listed in a comma seperated list (no spaces) in the detmech section. To temporarily disable the detector focus simply remove its name from the list.
[detmech_1] det1 = det1 det2 = det2 det3 = det3 offset1 = 0 offset2 = 0 offset3 = 0
The section describing the detector focus mechanism(s) needs the following entries:
- det1
Name of the linear mechanism corresponding to the first detector focus actuator. The units of this linear mechanism must be set such that one unit equals one micron of movement (i.e. units = 10.0).
- det2
Name of the linear mechanism corresponding to the second detector focus actuator. The units of this linear mechanism must be set such that one unit equals one micron of movement (i.e. units = 10.0).
- det3
Name of the linear mechanism corresponding to the third detector focus actuator. The units of this linear mechanism must be set such that one unit equals one micron of movement (i.e. units = 10.0).
- offset1
An offset, in microns, which is added to the det1 zero point when calculating required positions. Should not be adjusted manually, use the zeroTilts() command.
- offset2
An offset, in microns, which is added to the det2 zero point when calculating required positions. Should not be adjusted manually, use the zeroTilts() command.
- offset3
An offset, in microns, which is added to the det3 zero point when calculating required positions. Should not be adjusted manually, use the zeroTilts() command.
Commands
- setupDetmech()
Issues the setupLinear() command to each of the three detector focus linear mechanisms (actuators) in turn to establish the centres of the range of movement, limit switch positions and software limits.
Due to slight variations in limit switch positions this will not properly zero the tilts of the detector, in order to do this a target screen should be used together with manual tilt adjustments, and then zeroTilts() used to set the required offsets for each actuator.
Care should be taken in using this routine, and it should not be run unless necessary. As each of the actuator is exercised over its full range in turn large tilts will occur and there are some combinations of motor positions where this can result in the detector box contacting the LN2 can. Attempting to ensure that the actuators, and in particular det3, are near the middle of their range before beginning this process will minimise risk. This could be fixed at some point...
- zeroTilts()
Call this function after manually zeroing the tilt of the detector by imaging a test target screen. This adjusts the 3 offsets used in calculating the detector position so that afterwards the tilt calculations will be correct.
- moveTo(focus, tilt1, tilt2)
Moves the detector until the focus position in microns equals focus and the two tilts about the diagonals, in degrees, equals tilt1 and tilt2. The two tilts can be omitted and when this is done they default to zero.
In executing the move this command will break up the movement of each actuator into segments of no more than 1000 microns in order to avoid any possibility of the detector box contacting the nitrogen can.
- moveBy(dfocus, dtilt1, dtilt2)
Moves the detector such that the focus position changes by dfocus microns and the two tilts about the diagonals change by dtilt1 and dtilt2 degrees. The two tilts can be omitted and when this is done they default to zero.
In executing the move this command will break up the movement of each actuator into segments of no more than 1000 microns in order to avoid any possibility of the detector box contacting the nitrogen can.
- getPosition()
Returns current focus position, in microns, and the detector tilts about the two diagonals, as rotator.angle objects. Use this command if a machine readable position is required, otherwise use printPosition().
- printPosition()
Prints the current focus position, in microns, and the detector tilts about the two diagonals, in degree, to the terminal. Use this command if a human readable position is required, otherwise use getPosition().
- getLimits()
Returns the limits of focus position that are attainable without exceeding the software limits of any of the three actuators, if detector tilt is zero. If tilts are non-zero the available range will be reduced. Also the focus position determines the range of available tilts. This function doesn't try to work these additonal effects out.
Filter Wheels
The narrowband filter wheel, mask wheel, and the two camera blocking filter wheel are controlled using the 'filterwheel' interface.
Additional information about this module can be found in the extensive comments in the filterwheel.py [see also the pydoc generated filterwheel.html file].
INI file entries
[filterwheel] instances = mask_wheel,nb_wheel,camwheel1,camwheel2
The wheels are listed in a comma seperated list (no spaces) in the filterwheel section. In order to temporarily disable a wheel (e.g. one that isn't currently connected) simply remove its name from the list.
[mask_wheel] names = clear1,clear2,rmask,lmask cortex = cortex_1 icu_num = 1 axis_num = 1 base_speed = 62 max_speed = 124 acceleration = 62 deceleration = 62 position = 0 steps_per_rev = 4800 direction = 1
The sections describing each wheel need the following entries:
- names
A comma seperated list (no spaces) of names describing the contents of each filter position. This allows filters to be selected by name rather than number.
- cortex
The name of the cortex interface corresponding to the daisy chain of ICUs that the mechanism is connected to.
- icu_num
The position of the ICU that the mechanism is connected to in the daisy chain.
- axis_num
Which axis of the ICU that the mechanism is connected to.
- base_speed
The starting speed for the motor, in half-steps/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- max_speed
The top speed for the motor, in half-steps/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- acceleration
The acceleration for the motor, in half-steps/s/s. Must be at least 62 half-steps/s otherwise the ICU will reject it.
- deceleration
The deceleration for the motor, in half-steps/s/s Must be at least 62 half-steps/s otherwise the ICU will reject it.
- position
The current position of the mechanism, in half-steps.
- steps_per_rev
The number of half-steps per full revolution of the wheel.
- direction
Either +1 or -1, used to specify the direction in which to rotate the wheel. All movements are made in the same direction, and the direction should be chosen so as to 'drag' the feedback microswithes along their grooves instead of 'pushing' them.
Commands
- setupWheel()
Performs an automatic setup procedure. This attempts to find a series of positions exactly 90 degrees apart that are the within the filter position sectors as determined by the feedback microswitches. Reports whether this was successful.
>>> dazle.mask_wheel.setupWheel() 2005-08-26 14:44:19,627 mask_wheel INFO Filter wheel setup complete.
- getStatus()
Checks the feedback microswitches and returns the current status of the wheel as a number. The filter position sectors are reported as 0, 1, 2 and 3, while the sectors inbetween filters are reported as 0.5, 1.5, 2.5 and 3.5.
>>> dazle.mask_wheel.getStatus() 0
- goTo(filter)
Moves the wheel to filter position filter. The required filter can be specified either by number (0, 1, 2 or 3) or by name (as defined in the INI file). After moving the feedback microswitches are checked and the success (or otherwise) reported. If the correct filter position isn't reached it may be necessary to use setupWheel() again.
>>> dazle.mask_wheel.goTo('lmask') 2005-08-26 15:39:28,310 mask_wheel INFO goTo(lmask) successful >>> dazle.mask_wheel.goTo(2) 2005-08-26 15:40:07,236 mask_wheel INFO goTo(2) successful
- getPosition()
Retrieves the current position of the wheel, in half-steps.
- setPosition(new_pos)
Sets the current position of the wheel to new_pos half-steps. In general setupWheel() should be used instead of setPosition().
- getMotorParams()
Retrieves the current values of the motor motion parameters, base_speed, max_speed, acceleration and deceleration in half-steps/s or half-steps/s/s.
- setMotorParams(base_speed, max_speed, acceleration, deceleration)
Sets the values of the motor motion parameters, base_speed, max_speed, acceleration and deceleration in half-steps/s or half-steps/s/s.
- moveTo(new_pos)
Moves the wheel to position new_pos, given in half-steps.
- moveBy(distance)
Moves the mechanism by distance units.
Rotator Control
The camera dewar rotator/field derotation system is controlled via the rotator interface. Also included in this module are classes to store and calculate information related to particular telescopes/observatories and to individual target fields. These need to be provided in order for the rotator control to perform the calculations needed for tracking.
Additional information can be found in the extensive comments in the rotator.py file [see also the pydoc generated docfile .
INI file entries
[target] instances = goods,cosmos [telescope] instances = vlt_ut3 [rotator] instances = rotator_1
There are three list sections relating to rotator control. The names of target fields are listed as a comma seperated list (no spaces) in the target section, the names of telescope/observatories in the telescope section and rotator itself is named in the rotator section.
Any of these can be temporarily disabled by removing their name from the lists.
[cosmos] ra = +10 00 28.600 dec = +2 12 21.000 pa = 90.0
Each target field section must have the following entries:
- ra
The FK5 J2000 mean place Right Ascension coordinate of the centre of the target field, in hours, in sexagesimal format.
- dec
The FK5 J2000 mean place declination coordinate of the centre of the target field, in degrees, in sexagesimal format.
- pa
The desired position angle for the target field, defined as the angle North Pole - field centre - 'detector up direction', in degrees.
- longitude
Mean longitude of the telescope, east positive, in degrees, in sexagemsimal format.
Mean geodetic latitude of the telescope, in degrees, in sexagesimal format.
- altitude
Altitude above mean sea level, in metres.
- polar_motion_x
Polar motion X coordinate for today, in degrees, in sexagesimal format. This is obtained from the Internation Earth Rotation Service.
- polar_motion_y
Polar motion Y coordinate for today, in degrees, in sexagesimal format. This is obtained from the International Earth Rotation Service.
- delta_ut
UT1 - UTC for today, in seconds. This is obtained from the Internation Earth Rotation Service.
- temperature
Local ambient temperature, in Kelvin.
- pressure
Local atmospheric pressure, in millibars.
- humidity
Local relative humidity (0-1).
- tlr
Tropospheric lapse rate, in Kelvin per metre.
- wavelength
The effective wavelength of the observations, in microns.
- portname
The linux device name of the serial port that the Smartdrive Taranis is connected to.
- target
The name of target field currently selected.
- telescope
The name of the telescope that the instrument is attached to.
- idle
The motor idling current, in amps. Cannot be greater than run.
- run
The motor running current, used for motion at constant speed, in amps. Cannot be greater than boost.
- boost
The motor boost current, used for acceleration or deceleration, in amps. Cannot exceed 4.5A.
- dt
The interval between tracking corrections, in seconds.
- startTracking(logData)
Begins tracking to currently selected target field, based on information about the currently selected telescope. Displays a number of INFO level messages, including one to inform the user that the rotator has reached the correct position and is tracking within tolerance. The optional argument, logData, specifies whether tracking performance data should be saved to a dicstrack.log file or not. logData must be either True or False, and defaults to False if not specified.
- stopTracking()
If the rotator is currently tracking stops it doing so.
- isTracking()
Returns the status of the rotator, True if it is currently active or False if it isn't.
- isLockedOn()
If the rotator is currently tracking within tolerance returns True, otherwise returns False.
- setupRotator()
Performs an automatic setup routine. This finds the position of the upper and lower limit switches, sets the zero point to be the midpoint between the two, calculates the angular scale of the position encoder, and sets the software limits on the range of motion to be two degrees inside the limit switch positions. This can take several minutes to perform.
- setTarget(target)
Changes the currently selected to target field to target. target must be a rotator.target object described in the INI file. The target field cannot be changed while the rotator is active.
- setTelescope(telescope)
Changes the currently selected telescope to telescope. telescope must be a rotator.telescope object described in the INI file. The telescope cannot be changed while the rotator is active.
- setCurrents(idle, run, boost)
Sets the motor currents to idle, run and boost. These are described in the INI file section. The currents cannot be changed while the rotator is active
- where()
Produces an INFO level message containing the current position, lower limit and upper limit of the rotator. Cannot be used while the rotator is active.
- camera_url
The URL of the camera server on the DCS computer.
- filesave_URL
The URL of the filesave server on the DCS computer.
- powerOn()
Turns on the power supply to the detector. Will create a CRITICAL level message if the attempt fails.
- powerOff()
Turns off the power supply to the detector. Will create a CRITICAL level message if the attempt fails.
- dummy(DWELL, NUM_EXPS)
Executes the dummy SRR exposure application to create a frame of fake data. This can be used as a test of the detector system when the detector itself is not connected. DWELL and NUM_EXPS can be specified as for SRR() but do not have an effect on the frame. Will create a CRITICAL level message if the attempt fails.
- SRR(DWELL, NUM_EXPS)
Executes the single raw read application. DWELL is the delay between reset and commencing readout, in milliseconds, and defaults to 1 if not specified. If NUM_EXPS is not 1 (the default) then multiple exposures are taken and averaged together. Will create a CRITICAL level message if the exposure fails.
- CDS(DWELL, NUM_EXPS)
Executes the correlated double sampling application. DWELL is the delay between completing the first read and commencing the second, in milliseconds, and defaults to 1 if not specified. If NUM_EXPS is not 1 (the default) then multiple exposures are taken and averaged together. Will create a CRITICAL level message if the exposure fails.
- NDR(DWELL, NUM_READ, NUM_EXPS)
Executes the non-destructive read application. DWELL is the delay between completing the one read and commencing the next, in milliseconds. NUM_READ is the number of readouts during the exposure. If NUM_EXPS is not 1 (the default) then multiple exposures are taken and averaged together. Will create a CRITICAL level message if the exposure fails.
- getStatus()
Queries the state and status of the camera and filesave processes and return them in the order camera state, camera status, filesave state, filesave status.
- RCO()
Executes the 'RCO' command. I don't know what this does exactly, the ATC never told us. This is automatically performed at startup by DICS. Will create a CRITICAL level message if the attempt fails.
- RST()
Executes the 'RST' command. I don't know what this does exactly, the ATC never told us. This is automatically performed at startup by DICS. Will create a CRITICAL level message if the attempt fails.
[vlt_ut3] longitude = -70 24 09.896 latitude = -24 37 30.300 altitude = 2635.43 polar_motion_x = -0 00 00.05013 polar_motion_y = +0 00 00.39225 delta_ut = -0.614204 temperature = 278.15 pressure = 750.0 humidity = 0.1 tlr = 0.007 wavelength = 1.06
The telescope section must have the following entries:
[rotator_1] portname = /dev/ttyS2 target = cosmos telescope = vlt_ut3 idle = 1.0 run = 3.0 boost = 3.5 dt = 0.2
The rotator section must have the following entries:
Commands
The rotator has the following commands:
The telescope and target objects also have a number of commands, however these are mostly for use by the rotator rather than the user. They are documented in the comments in the rotator.py file.
Detector Control
DICS can connect to the detector control system to set exposures running.
Additional information can be found in the file dcs.py and the ATC provided Ultracam.py file.
INI file entries
[dcs] instances = dcs1
Detector control systems (though there will be only one) are listed in a comma seperated list (no spaces) in the dcs section. In order to temporarily disable connection to the DCS simply remove the name.
[dcs1] camera_url = optics26:7063 filesave_url = optics26:5417
The section describing the DCS needs the following entries:
Commands
Temperature Logging
This is currently a bit broken due to bugs in the outdated linux driver provided by Pico Technology for their TC-08 temperature loggers. It's possible to work around the driver failures however, and I have a plan for how to do so but I haven't had time to implement it yet.
Extending DICS
First learn some Python.
The best way to create 'observing blocks' will be to add methods to the instrument object in the dics.py [see also the pydoc generated dics.html file]. file which execute a sequence of actions.