pid_controller 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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