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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed3b92ab6f402ed7ca931150c9832a245c62a8fa
4
- data.tar.gz: 02b6b58e47954514a8b89d79bc5a3b30bb99595c
3
+ metadata.gz: 64075129161ab9782dc7fabaf471d096e75bf877
4
+ data.tar.gz: db661feaafaa8af5d4ff1b4be7c76364e22064ab
5
5
  SHA512:
6
- metadata.gz: 28b63c397d384f6f06f077185c1b833a5330702286c4e5f0072cfea0dcd77c8f60adcec4b0ff8bcd92bd1e8bff251a32ab16a3852e2b89f78d7da9c55f6d1e86
7
- data.tar.gz: 90bee02b13d177287108d51f869001061856a4b14bc4c2955dedc3fa97138c15ae8ca6f7df70df1c352f3923242f3ab76a61261ff2b959ae338d30dce3188780
6
+ metadata.gz: 2ee1c8f010b1e235aa883b1e33f6b4fce083c991f0e87614f12a6bf99892814cf8abd57e79165e87ca46c1d7093dc450fa94958aafc441cc894deb5b9212d8f5
7
+ data.tar.gz: b4919aca65fd37811c77ccf6e7900f4fcd63d9241fd97885ae669480c5e584371761a6faf66d4c6c13458c1f62b9f71f350dde418a10939b06352da27ab73431
@@ -5,3 +5,12 @@ Metrics/BlockLength:
5
5
  ExcludedMethods:
6
6
  - context
7
7
  - describe
8
+
9
+ Metrics/LineLength:
10
+ Max: 120
11
+
12
+ Metrics/MethodLength:
13
+ Max: 15
14
+
15
+ Metrics/ParameterLists:
16
+ CountKeywordArgs: false
@@ -1,6 +1,8 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
+ - 2.2.8
5
+ - 2.3.5
4
6
  - 2.4.2
5
7
  cache: bundler
6
8
  before_install: gem install bundler -v 1.16.0
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pid_controller (0.1.0)
4
+ pid_controller (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  # PidController
2
+ [![Gem Version](https://badge.fury.io/rb/pid_controller.svg)](https://badge.fury.io/rb/pid_controller)
3
+ [![Build Status](https://travis-ci.org/gabetax/pid_controller.svg?branch=master)](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
 
@@ -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(setpoint:, kp: 1.0, ki: 1.0, kd: 1.0)
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 += error * dt
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
@@ -1,3 +1,3 @@
1
1
  class PidController
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pid_controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabe Martin-Dempesy