Last active
July 17, 2018 10:39
-
-
Save TeWu/eca9cd728f591c1d627f to your computer and use it in GitHub Desktop.
PID Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PID | |
attr_reader :kp, :ki, :kd, :output, :previous_error | |
attr_accessor :setpoint, :history_depth, :output_range, :invert_output | |
def initialize(setpoint, options = {}) | |
@setpoint = setpoint | |
@kp = options[:kp] || 1 | |
@ki = options[:ki] || 0 | |
@kd = options[:kd] || 0 | |
@history_depth = options[:history_depth] || 0 | |
@output_range = options[:output_range] || (-1..1) | |
@invert_output = options[:invert_output] || false | |
reset | |
end | |
def reset | |
@last_time = nil | |
@previous_error = 0.0 | |
@integrative = 0.0 | |
@history = [] | |
end | |
def control(input) | |
dt = step_time | |
error = setpoint - input | |
out = proportional(error) + integrative(error, dt) + derivative(error, dt) | |
out = -out if invert_output | |
@previous_error = error | |
@output = out.clamp_to output_range | |
end | |
protected # ------- | |
def step_time | |
now = Time.now.to_f | |
dt = @last_time.nil? ? 1.0 : now - @last_time | |
@last_time = now | |
dt | |
end | |
def proportional(error) | |
kp * error | |
end | |
def integrative(error, dt) | |
# classic mode | |
@integrative += error * dt | |
# window mode | |
if @history_depth > 0 | |
@history << error * dt # push last sample | |
@history = @history.last(@history_depth) # keep the last one | |
@integrative = @history.reduce(:+) | |
@integrative /= @history_depth # normalize | |
end | |
ki * @integrative | |
end | |
def derivative(error, dt) | |
kd * (error - @previous_error) / dt | |
end | |
end | |
module Comparable | |
def clamp_to(range) | |
return range.min if self < range.min | |
return range.max if self > range.max | |
self | |
end | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require './pid' | |
class Vessel | |
attr_accessor :speed, :engine_force, :grav_force | |
def initialize | |
@grav_force = -150 | |
@engine_force = 0 | |
@speed = 0 | |
end | |
def step | |
@grav_force -= 0.5 if @grav_force > -500 | |
@engine_force = 0 if @engine_force < 0 | |
@speed += @grav_force + @engine_force | |
puts "#{grav_force} + #{engine_force} = #{speed}" | |
end | |
end | |
pid = PID.new(-51.3, kp: 1, kd: 0.1, output_range: -100..100) | |
v = Vessel.new | |
File.open "out", "w+" do |f| | |
for i in 1..50 | |
c = pid.control v.speed | |
f.puts [v.speed.to_f.round(3), c.to_f.round(3), pid.previous_error.to_f.round(3)].join(", ") | |
v.engine_force += c | |
pid.setpoint = -200 if i == 30 | |
v.step | |
end | |
end | |
puts v.grav_force | |
puts v.engine_force | |
puts v.speed | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment