Class: PidController

Inherits:
Object
  • Object
show all
Defined in:
lib/pid_controller.rb,
lib/pid_controller/version.rb

Overview

Defined Under Namespace

Modules: NumericClamp

Constant Summary collapse

VERSION =
'0.2.3'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(setpoint:, kp: 1.0, ki: 1.0, kd: 1.0, integral_min: nil, integral_max: nil, output_min: nil, output_max: nil) ⇒ PidController

Returns a new instance of PidController.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/pid_controller.rb', line 7

def initialize(
  setpoint:,
  kp: 1.0,
  ki: 1.0,
  kd: 1.0,
  integral_min: nil,
  integral_max: nil,
  output_min: nil,
  output_max: nil
)
  @setpoint = setpoint
  @kp = kp
  @ki = ki
  @kd = kd
  # Prevents https://en.wikipedia.org/wiki/Integral_windup via bounds
  @integral_min = integral_min || -Float::INFINITY
  @integral_max = integral_max || Float::INFINITY
  @output_min = output_min || -Float::INFINITY
  @output_max = output_max || Float::INFINITY
  @integral   = 0.0
  @derivative = 0.0
  @last_error  = nil
  @last_update = nil
end

Instance Attribute Details

#kdObject

Returns the value of attribute kd.



5
6
7
# File 'lib/pid_controller.rb', line 5

def kd
  @kd
end

#kiObject

Returns the value of attribute ki.



5
6
7
# File 'lib/pid_controller.rb', line 5

def ki
  @ki
end

#kpObject

Returns the value of attribute kp.



5
6
7
# File 'lib/pid_controller.rb', line 5

def kp
  @kp
end

#setpointObject

Returns the value of attribute setpoint.



5
6
7
# File 'lib/pid_controller.rb', line 5

def setpoint
  @setpoint
end

Instance Method Details

#clock_timeObject

Read the monotonic clock. It avoid horrors of leap seconds and NTP.



88
89
90
# File 'lib/pid_controller.rb', line 88

def clock_time
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

#d_termObject



83
84
85
# File 'lib/pid_controller.rb', line 83

def d_term
  kd * @derivative
end

#i_termObject



79
80
81
# File 'lib/pid_controller.rb', line 79

def i_term
  ki * @integral
end

#outputObject



71
72
73
# File 'lib/pid_controller.rb', line 71

def output
  (p_term + i_term + d_term).clamp(@output_min, @output_max)
end

#p_termObject



75
76
77
# File 'lib/pid_controller.rb', line 75

def p_term
  kp * (@last_error || 0.0)
end

#update(measurement) ⇒ Object Also known as: <<



45
46
47
48
49
50
51
52
53
54
# File 'lib/pid_controller.rb', line 45

def update(measurement)
  now = clock_time
  dt = if @last_update
         now - @last_update
       else
         0.0
       end
  @last_update = now
  update_with_duration(measurement, dt)
end

#update_with_duration(measurement, dt) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/pid_controller.rb', line 58

def update_with_duration(measurement, dt)
  error = setpoint - measurement.to_f

  if dt > 0.0
    @integral = (@integral + error * dt).clamp(@integral_min, @integral_max)
    @derivative = (error - @last_error) / dt if @last_error
  end

  @last_error = error

  output
end