pid_controller 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/.travis.yml +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/lib/pid_controller.rb +31 -3
- data/lib/pid_controller/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64075129161ab9782dc7fabaf471d096e75bf877
|
4
|
+
data.tar.gz: db661feaafaa8af5d4ff1b4be7c76364e22064ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ee1c8f010b1e235aa883b1e33f6b4fce083c991f0e87614f12a6bf99892814cf8abd57e79165e87ca46c1d7093dc450fa94958aafc441cc894deb5b9212d8f5
|
7
|
+
data.tar.gz: b4919aca65fd37811c77ccf6e7900f4fcd63d9241fd97885ae669480c5e584371761a6faf66d4c6c13458c1f62b9f71f350dde418a10939b06352da27ab73431
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# PidController
|
2
|
+
[](https://badge.fury.io/rb/pid_controller)
|
3
|
+
[](https://travis-ci.org/gabetax/pid_controller)
|
2
4
|
|
3
5
|
This is a Ruby implementation of a [PID Controller](https://en.wikipedia.org/wiki/PID_controller). A PID controller is a feedback system that is configured with a target setpoint, can read measurements of the system to see how close we are to the setpoint, and will omit an output. Every day examples include:
|
4
6
|
|
data/lib/pid_controller.rb
CHANGED
@@ -4,17 +4,44 @@ require 'pid_controller/version'
|
|
4
4
|
class PidController
|
5
5
|
attr_accessor :setpoint, :kp, :ki, :kd
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(
|
8
|
+
setpoint:,
|
9
|
+
kp: 1.0,
|
10
|
+
ki: 1.0,
|
11
|
+
kd: 1.0,
|
12
|
+
integral_min: nil,
|
13
|
+
integral_max: nil,
|
14
|
+
output_min: nil,
|
15
|
+
output_max: nil
|
16
|
+
)
|
8
17
|
@setpoint = setpoint
|
9
18
|
@kp = kp
|
10
19
|
@ki = ki
|
11
20
|
@kd = kd
|
21
|
+
# Prevents https://en.wikipedia.org/wiki/Integral_windup via bounds
|
22
|
+
@integral_min = integral_min || -Float::INFINITY
|
23
|
+
@integral_max = integral_max || Float::INFINITY
|
24
|
+
@output_min = output_min || -Float::INFINITY
|
25
|
+
@output_max = output_max || Float::INFINITY
|
12
26
|
@integral = 0.0
|
13
27
|
@derivative = 0.0
|
14
28
|
@last_error = nil
|
15
29
|
@last_update = nil
|
16
30
|
end
|
17
31
|
|
32
|
+
unless defined?(0.clamp)
|
33
|
+
# Comparable#clamp is introduced in Ruby 2.4
|
34
|
+
module NumericClamp
|
35
|
+
# I'd refine Comparable itself, but older Rubies can't refine modules
|
36
|
+
refine Numeric do
|
37
|
+
def clamp(min, max)
|
38
|
+
[min, [max, self].min].max
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
using NumericClamp
|
43
|
+
end
|
44
|
+
|
18
45
|
def update(measurement)
|
19
46
|
now = clock_time
|
20
47
|
dt = if @last_update
|
@@ -32,7 +59,7 @@ class PidController
|
|
32
59
|
error = setpoint - measurement.to_f
|
33
60
|
|
34
61
|
if dt > 0.0
|
35
|
-
@integral
|
62
|
+
@integral = (@integral + error * dt).clamp(@integral_min, @integral_max)
|
36
63
|
@derivative = (error - @last_error) / dt
|
37
64
|
end
|
38
65
|
|
@@ -42,7 +69,7 @@ class PidController
|
|
42
69
|
end
|
43
70
|
|
44
71
|
def output
|
45
|
-
p_term + i_term + d_term
|
72
|
+
(p_term + i_term + d_term).clamp(@output_min, @output_max)
|
46
73
|
end
|
47
74
|
|
48
75
|
def p_term
|
@@ -57,6 +84,7 @@ class PidController
|
|
57
84
|
kd * @derivative
|
58
85
|
end
|
59
86
|
|
87
|
+
# Read the monotonic clock. It avoid horrors of leap seconds and NTP.
|
60
88
|
def clock_time
|
61
89
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
62
90
|
end
|