diff --git a/src/main/jastadd/cleanup/Cleanup.jrag b/src/main/jastadd/cleanup/Cleanup.jrag
index d521f734d9bc146095008e9fec7f5b3ee94d8e8d..7e44ce3e84a5f677870ab6453a0218c2d4d6091e 100644
--- a/src/main/jastadd/cleanup/Cleanup.jrag
+++ b/src/main/jastadd/cleanup/Cleanup.jrag
@@ -11,21 +11,6 @@ aspect CleanupAttributes {
     throw new UnsupportedOperationException("Invalid use of attribute object():String");
   }
 
-  syn double ASTNode.time(); // TODO can this be avoided?
-  eq RobotIsNotReadyToPick.time() = 1;
-  eq RobotIsNotReadyToDrop.time() = 1;
-  eq WaitForEmptyTable.time() = 1;
-  eq WaitForFullTable.time() = 1;
-  eq ASTNode.time() {
-    throw new UnsupportedOperationException("Invalid use of attribute time():double");
-  }
-
-  inh double Wait.time();
-  eq RobotIsNotReadyToPick.getWait().time() = time();
-  eq RobotIsNotReadyToDrop.getWait().time() = time();
-  eq WaitForEmptyTable.getWait().time() = time();
-  eq WaitForFullTable.getWait().time() = time();
-
   syn String ASTNode.place(); // TODO can this be avoided?
   eq DropObjectAtRightPlace.place() = getRightPlace().getPlace();
   eq ASTNode.place() {
diff --git a/src/main/jastadd/cleanup/Cleanup.relast b/src/main/jastadd/cleanup/Cleanup.relast
index 79abc76e8bf71648dc80bc6c0c4774b8c2ef6ce9..39318151d87bd941bdbd63280d897f38cdb35778 100644
--- a/src/main/jastadd/cleanup/Cleanup.relast
+++ b/src/main/jastadd/cleanup/Cleanup.relast
@@ -1,15 +1,7 @@
-Tidy : MotionGrammarElement ::= WaitForFullTable* MoveObjectToCorrectPlace* WaitForEmptyTable* EmptyTable;
+Tidy : MotionGrammarElement ::= NotEmptyTable MoveObjectToCorrectPlace* EmptyTable;
 MoveObjectToCorrectPlace : MotionGrammarElement ::= ObjectAtWrongPlace/*provides object*/ PickUpObject/*uses object*/ DropObjectAtRightPlace/*uses object*/;
-PickUpObject/*requires object*/ : MotionGrammarElement ::= RobotIsReadyToPick;
-abstract RobotIsReadyToPick : MotionGrammarElement;
-RobotIsReallyReadyToPick : RobotIsReadyToPick ::= RobotIsReadyToPickToken;
-RobotIsNotReadyToPick    : RobotIsReadyToPick ::= RobotIsNotReadyToPickToken Wait/*uses const "1sec"*/ RobotIsReadyToPick;
-abstract RobotIsReadyToDrop : MotionGrammarElement;
-RobotIsReallyReadyToDrop : RobotIsReadyToDrop ::= RobotIsReadyToDropToken;
-RobotIsNotReadyToDrop    : RobotIsReadyToDrop ::= RobotIsNotReadyToDropToken Wait/*uses const "1sec"*/ RobotIsReadyToDrop;
-DropObjectAtRightPlace/*requires object*/ : MotionGrammarElement ::= RobotIsReadyToDrop RightPlace/*uses object, provides place*/;
-WaitForEmptyTable : MotionGrammarElement ::= NotEmptyTable Wait/*uses const "1sec"*/;
-WaitForFullTable : MotionGrammarElement ::= EmptyTable Wait/*uses const "1sec"*/;
+PickUpObject/*requires object*/ : MotionGrammarElement ::= RobotIsReadyToPickToken;
+DropObjectAtRightPlace/*requires object*/ : MotionGrammarElement ::= RobotIsReadyToDropToken RightPlace/*uses object, provides place*/;
 
 // Tokens
 EmptyTable                        : Token;
@@ -23,5 +15,4 @@ RobotIsIdle                       : Token;
 RobotIsNotIdle                    : Token; // TODO negated RobotIsIdle
 RobotHasItemAttached              : Token;
 RobotHasNoItemAttached            : Token; // TODO negated RobotHasItemAttached
-Wait/*requires time*/             : Token; // artificial token, which parsing takes a specified amount of time
 RightPlace/*requires object*/     : Token ::= <Place:String>;
diff --git a/src/main/jastadd/cleanup/RobotWorld.jadd b/src/main/jastadd/cleanup/RobotWorld.jadd
index e2625a269a6dc258bd006006ca3ed669576ab322..edadbe3640db841bfb6a1f281f6dca1e75b84947 100644
--- a/src/main/jastadd/cleanup/RobotWorld.jadd
+++ b/src/main/jastadd/cleanup/RobotWorld.jadd
@@ -37,7 +37,6 @@ aspect RobotWorld {
   public static TokenType RobotIsNotIdle.type()             { return TokenType.of("ROBOT_IS_NOT_IDLE"); }
   public static TokenType RobotHasItemAttached.type()       { return TokenType.of("ROBOT_HAS_ITEM_ATTACHED"); }
   public static TokenType RobotHasNoItemAttached.type()     { return TokenType.of("ROBOT_HAS_NO_ITEM_ATTACHED"); }
-  public static TokenType Wait.type()                       { return TokenType.of("WAIT"); }
   public static TokenType RightPlace.type()                 { return TokenType.of("RIGHT_PLACE"); }
 
   public static Pose Pose.of(double x, double y, double z) {
@@ -217,15 +216,6 @@ aspect RobotWorld {
     }
   }
 
-  public Wait World.parseWait(double time) {
-    return null;
-  }
-  public Wait RobotWorld.parseWait(double time) {
-    System.out.print("Trying to parse token <Wait> for " + time + " seconds... ");
-    System.out.println("success");
-    return new Wait();
-  }
-
   public RightPlace World.parseRightPlace(String objectName) {
     return null;
   }
diff --git a/src/main/jastadd/cleanup/SemanticActions.jadd b/src/main/jastadd/cleanup/SemanticActions.jadd
index bbb808dd372d3baeac23cc931b9464c8f9cbd65f..0de455177803a8c3a47c6365011e5045a697eed6 100644
--- a/src/main/jastadd/cleanup/SemanticActions.jadd
+++ b/src/main/jastadd/cleanup/SemanticActions.jadd
@@ -73,14 +73,4 @@ aspect SemanticActions {
         }
     }
 
-    public void Wait.action(World world) {
-        RobotWorld container = world.asRobotWorld();
-        System.out.println("performing semantic action for element Wait");
-        try {
-            Thread.sleep((long) (time() * 1000));
-        } catch (InterruptedException e) {
-            // ignore
-        }
-    }
-
 }
