Problem calling keyPressed ()

edited January 2016 in Arduino

Here is the thing, I'm trying to comunicate with arduino to create a robot, right now processing will send information for how the robot will move and when I press the key 'g' it will work like a switch to activate the sensors in the arduino and get the values, here is the code

import processing.serial.*;       //use the Serial library
Serial myPort; 

boolean keyup = false;
boolean keyright = false;        // Booleanos de las teclas que se presionan
boolean keyleft = false;
boolean keydown = false;
boolean sensor = false;

float x,y;
boolean loop = false;
int inByte;

void setup() {
  size(200, 200);                                  //set window size to 200 by 200 pixels
  String portName = Serial.list()[0];              //list serial ports, save the first one as portName
  myPort = new Serial(this, portName, 9600);  
}

    void draw() {

  background(255);
  loop = sensor;
  while(loop == false){
    if (keyup && !keydown && !keyleft && !keyright) {  myPort.write('w');  println('w');   }
    if (keyup && !keydown && keyleft && keyright) {  myPort.write('w');  println('w');   }
    if (keyup && !keydown && keyleft && !keyright) {  myPort.write('q');  println('q');   }              // Dependiendo de la combinacion de letras que lee es la letra que manda
    if (keyup && !keydown && !keyleft && keyright) {  myPort.write('e');  println('e');   }              // Para hacer de el teclado   "asdw" un teclado de 9 botones
    if (!keyup && !keydown && keyleft && !keyright) {  myPort.write('a');  println('a');   }
    if (!keyup && !keydown && !keyleft && keyright) {  myPort.write('d');  println('d');   }
    if (!keyup && keydown && !keyleft && !keyright) {  myPort.write('x');  println('x');   }
    if (!keyup && keydown && keyleft && keyright) {  myPort.write('x');  println('x');   }
    if (!keyup && keydown && keyleft && !keyright) {  myPort.write('z');  println('z');   }
    if (!keyup && keydown && !keyleft && keyright) {  myPort.write('c');  println('c');   }
    if (!keyup && !keydown && !keyleft && !keyright) {  myPort.write('s');  println('s');   }

    loop = sensor;       
  }  
  while(loop == true){loop = sensor;}                                                                         // Si se presiono sensor sigue hasta que la condicion de presionado cambie
  while(loop == false){                                                                                       // Se asume que el boton de sensor se solto

    myPort.write('g');   // pide informacion al arduino
    inByte = myPort.read();                                                                               // lee la informacion
    println(inByte);                                                                                          // la escribe en processing

    if (keyup && !keydown && !keyleft && !keyright) {  myPort.write('w');  println('w');   }
    if (keyup && !keydown && keyleft && keyright) {  myPort.write('w');  println('w');   }
    if (keyup && !keydown && keyleft && !keyright) {  myPort.write('q');  println('q');   }
    if (keyup && !keydown && !keyleft && keyright) {  myPort.write('e');  println('e');   }
    if (!keyup && !keydown && keyleft && !keyright) {  myPort.write('a');  println('a');   }
    if (!keyup && !keydown && !keyleft && keyright) {  myPort.write('d');  println('d');   }        // manda informacion de movimiento al arduino
    if (!keyup && keydown && !keyleft && !keyright) {  myPort.write('x');  println('x');   }
    if (!keyup && keydown && keyleft && keyright) {  myPort.write('x');  println('x');   }
    if (!keyup && keydown && keyleft && !keyright) {  myPort.write('z');  println('z');   }
    if (!keyup && keydown && !keyleft && keyright) {  myPort.write('c');  println('c');   }
    if (!keyup && !keydown && !keyleft && !keyright) {  myPort.write('s');  println('s');   }

    loop = sensor;
  }
  while(loop == true){loop = sensor;}                                                                          // mantiene el ciclo hasta que se suelta el sensor para salir de ese modo
}

void keyPressed() {

    if (key == 'w' || key == 'W') keyup = true; 
    if (key == 's' || key == 'S') keydown = true; 
    if (key == 'a' || key == 'A') keyleft = true;                   // Si alguna de las teclas esta presionada hace true el booleano
    if (key == 'd' || key == 'D') keyright = true; 
    if (key == 'g' || key == 'G') sensor  = true; 

}

