Skip to content

Commit

Permalink
Use time.monotonic() for python>=3.3 to ensure no negative time delta…
Browse files Browse the repository at this point in the history
…s due to changed system time. Will default back to time.time() if time.monotonic() is not available. Fixes #1.
  • Loading branch information
m-lundberg committed Oct 2, 2018
1 parent ec42f12 commit f8cc624
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ build/
.pytest_cache/
.tox/
*.pyc
.idea/
.envrc
19 changes: 15 additions & 4 deletions simple_pid/PID.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
import warnings


def _clamp(value, limits):
Expand All @@ -12,6 +13,15 @@ def _clamp(value, limits):
return value


try:
# get monotonic time to ensure that time deltas are always positive
_current_time = time.monotonic
except AttributeError:
# time.monotonic() not available (using python < 3.3), fallback to time.time()
_current_time = time.time
warnings.warn('time.monotonic() not available, using time.time() as fallback. Consider using Python 3.3 or newer to get monotonic time measurements.')


class PID(object):
"""
A simple PID controller. No fuss.
Expand All @@ -37,7 +47,7 @@ def __init__(self, Kp=1.0, Ki=0.0, Kd=0.0, setpoint=0, sample_time=0.01, output_

self._error_sum = 0

self._last_time = time.time()
self._last_time = _current_time()
self._last_output = None
self._proportional = 0
self._last_input = None
Expand All @@ -50,8 +60,9 @@ def __call__(self, input_):
"""
if not self.auto_mode:
return self._last_output

dt = time.time() - self._last_time

now = _current_time()
dt = now - self._last_time

if self.sample_time is not None and dt < self.sample_time and self._last_output is not None:
# only update every sample_time seconds
Expand Down Expand Up @@ -81,7 +92,7 @@ def __call__(self, input_):
# keep track of state
self._last_output = output
self._last_input = input_
self._last_time = time.time()
self._last_time = now

return output

Expand Down
11 changes: 10 additions & 1 deletion tests/test_pid.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

import sys
import time
import pytest
from simple_pid import PID
Expand Down Expand Up @@ -99,6 +99,15 @@ def test_sample_time():
assert pid(100) == control


def test_monotonic():
from simple_pid.PID import _current_time

if sys.version_info < (3, 3):
assert _current_time == time.time
else:
assert _current_time == time.monotonic


def test_clamp():
from simple_pid.PID import _clamp

Expand Down

0 comments on commit f8cc624

Please sign in to comment.