m-lundberg / simple-pid

A simple and easy to use PID controller in Python
MIT License
792 stars 216 forks source link

Running script in the command line gives unexpected result #17

Closed bboysteed closed 4 years ago

bboysteed commented 4 years ago

why me run the example file:water_boiler.py in the command line get an unexpected result.but when i run this file in the original python IDE ,it works.

m-lundberg commented 4 years ago

Hello,

I don't know. You will have to provide some more information for me to help you. What do you mean by unexpected result? Which operating system do you use? Which IDE? What is different when you run it in the command line vs in the IDE (does it use the same interpreter etc)?

bboysteed commented 4 years ago

Hello, I don't know. You will have to provide some more information for me to help you. What do you mean by unexpected result? Which operating system do you use? Which IDE? What is different when you run it in the command line vs in the IDE (does it use the same interpreter etc)?

Thanks for your reply!

  1. my operating system is: WINDOWS10 x64

  2. due to my destination to reach using your code,i changed some codes in the water_bolier.py,as flows:

    
    #!/usr/bin/env python

import time import matplotlib.pyplot as plt from simple_pid import PID

class WaterBoiler: """ Simple simulation of a water boiler which can heat up water and where the heat dissipates slowly over time """

def __init__(self):
    self.water_temp = 20

def update(self, boiler_power,dt):
    if boiler_power >0:
        print("turn right!")
        self.water_temp += 3 * boiler_power #boiler_power is my control parameter
    if boiler_power < 0:
        print("turn left!")
        self.water_temp += 3 * boiler_power 

    return self.water_temp

if name == 'main': angle_sets = [100,30] rank = 0 boiler = WaterBoiler() water_temp = boiler.water_temp

pid = PID(0.02, 0.0001, 0, setpoint=angle_sets[0])
pid.sample_time=0.3
#pid.output_limits = (0, 360)

start_time = time.time()
last_time = start_time

# keep track of values for plotting
setpoint, y, x = [], [], []

while rank < len(angle_sets):
    print("                        "+str(water_temp)+"°")
    current_time = time.time()
    dt = current_time - last_time

    power = pid(water_temp)
    print(power)
    water_temp = boiler.update(power,dt)

    x += [current_time - start_time]
    y += [water_temp]
    setpoint += [pid.setpoint]

    last_time = current_time

    if abs(water_temp-pid.setpoint) < 0.5 :
        rank+=1
        if pid.setpoint==angle_sets[-1]:
            break
        pid.setpoint = angle_sets[rank]

plt.plot(x, y, label='measured')
plt.plot(x, setpoint, label='target')
plt.xlabel('time')
plt.ylabel('temperature')
plt.legend()
plt.show()


3. the differences are as flows:
when run upper codes in the original python IDlE( Python's Integrated Development and Learning
Environment) I get the nice result:
![image](https://user-images.githubusercontent.com/45219937/77317657-8ed9d400-6d46-11ea-9d97-8f4fae5540ed.png)

but when  I run it in the Pycharm,I got a very big value of my control parameter,which obviously lose control.  as flows:
![image](https://user-images.githubusercontent.com/45219937/77317439-23900200-6d46-11ea-976b-d1bc7f78655b.png)
bboysteed commented 4 years ago

and I use the python 3.8 interpreter

bboysteed commented 4 years ago

by the way,i want to control a raspberry car to go ahead with a right direction.such as i want the car to go in the direction of 60°,use PID algorithm

m-lundberg commented 4 years ago

So I see you are not running the water boiler example at all but your own script. I was able to reproduce the uncontrollably growing value you observed by running your script as-is.

I suspect the issue comes from your removing the * dt in the WaterBoiler.update() method. By not having the updated value depend on the time passed since the last update, your script depends on how fast the code is running and will give different results depending on the performance of your hardware, Python interpreter etc. This theory is also backed up by the fact that the script seemingly works if I add a time.sleep(0.1) somewhere in the loop, making the code run a bit slower:

After introducing time.sleep(0.1)

So the real solution is to bring back the * dt, so it looks like:

self.water_temp += 3 * boiler_power * dt  # boiler_power is my control parameter

With this fix (and without the time.sleep(0.1)) I get the following plot, which should be more like what you expect:

With dt

You may need to change your tuning parameters Kp, Ki and Kd after doing this.

bboysteed commented 4 years ago

thanks very much for your professional reply.it makes me realize the speed of pycharm running code is much faster than the original python IDE,so add sleep(0.1) in the pycharm helps.I can not add *dt ,the reason is my control parameter:self.water_temp has nothing to do 'dt',just depend on water_power.

this is my first time using github,you are really helpful.have a nice day!