diff --git a/src/main/jastadd/select/Select.relast b/src/main/jastadd/select/Select.relast
new file mode 100644
index 0000000000000000000000000000000000000000..7600879183209c1c0b33777e7468d7e783731ece
--- /dev/null
+++ b/src/main/jastadd/select/Select.relast
@@ -0,0 +1,9 @@
+Task : MotionGrammarElement ::= Assignment;
+Assignment : MotionGrammarElement ::= Selection/*any type, any id*/ RestAssignment;
+abstract RestAssignment : MotionGrammarElement;
+SelectionChange : RestAssignment ::= Selection/*type == last type, id  != last id*/ ObjectAssignment;
+Unselect : RestAssignment ::= Selection/*type == last type, id  == last id*/ Assignment;
+CompleteAssignment : RestAssignment ::= Selection/*type != last type, id != last id*/;
+
+// Tokens
+Selection : Token;
\ No newline at end of file
diff --git a/src/main/java/de/tudresden/inf/st/mg/RobotParser.java b/src/main/java/de/tudresden/inf/st/mg/RobotParser.java
index b59cf427cc87af07416f3ff9e2fdfffb02c6d508..8cbe2fc7f87e12de20db4be864880447b40d21d9 100644
--- a/src/main/java/de/tudresden/inf/st/mg/RobotParser.java
+++ b/src/main/java/de/tudresden/inf/st/mg/RobotParser.java
@@ -48,7 +48,7 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
     printAST("parseEmptyTable", result);
   }
 
-  private NotEmptyTable peekedNotEmptyTable_ = null;
+  private volatile NotEmptyTable peekedNotEmptyTable_ = null;
 
   private boolean peekNotEmptyTable() {
     peekedNotEmptyTable_ = getWorld().parseNotEmptyTable();
@@ -318,21 +318,6 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
     printAST("parseRobotHasNoItemAttached", result);
   }
 
