diff --git a/src/main/java/com/ardublock/translator/block/numbers/DefineBlock.java b/src/main/java/com/ardublock/translator/block/numbers/DefineBlock.java index a8bcdaa0c5290798974062deddb973897b4f3cb1..8cef1cbf2bbbb7bc9f823e63ae4c60c343d93895 100644 --- a/src/main/java/com/ardublock/translator/block/numbers/DefineBlock.java +++ b/src/main/java/com/ardublock/translator/block/numbers/DefineBlock.java @@ -8,10 +8,6 @@ import com.ardublock.translator.block.exception.BlockException; import com.ardublock.translator.block.exception.SocketNullException; import com.ardublock.translator.block.exception.SubroutineNotDeclaredException; -import tec.letsgoing.ardublock.simulator.simcode.SimCode; -import tec.letsgoing.ardublock.simulator.simcode.datatypes.SimTypeBool; -import tec.letsgoing.ardublock.simulator.simcode.datatypes.SimTypeString; -import tec.letsgoing.ardublock.simulator.simcode.vars.CodeBoolSet; public class DefineBlock extends TranslatorBlock { @@ -25,7 +21,7 @@ public class DefineBlock extends TranslatorBlock public String toCode() throws SocketNullException, SubroutineNotDeclaredException { //Label autoText set in edu.mit.blocks.renderable.BlockLabel -> generateLabelText() - String suffix = ""; + //String suffix = ""; String newMarker = "_.new"; String regex = "\\s*"+newMarker+"\\b\\s*"; diff --git a/src/main/java/com/ardublock/translator/block/operators/PidBlock.java b/src/main/java/com/ardublock/translator/block/operators/PidBlock.java new file mode 100644 index 0000000000000000000000000000000000000000..8fce63b60bef1d5e01772c9bc33a58dd18c87995 --- /dev/null +++ b/src/main/java/com/ardublock/translator/block/operators/PidBlock.java @@ -0,0 +1,108 @@ +package com.ardublock.translator.block.operators; + +import java.util.ResourceBundle; +import java.util.function.ToIntFunction; + +import com.ardublock.translator.Translator; +import com.ardublock.translator.block.TranslatorBlock; +import com.ardublock.translator.block.exception.BlockException; +import com.ardublock.translator.block.exception.SocketNullException; +import com.ardublock.translator.block.exception.SubroutineNotDeclaredException; + +public class PidBlock extends TranslatorBlock +{ + private static ResourceBundle uiMessageBundle = ResourceBundle.getBundle("com/ardublock/block/ardublock"); + + public PidBlock(Long blockId, Translator translator, String codePrefix, String codeSuffix, String label) + { + super(blockId, translator, codePrefix, codeSuffix, label); + } + + @Override + public String toCode() throws SocketNullException, SubroutineNotDeclaredException + { + TranslatorBlock tb_input = this.getRequiredTranslatorBlockAtSocket(0); + TranslatorBlock tb_setpoint = this.getRequiredTranslatorBlockAtSocket(1); + TranslatorBlock tb_interval = this.getRequiredTranslatorBlockAtSocket(2); + TranslatorBlock tb_kp = this.getRequiredTranslatorBlockAtSocket(3); + TranslatorBlock tb_ki = this.getTranslatorBlockAtSocket(4); + TranslatorBlock tb_kd = this.getTranslatorBlockAtSocket(5); + TranslatorBlock tb_limitL = this.getTranslatorBlockAtSocket(6); + TranslatorBlock tb_limitH = this.getTranslatorBlockAtSocket(7); + + boolean integrative = tb_ki != null; + boolean derivative = tb_kd != null; + boolean limited = (tb_limitL != null) && (tb_limitH != null); + + + //FUNCTION CODE ASSEMBLY + String functionCode = "int computePID(int input, int setpoint, long interval, int kp"; + + if(integrative) { + functionCode +=", double ki"; + } + if(derivative) { + functionCode +=", double kd"; + } + if(limited) { + functionCode +=", int limitLow, int limitHigh"; + } + + functionCode += "){" + + " static int lastError = 0;\n" + + " static int out = 0;\n" + + " static long lastTime = 0L;\n\n" + + " long currentTime = millis();\t//get current time\n\n" + + " if (currentTime >= lastTime + interval) {\n" + + " long elapsedTime = (double)(currentTime - lastTime); //compute time elapsed from previous computation\n" + + " \n" + + " long error = setpoint - input; // get error\n" + + " out = kp * error; //P output\n\n"; + if(integrative) { + functionCode +=" long cumError = cumError + error * elapsedTime; // compute integral\n" + + " out = out + ki * cumError; //I output\n\n"; + } + if(derivative) { + functionCode +=" long rateError = (error - lastError) / elapsedTime; // compute derivative\n" + + " out = out + kd * rateError; //D output\n\n"; + } + if(limited) { + functionCode +=" out = constrain(out, limitLow, limitHigh); //limit output\n\n"; + } + + functionCode += " lastError = error; //remember current error\n" + + " lastTime = currentTime; //remember current time\n" + + " }\n" + + " return out; //return the PID output\n" + + "}"; + + translator.addDefinitionCommand(functionCode); + + //RETURN (BLOCK) CODE ASSEMBLY + String ret = "computePID("; + ret += tb_input.toCode().replaceAll("\\s*_.new\\b\\s*", "")+", "+tb_setpoint.toCode().replaceAll("\\s*_.new\\b\\s*", "") + ", " + tb_interval.toCode().replaceAll("\\s*_.new\\b\\s*", "") + ", " + tb_kp.toCode().replaceAll("\\s*_.new\\b\\s*", ""); + + if(integrative) { + ret +=", " + tb_ki.toCode().replaceAll("\\s*_.new\\b\\s*", ""); + } + if(derivative) { + ret +=", " + tb_kd.toCode().replaceAll("\\s*_.new\\b\\s*", ""); + } + if(limited) { + String limitL = tb_limitL.toCode().replaceAll("\\s*_.new\\b\\s*", ""); + String limitH = tb_limitH.toCode().replaceAll("\\s*_.new\\b\\s*", ""); + + if(Integer.parseInt(limitL) < Integer.parseInt(limitH)) { + ret +=", " + limitL + ", " + limitH; + }else { + throw new BlockException(blockId, uiMessageBundle.getString("ardublock.error_msg.pid_limit_error")); + } + + + } + ret += ")"; + + return codePrefix + ret + codeSuffix; + } + +} diff --git a/src/main/resources/com/ardublock/block/ardublock.properties b/src/main/resources/com/ardublock/block/ardublock.properties index ca99fceb935884207a6ef29d2386c0d7bde9517e..27c9c3bf957921b20c42b265cf4dcde7b544aca1 100644 --- a/src/main/resources/com/ardublock/block/ardublock.properties +++ b/src/main/resources/com/ardublock/block/ardublock.properties @@ -118,6 +118,7 @@ ardublock.error_msg.stepper_duplicated=There is already a stepper with this name ardublock.error_msg.stepper_not_existing=There is no stepper with this name ardublock.error_msg.paste.invalid=clipboard contains no blocks ardublock.error_msg.paste.notpossible=Past not possible without Blocks +ardublock.error_msg.pid_limit_error=PID-Block: Upper limit is smaller or equal to lower limit ardublock.error_msg.no_sim_for_block=This Block is not suitable for simulation @@ -490,6 +491,7 @@ bd.operators=Math Operators bg.mathDivider1=| operators | bg.mathDivider2=| signal attributes | bg.mathDivider3=| random | +bg.mathDivider4=| PID-Controller | bg.constrain=constrain bg.abs=abs @@ -537,6 +539,20 @@ bc.low=lower bc.high=higher bc.element = element +bg.pid=PID +bg.pid_limit=PID +bg.pid.description= PID controller block +bg.pid_limit.description= PID controller block with limit + +bc.input=input +bc.setpoint=setpoint +bc.interval=interval +bc.kp=Kp +bc.ki=Ki +bc.kd=Kd +bc.limitL=lower limit +bc.limitH=upper limit + #CAST #**************************** bd.cast=type cast diff --git a/src/main/resources/com/ardublock/block/ardublock.xml b/src/main/resources/com/ardublock/block/ardublock.xml index 59f7d9de2e4a3e0daadafec8fab369de6d84da35..6be7bd5d0c091d346a55ac8b074f1b67864be477 100644 --- a/src/main/resources/com/ardublock/block/ardublock.xml +++ b/src/main/resources/com/ardublock/block/ardublock.xml @@ -1257,6 +1257,7 @@ <BlockGenus name="mathDivider1" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.mathDivider1" color="150 150 150" /> <BlockGenus name="mathDivider2" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.mathDivider2" color="150 150 150" /> <BlockGenus name="mathDivider3" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.mathDivider3" color="150 150 150" /> + <BlockGenus name="mathDivider4" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.mathDivider3" color="150 150 150" /> <BlockGenus name="addition" kind="function" initlabel="bg.addition" color="160 32 240"> <description> @@ -1473,6 +1474,56 @@ </BlockConnectors> </BlockGenus> + <BlockGenus name="pid" kind="function" color="160 32 240" initlabel="bg.pid"> + <description> + <text>PID</text> + </description> + <BlockConnectors> + <BlockConnector connector-type="number" connector-kind="plug" /> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.input" /> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.setpoint"> + <DefaultArg genus-name="number" label="512" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.interval"> + <DefaultArg genus-name="number" label="100" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.kp"> + <DefaultArg genus-name="number" label="2" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.ki"> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.kd"> + </BlockConnector> + </BlockConnectors> + </BlockGenus> + + <BlockGenus name="pid_limit" kind="function" color="160 32 240" initlabel="bg.pid_limit"> + <description> + <text>PID with limits</text> + </description> + <BlockConnectors> + <BlockConnector connector-type="number" connector-kind="plug" /> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.input" /> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.setpoint"> + <DefaultArg genus-name="number" label="512" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.interval"> + <DefaultArg genus-name="number" label="100" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.kp"> + <DefaultArg genus-name="number" label="2" /> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.ki"> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.kd"> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.limitL"> + </BlockConnector> + <BlockConnector connector-type="number" connector-kind="socket" label="bc.limitH"> + </BlockConnector> + </BlockConnectors> + </BlockGenus> + <!-- ******************** Cast *************** --> <BlockGenus name="castDivider1" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.castDivider1" color="150 150 150" /> <BlockGenus name="castDivider2" kind="command" is-starter="yes" is-terminator="yes" initlabel="bg.castDivider2" color="150 150 150" /> @@ -3134,6 +3185,10 @@ <BlockGenusMember>mathDivider3</BlockGenusMember> <BlockGenusMember>random</BlockGenusMember> <BlockGenusMember>random_range</BlockGenusMember> + + <BlockGenusMember>mathDivider4</BlockGenusMember> + <BlockGenusMember>pid</BlockGenusMember> + <BlockGenusMember>pid_limit</BlockGenusMember> </BlockDrawer> <BlockDrawer button-color="160 32 240" name="bd.operators" type="page"> <BlockGenusMember>mathDivider1</BlockGenusMember> diff --git a/src/main/resources/com/ardublock/block/ardublock_de.properties b/src/main/resources/com/ardublock/block/ardublock_de.properties index 9fab4dfd01a87277d7ad3a76597b327cac358ff9..c74aa134b1c720e0d798307a53e01d0493cb77af 100644 --- a/src/main/resources/com/ardublock/block/ardublock_de.properties +++ b/src/main/resources/com/ardublock/block/ardublock_de.properties @@ -121,6 +121,8 @@ ardublock.error_msg.stepper_not_existing=Es gibt keinen Stepper mit diesem Namen ardublock.error_msg.paste.invalid=Zwischenablage enthält keine ArduBlock-Blöcke ardublock.error_msg.paste.notpossible=Einfügen ohne Blöcke nicht möglich. +ardublock.error_msg.pid_limit_error=PID-Block: Oberes Limit ist kleiner oder gleich wie unteres Limit + ardublock.error_msg.no_sim_for_block=Dieser Block ist für die Simulation nicht geeignet. #TRANSLATOR @@ -486,7 +488,8 @@ bd.operators=Math. Operatoren bg.mathDivider1=| Operatoren | bg.mathDivider2=| Signalanpassung | -bg.mathDivider3=| Zufallszahl | +bg.mathDivider3=| Zufallszahl | +bg.mathDivider4=| PID-Regler | bg.constrain=einschränken bg.abs=abs @@ -534,6 +537,22 @@ bc.low=unterer bc.high=oberer bc.element = Element + +bg.pid=PID +bg.pid_limit=PID +bg.pid.description= PID Regler-Block +bg.pid_limit.description= PID Regler-Block mit Begrenzung + + +bc.input=Istwert +bc.setpoint=Sollwert +bc.interval=Intervall +bc.kp=Kp +bc.ki=Ki +bc.kd=Kd +bc.limitL=unteres Limit +bc.limitH=oberes Limit + #CAST #**************************** bd.cast=Typ Konvertierung diff --git a/src/main/resources/com/ardublock/block/ardublock_en_GB.properties b/src/main/resources/com/ardublock/block/ardublock_en_GB.properties index b960082f81b34042abf930aea08a08b90e0e6e2d..b403f4162ae3fb446cb7f7a1a845ec8e4e564224 100644 --- a/src/main/resources/com/ardublock/block/ardublock_en_GB.properties +++ b/src/main/resources/com/ardublock/block/ardublock_en_GB.properties @@ -122,6 +122,8 @@ ardublock.error_msg.stepper_not_existing=Es gibt keinen Stepper mit diesem Namen ardublock.error_msg.paste.invalid=Zwischenablage enthält keine ArduBlock-Blöcke ardublock.error_msg.paste.notpossible=Einfügen ohne Blöcke nicht möglich. +ardublock.error_msg.pid_limit_error=PID-Block: Oberes Limit ist kleiner oder gleich wie unteres Limit + ardublock.error_msg.no_sim_for_block=Dieser Block ist für die Simulation nicht geeignet. #TRANSLATOR @@ -487,7 +489,8 @@ bd.operators=Math. Operatoren bg.mathDivider1=| Operatoren | bg.mathDivider2=| Signalanpassung | -bg.mathDivider3=| Zufallszahl | +bg.mathDivider3=| Zufallszahl | +bg.mathDivider4=| PID-Regler | bg.constrain=constrain bg.abs=abs @@ -535,6 +538,20 @@ bc.low=unterer bc.high=oberer bc.element = Element +bg.pid=PID +bg.pid_limit=PID +bg.pid.description= PID Regler-Block +bg.pid_limit.description= PID Regler-Block mit Begrenzung + +bc.input=Istwert +bc.setpoint=Sollwert +bc.interval=Intervall +bc.kp=Kp +bc.ki=Ki +bc.kd=Kd +bc.limitL=unteres Limit +bc.limitH=oberes Limit + #CAST #**************************** bd.cast=Typ Konvertierung diff --git a/src/main/resources/com/ardublock/block/block-mapping.properties b/src/main/resources/com/ardublock/block/block-mapping.properties index 0036c25d10427ebd40f3adb5680ba32bc3a438f5..3707487a5c2d749304800134b59c9078700f13d9 100644 --- a/src/main/resources/com/ardublock/block/block-mapping.properties +++ b/src/main/resources/com/ardublock/block/block-mapping.properties @@ -167,6 +167,9 @@ random_range=com.ardublock.translator.block.operators.RandomRangeBlock map_common=com.ardublock.translator.block.operators.MapCommonBlock map=com.ardublock.translator.block.operators.MapBlock +pid=com.ardublock.translator.block.operators.PidBlock +pid_limit=com.ardublock.translator.block.operators.PidBlock + #CAST #**************************** cast_atoi=com.ardublock.translator.block.cast.CastAtoi