void keyReleased() {
    if (key == 'w' || key == 'W') keyup = false; 
    if (key == 's' || key == 'S') keydown = false; 
    if (key == 'a' || key == 'A') keyleft = false;                  // Si la tecla no esta presionada hace false el booleano 
    if (key == 'd' || key == 'D') keyright = false;
    if (key == 'g' || key == 'G') sensor = false; 
}

Excuse the anotations in spanish, the code should be self explanatory for slightly more advanced programmers, my mates and I are kind of noobs (if you want english anotations please ask)

Anyway, in the void draw the keyPressed and keyReleased functions should be called automatically, and they do, when I do

loop = sensor;

the action is done, but after entering the first while all my code does is read the values before the while and wont let me press any keys to change how the robot will move or to get out of the while. Please help How do I explicitly call the void keyreleased within my whiles, or how do I fix the problem?

Answers

  • edited October 2013 Answer ✓

    The problem is the while loops in the draw method. The draw method is called (~60 times per second) is part of the main event loop. So if you consider line 49 you have

    while(loop == true){loop = sensor;}

    If loop is true then the code loops until sensor is false but that only happens when the g key is released but that can't happen because the keyPressed method is also on the main event thread but the program is stuck on the draw method.

    You need to revisit the program logic to get rid of the loops in draw. I suggest that you start by simply changing the while(s) with if(s) and see what happens.

  • edited October 2013 Answer ✓

    To add to what quark said above:

    You're in the false assumption that Processing's event functions like keyPressed() and such would be asynchronous.
    That is, erroneously thinking they'd run in parallel to draw() as separate threads! :O
    If you were programming in a .Net Framework language like C#, that'd much probably be so.

    Thus, such blocks like:

    while (loop)   loop = sensor;
    

    won't ever break free, b/c keyPressed() wouldn't be reached in order to toggle sensor variable, while draw() is running! b-(

    You gotta change your approach then. A good 1 is to turn off auto draw() calls w/ noLoop().
    And then use redraw() within keyPressed() & keyReleased() to control whether to run draw() or not. :-B

    A more advanced 1 is to turn your code inside draw() into another Thread function.
    That way, your strategy of awaiting for sensor would work alright,
    b/c your threaded function and Processing's event functions would run at the same time! $-)

    To go along w/ this 1, just transfer your main code into some function;
    and use thread("function name") inside setup() to ignite it! :bz

  • edited October 2013 Answer ✓

    And a template using noLoop() & redraw(): <):)

    import processing.serial.*;
    Serial myPort; 
    
    static boolean isKeyUp, isKeyRight, isKeyLeft, isKeyDown;
    static boolean isSensorOn, isLooping;
    
    void setup() {
      size(200, 200);
    
      noLoop();
    
      background(-1);
    
      myPort = new Serial(this, Serial.list()[0], 9600);
    }
    
    void draw() {
      // ...
    }
    
    void keyPressed() {
      setDirection(keyCode, true);
      redraw();
    }
    
    void keyReleased() {
      setDirection(keyCode, false);
      redraw();
    }
    
    static final void setDirection(int k, boolean bool) {
      if      (k == UP    | k == 'W')   isKeyUp    = bool;
      else if (k == DOWN  | k == 'S')   isKeyDown  = bool;
      else if (k == LEFT  | k == 'A')   isKeyLeft  = bool;
      else if (k == RIGHT | k == 'D')   isKeyRight = bool;
      else if (k == ENTER | k == 'G')   isSensorOn = bool;
    }
    
  • edited October 2013 Answer ✓

    Just to add a bit more of clarification for everybody's education:

    Events are collected asynchronously meaning that there's a separate thread which is collecting all mouse and keyboard events. However this thread only saves events in the internam memory buffer.

    Processing sketch, meanwhile will be notified about those evens via keyPressed() mouseMoved() and other event methods, but only on MAIN DRAWING THREAD.

    Because these methods will be called on the main event thread, when you stall the thread with your

    while(loop == true){loop = sensor;}
    

    you will not be notified of them. (All the events are collected, but they are in memory buffer somewhere in the memory of your computer, but your sketch is not notified of them).

    Your app is stalling main app thead similarly to this example:

    void setup(){
    }
    
    void keyPressed(){
       println("pressed key: " + key);
    }
    
    void mouseMoved(){
      println("Mouse moved: " + mouseX + ", " + mouseY );
    }
    
    
    void draw(){
      try{
       Thread.sleep(10 * 1000); // sleep for 10 seconds
      }
      catch(InterruptedException intex){
    
      }
      println("******************draw has finished executing frame: "+ frameCount);
    }
    

    If you run this sketch, you can see that all events are actually collected (and saved/queued in internal memory somewhere) but only once per 10 seconds, after the draw() has finished executing they will become known to your sketch.

  • First of all you guys are fantastic. Second, as I thought about it I figured that a way to go would be the second one that GoToLoop mentioned, a problem with the first solution is that (to my understanding) this method involves having the sensor key pressed all the time to collect sensor values, where what I'm looking for is to use it as a latching state switch (not sure how to say this in english, and it's more of an electrical term). I will try to do the separate thread kind of solution, but' I'll also run the other one to compare results... anyways thanks guys, I have only used processing very few times and I mostly use C languages instead of JAVA so I feel lost. I'll post what happens ASAP.

  • edited October 2013 Answer ✓

    So you wanna toggle the key states, like a light switch? If so, only keyPressed() is needed! ;)
    The pair keyPressed() + keyReleased() is used for games! (*)

    import processing.serial.*;
    Serial myPort; 
    
    static boolean isKeyUp, isKeyRight, isKeyLeft, isKeyDown;
    static boolean isSensorOn, isLooping;
    
    void setup() {
      size(200, 200);
    
      noLoop();
    
      background(-1);
    
      myPort = new Serial(this, Serial.list()[0], 9600);
    }
    
    void draw() {
      // ...
    }
    
    void keyPressed() {
      final int k = keyCode;
    
      if      (k == UP    | k == 'W')   isKeyUp    = !isKeyUp;
      else if (k == DOWN  | k == 'S')   isKeyDown  = !isKeyDown;
      else if (k == LEFT  | k == 'A')   isKeyLeft  = !isKeyLeft;
      else if (k == RIGHT | k == 'D')   isKeyRight = !isKeyRight;
      else if (k == ENTER | k == 'G')   isSensorOn = !isSensorOn;
    
      redraw();
    }
    
  • I'm actually looking for the videogame approach, since it will later go to a robot (I think that a robot or a videogame car might work the same in terms of direction), with sensor the idea is that if you press 'G' the sensor is on and even if you release said key it's still on, if you press it again it'll change to off, and so on... tried the thread solution really quickly and it didn't load keypressed at all, do I have to call it in thread or do you think it's a synchrony issue?

  • edited October 2013 Answer ✓

    Well, you can mix both approaches for keys. Since only 'G' needs to be toggled for each keyPressed(), we set that apart.
    The other keys are active as long as they're being pressed down. *-:)

    Also, I've got an online example which uses the mixed approach. Space or Enter keys toggle rect/ellipse shapes! :-h
    Take a look at it here: http://studio.processingtogether.com/sp/pad/export/ro.9bY07S95k2C2a/latest

    // forum.processing.org/two/discussion/518/problem-calling-keypressed-
    
    import processing.serial.*;
    Serial myPort; 
    
    static boolean isKeyUp, isKeyRight, isKeyLeft, isKeyDown;
    static boolean isSensorOn, isLooping;
    
    void setup() {
      size(200, 200);
      frameRate(60);
      smooth();
    
      myPort = new Serial(this, Serial.list()[0], 9600);
    }
    
    void draw() {
      background(-1);
    
      // ...
    }
    
    void keyPressed() {
      final int k = keyCode;
    
      if (k == ' ' | k == 'G')   isSensorOn = !isSensorOn;
      else                       setDirection(k, true);
    }
    
    void keyReleased() {
      setDirection(keyCode, false);
    }
    
    static final void setDirection(int k, boolean bool) {
      if      (k == UP    | k == 'W')   isKeyUp    = bool;
      else if (k == DOWN  | k == 'S')   isKeyDown  = bool;
      else if (k == LEFT  | k == 'A')   isKeyLeft  = bool;
      else if (k == RIGHT | k == 'D')   isKeyRight = bool;
    }
    
Sign In or Register to comment.