Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/TCC/html/compute_slew_8py_source.html
Дата изменения: Tue Sep 15 02:25:37 2015
Дата индексирования: Sun Apr 10 02:20:05 2016
Кодировка:
lsst.tcc: python/tcc/axis/computeSlew.py Source File
lsst.tcc  1.2.2-3-g89ecb63
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
computeSlew.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
2 
3 import collections
4 
5 import coordConv
6 from twistedActor import log
7 
8 import tcc.base
9 from tcc.util import getAxisNames
10 from .computeObj import computeObj
11 from .checkSlewPath import checkSlewPath
12 from .oneSlewIter import oneSlewIter
13 
14 ShortSlewTime = 5.0 # replace this with a suitable test of tune parameters;
15  # a short slew's end-time < slew end time + track adv time + perhaps extra for time to send all slew mnodes
16 
17 class SlewData(object):
18  """!Data about a slew
19  """
20  def __init__(self, pathList, begTime, endTime, numIter):
21  """!Construct a SlewData
22 
23  @param[in] pathList a list of pvtList, one per axis;
24  pvtList will be () in two cases:
25  - axes for which a gentle halt was wanted, but a valid slew could not be computed
26  (in this case you should command an immediate halt)
27  - axes that were not drifting
28  @param[in] begTime starting time of slew
29  @param[in] endTime end time of slew, ignoring fudge factors such as tune.slewFudge
30  (the fudged end time is obj.slewEndTime)
31  @param[in] numIter number of iterations for slew to converge
32  """
33  self.pathList = pathList
34  self.begTime = begTime
35  self.endTime = endTime
36  self.numIter = numIter
37 
38 _ValidStartingStateSet = set((
39  tcc.base.AxisState_NotAvailable,
40  tcc.base.AxisState_Halted,
41  tcc.base.AxisState_Drifting,
42 ))
43 
44 class FullSlewData(object):
45  """!Contains full data about one slew iteration
46 
47  Intended for debugging problems with slew iteration
48  """
49  def __init__(self, iterNum, obj, begTime, minDuration, estEndTime, pathList, endTime, duration):
50  self.iterNum = iterNum
51  self.obj = tcc.base.Obj(obj)
52  self.begTime = begTime
53  self.minDuration = minDuration
54  self.estEndTime = estEndTime
55  self.pathList = pathList[:]
56  self.endTime = endTime
57  self.duration = duration
58 
59  def __repr__(self):
60  outStrList = (
61  repr(self.obj),
62  repr(self.obj.site),
63  "begTime = %r" % (self.begTime,),
64  "minDuration = %r" % (self.minDuration,),
65  "estEndTime = %r" % (self.estEndTime,),
66  "pathList = %r" % (self.pathList,),
67  "endTime = %r" % (self.endTime,),
68  "duration = %r" % (self.duration,),
69  )
70  return "FullSlewData for iter %s:\n%s" % (self.iterNum, "\n* ".join(outStrList))
71 
72 def computeSlew(minEndTime, obj, earth, inst, telMod, axeLim, tune):
73  """!Compute a slew to a given user-specified position, by iteration
74 
75  Before calling this:
76  - Update obj at some time near "now" including applying doRestart and wrap preferences.
77  - Send the DRIFT command to all axes that are moving (whether you want to halt them or slew them)
78  and update obj.actMount and obj.axisCmdState accordingly.
79 
80  This routine then does the following for each axis:
81  - If obj.axisCmdState==AxisState_Drifting and obj.targetMount[axis].isfinite():
82  compute a slew to the new position. Raise an exception if such a slew cannot be computed.
83  - If obj.axisCmdState==AxisState_Drifting and not obj.targetMount.isfinite():
84  try to compute a slew to a halt. If that fails, set SlewData.pathList[axis]=();
85  the caller then must command that axis to halt!
86  - For other axes, leave the axis alone.
87 
88  @param[in,out] obj object block:
89  input: object block computed at approximately the current time (see above)
90  output:
91  - the object block is be recomputed
92  - obj.targetMount is set to the final pvt for each axis that is slewing or halting;
93  it is unchanged for axes that are already halted
94  - obj.axisCmdState is set to AxisState_Halting or AxisState_Slewing for axes that are drifting
95  - obj.axisErrCode is updated appropriately for axes that are drifting
96  - obj.slewEndTime is set
97  @param[in] minEndTime earliest date at which slew may finish (TAI, MJD sec)
98  @param[in] earth earth orientation data, a tcc.base.Earth
99  @param[in] inst instrument-position information block, a tcc.base.Inst
100  @param[in] telMod telescope model, a tcc.base.TelMod
101  @param[in] axeLim axes limits block, a tcc.base.AxeLim
102  @param[in] tune axes motion tuning constants block, a tc.base.Tune
103 
104  @return slewData: a SlewData
105 
106  @throw RuntimeError if any of the following are true:
107  - obj.axisCmdState is not one of AxisState_NotAvailable, AxisState_Halted, or AxisState_Drifting for any axis
108  - obj.actMount is not finite for any axis whose axisCmdState = AxisState_Drifting
109  - a valid slew cannot be computed for an axis being slewed (not halted)
110 
111  @warning
112  - If an axis is to be halted, and a valid slew cannot be computed,
113  then slewData.pathList[axis] = (). The caller must stop the axis!
114 
115  Special cases:
116  - If no axes are to be slewed, pathList[axis] will be an empty list for all axes, but begTime
117  and endTime will be correct -- set as for the shortest possible slew.
118 
119  Details:
120  The slew path is computed by iteration, as follows:
121  - The end time of the slew is estimated (based on many factors, see code)
122  - the target mount coordinates (p,v,t) are computed at that instant
123  - A slew is computed which meets the target path (using linear extrapolation);
124  this also gives us the true end time
125  - The estimated and true end times are compared;
126  if they are too far apart, the cycle is repeated
127 
128  There are several parameters in the Tune block which control this
129  iteration process. See TuneBlkDef for more info.
130 
131  Types of motion:
132  - Slew: move to a requested position via a computed, smooth path.
133  Used for axes with a requested target position.
134  - Controlled stop: move to the current pos. via a computed, smooth path.
135  Used for axes with no position requested (e.g. coord. sys. = "none").
136 
137  History:
138  2013-12-09 ROwen converted from computeSlew.for
139  """
140  if any(cmdState not in _ValidStartingStateSet for cmdState in obj.axisCmdState):
141  raise RuntimeError("obj.axisCmdState = %s; must be NotAvailable, Halted or Drifting for all axes" % (obj.axisCmdState,))
142 
143  oldMount = [coordConv.PVT(mt) for mt in obj.actMount]
144 
145  # doAxis: axis is to be slewed or halted
146  doAxis = [cmdState == tcc.base.AxisState_Drifting for cmdState in obj.axisCmdState]
147  # doSlewAxis: axis is to be slewed to a new position (not halted)
148  doSlewAxis = [doAx and obj.axisErrCode[axis] == tcc.base.AxisErr_OK for axis, doAx in enumerate(doAxis)]
149  if obj.userSys.getName() == "none":
150  for i in range(2):
151  doSlewAxis[i] = False
152  if obj.rotType == tcc.base.RotType_None:
153  doSlewAxis[2] = False
154  # doHaltAxis: axis is to be halted, by slewing if possible, else abruptly
155  doHaltAxis = [doAxis[axis] and not doSlewAxis[axis] for axis in range(tcc.base.NAxes)]
156 
157  badAxisList = [doAxis[axis] and not obj.actMount[axis].isfinite() for axis in range(tcc.base.NAxes)]
158  if any(badAxisList):
159  raise RuntimeError("Axis drifting but actMount unknown for axes: %s" % (getAxisNames(badAxisList),))
160 
161  # compute current mount position to use as the final position for axes wanting a controlled stop
162  # (the result will be invalid for axes that aren't drifting, but so what?)
163  currTAI = tcc.base.tai()
164  stopPos = [actMount.getPos(currTAI) for actMount in obj.actMount]
165 
166  # Iterate the slew computation until endTime converges.
167  iterNum = 0 # incremented at the beginning of the loop
168  endTime = None
169  estEndTime = None # gurantees non-convergence at the first test
170  duration = 0.0
171 
172  # a list of slew data -- in case slew iterations fail it can be printed
173  fullSlewDataQueue = collections.deque(maxlen=5)
174  while estEndTime is None or abs(endTime - estEndTime) > tune.slewConvTime:
175  iterNum += 1
176  if iterNum > tune.slewMaxIter:
177  errMsg = "Slew computation did not converge in %s iterations" % (tune.slewMaxIter,)
178  log.error(errMsg)
179  for fullSlewData in fullSlewDataQueue:
180  print fullSlewData
181  raise RuntimeError(errMsg)
182 
183  # Compute the begin-time and estimated end-time for this iteration:
184  # begin-time = current time + time needed to start sending the resulting slew to the axes
185  # min. duration must be large enough that the slew will not end
186  # before "minEndTime" and we have time to send the slew commands
187  # estimated end-time = begin-time + duration computed in prev. iter.
188  # (or substitute min. duration if larger)
189  begTime = tcc.base.tai() + tune.slewAdvTime
190  minDuration = max(tune.slewMinDuration, minEndTime - begTime)
191  estEndTime = begTime + max(duration, minDuration)
192 
193  # Compute object block at estimated end-time of slew
194  #
195  # The object block has already been computed once with doRestart and user-specified
196  # wrap applied, so for these iterations do not use user-specified wrap
197  # (to avoid dithering near a wrap transition) and do further attempt to restart axes.
198  computeObj(
199  obj = obj,
200  doWrap = False,
201  doRestart = [False]*tcc.base.NAxes,
202  reportLim = False,
203  earth = earth,
204  inst = inst,
205  telMod = telMod,
206  axeLim = axeLim,
207  tai = estEndTime,
208  )
209 
210  # set any axes which are to be halted in a controlled fashion to the proper stopped position
211  for axis in range(tcc.base.NAxes):
212  if doHaltAxis[axis]:
213  obj.targetMount[axis] = coordConv.PVT(stopPos[axis], 0, estEndTime)
214 
215  # compute the slew (yielding the true end-time for this iteration), and compute the resulting duration
216  pathList, endTime = oneSlewIter(
217  doAxis = doAxis,
218  oldMount = obj.actMount,
219  newMount = obj.targetMount,
220  begTime = begTime,
221  minTime = minDuration,
222  axeLim = axeLim,
223  )
224  if endTime <= 0.0:
225  raise RuntimeError("Slew iteration failed: no axes were slewable")
226  duration = endTime - begTime
227 
228  fullSlewDataQueue.append(FullSlewData(
229  iterNum = iterNum,
230  obj = obj,
231  begTime = begTime,
232  minDuration = minDuration,
233  estEndTime = estEndTime,
234  pathList = pathList,
235  endTime = endTime,
236  duration = duration,
237  ))
238 
239  # update obj at actual end time, or if slew is really short, at first post-slew tracking time
240  if duration <= ShortSlewTime:
241  # Slew is so short I'm worried about getting the first tracking update out on time,
242  # so add a PVT node for the first tracking update after the slew
243  extraNodeTime = endTime + tune.trackInterval
244  computeObj(
245  obj = obj,
246  doWrap = False,
247  doRestart = [False]*tcc.base.NAxes,
248  reportLim = False,
249  earth = earth,
250  inst = inst,
251  telMod = telMod,
252  axeLim = axeLim,
253  tai = extraNodeTime,
254  )
255  for axis in range(tcc.base.NAxes):
256  pvtList = pathList[axis]
257  if len(pvtList) > 0 and obj.targetMount[axis].isfinite() and pvtList[-1].isfinite():
258  pvtList.append(obj.targetMount[axis])
259  else:
260  computeObj(
261  obj = obj,
262  doWrap = False,
263  doRestart = [False]*tcc.base.NAxes,
264  reportLim = False,
265  earth = earth,
266  inst = inst,
267  telMod = telMod,
268  axeLim = axeLim,
269  tai = endTime,
270  )
271  obj.slewEndTime = endTime + tune.slewFudge
272 
273  # test the position limits of the resulting slew
274  # (but not velocity, acceleration or jerk, because they are constrained as part of generating the slew)
275  # handle the results in the final sanity check, since bad limits are acceptable if halting the axis
276  limErrCodeList = [tcc.base.AxisErr_OK]*tcc.base.NAxes
277  checkSlewPath(limErrCodeList, doAxis, pathList, doPos=True, doVel=False, doAccel=False, doJerk=False, axeLim=axeLim, inst=inst)
278  badLimitList = [limErrCode != tcc.base.AxisErr_OK for limErrCode in limErrCodeList]
279 
280  # set obj.axisCmdState and make sure obj.axisErrCode not OK if halting
281  # and perform a final sanity-check
282  badAxisList = [False]*tcc.base.NAxes
283  for axis in range(tcc.base.NAxes):
284  if doSlewAxis[axis]:
285  obj.axisCmdState[axis] = tcc.base.AxisState_Slewing
286  if badLimitList[axis] or obj.axisErrCode[axis] != tcc.base.AxisErr_OK:
287  # this axis didn' work out
288  badAxisList[axis] = True
289  elif doHaltAxis[axis]:
290  obj.axisCmdState[axis] = tcc.base.AxisState_Halting
291  if obj.axisErrCode[axis] == tcc.base.AxisErr_OK:
292  logMsg = "doHalt Error axis %i\ncomputeSlew(minEndTime=%s, obj, earth, inst, telMod, axeLim, tune)\nDumping desObj block:\n%s\nDumping inst block:\n%s\nDumping tune block:\n%s\nDumping axeLim block:\n%s"%(axis, str(minEndTime), str(obj), str(inst), str(tune), str(axeLim))
293  log.error(logMsg)
294  obj.axisErrCode[axis] = tcc.base.AxisErr_CannotCompute
295  if badLimitList[axis]:
296  # cannot slew this axis gently to a halt, so command an immediate stop
297  pathList[axis] = ()
298  else:
299  # restore original mount position and make sure error is set
300  obj.actMount[axis] = oldMount[axis]
301  if obj.axisErrCode[axis] == tcc.base.AxisErr_OK:
302  logMsg = "noHalt Error axis %i\ncomputeSlew(minEndTime=%s, obj, earth, inst, telMod, axeLim, tune)\nDumping desObj block:\n%s\nDumping inst block:\n%s\nDumping tune block:\n%s\nDumping axeLim block:\n%s"%(axis, str(minEndTime), str(obj), str(inst), str(tune), str(axeLim))
303  log.error(logMsg)
304  obj.axisErrCode[axis] = tcc.base.AxisErr_CannotCompute
305 
306  if any(badAxisList):
307  raise RuntimeError("Could not compute a slew for axes: %s" % (getAxisNames(badAxisList),))
308 
309  return SlewData(
310  pathList = pathList,
311  begTime = begTime,
312  endTime = endTime,
313  numIter = iterNum,
314  )
def computeSlew
Compute a slew to a given user-specified position, by iteration.
Definition: computeSlew.py:72
Data about a slew.
Definition: computeSlew.py:17
def checkSlewPath
Check a slew to make sure each segment is in bounds.
def __init__
Construct a SlewData.
Definition: computeSlew.py:20
def computeObj
Compute all computed obj fields from user-specified fields except path generator outputs.
Definition: computeObj.py:22
def oneSlewIter
Compute a slew for all axes, given the starting and target paths.
Definition: oneSlewIter.py:15
Contains full data about one slew iteration.
Definition: computeSlew.py:44
def getAxisNames
Convert a list of bools (one per axis) to a comma-separated string of axis names. ...
Definition: getAxisNames.py:7