Skip to content

Commit f8cc624

Browse files
committed
Use time.monotonic() for python>=3.3 to ensure no negative time deltas due to changed system time. Will default back to time.time() if time.monotonic() is not available. Fixes #1.
1 parent ec42f12 commit f8cc624

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ build/
88
.pytest_cache/
99
.tox/
1010
*.pyc
11+
.idea/
12+
.envrc

simple_pid/PID.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import time
2+
import warnings
23

34

45
def _clamp(value, limits):
@@ -12,6 +13,15 @@ def _clamp(value, limits):
1213
return value
1314

1415

16+
try:
17+
# get monotonic time to ensure that time deltas are always positive
18+
_current_time = time.monotonic
19+
except AttributeError:
20+
# time.monotonic() not available (using python < 3.3), fallback to time.time()
21+
_current_time = time.time
22+
warnings.warn('time.monotonic() not available, using time.time() as fallback. Consider using Python 3.3 or newer to get monotonic time measurements.')
23+
24+
1525
class PID(object):
1626
"""
1727
A simple PID controller. No fuss.
@@ -37,7 +47,7 @@ def __init__(self, Kp=1.0, Ki=0.0, Kd=0.0, setpoint=0, sample_time=0.01, output_
3747

3848
self._error_sum = 0
3949

40-
self._last_time = time.time()
50+
self._last_time = _current_time()
4151
self._last_output = None
4252
self._proportional = 0
4353
self._last_input = None
@@ -50,8 +60,9 @@ def __call__(self, input_):
5060
"""
5161
if not self.auto_mode:
5262
return self._last_output
53-
54-
dt = time.time() - self._last_time
63+
64+
now = _current_time()
65+
dt = now - self._last_time
5566

5667
if self.sample_time is not None and dt < self.sample_time and self._last_output is not None:
5768
# only update every sample_time seconds
@@ -81,7 +92,7 @@ def __call__(self, input_):
8192
# keep track of state
8293
self._last_output = output
8394
self._last_input = input_
84-
self._last_time = time.time()
95+
self._last_time = now
8596

8697
return output
8798

tests/test_pid.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
import sys
22
import time
33
import pytest
44
from simple_pid import PID
@@ -99,6 +99,15 @@ def test_sample_time():
9999
assert pid(100) == control
100100

101101

102+
def test_monotonic():
103+
from simple_pid.PID import _current_time
104+
105+
if sys.version_info < (3, 3):
106+
assert _current_time == time.time
107+
else:
108+
assert _current_time == time.monotonic
109+
110+
102111
def test_clamp():
103112
from simple_pid.PID import _clamp
104113

0 commit comments

Comments
 (0)