--- /dev/null
+Name MartNatanael
+Acceleration 1000
+Speed 200
+Behaviour Wander
+ take control:
+ action:
+ Left motor Forwards
+ Right motor Forwards
+ wait forever
+Behaviour AvoidLowLeftObjects
+ take control: Touched on Left
+ action:
+ Left motor Backwards
+ Right motor Backwards
+ wait 250 ms
+ Right motor Backwards
+ Left motor Forwards
+ wait 250 ms
+Behaviour AvoidLowRightObjects
+ take control: Touched on Right
+ action:
+ Left motor Backwards
+ Right motor Backwards
+ wait 250 ms
+ Right motor Forwards
+ Left motor Backwards
+ wait 250 ms
+Behaviour AvoidHighObjects
+ take control: Distance < 50 cm
+ action:
+ Right motor Forwards
+ wait 250 ms
+Behaviour StayInLine
+ take control: (or Color is Black Color is DarkGray)
+ action:
+ Right motor Forwards
+ Left motor Backwards
+ wait 250 ms
+Mission Assignment
+using
+ Wander
+ AvoidLowLeftObjects
+ AvoidLowRightObjects
+ AvoidHighObjects
+ StayInLine
+and stops when
+ Collected at least Blue Green Yellow
--- /dev/null
+package nl.ru.des;
+
+import lejos.hardware.motor.EV3LargeRegulatedMotor;
+import lejos.robotics.subsumption.Behavior;
+
+public abstract class BasicBehaviour implements Behavior{
+ protected EV3LargeRegulatedMotor leftMotor, rightMotor;
+
+ public BasicBehaviour(nl.ru.des.Sensors sensors, EV3LargeRegulatedMotor leftMotor, EV3LargeRegulatedMotor rightMotor){
+ this.leftMotor = leftMotor;
+ this.rightMotor = rightMotor;
+ }
+
+ @Override
+ public boolean takeControl() {
+ return true;
+ }
+
+ @Override
+ public void suppress() {}
+}
--- /dev/null
+package nl.ru.des;
+
+import lejos.hardware.Key;
+import lejos.hardware.KeyListener;
+
+class ButtonListener implements KeyListener {
+
+ @Override
+ public void keyPressed(Key k) {
+ LCDPrinter.print("Bye");
+ System.exit(0);
+ }
+
+ @Override
+ public void keyReleased(Key k) {}
+}
\ No newline at end of file
--- /dev/null
+package nl.ru.des;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Deque;
+import java.util.LinkedList;
+
+import lejos.hardware.lcd.TextLCD;
+import lejos.utility.Delay;
+
+public class LCDPrinter{
+ public static final int PRINTDELAY = 50;
+
+ private static Deque<String> buffer = new LinkedList<String>();
+
+ public static void startLCDPrinter(final TextLCD glcd) {
+ new Thread(new Runnable(){
+ @Override
+ public void run() {
+ while (true) {
+ if (!buffer.isEmpty()) {
+ String c = buffer.remove();
+ if(c.length() > glcd.getTextWidth()){
+ buffer.addFirst(c.substring(glcd.getTextWidth(), c.length()));
+ c = c.substring(0, glcd.getTextWidth());
+ }
+ glcd.scroll();
+ glcd.drawString(c, 0, glcd.getTextHeight()-1);
+ }
+ Delay.msDelay(PRINTDELAY);
+ }
+ }
+ }).start();
+ LCDPrinter.print("LCDThread started");
+ }
+
+ public static void print(String s){
+ buffer.addLast(s);
+ }
+
+ public static PrintStream getPrefixedPrintstream(final String prefix, final TextLCD glcd){
+ return new PrintStream(new OutputStream(){
+ private char[] line = new char[glcd.getTextWidth()];
+ private int index = 0;
+
+ @Override
+ public void write(int b) throws IOException {
+ if(index == line.length-prefix.length() || b == '\n'){
+ LCDPrinter.print(prefix + String.valueOf(line, 0, index));
+ index = 0;
+ } else {
+ line[index++] = (char)b;
+ }
+ }
+ });
+ }
+}
\ No newline at end of file
--- /dev/null
+package nl.ru.des;
+
+import lejos.hardware.ev3.EV3;
+import lejos.hardware.ev3.LocalEV3;
+import lejos.hardware.lcd.Font;
+import lejos.hardware.lcd.TextLCD;
+import lejos.hardware.motor.EV3LargeRegulatedMotor;
+import lejos.hardware.port.MotorPort;
+import lejos.hardware.sensor.EV3ColorSensor;
+import lejos.hardware.sensor.EV3TouchSensor;
+import lejos.hardware.sensor.EV3UltrasonicSensor;
+import lejos.robotics.SampleProvider;
+import nl.ru.des.dsl.Constants;
+
+public class MarsRover {
+ public static final float SAMPLERATE = 100;
+
+ @SuppressWarnings("resource")
+ public static void main(String[] args) {
+ EV3 brick = LocalEV3.get();
+ TextLCD tlcd = brick.getTextLCD(Font.getSmallFont());
+ LCDPrinter.startLCDPrinter(tlcd);
+ System.setOut(LCDPrinter.getPrefixedPrintstream("out: ", tlcd));
+ System.setErr(LCDPrinter.getPrefixedPrintstream("err: ", tlcd));
+
+ LCDPrinter.print("Loading keylistener...");
+ brick.getKey("Escape").addKeyListener(new ButtonListener());
+
+ LCDPrinter.print("Loading motors...");
+ EV3LargeRegulatedMotor rightMotor = new EV3LargeRegulatedMotor(MotorPort.D);
+ EV3LargeRegulatedMotor leftMotor = new EV3LargeRegulatedMotor(MotorPort.A);
+ leftMotor.setSpeed(Constants.defaultSpeed);
+ rightMotor.setSpeed(Constants.defaultSpeed);
+ rightMotor.setAcceleration(Constants.defaultAcceleration);
+ leftMotor.setAcceleration(Constants.defaultAcceleration);
+
+ LCDPrinter.print("Loading touch sensors...");
+ SampleProvider leftTouch = new EV3TouchSensor(brick.getPort("S1")).getTouchMode();
+ SampleProvider rightTouch = new EV3TouchSensor(brick.getPort("S4")).getTouchMode();
+
+ LCDPrinter.print("Loading color sensor...");
+ SampleProvider color = new EV3ColorSensor(brick.getPort("S2")).getColorIDMode();
+
+ LCDPrinter.print("Loading ultrasone sensor...");
+ SampleProvider ultraSonic = new EV3UltrasonicSensor(brick.getPort("S3")).getDistanceMode();
+
+ LCDPrinter.print("Initializing behaviours...");
+ Sensors sensors = new Sensors(ultraSonic, color, leftTouch, rightTouch);
+ }
+}
\ No newline at end of file
--- /dev/null
+package nl.ru.des;
+
+import lejos.hardware.motor.EV3LargeRegulatedMotor;
+import nl.ru.des.Sensors;
+
+public abstract class ReactiveBehaviour extends BasicBehaviour {
+ protected boolean suppressed;
+ protected Sensors sensors;
+
+ public ReactiveBehaviour(Sensors sensors, EV3LargeRegulatedMotor leftMotor, EV3LargeRegulatedMotor rightMotor) {
+ super(sensors, leftMotor, rightMotor);
+ this.sensors = sensors;
+ }
+
+ @Override
+ public void action() {
+ suppressed = false;
+ }
+
+ @Override
+ public void suppress() {
+ suppressed = true;
+ }
+}
\ No newline at end of file
--- /dev/null
+package nl.ru.des;
+
+import lejos.robotics.SampleProvider;
+
+public class Sensors{
+ public static final int DELAY = 50;
+
+ private SampleProvider ultrasone, color, leftTouch, rightTouch;
+ private float[] ultrasoneSamples, colorSamples, leftTouchSamples, rightTouchSamples;
+ private long ultrasoneTime, colorTime, leftTouchTime, rightTouchTime;
+
+ public Sensors(SampleProvider ultrasone,
+ SampleProvider color,
+ SampleProvider leftTouch,
+ SampleProvider rightTouch){
+ this.ultrasone = ultrasone;
+ this.color = color;
+ this.leftTouch = leftTouch;
+ this.rightTouch = rightTouch;
+ ultrasoneSamples = new float[ultrasone.sampleSize()];
+ colorSamples = new float[color.sampleSize()];
+ leftTouchSamples = new float[leftTouch.sampleSize()];
+ rightTouchSamples = new float[rightTouch.sampleSize()];
+ ultrasoneTime = System.currentTimeMillis();
+ colorTime = System.currentTimeMillis();
+ leftTouchTime = System.currentTimeMillis();
+ rightTouchTime = System.currentTimeMillis();
+ }
+
+ public float getDistance(){
+ if(System.currentTimeMillis()-ultrasoneTime>DELAY){
+ ultrasone.fetchSample(ultrasoneSamples, 0);
+ ultrasoneTime = System.currentTimeMillis();
+ }
+ return ultrasoneSamples[0];
+ }
+
+ public int getColor(){
+ if(System.currentTimeMillis()-colorTime>DELAY){
+ color.fetchSample(colorSamples, 0);
+ colorTime = System.currentTimeMillis();
+ }
+ return (int)colorSamples[0];
+ }
+
+ public boolean getLeftTouch(){
+ if(System.currentTimeMillis()-leftTouchTime>DELAY){
+ leftTouch.fetchSample(leftTouchSamples, 0);
+ leftTouchTime = System.currentTimeMillis();
+ }
+ return leftTouchSamples[0]==1;
+ }
+
+ public boolean getRightTouch(){
+ if(System.currentTimeMillis()-rightTouchTime>DELAY){
+ rightTouch.fetchSample(rightTouchSamples, 0);
+ rightTouchTime = System.currentTimeMillis();
+ }
+ return rightTouchSamples[0]==1;
+ }
+}
\ No newline at end of file
+++ /dev/null
-/* The first part specifies the robot specific information such as
- * which sensor is plugged in which port. */
-Name MartNatanael
-Acceleration 10000
-Speed 200
-LeftMotor plugged in A
-RightMotor plugged in D
-ColorSensor plugged in S1
-TouchSensor plugged in S2 and S3
-UltrasoneSensor plugged in S4
-/* After the static part you can specify one or more missions
- * Every mission is a list of behaviours in the order of priority
- * and a stopping condition.
- */
-Mission:
- /* All behaviours have an action and possibly a take control predicate
- * When the take control predicate is not specified the behaviour will
- * always try to take control.
- */
- Behaviour
- Name: DontFallOff
- TakeControl: ColorLimit: Black
- Action: Avoid
- Behaviour
- Name: AvoidLowObjects
- TakeControl: TouchStatus: Touch
- Action: Avoid
- Behaviour
- Name: AvoidHighObjects
- TakeControl: Distance: "0.5" meter
- Action: Avoid
- Behaviour
- Name: Wandering
- TakeControl:
- Action: Wander
- stops when
- Collected Colors: Red Yellow Blue
-
\ No newline at end of file
--- /dev/null
+module robots.missions.GenerateTaskDSL
+
+import org.eclipse.emf.mwe.utils.*
+import org.eclipse.xtext.generator.*
+import org.eclipse.xtext.ui.generator.*
+
+var grammarURI = "classpath:/robots/missions/TaskDSL.xtext"
+var fileExtensions = "tdsl"
+var projectName = "desdsl"
+var runtimeProject = "../${projectName}"
+var generateXtendStub = true
+var encoding = "UTF-8"
+
+Workflow {
+ bean = StandaloneSetup {
+ scanClassPath = true
+ platformUri = "${runtimeProject}/.."
+ // The following two lines can be removed, if Xbase is not used.
+ registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
+ registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
+ }
+
+ component = DirectoryCleaner {
+ directory = "${runtimeProject}/src-gen"
+ }
+
+ component = DirectoryCleaner {
+ directory = "${runtimeProject}/model/generated"
+ }
+
+ component = DirectoryCleaner {
+ directory = "${runtimeProject}.ui/src-gen"
+ }
+
+ component = DirectoryCleaner {
+ directory = "${runtimeProject}.tests/src-gen"
+ }
+
+ component = Generator {
+ pathRtProject = runtimeProject
+ pathUiProject = "${runtimeProject}.ui"
+ pathTestProject = "${runtimeProject}.tests"
+ projectNameRt = projectName
+ projectNameUi = "${projectName}.ui"
+ encoding = encoding
+ language = auto-inject {
+ uri = grammarURI
+
+ // Java API to access grammar elements (required by several other fragments)
+ fragment = grammarAccess.GrammarAccessFragment auto-inject {}
+
+ // generates Java API for the generated EPackages
+ fragment = ecore.EMFGeneratorFragment auto-inject {}
+
+ // the old serialization component
+ // fragment = parseTreeConstructor.ParseTreeConstructorFragment auto-inject {}
+
+ // serializer 2.0
+ fragment = serializer.SerializerFragment auto-inject {
+ generateStub = false
+ }
+
+ // a custom ResourceFactory for use with EMF
+ fragment = resourceFactory.ResourceFactoryFragment auto-inject {}
+
+ // The antlr parser generator fragment.
+ fragment = parser.antlr.XtextAntlrGeneratorFragment auto-inject {
+ // options = {
+ // backtrack = true
+ // }
+ }
+
+ // Xtend-based API for validation
+ fragment = validation.ValidatorFragment auto-inject {
+ // composedCheck = "org.eclipse.xtext.validation.ImportUriValidator"
+ // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
+ }
+
+ // old scoping and exporting API
+ // fragment = scoping.ImportURIScopingFragment auto-inject {}
+ // fragment = exporting.SimpleNamesFragment auto-inject {}
+
+ // scoping and exporting API
+ fragment = scoping.ImportNamespacesScopingFragment auto-inject {}
+ fragment = exporting.QualifiedNamesFragment auto-inject {}
+ fragment = builder.BuilderIntegrationFragment auto-inject {}
+
+ // generator API
+ fragment = generator.GeneratorFragment auto-inject {}
+
+ // formatter API
+ fragment = formatting.FormatterFragment auto-inject {}
+
+ // labeling API
+ fragment = labeling.LabelProviderFragment auto-inject {}
+
+ // outline API
+ fragment = outline.OutlineTreeProviderFragment auto-inject {}
+ fragment = outline.QuickOutlineFragment auto-inject {}
+
+ // quickfix API
+ fragment = quickfix.QuickfixProviderFragment auto-inject {}
+
+ // content assist API
+ fragment = contentAssist.ContentAssistFragment auto-inject {}
+
+ // generates a more lightweight Antlr parser and lexer tailored for content assist
+ fragment = parser.antlr.XtextAntlrUiGeneratorFragment auto-inject {}
+
+ // generates junit test support classes into Generator#pathTestProject
+ fragment = junit.Junit4Fragment auto-inject {}
+
+ // rename refactoring
+ fragment = refactoring.RefactorElementNameFragment auto-inject {}
+
+ // provides the necessary bindings for java types integration
+ fragment = types.TypesGeneratorFragment auto-inject {}
+
+ // generates the required bindings only if the grammar inherits from Xbase
+ fragment = xbase.XbaseGeneratorFragment auto-inject {}
+
+ // generates the required bindings only if the grammar inherits from Xtype
+ fragment = xbase.XtypeGeneratorFragment auto-inject {}
+
+ // provides a preference page for template proposals
+ fragment = templates.CodetemplatesGeneratorFragment auto-inject {}
+
+ // provides a compare view
+ fragment = compare.CompareFragment auto-inject {}
+ }
+ }
+}
+
--- /dev/null
+grammar robots.missions.TaskDSL with org.eclipse.xtext.common.Terminals
+
+generate taskDSL "http://www.missions.robots/TaskDSL"
+
+Robot:
+ 'Name' name=ID
+ 'Acceleration' acc=INT
+ 'Speed' spd=INT
+ behaviour+=Behaviour+
+ mission+=Mission+;
+
+Mission: 'Mission' name=ID 'using' behaviours+=[Behaviour]+ 'and stops when' stoppingExpression=StoppingExpression;
+
+StoppingExpression:
+ '(' op=Operator s+=StoppingExpression s+=StoppingExpression* ')' |
+ scond=StoppingCondition
+;
+
+StoppingCondition:
+ 'Collected at least' colors+=Color+ |
+ 'Touched on' touch=LeftRight |
+ 'Distance' op=Comparison dist=INT 'cm' |
+ 'Color is' color=Color;
+
+Behaviour: 'Behaviour' name=ID
+ 'take control:' tc=StoppingExpression?
+ 'action:' actions+=Action+;
+
+Action:
+ whichMotor=LeftRight 'motor' dir=Direction ('with speed' spd=INT 'acceleration' acc=INT)? |
+ 'wait' time=Time;
+
+Time: time=INT 'ms' | {Time} 'forever';
+
+enum Direction: BACKWARDS = 'Backwards' | FORWARDS = 'Forwards';
+enum Operator: AND = 'and' | OR = 'or';
+enum Comparison: GE='>' | LE='<';
+enum LeftRight: LEFT='Left' | RIGHT='Right';
+enum Color:
+ BLACK='Black' | BLUE='Blue' | BROWN='Brown' | CYAN='Cyan' |
+ DARKGRAY='DarkGray' | GRAY='Gray' | GREEN='Green' |
+ LIGHTGRAY='LightGray' | MAGENTA='Magenta' | ORANGE='Orange' | PINK='Pink' |
+ RED='Red' | WHITE='White' | YELLOW='Yellow';
\ No newline at end of file
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions;
+
+/**
+ * Use this class to register components to be used at runtime / without the Equinox extension registry.
+ */
+public class TaskDSLRuntimeModule extends robots.missions.AbstractTaskDSLRuntimeModule {
+
+}
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions;
+
+/**
+ * Initialization support for running Xtext languages
+ * without equinox extension registry
+ */
+public class TaskDSLStandaloneSetup extends TaskDSLStandaloneSetupGenerated{
+
+ public static void doSetup() {
+ new TaskDSLStandaloneSetup().createInjectorAndDoEMFRegistration();
+ }
+}
+
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions.formatting
+
+import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter
+import org.eclipse.xtext.formatting.impl.FormattingConfig
+// import com.google.inject.Inject;
+// import robots.missions.services.TaskDSLGrammarAccess
+
+/**
+ * This class contains custom formatting declarations.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#formatting
+ * on how and when to use it.
+ *
+ * Also see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an example
+ */
+class TaskDSLFormatter extends AbstractDeclarativeFormatter {
+
+// @Inject extension TaskDSLGrammarAccess
+
+ override protected void configureFormatting(FormattingConfig c) {
+// It's usually a good idea to activate the following three statements.
+// They will add and preserve newlines around comments
+// c.setLinewrap(0, 1, 2).before(SL_COMMENTRule)
+// c.setLinewrap(0, 1, 2).before(ML_COMMENTRule)
+// c.setLinewrap(0, 1, 1).after(ML_COMMENTRule)
+ }
+}
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions.generator
+
+import org.eclipse.emf.ecore.resource.Resource
+import org.eclipse.xtext.generator.IGenerator
+import org.eclipse.xtext.generator.IFileSystemAccess
+
+/**
+ * Generates code from your model files on save.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
+ */
+class TaskDSLGenerator implements IGenerator {
+
+ override void doGenerate(Resource resource, IFileSystemAccess fsa) {
+// fsa.generateFile('greetings.txt', 'People to greet: ' +
+// resource.allContents
+// .filter(typeof(Greeting))
+// .map[name]
+// .join(', '))
+ }
+}
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions.scoping
+
+/**
+ * This class contains custom scoping description.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping
+ * on how and when to use it.
+ *
+ */
+class TaskDSLScopeProvider extends org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider {
+
+}
--- /dev/null
+/*
+ * generated by Xtext
+ */
+package robots.missions.validation
+
+//import org.eclipse.xtext.validation.Check
+
+/**
+ * This class contains custom validation rules.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation
+ */
+class TaskDSLValidator extends AbstractTaskDSLValidator {
+
+// public static val INVALID_NAME = 'invalidName'
+//
+// @Check
+// def checkGreetingStartsWithCapital(Greeting greeting) {
+// if (!Character.isUpperCase(greeting.name.charAt(0))) {
+// warning('Name should start with a capital',
+// MyDslPackage.Literals.GREETING__NAME,
+// INVALID_NAME)
+// }
+// }
+}