Permalink
Browse files

added simple PID test

  • Loading branch information...
1 parent 7591527 commit 318e962dffe05a97f2b676841365735323ef34d3 @aktur aktur committed Dec 29, 2016
View
@@ -16,3 +16,5 @@ bin/
*~
manager/.factorypath
manager/src/
+
+out/
@@ -0,0 +1,75 @@
+package org.openremote.test.rules
+
+import org.kie.api.KieServices
+import org.kie.api.io.Resource
+import org.openremote.agent.AgentService
+import org.openremote.agent.rules.RulesProvider
+import org.openremote.agent.sensor.CustomSensorState
+import org.openremote.test.ContainerTrait
+import spock.lang.Specification
+
+import java.util.stream.Stream
+
+class PIDTest extends Specification implements ContainerTrait {
+
+ def "PID controller basic test"() {
+
+ given: "a deployment with commands and sensors"
+ def deploymentXml = getClass().getResourceAsStream(
+ "/org/openremote/test/rules/pid/agent.xml"
+ )
+
+ and: "some rules"
+ def rulesProvider = new RulesProvider() {
+ @Override
+ Stream<Resource> getResources(KieServices kieServices) {
+ Stream.of(
+ kieServices.getResources().newClassPathResource(
+ "org/openremote/test/rules/pid/PID.drl"
+ )
+ )
+ }
+ }
+
+ and: "the started server"
+ def testCommandBuilder = new TestCommandBuilder();
+ def agentService = new AgentService(
+ deploymentXml,
+ testCommandBuilder,
+ rulesProvider
+ )
+ def serverPort = findEphemeralPort()
+ def container = startContainer(defaultConfig(serverPort), [agentService])
+
+ when: "we increase Sp"
+ // can we run PID.sp.inc.ON command instead?
+ def customStateEvent = new CustomSensorState(358537, "PID.sp.inc", "ON");
+ agentService.getContext().update(customStateEvent);
+
+ and: "we wait"
+ Thread.sleep(1000);
+
+ then: "set point should be 1.5"
+ agentService.getContext().queryValue(358531) == "1.5" // can we check sensors by name?
+ agentService.getContext().queryValue(358532) == "1.5000" // PID output
+
+ when: "we decrease Sp"
+ customStateEvent = new CustomSensorState(358525, "PID.sp.dec", "ON");
+ agentService.getContext().update(customStateEvent);
+
+ and: "we wait"
+ Thread.sleep(1000);
+
+ then: "set point should be 1.0"
+ agentService.getContext().queryValue(358531) == "1.0" // set point
+ agentService.getContext().queryValue(358532) == "1.0000" // PID output
+
+ // how can I test if there is no overshot?
+ // how can I test if there are no oscillations?
+
+ // Problem: sometimes it passes, sometimes fails...
+
+ cleanup: "the server should be stopped"
+ stopContainer(container)
+ }
+}
@@ -0,0 +1,199 @@
+package org.openremote.agent.test.rules;
+
+import java.util.concurrent.*;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+import java.io.*;
+import org.openremote.agent.sensor.*;
+
+global org.openremote.agent.command.Commands commands;
+global org.openremote.agent.rules.RulePersistence persistence;
+global org.openremote.agent.rules.RuleUtil util;
+global com.fasterxml.jackson.databind.ObjectMapper JSON;
+global java.util.logging.Logger LOG;
+
+declare SensorState
+ @role(event)
+end
+
+// PID controller start
+
+rule "-PID: init"
+then
+ commands.execute("GV.PID.Kp",persistence.readData("GV.PID.Kp", "0.6"));
+ commands.execute("GV.PID.Ki",persistence.readData("GV.PID.Ki", "0.3"));
+ commands.execute("GV.PID.Kd",persistence.readData("GV.PID.Kd", "0.0"));
+ commands.execute("GV.PID.Db",persistence.readData("GV.PID.Db", "0.0"));
+ commands.execute("GV.PID.Sp",persistence.readData("GV.PID.Sp", "1.0"));
+end
+
+// PID UI
+
+rule "-PID: increase Kp"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Kp", $v: value)
+ SensorState($s:sensorName=="PID.kp.inc", value=="ON")
+then
+ commands.execute("GV.PID.Kp", String.format("%.1f", Double.parseDouble($v.toString())+0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: decrease Kp"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Kp", $v: value)
+ SensorState($s:sensorName=="PID.kp.dec", value=="ON")
+then
+ commands.execute("GV.PID.Kp", String.format("%.1f", Double.parseDouble($v.toString())-0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: increase Ki"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Ki", $v: value)
+ SensorState($s:sensorName=="PID.ki.inc", value=="ON")
+then
+ commands.execute("GV.PID.Ki", String.format("%.1f", Double.parseDouble($v.toString())+0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: decrease Ki"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Ki", $v: value)
+ SensorState($s:sensorName=="PID.ki.dec", value=="ON")
+then
+ commands.execute("GV.PID.Ki", String.format("%.1f", Double.parseDouble($v.toString())-0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: increase Kd"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Kd", $v: value)
+ SensorState($s:sensorName=="PID.kd.inc", value=="ON")
+then
+ commands.execute("GV.PID.Kd", String.format("%.1f", Double.parseDouble($v.toString())+0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: decrease Kd"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Kd", $v: value)
+ SensorState($s:sensorName=="PID.kd.dec", value=="ON")
+then
+ commands.execute("GV.PID.Kd", String.format("%.1f", Double.parseDouble($v.toString())-0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: increase Db"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Db", $v: value)
+ SensorState($s:sensorName=="PID.db.inc", value=="ON")
+then
+ commands.execute("GV.PID.Db", String.format("%.1f", Double.parseDouble($v.toString())+0.1) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: decrease Db"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Db", $v: value)
+ SensorState($s:sensorName=="PID.db.dec", value=="ON")
+then
+ commands.execute("GV.PID.Db", String.format("%.1f", Double.parseDouble($v.toString())-0.1) );
+ commands.execute($s, "off");
+end
+
+rule "PID: increase Sp"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Sp", $v: value)
+ SensorState($s:sensorName=="PID.sp.inc", value=="ON")
+then
+ commands.execute("GV.PID.Sp", String.format("%.1f", Double.parseDouble($v.toString())+0.5) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: decrease Sp"
+ timer(int:300ms)
+when
+ SensorState(sensorName=="GV.PID.Sp", $v: value)
+ SensorState($s:sensorName=="PID.sp.dec", value=="ON")
+then
+ commands.execute("GV.PID.Sp", String.format("%.1f", Double.parseDouble($v.toString())-0.5) );
+ commands.execute($s, "off");
+end
+
+rule "-PID: reset inc/dec"
+ salience -10
+ timer(int: 1s)
+when
+ SensorState($s: sensorName matches "^PID......c$", value!="off")
+then
+ commands.execute($s, "off");
+end
+
+// PID algorithm
+
+declare PIDVars
+// Input==Output;
+ output: double
+ iterm: double
+ prevInput: double
+ outMin: double
+ outMax: double
+ active: Boolean
+end
+
+rule "-PID: algo init"
+then
+ PIDVars pv = new PIDVars();
+ pv.setActive(true);
+ pv.setOutMax(100);
+ pv.setOutMin(-100);
+ insert(pv);
+end
+
+rule "-PID: compute"
+ timer(int: 0 10) // 10 times faster than the implemented one
+when
+ $pv: PIDVars(active==true)
+ SensorState(sensorName=="GV.PID.Kp", $kp: value)
+ SensorState(sensorName=="GV.PID.Ki", $ki: value)
+ SensorState(sensorName=="GV.PID.Kd", $kd: value)
+ SensorState(sensorName=="GV.PID.Sp", $sp: value)
+ SensorState(sensorName=="GV.PID.Db", $db: value)
+then
+ double error = Double.parseDouble($sp.toString() ) - $pv.getOutput();
+ double kp = Double.parseDouble($kp.toString());
+ double ki = Double.parseDouble($ki.toString()); // * sample time in sec
+ double kd = Double.parseDouble($kd.toString()); // / sample time in sec
+ double sp = Double.parseDouble($sp.toString());
+ double db = Double.parseDouble($db.toString());
+
+ double iterm = $pv.getIterm() + (ki * error);
+ if(iterm > $pv.getOutMax() ) iterm = $pv.getOutMax();
+ else if(iterm < $pv.getOutMin() ) iterm = $pv.getOutMin();
+ $pv.setIterm( iterm );
+
+ //double dInput = (Input - lastInput);
+ double dInput = ($pv.getOutput() - $pv.getPrevInput() );
+ $pv.setPrevInput($pv.getOutput());
+
+ // Compute PID Output
+ double output = kp * error + $pv.getIterm()- kd * dInput;
+ if(output > $pv.getOutMax()) output = $pv.getOutMax();
+ else if(output < $pv.getOutMin()) output = $pv.getOutMin();
+ $pv.setOutput(output);
+
+ commands.execute("PID.Se", String.format("%.4f", error) );
+ commands.execute("PID.Output", String.format("%.4f", output) );
+ LOG.fine($pv.toString() + " error: "+String.format("%f", Double.parseDouble($sp.toString() ) - $pv.getOutput()));
+end
+
+// PID end
Oops, something went wrong.

0 comments on commit 318e962

Please sign in to comment.