-  private void parseWait(ASTNode<?> parent, int index) throws ParseException {
-    Wait result;
-
-    result = getWorld().parseWait(parent.time());
-    if (result == null) {
-      throw new ParseException(Wait.type());
-    }
-
-    parent.setChild(result, index);
-
-    // semantic action for Wait
-    result.action(getWorld());
-    printAST("parseWait", result);
-  }
-
   private void parseRightPlace(ASTNode<?> parent, int index) throws ParseException {
     RightPlace result;
 
@@ -353,16 +338,11 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
     result.parser = this;
     parent.setChild(result, index);
 
-    while (true) {
-      peekEmptyTable();
-      if (peekedEmptyTable_ != null) {
-        int i = result.getNumWaitForFullTable();
-        result.addWaitForFullTable(null);
-        parseWaitForFullTable(result.getWaitForFullTableList(), i);
-      } else {
-        break;
-      }
+    peekNotEmptyTable();
+    while (peekedNotEmptyTable_ == null) {
+      waitSomeTime();
     }
+    parseNotEmptyTable(result, 0);
 
     while (true) {
       peekObjectAtWrongPlace(result);
@@ -371,22 +351,16 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
         result.addMoveObjectToCorrectPlace(null);
         parseMoveObjectToCorrectPlace(result.getMoveObjectToCorrectPlaceList(), i);
       } else {
-        break;
+        peekEmptyTable();
+        if (peekedEmptyTable_ != null) {
+          break;
+        } else {
+          waitSomeTime();
+        }
       }
     }
 
-    while (true) {
-      peekNotEmptyTable();
-      if (peekedNotEmptyTable_ != null) {
-        int i = result.getNumWaitForEmptyTable();
-        result.addWaitForEmptyTable(null);
-        parseWaitForEmptyTable(result.getWaitForEmptyTableList(), i);
-      } else {
-        break;
-      }
-    }
-
-    parseEmptyTable(result, 3);
+    parseEmptyTable(result, 2);
 
     // semantic action for Tidy
     result.action(getWorld());
@@ -407,38 +381,18 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
     printAST("parseMoveObjectToCorrectPlace", result);
   }
 
