Package roslib :: Module rostime

Source Code for Module roslib.rostime

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id: rostime.py 14969 2011-09-12 20:09:18Z kwc $ 
 34   
 35  """ 
 36  ROS Time representation, including Duration 
 37  """ 
 38   
 39  import itertools 
 40  import time 
 41  import sys 
 42   
 43  if sys.version > '3': 
 44          long = int 
 45   
46 -def _canon(secs, nsecs):
47 #canonical form: nsecs is always positive, nsecs < 1 second 48 while nsecs >= 1000000000: 49 secs += 1 50 nsecs -= 1000000000 51 while nsecs < 0: 52 secs -= 1 53 nsecs += 1000000000 54 return secs,nsecs
55
56 -class TVal(object):
57 """ 58 Base class of L{Time} and L{Duration} representations. Representation 59 is secs+nanoseconds since epoch. 60 """ 61 62 __slots__ = ['secs', 'nsecs']
63 - def __init__(self, secs=0, nsecs=0):
64 """ 65 @param secs: seconds. If secs is a float, then nsecs must not be set or 0 66 @type secs: int/float 67 @param nsecs: nanoseconds 68 @type nsecs: int 69 """ 70 if type(secs) != int: 71 # float secs constructor 72 if nsecs != 0: 73 raise ValueError("if secs is a float, nsecs cannot be set") 74 float_secs = secs 75 secs = int(float_secs) 76 nsecs = int((float_secs - secs) * 1000000000) 77 78 self.secs, self.nsecs = _canon(secs, nsecs)
79
80 - def is_zero(self):
81 """ 82 @return: True if time is zero (secs and nsecs are zero) 83 @rtype: bool 84 """ 85 return self.secs == 0 and self.nsecs == 0
86
87 - def set(self, secs, nsecs):
88 """ 89 Set time using separate secs and nsecs values 90 91 @param secs: seconds since epoch 92 @type secs: int 93 @param nsecs: nanoseconds since seconds 94 @type nsecs: int 95 """ 96 self.secs = secs 97 self.nsecs = nsecs
98
99 - def canon(self):
100 """ 101 Canonicalize the field representation in this instance. should 102 only be used when manually setting secs/nsecs slot values, as 103 in deserialization. 104 """ 105 self.secs, self.nsecs = _canon(self.secs, self.nsecs)
106
107 - def to_sec(self):
108 """ 109 @return: time as float seconds (same as time.time() representation) 110 @rtype: float 111 """ 112 return float(self.secs) + float(self.nsecs) / 1e9
113
114 - def to_nsec(self):
115 """ 116 @return: time as nanoseconds 117 @rtype: long 118 """ 119 return self.secs * long(1e9) + self.nsecs
120
121 - def __hash__(self):
122 """ 123 Time values are hashable. Time values with identical fields have the same hash. 124 """ 125 return ("%s.%s"%(self.secs, self.nsecs)) .__hash__()
126
127 - def __str__(self):
128 return str(self.to_nsec())
129
130 - def __repr__(self):
131 return "rostime.TVal[%d]"%self.to_nsec()
132
133 - def __nonzero__(self):
134 """ 135 Check if time value is zero 136 """ 137 return self.secs or self.nsecs
138
139 - def __lt__(self, other):
140 """ 141 < test for time values 142 """ 143 try: 144 return self.__cmp__(other) < 0 145 except TypeError: 146 return NotImplemented
147 - def __le__(self, other):
148 """ 149 <= test for time values 150 """ 151 try: 152 return self.__cmp__(other) <= 0 153 except TypeError: 154 return NotImplemented
155 - def __gt__(self, other):
156 """ 157 > test for time values 158 """ 159 try: 160 return self.__cmp__(other) > 0 161 except TypeError: 162 return NotImplemented
163 - def __ge__(self, other):
164 """ 165 >= test for time values 166 """ 167 try: 168 return self.__cmp__(other) >= 0 169 except TypeError: 170 return NotImplemented
171 - def __ne__(self, other):
172 return not self.__eq__(other)
173 - def __cmp__(self, other):
174 if not isinstance(other, TVal): 175 raise TypeError("Cannot compare to non-TVal") 176 nanos = self.to_nsec() - other.to_nsec() 177 if nanos > 0: 178 return 1 179 if nanos == 0: 180 return 0 181 return -1
182 - def __eq__(self, other):
183 if not isinstance(other, TVal): 184 return False 185 return self.to_nsec() == other.to_nsec()
186
187 -class Time(TVal):
188 """ 189 Time contains the ROS-wide 'time' primitive representation, which 190 consists of two integers: seconds since epoch and nanoseconds since 191 seconds. Time instances are mutable. 192 """ 193 __slots__ = ['secs', 'nsecs']
194 - def __init__(self, secs=0, nsecs=0):
195 """ 196 Constructor: secs and nsecs are integers. You may prefer to use the static L{from_sec()} factory 197 method instead. 198 199 @param secs: seconds since epoch 200 @type secs: int 201 @param nsecs: nanoseconds since seconds (since epoch) 202 @type nsecs: int 203 """ 204 super(Time, self).__init__(secs, nsecs) 205 if self.secs < 0: 206 raise TypeError("time values must be positive")
207
208 - def __getstate__(self):
209 """ 210 support for Python pickling 211 """ 212 return [self.secs, self.nsecs]
213
214 - def __setstate__(self, state):
215 """ 216 support for Python pickling 217 """ 218 self.secs, self.nsecs = state
219
220 - def from_sec(float_secs):
221 """ 222 Create new Time instance using time.time() value (float 223 seconds) 224 225 @param float_secs: time value in time.time() format 226 @type float_secs: float 227 @return: Time instance for specified time 228 @rtype: L{Time} 229 """ 230 secs = int(float_secs) 231 nsecs = int((float_secs - secs) * 1000000000) 232 return Time(secs, nsecs)
233 234 from_sec = staticmethod(from_sec) 235
236 - def to_time(self):
237 """ 238 Get Time in time.time() format. alias of L{to_sec()} 239 240 @return: time in floating point secs (time.time() format) 241 @rtype: float 242 """ 243 return self.to_sec()
244
245 - def __repr__(self):
246 return "rostime.Time[%d]"%self.to_nsec()
247
248 - def __add__(self, other):
249 """ 250 Add duration to this time 251 252 @param other: duration 253 @type other: L{Duration} 254 """ 255 if not isinstance(other, Duration): 256 return NotImplemented 257 return Time(self.secs + other.secs, self.nsecs + other.nsecs)
258
259 - def __sub__(self, other):
260 """ 261 Subtract time or duration from this time 262 @param other: duration 263 @type other: L{Duration}/L{Time} 264 @return: L{Duration} if other is a L{Time}, L{Time} if other is a L{Duration} 265 """ 266 if isinstance(other, Time): 267 return Duration(self.secs - other.secs, self.nsecs - other.nsecs) 268 elif isinstance(other, Duration): 269 return Time(self.secs - other.secs, self.nsecs - other.nsecs) 270 else: 271 return NotImplemented
272
273 - def __cmp__(self, other):
274 """ 275 Compare to another time 276 @param other: Time 277 @type other: L{Time} 278 """ 279 if not isinstance(other, Time): 280 raise TypeError("cannot compare to non-Time") 281 nanos = self.to_nsec() - other.to_nsec() 282 if nanos > 0: 283 return 1 284 if nanos == 0: 285 return 0 286 return -1
287
288 - def __eq__(self, other):
289 """ 290 Equals test for Time. Comparison assumes that both time 291 instances are in canonical representation; only compares fields. 292 293 @param other: Time 294 @type other: L{Time} 295 """ 296 if not isinstance(other, Time): 297 return False 298 return self.secs == other.secs and self.nsecs == other.nsecs
299
300 -class Duration(TVal):
301 """ 302 Duration represents the ROS 'duration' primitive, which consists 303 of two integers: seconds and nanoseconds. The Duration class 304 allows you to add and subtract Duration instances, including 305 adding and subtracting from L{Time} instances. 306 """ 307 __slots__ = ['secs', 'nsecs']
308 - def __init__(self, secs=0, nsecs=0):
309 """ 310 Create new Duration instance. secs and nsecs are integers and correspond to the ROS 'duration' primitive. 311 312 @param secs: seconds 313 @type secs: int 314 @param nsecs: nanoseconds 315 @type nsecs: int 316 """ 317 super(Duration, self).__init__(secs, nsecs)
318
319 - def __getstate__(self):
320 """ 321 support for Python pickling 322 """ 323 return [self.secs, self.nsecs]
324
325 - def __setstate__(self, state):
326 """ 327 support for Python pickling 328 """ 329 self.secs, self.nsecs = state
330
331 - def __repr__(self):
332 return "rostime.Duration[%d]"%self.to_nsec()
333
334 - def from_sec(float_seconds):
335 """ 336 Create new Duration instance from float seconds format. 337 338 @param float_seconds: time value in specified as float seconds 339 @type float_seconds: float 340 @return: Duration instance for specified float_seconds 341 @rtype: Duration 342 """ 343 secs = int(float_seconds) 344 nsecs = int((float_seconds - secs) * 1000000000) 345 return Duration(secs, nsecs)
346 347 from_sec = staticmethod(from_sec) 348
349 - def __neg__(self):
350 """ 351 @return: Negative value of this duration 352 @rtype: L{Duration} 353 """ 354 return Duration(-self.secs, -self.nsecs)
355 - def __abs__(self):
356 """ 357 Absolute value of this duration 358 @return: positive duration 359 @rtype: L{Duration} 360 """ 361 if self.secs > 0: 362 return self 363 return self.__neg__()
364
365 - def __add__(self, other):
366 """ 367 Add duration to this duration, or this duration to a time, creating a new time value as a result. 368 @param other: duration or time 369 @type other: L{Duration}/L{Time} 370 @return: L{Duration} if other is a L{Duration}, L{Time} if other is a L{Time} 371 """ 372 if isinstance(other, Time): 373 return other.__add__(self) 374 elif isinstance(other, Duration): 375 return Duration(self.secs+other.secs, self.nsecs+other.nsecs) 376 else: 377 return NotImplemented
378 - def __sub__(self, other):
379 """ 380 Subtract duration from this duration, returning a new duration 381 @param other: duration 382 @type other: L{Duration} 383 @return: L{Duration} 384 """ 385 if not isinstance(other, Duration): 386 return NotImplemented 387 return Duration(self.secs-other.secs, self.nsecs-other.nsecs)
388
389 - def __mul__(self, val):
390 """ 391 Multiply this duration by an integer or float 392 @param val: multiplication factor 393 @type val: int/float 394 @return: Duration multiplied by val 395 @rtype: L{Duration} 396 """ 397 t = type(val) 398 if t in (int, long): 399 return Duration(self.secs * val, self.nsecs * val) 400 elif t == float: 401 return Duration.from_sec(self.to_sec() * val) 402 else: 403 return NotImplemented
404
405 - def __floordiv__(self, val):
406 """ 407 Floor divide this duration by an integer or float 408 @param val: division factor 409 @type val: int/float 410 @return: Duration multiplied by val 411 @rtype: L{Duration} 412 """ 413 t = type(val) 414 if t in (int, long): 415 return Duration(self.secs // val, self.nsecs // val) 416 elif t == float: 417 return Duration.from_sec(self.to_sec() // val) 418 else: 419 return NotImplemented
420
421 - def __div__(self, val):
422 """ 423 Divide this duration by an integer or float 424 @param val: division factor 425 @type val: int/float 426 @return: Duration multiplied by val 427 @rtype: L{Duration} 428 """ 429 # unlike __floordiv__, this uses true div for float arg. 430 # PEP 238 431 t = type(val) 432 if t in (int, long): 433 return Duration(self.secs // val, self.nsecs // val) 434 elif t == float: 435 return Duration.from_sec(self.to_sec() / val) 436 else: 437 return NotImplemented
438
439 - def __truediv__(self, val):
440 """ 441 Divide this duration by an integer or float 442 @param val: division factor 443 @type val: int/float 444 @return: Duration multiplied by val 445 @rtype: L{Duration} 446 """ 447 if type(val) in (int, long, float): 448 return Duration.from_sec(self.to_sec() / val) 449 else: 450 return NotImplemented
451
452 - def __cmp__(self, other):
453 if not isinstance(other, Duration): 454 raise TypeError("Cannot compare to non-Duration") 455 nanos = self.to_nsec() - other.to_nsec() 456 if nanos > 0: 457 return 1 458 if nanos == 0: 459 return 0 460 return -1
461
462 - def __eq__(self, other):
463 if not isinstance(other, Duration): 464 return False 465 return self.secs == other.secs and self.nsecs == other.nsecs
466