Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/TCC/html/trap_slew_8py_source.html
Дата изменения: Tue Sep 15 02:25:37 2015
Дата индексирования: Sun Apr 10 01:37:09 2016
Кодировка:
lsst.tcc: python/tcc/mov/trapSlew.py Source File
lsst.tcc  1.2.2-3-g89ecb63
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
trapSlew.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
2 
3 import math
4 import sys
5 
6 from coordConv import DoubleMax
7 
8 __all__ = ["trapSlew"]
9 
10 Fudge = 1.05 # fudge factor to avoid borderline cases
11 
12 class TrapSlewData(object):
13  """!Data returned by trapSlew. Fields match inputs to constructor.
14  """
15  def __init__(self, dt1, dt2, dt3, vP, a1, a3, slewType):
16  """!Construct a TrapSlewData
17 
18  @param[in] dt1 duration of segment 1 (first constant acceleration) (sec)
19  @param[in] dt2 duration of segment 2 (constant velocity) (sec)
20  @param[in] dt3 duration of segment 3 (last constant acceleration) (sec)
21  @param[in] vP velocity of segment 2 (deg/sec)
22  @param[in] a1 acceleration of segment 1 (deg/sec^2)
23  @param[in] a3 acceleration of segment 3 (deg/sec^2)
24  @param[in] slewType type of slew; one of:
25  0: null slew: vB = vA and rBAi = 0:
26  a1 = a3 = 0
27  1: sign(vB - vA) = sign(rBAi), or one of vBA or rBAi = 0:
28  sign(a1) = sign(rBAi), |a1| = aMax, a3 = - a1
29  2: sign(vB - vA) = - sign(rBAi), and a solution exists such that:
30  sign(a1) = sign(rBAi), |a1| = aMax, a3 = - a1
31  3: sign(vB - vA) = - sign(rBAi), and a solution exists such that:
32  sign(a1) = - sign(rBAi), |a1| = aMax, a3 = - a1
33  4: same as type 3 but |a1| reduced as required so a solution exists
34  """
35  self.dt1 = float(dt1)
36  self.dt2 = float(dt2)
37  self.dt3 = float(dt3)
38  self.vP = float(vP)
39  self.a1 = float(a1)
40  self.a3 = float(a3)
41  self.slewType = int(slewType)
42 
43  def __repr__(self):
44  return "TrapSlewData(dt1=%s, dt2=%s, dt3=%s, vP=%s, a1=%s, a3=%s, slewType=%s)" % \
45  (self.dt1, self.dt2, self.dt3, self.vP, self.a1, self.a3, self.slewType)
46 
47 
48 def trapSlew(rBAi, vA, vB, dt2min, vMax, aMax):
49  """!Compute a trapezoidal slew.
50 
51  You may specify a minimum duration for the constant-velocity segment, which is useful for "rounding the
52  corners" of the slew to make it jerk-limited (see mov.fullSlew).
53 
54  @param[in] rBAi distance between "A" and "B" at time t = 0 (deg)
55  @param[in] vA velocity of "A" (deg/sec)
56  @param[in] vB velocity of "B" (deg/sec)
57  @param[in] dt2min minimum duration of segment 2 (constant velocity) (sec)
58  @param[in] vMax maximum allowed velocity (deg/sec)
59  @param[in] aMax maximum allowed acceleration (deg/sec^2)
60 
61  @return a TrapSlewData
62 
63  @throw RuntimeError if:
64  * dt2min < 0
65  * vMax <= 0
66  * aMax <= 0
67  * |vB| > vMax / Fudge
68 
69  Dies if vMax or aMax are so small as to cause under- or over-flow.
70 
71  Details:
72  The magic number "Fudge" is used to avoid borderline cases.
73  It is set below, and should be a number a bit bigger than one.
74 
75  How it works:
76  The slew begins by tracking object A, and ends by tracking object B.
77  Both objects are assumed to be moving at constant velocity.
78 
79  A trapezoidal slew has three segments, two of constant acceleration
80  separated by a constant velocity segment. It is called "trapezoidal"
81  because that is the shape of the v vs. t curve.
82 
83  Here are the initial velocity and constant acceleration for each segment,
84  and the duration of that segment, in the notation of this subroutine:
85 
86  segment v a duration
87  1 vA a1 dt1
88  2 vP 0 dt2
89  3 vP a2 dt3
90 
91 
92  The slew numbering and notation used in this subroutine are quite different
93  than those used in the math notebook. Significant changes include:
94  dt2 = delta-t3 in notebook
95  slew type 0 is not mentioned in the notebook
96  slew type 1 = notebook type 0
97  slew type 2 = notebook type 1
98  slew type 3, 4 = notebook type 3
99  note that the notebook type 2 slew (the only "reversed" slew)
100  is NOT USED by this subroutine, because it is not needed, and it saves
101  the bother of implementing the reversed slew equations; instead,
102  a type 3 or 4 slew (this subr.) is used with reduced acceleration.
103 
104  References:
105  "Control of the Apache Point 3.5m Telescope: Slewing", R. Owen, 1990, unpub
106 
107  TCC Math Notebook, section on slewing (warning: different notation)
108 
109  History:
110  2013-12-06 ROwen Converted from mov_TrapSlew.for
111  """
112  def reportBug(msgStr):
113  """!Write a message to stderr that includes outputs, then raise RuntimeError
114  """
115  sys.stderr.write("%s\ntrapSlew(rBai=%s, vA=%s, vB=%s, dt2min=%s, vMax=%s, aMax=%s)\n" % \
116  (msgStr, rBAi, vA, vB, dt2min, vMax, aMax))
117  raise RuntimeError(msgStr)
118 
119  if dt2min < 0.0:
120  raise RuntimeError("dt2min=%s < 0" % (dt2min,))
121  if vMax <= 0.0:
122  raise RuntimeError("vMax=%s < 0" % (vMax,))
123  if aMax <= 0.0:
124  raise RuntimeError("aMax=%s < 0" % (aMax,))
125 
126  # check velocities; errors are: |vB| Fudge > vMax,
127  # |vA| Fudge > vMax (can lead to dt1 < 0 for type 2 slews)
128  if abs(vA) > vMax * Fudge:
129  raise RuntimeError("Telescope is moving too fast (|%0.4f| > %s * %s). Stop the telescope, then try your slew again."
130  % (vA, Fudge, vMax))
131  if abs(vB) * Fudge > vMax:
132  raise RuntimeError("Target is moving too fast (|%0.4f| * %s > %s; telescope cannot acquire it." \
133  % (vB, Fudge, vMax))
134 
135  #+
136  # compute vBA, half_vBAsq, sign_rBAi and sign_vBA
137  # and handle null slews (rBAi and vBA both zero)
138  #-
139  vBA = vB - vA
140  half_vBAsq = 0.5 * vBA * vBA
141  if (rBAi != 0.0) and (vBA != 0.0):
142  sign_rBAi = math.copysign(1.0, rBAi)
143  sign_vBA = math.copysign(1.0, vBA)
144  elif rBAi != 0.0:
145  sign_rBAi = math.copysign(1.0, rBAi)
146  sign_vBA = sign_rBAi
147  elif vBA != 0.0:
148  sign_vBA = math.copysign(1.0, vBA)
149  sign_rBAi = sign_vBA
150  else:
151  return TrapSlewData(
152  dt1 = 0,
153  dt2 = dt2min,
154  dt3 = 0,
155  vP = vA,
156  a1 = 0,
157  a3 = 0,
158  slewType = 0,
159  )
160 
161  #+
162  # compute slewType, a1 and a3
163  #-
164  # if sign(rBAi) = sign(vBA), slew is type 1
165  # a solution is sure because dt3 has no upper limit over range of soln
166  if sign_rBAi == sign_vBA:
167  slewType = 1
168  a1 = sign_rBAi * aMax
169 
170  # else sign(rBAi) = - sign(vBA) so we use type 2, 3 or 4 slew...
171 
172  # a type 2 slew has a maximum dt2 dependent on initial conditions;
173  # the biggest dt2 occurs at largest |a|, |a| = aMax,
174  # and smallest |vPB|, |vPB| = |vBA|
175  # so test at that point to see if solutions exist with dt2 > dt2min
176  elif abs(vA) * Fudge < vMax and (dt2min * aMax * abs(vBA)) <= ((aMax * abs(rBAi)) - half_vBAsq):
177  slewType = 2
178  a1 = sign_rBAi * aMax
179 
180  # a type 3 slew only exists if aMax is small enough
181  elif (aMax * abs(rBAi) * Fudge) <= half_vBAsq:
182  slewType = 3
183  a1 = - sign_rBAi * aMax
184 
185  # a type 4 slew requires reducing accel. to obtain a solution
186  else:
187  slewType = 4
188  # since the equation for a1 is sure to give |a1| < aMax
189  # (otherwise slew would have been type 3)
190  # the equation is guranteed to not overflow
191  a1 = - half_vBAsq / (Fudge * rBAi)
192  a3 = - a1
193 
194  # make sure velocity / acceleration divisions will not overflow;
195  # this is especially important for slew type 4 because acceleration
196  # gets reduced, but could also catch stupid aMax or vMax inputs
197  max_vdiff = vMax + abs(vA) + abs(vB)
198  if max_vdiff >= min(abs(a1), 1.0) * DoubleMax:
199  raise reportBug('Computed slew time is ridiculous')
200 
201  #+
202  # compute dt2 and vP
203  #-
204  # first assume that dt2 = dt2min and compute vP;
205  # if resulting vP is too big, reduce it to maximum allowed
206  # and compute corresponding increased dt2
207  dt2 = dt2min
208  vPB_temp = (0.5 * a1 * dt2)**2 + half_vBAsq + a1 * rBAi
209  if vPB_temp < 0.0:
210  raise RuntimeError('Bug! Tried to compute square root of negative value')
211  vPB = math.copysign(math.sqrt(vPB_temp), a1) - (0.5 * a1 * dt2)
212  vP = vPB + vB
213  if abs(vP) > vMax:
214  # |vP| is too big, and so must be reduced.
215  # Note that |vB| < vMax / Fudge (as tested far above),
216  # so |vP| is guaranteed to be reducible to vMax without causing
217  # vPB to approach zero (much less change sign).
218  # The division velocity / acceleration was proved safe above.
219  # Thus dt2 may be computed without overflow.
220  vP = math.copysign(vMax, vP)
221  vPB = vP - vB
222  dt2 = (rBAi + ((half_vBAsq - (vPB * vPB)) / a1)) / vPB
223  #+
224  # compute dt1 and dt3
225  #-
226  # the following divisions were proved safe from overflow above,
227  # just after computing a1 and a3
228  vPA = vPB + vBA
229  dt1 = vPA / a1
230  dt3 = - vPB / a3
231 
232  # sanity checks
233  if (dt1 < 0.0) or (dt2 < 0.0) or (dt3 < 0.0):
234  reportBug('Bug! Computed negative duration for one or more segments')
235  if abs(vP) > vMax:
236  reportBug('Bug! Computed velocity greater than max velocity')
237  if abs(a1) > aMax:
238  reportBug('Bug! Computed acceleration greater than max acceleration')
239 
240  return TrapSlewData(
241  dt1 = dt1,
242  dt2 = dt2,
243  dt3 = dt3,
244  vP = vP,
245  a1 = a1,
246  a3 = a3,
247  slewType = slewType,
248  )
Data returned by trapSlew.
Definition: trapSlew.py:12
def trapSlew
Compute a trapezoidal slew.
Definition: trapSlew.py:48
def __init__
Construct a TrapSlewData.
Definition: trapSlew.py:15