-  private void parseWaitForFullTable(ASTNode<?> parent, int index) throws ParseException {
-    WaitForFullTable result = new WaitForFullTable();
-    result.parser = this;
-    parent.setChild(result, index);
-
-    parseEmptyTable(result, 0);
-    parseWait(result, 1);
-
-    // semantic action for WaitForFullTable
-    result.action(getWorld());
-    printAST("parseWaitForFullTable", result);
-  }
-
-  private void parseWaitForEmptyTable(ASTNode<?> parent, int index) throws ParseException {
-    WaitForEmptyTable result = new WaitForEmptyTable();
-    result.parser = this;
-    parent.setChild(result, index);
-
-    parseNotEmptyTable(result, 0);
-    parseWait(result, 1);
-
-    // semantic action for WaitForEmptyTable
-    result.action(getWorld());
-    printAST("parseWaitForEmptyTable", result);
-  }
-
   private void parseDropObjectAtRightPlace(ASTNode<?> parent, int index) throws ParseException {
     DropObjectAtRightPlace result = new DropObjectAtRightPlace();
     result.parser = this;
     parent.setChild(result, index);
 
-    parseRobotIsReadyToDrop(result, 0);
+
+    peekRobotIsReadyToDropToken();
+    while (peekedRobotIsReadyToDropToken_ == null) {
+      waitSomeTime();
+    }
+    parseRobotIsReadyToDropToken(result, 0);
+
     parseRightPlace(result, 1);
 
     // semantic action for DropObjectAtRightPlace
@@ -451,103 +405,15 @@ public final class RobotParser extends MotionGrammarParser<Tidy> {
     result.parser = this;
     parent.setChild(result, index);
 
-    parseRobotIsReadyToPick(result, 0);
-
-    // semantic action for PickUpObject
-    result.action(getWorld());
-    printAST("parsePickUpObject", result);
-  }
-
-  private void parseRobotIsReadyToPick(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsReadyToPick result;
-
-    // try the different types of RobotIsReadyToPick
-    if (peekRobotIsReadyToPickToken()) {
-      result = new RobotIsReallyReadyToPick();
-      result.parser = this;
-      parent.setChild(result, index);
-      parseRobotIsReallyReadyToPick(parent, index);
-    } else if (peekRobotIsNotReadyToPickToken()) {
-      result = new RobotIsNotReadyToPick();
-      result.parser = this;
-      parent.setChild(result, index);
-      parseRobotIsNotReadyToPick(parent, index);
-    } else {
-      throw new ParseException("RobotIsReadyToPick", RobotIsReadyToPickToken.type(), RobotIsNotReadyToPickToken.type());
+    peekRobotIsReadyToPickToken();
+    while (peekedRobotIsReadyToPickToken_ == null) {
+      waitSomeTime();
     }
-
-
-    // semantic action for RobotIsReadyToPick
-    result.action(getWorld());
-    printAST("parseRobotIsReadyToPick", result);
-  }
-
-  private void parseRobotIsReallyReadyToPick(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsReallyReadyToPick result = (RobotIsReallyReadyToPick) parent.getChild(index);
-
     parseRobotIsReadyToPickToken(result, 0);
 
-    // semantic action for RobotIsReallyReadyToPick
-    result.action(getWorld());
-    printAST("parseRobotIsReallyReadyToPick", result);
-  }
-
-  private void parseRobotIsNotReadyToPick(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsNotReadyToPick result = (RobotIsNotReadyToPick) parent.getChild(index);
-
-    parseRobotIsNotReadyToPickToken(result, 0);
-    parseWait(result, 1);
-    parseRobotIsReadyToPick(result, 2);
-
-    // semantic action for RobotIsNotReadyToPick
-    result.action(getWorld());
-    printAST("parseRobotIsNotReadyToPick", result);
-  }
-
-  private void parseRobotIsReadyToDrop(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsReadyToDrop result;
-
-    // try the different types of RobotIsReadyToDrop
-    if (peekRobotIsReadyToDropToken()) {
-      result = new RobotIsReallyReadyToDrop();
-      result.parser = this;
-      parent.setChild(result, index);
-      parseRobotIsReallyReadyToDrop(parent, index);
-    } else if (peekRobotIsNotReadyToDropToken()) {
-      result = new RobotIsNotReadyToDrop();
-      result.parser = this;
-      parent.setChild(result, index);
-      parseRobotIsNotReadyToDrop(parent, index);
-    } else {
-      throw new ParseException("RobotIsReadyToDrop", RobotIsReadyToDropToken.type(), RobotIsNotReadyToDropToken.type());
-    }
-
-
-    // semantic action for RobotIsReadyToDrop
-    result.action(getWorld());
-    printAST("parseRobotIsReadyToDrop", result);
-  }
-
-  private void parseRobotIsReallyReadyToDrop(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsReallyReadyToDrop result = (RobotIsReallyReadyToDrop) parent.getChild(index);
-
-    parseRobotIsReadyToDropToken(result, 0);
-
-    // semantic action for RobotIsReallyReadyToDrop
-    result.action(getWorld());
-    printAST("parseRobotIsReallyReadyToDrop", result);
-  }
-
-  private void parseRobotIsNotReadyToDrop(ASTNode<?> parent, int index) throws ParseException {
-    RobotIsNotReadyToDrop result = (RobotIsNotReadyToDrop) parent.getChild(index);
-
-    parseRobotIsNotReadyToDropToken(result, 0);
-    parseWait(result, 1);
-    parseRobotIsReadyToDrop(result, 2);
-
-    // semantic action for RobotIsNotReadyToDrop
+    // semantic action for PickUpObject
     result.action(getWorld());
-    printAST("parseRobotIsNotReadyToDrop", result);
+    printAST("parsePickUpObject", result);
   }
 
 }
diff --git a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
index 1f22d5faa462036d5813090b223b7bf2d78c5870..1122a4a877310f5199601615ff090e2252f77ba3 100644
--- a/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
+++ b/src/main/java/de/tudresden/inf/st/mg/common/MotionGrammarParser.java
@@ -20,6 +20,13 @@ public abstract class MotionGrammarParser<T extends MotionGrammarElement> {
   protected ASTNode<T> rootContainer_;
   private int timeStep_;
 
+  protected static void waitSomeTime() {
+    try {
+      Thread.sleep(100/*ms*/);
+    } catch(InterruptedException ignored) {
+    }
+  }
+
   public void setDebugDiagramDir(Path p) {
     MotionGrammarConfig.astDiagramDir = p;
   }
diff --git a/src/main/resources/template-configs/ControlParser.yaml b/src/main/resources/template-configs/ControlParser.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..577841f2ba89d19cb8def753933b0c1568383111
--- /dev/null
+++ b/src/main/resources/template-configs/ControlParser.yaml
@@ -0,0 +1,51 @@
+name: "ControlParser"
+package: "de.tudresden.inf.st.mg"
+genPackage: "de.tudresden.inf.st.mg.jastadd.model"
+targetType: "Task"
+
+tokenContext:
+  context: false            # default value
+  peek: true                # default value
+  worldParserArguments: [ ] # default value
+  tokens:
+    - name: "Bin"
+      peek: false
+    - name: "Box"
+      peek: false
+
+ruleContext:
+  constructObject: false # default value
+  peekForType: false     # default value
+  token: false           # default value
+  first: false           # default value
+  last: false            # default value
+  list: false            # default value
+  additionalArgs: ""     # default value
+  peekContext: ""        # default value
+  rules:
+    - ruleName: "T"
+      peekForType: true
+      types:
+        - type: "T2"
+          token: "Full"
+          first: true
+        - type: "T1"
+          token: "Load"
+          last: true
+      components: []
+    - ruleName: "T1"
+      components:
+        - componentName: "Load"
+          token: true
+          index: 0
+        - componentName: "T"
+          token: true
+          index: 1
+        - componentName: "Unload"
+          token: true
+          index: 2
+    - ruleName: "T2"
+      components:
+        - componentName: "Full"
+          token: true
+          index: 0