1 from __future__
import division, absolute_import
6 from twistedActor
import log
10 from .computeObj
import computeObj
11 from .checkSlewPath
import checkSlewPath
12 from .oneSlewIter
import oneSlewIter
20 def __init__(self, pathList, begTime, endTime, numIter):
21 """!Construct a SlewData
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
38 _ValidStartingStateSet = set((
39 tcc.base.AxisState_NotAvailable,
40 tcc.base.AxisState_Halted,
41 tcc.base.AxisState_Drifting,
45 """!Contains full data about one slew iteration
47 Intended for debugging problems with slew iteration
49 def __init__(self, iterNum, obj, begTime, minDuration, estEndTime, pathList, endTime, duration):
51 self.
obj = tcc.base.Obj(obj)
63 "begTime = %r" % (self.
begTime,),
67 "endTime = %r" % (self.
endTime,),
70 return "FullSlewData for iter %s:\n%s" % (self.
iterNum,
"\n* ".join(outStrList))
72 def computeSlew(minEndTime, obj, earth, inst, telMod, axeLim, tune):
73 """!Compute a slew to a given user-specified position, by iteration
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.
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.
88 @param[in,out] obj object block:
89 input: object block computed at approximately the current time (see above)
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
104 @return slewData: a SlewData
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)
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!
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.
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
128 There are several parameters in the Tune block which control this
129 iteration process. See TuneBlkDef for more info.
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").
138 2013-12-09 ROwen converted from computeSlew.for
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,))
143 oldMount = [coordConv.PVT(mt)
for mt
in obj.actMount]
146 doAxis = [cmdState == tcc.base.AxisState_Drifting
for cmdState
in obj.axisCmdState]
148 doSlewAxis = [doAx
and obj.axisErrCode[axis] == tcc.base.AxisErr_OK
for axis, doAx
in enumerate(doAxis)]
149 if obj.userSys.getName() ==
"none":
151 doSlewAxis[i] =
False
152 if obj.rotType == tcc.base.RotType_None:
153 doSlewAxis[2] =
False
155 doHaltAxis = [doAxis[axis]
and not doSlewAxis[axis]
for axis
in range(tcc.base.NAxes)]
157 badAxisList = [doAxis[axis]
and not obj.actMount[axis].isfinite()
for axis
in range(tcc.base.NAxes)]
159 raise RuntimeError(
"Axis drifting but actMount unknown for axes: %s" % (
getAxisNames(badAxisList),))
163 currTAI = tcc.base.tai()
164 stopPos = [actMount.getPos(currTAI)
for actMount
in obj.actMount]
173 fullSlewDataQueue = collections.deque(maxlen=5)
174 while estEndTime
is None or abs(endTime - estEndTime) > tune.slewConvTime:
176 if iterNum > tune.slewMaxIter:
177 errMsg =
"Slew computation did not converge in %s iterations" % (tune.slewMaxIter,)
179 for fullSlewData
in fullSlewDataQueue:
181 raise RuntimeError(errMsg)
189 begTime = tcc.base.tai() + tune.slewAdvTime
190 minDuration = max(tune.slewMinDuration, minEndTime - begTime)
191 estEndTime = begTime + max(duration, minDuration)
201 doRestart = [
False]*tcc.base.NAxes,
211 for axis
in range(tcc.base.NAxes):
213 obj.targetMount[axis] = coordConv.PVT(stopPos[axis], 0, estEndTime)
218 oldMount = obj.actMount,
219 newMount = obj.targetMount,
221 minTime = minDuration,
225 raise RuntimeError(
"Slew iteration failed: no axes were slewable")
226 duration = endTime - begTime
232 minDuration = minDuration,
233 estEndTime = estEndTime,
240 if duration <= ShortSlewTime:
243 extraNodeTime = endTime + tune.trackInterval
247 doRestart = [
False]*tcc.base.NAxes,
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])
263 doRestart = [
False]*tcc.base.NAxes,
271 obj.slewEndTime = endTime + tune.slewFudge
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]
282 badAxisList = [
False]*tcc.base.NAxes
283 for axis
in range(tcc.base.NAxes):
285 obj.axisCmdState[axis] = tcc.base.AxisState_Slewing
286 if badLimitList[axis]
or obj.axisErrCode[axis] != tcc.base.AxisErr_OK:
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))
294 obj.axisErrCode[axis] = tcc.base.AxisErr_CannotCompute
295 if badLimitList[axis]:
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))
304 obj.axisErrCode[axis] = tcc.base.AxisErr_CannotCompute
307 raise RuntimeError(
"Could not compute a slew for axes: %s" % (
getAxisNames(badAxisList),))
def computeSlew
Compute a slew to a given user-specified position, by iteration.
def checkSlewPath
Check a slew to make sure each segment is in bounds.
def __init__
Construct a SlewData.
def computeObj
Compute all computed obj fields from user-specified fields except path generator outputs.
def oneSlewIter
Compute a slew for all axes, given the starting and target paths.
Contains full data about one slew iteration.
def getAxisNames
Convert a list of bools (one per axis) to a comma-separated string of axis names. ...