update
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
##############################################################################
|
||||
### PID Controller Library and Example
|
||||
##############################################################################
|
||||
### Like all of the scripts in my folder here, this file contains
|
||||
### functions you might want to include into your own scripts for
|
||||
### actual use and a demo in the 'main' function that you can just
|
||||
### run to see how it works.
|
||||
###
|
||||
### This file includes a simple and generic PID controller that we use in
|
||||
### many of the other examples when we want to smoothly control one value
|
||||
### based on our measurement of another. The PID class docstring explains
|
||||
### the basics of using it in your project. The demo code below that
|
||||
### shows how to use the PID controller to hold a vertical velocity with
|
||||
### variation of engine thrust.
|
||||
|
||||
### From https://github.com/krpc/krpc-library/blob/master/Art_Whaleys_KRPC_Demos/pid.py
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import krpc
|
||||
|
||||
|
||||
class PID(object):
|
||||
'''
|
||||
Generic PID Controller Class
|
||||
Based on the PID recipe at :
|
||||
|
||||
http://code.activestate.com/recipes/577231-discrete-pid-controller/
|
||||
|
||||
and the code and discussions in the blog at:
|
||||
|
||||
http://brettbeauregard.com/blog/2011/04/
|
||||
improving-the-beginners-pid-introduction/
|
||||
|
||||
An instance is created with the format
|
||||
your_pid=PID(P=.0001, I=0.00001, D=0.000001)
|
||||
|
||||
Finding the right values for those three gain numbers is called 'tuning' and
|
||||
that's beyond the scope of this doc string!
|
||||
|
||||
Use your_pid.setpoint(X) to set the target output value of the controller.
|
||||
|
||||
Regularly call your_pid.update(Y), passing it the input data that the
|
||||
controller should respond to.
|
||||
output_data = your_pid.update(input_data)
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, P=1.0, I=0.1, D=0.01):
|
||||
self.Kp = P # P controls reaction to the instantaneous error
|
||||
self.Ki = I # I controls reaction to the history of error
|
||||
self.Kd = D # D prevents overshoot by considering rate of change
|
||||
self.P = 0.0
|
||||
self.I = 0.0
|
||||
self.D = 0.0
|
||||
self.SetPoint = 0.0 # Target value for controller
|
||||
self.ClampI = 1.0 # clamps i_term to prevent 'windup.'
|
||||
self.LastTime = time.time()
|
||||
self.LastMeasure = 0.0
|
||||
|
||||
def update(self, measure):
|
||||
now = time.time()
|
||||
change_in_time = now - self.LastTime
|
||||
if not change_in_time:
|
||||
change_in_time = 1.0 # avoid potential divide by zero if PID just created.
|
||||
|
||||
error = self.SetPoint - measure
|
||||
self.P = error
|
||||
self.I += error
|
||||
self.I = self.clamp_i(self.I) # clamp to prevent windup lag
|
||||
self.D = (measure - self.LastMeasure) / (change_in_time)
|
||||
|
||||
self.LastMeasure = measure # store data for next update
|
||||
self.lastTime = now
|
||||
|
||||
return (self.Kp * self.P) + (self.Ki * self.I) - (self.Kd * self.D)
|
||||
|
||||
def clamp_i(self, i):
|
||||
if i > self.ClampI:
|
||||
return self.ClampI
|
||||
elif i < -self.ClampI:
|
||||
return -self.ClampI
|
||||
else:
|
||||
return i
|
||||
|
||||
def setpoint(self, value):
|
||||
self.SetPoint = value
|
||||
self.I = 0.0
|
||||
|
||||
|
||||
##############################################################################
|
||||
## Demo Code Below This Line!
|
||||
##############################################################################
|
||||
|
||||
Target_Velocity = 5 # The value we're trying to limit ourselves to
|
||||
|
||||
|
||||
##############################################################################
|
||||
## Main -- only run when we execute this file directly.
|
||||
## ignored when we import the PID into other files!
|
||||
##############################################################################
|
||||
def main():
|
||||
# Setup KRPC
|
||||
conn = krpc.connect()
|
||||
sc = conn.space_center
|
||||
v = sc.active_vessel
|
||||
telem = v.flight(v.orbit.body.reference_frame)
|
||||
|
||||
# Create PID controller.
|
||||
p = PID(P=.25, I=0.025, D=0.0025)
|
||||
p.ClampI = 20
|
||||
p.setpoint(Target_Velocity)
|
||||
|
||||
# starting with locked SAS and throttle at full
|
||||
v.control.sas = True
|
||||
v.control.throttle = 1.0
|
||||
while not v.thrust: # stage if we just launched a new rocket
|
||||
v.control.activate_next_stage()
|
||||
|
||||
# Loop Forever, or until you get the point of this example and stop it.
|
||||
while True:
|
||||
the_pids_output = p.update(telem.vertical_speed)
|
||||
v.control.throttle = the_pids_output
|
||||
print('Vertical V:{:03.2f} PID returns:{:03.2f} Throttle:{:03.2f}'
|
||||
.format(telem.vertical_speed,
|
||||
the_pids_output,
|
||||
v.control.throttle))
|
||||
time.sleep(.1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
print('--')
|
||||
Reference in New Issue
Block a user