Problem with Blink LED test using Shapes and Mouse

edited June 2016 in Raspberry PI

Hello, This is my first time using Processing on the Raspberry PI. So I made the traditional 'Blink the LED' test in Processing and it works fine. I connected a Red and Yellow LED on the breadboard to create a "ping-pong" type display.

But I noticed something when I started adding Shapes into the code. I added 2 shapes to represent the LED's, one is a red box and the other is a yellow box. And I have the code written to 'turn' on the shapes by changing the color whenever the LED on the breadboard is turned ON. Then when the LED is turned OFF, I change the color of the box to black.

But there seems to be some lag in the graphics. Basically the LED on the breadboard will turn on and the box in the window will change color about 1 second later. At first I thought maybe the "GPIO.digitalWrite" instruction is taking too long. But I swapped the code so the "fill" and "rect" instruction is done first and then after the "GPIO.digitalWrite" instruction is executed. But there was no difference or improvment.

Then I decided to add a mouse event so I can control when to start and end the blinking. There I noticed the lag in the graphics. If I clicked the mouse for a split second, where the LED's would change state just once. I would see the LED's change first, then about 1 sec later the graphics in the window would be updated. And this is a consistent anomaly.

I can't verify this on my desktop to see if I can reproduce the problem as I don't have any GPIO's available at the moment.

Has anyone noticed this before ?

Would I have something out of sequence in the code ?

below is my test code



//==================================================
// Import hardware IO library.
import processing.io.*;

// Pin #'s for LEDs and Button:
int redLEDPin   = 22;
int yelLEDPin = 27;
int count = 0;
int count2 = 0;
int i = 1;

// LED state, on or off (true or false).
boolean redLED = true;
boolean yelLED = false;
boolean mouseclk = false;

//----------------------------------------------------
void setup() 
{
  size(300, 200);
  textSize(10);
  //textFont(mono);

  // Initialize LEDs as outputs.
  GPIO.pinMode(redLEDPin, GPIO.OUTPUT);
  GPIO.pinMode(yelLEDPin, GPIO.OUTPUT);


  // Default to drawing black lines around buttons.
  stroke(0, 0, 0);
  
  // Turn the LEDs off.
  GPIO.digitalWrite(redLEDPin, false);
  GPIO.digitalWrite(yelLEDPin, false);

}

//-------------------------------------------------------
void draw()
{

  if (mouseclk)                      //check flag, only do this once
  {
    background(0, 0, 255);
    fill(255,255,255);
    text("BEGIN TEST:",5,10);
    text("WAIT FOR MOUSE CLICK",150, 10);
        
    text("TEST LOOP# " + i + " ",150,100);
    //blink
    redLEDiconON();
  
    redLEDiconOFF();
    
    yelLEDiconON();
  
    yelLEDiconOFF();
  
    redLED = !redLED;
    yelLED = !yelLED;
    
    i++;
    
    delay(1000);
      
    //count = 1;
    
  }
  
  if (!mouseclk)                      //check flag, only do this once
  {
    fill(255,255,255);
    text("END TEST:", 150,150);
  }

  //noLoop();
}

//------------------------------------------------------
void mousePressed() 
{
  count2 = 1;
  i = 1;
  redLED = true;
  yelLED = false;
  mouseclk = true;
}


//------------------------------------------------------
void mouseReleased() 
{
  mouseclk = false;
}
//----------------------------------------------------
void redLEDiconON()
{
  if (redLED)
  {
  fill(255, 0, 0);
  text("Red=ON",50, 80);
  rect(50, 20, 30, 30, 7);
  GPIO.digitalWrite(redLEDPin, true);
  //delay(200);
  }
}

//----------------------------------------------------
void redLEDiconOFF()
{
  if (!redLED)
  {
  fill(255, 0, 0);
  text("Red=OFF",50, 80);
  fill(0, 0, 0);
  rect(50, 20, 30, 30, 7);
  GPIO.digitalWrite(redLEDPin, false);
  //delay(200);
  }
}
//----------------------------------------------------
void yelLEDiconON()
{
  if (yelLED)
  {
  fill(255, 255, 0);
  text("Yel=ON",200, 80);
  rect(200, 20, 30, 30, 7);
  GPIO.digitalWrite(yelLEDPin, true);
  //delay(200);
  }
}

//----------------------------------------------------
void yelLEDiconOFF()
{
  if (!yelLED)
  {
  fill(255, 255, 0);
  text("Yel=OFF",200, 80);
  fill(0, 0, 0);
  rect(200, 20, 30, 30, 7);
  GPIO.digitalWrite(yelLEDPin, false);
  //delay(200);
  }
}
//=====================================================


Answers

  • mouseclk is changing from true to false each time round the loop. it's only turned off when you release the mouse, so it's random whether it ends up true or false. Maybe try setting mouseclk to false during the if (mouseclk) { bit so it only runs once, and you could take the delay() out.

    if (mouseclk) {
        mouseclk = false;
    
  • edited June 2016

    the updated code is below

    yes, this was my intention. I only wanted to the blink code so it runs while I press 'n hold the mouse button. So it runs continuously. And this would stop blinking when I released the mouse button. I did this to get control over when the blink code starts 'n stops.

    About the delay, I thought I would need it because the code itself runs fast enough by itself and I couldn't see if the LEDs and shapes were actually in sync because they blink so fast.

    I tried your suggestion to see what happens. And it won't run continuously, it only loops once.

    I went ahead and changed the code a little and optimized the if/then statements. So now the mouse click is a toggle function. I click the mouse once to start the LEDs blinking. I click the mouse button again, and the LEDs stop blinking.

    But I still see the lag in the graphics. The LED will always turn on before the graphics in the screen is updated.

    Then I removed the delay again as you suggested. And the LEDs were blinking wildly fast. If I stop the blinking with the mouse click, the LED and it's corresponding box on the screen is always perfectly in sync. I don't see any lag any more. But this should hold true if I run it slower. Instead I see the lag appear again.

    The moment I click the mouse button to stop the blinking, the LEDs stop blinking immediately. Then there's a 1 second lag and then finally the box on the screen is updated. As you can see in the code, I placed the delay at the end of the draw function which is the most obvious place

    So with the current state of the code [below] If I toggle the mouse button, once to start the blinking and then quickly click the mouse button again to stop the blinking when I see the LEDs change. So it only loops once. I will see the LED change first before the boxes on the screen is updated. And this lag can be as long as 1 second.

    It's almost as if there was some mysterious delay function between these two lines of code

        rect(50, 20, 30, 30, 7);
        GPIO.digitalWrite(redLEDPin, true);
    

    Would the delay need to go somewhere else ?

    Do you think my Raspberry PI is too slow. I'm using one of the older boards, the 700mhz B+. BTW, the Processing IDE is terribly slow on this. I suppose it would run better on a RPi2 or 3.

    So what I do is write and build the code on my desktop using the Raspberry PI libraries, export the files to LinuxArmv6 platform, and then FTP those files to the PI and run it on there directly.

    Would somebody be able to try this little Blinking LED test on their RPi and compare their results.

    
    
    //==================================================
    // LED Blink test
    //==================================================
    // Import hardware IO library.
    import processing.io.*;
    
    // Pin #'s for LEDs and Button:
    int redLEDPin   = 22;
    int yelLEDPin = 27;
    int count = 0;
    int count2 = 0;
    int i = 1;
    
    // LED state, on or off (true or false).
    boolean redLED = true;
    boolean yelLED = false;
    boolean mouseclk = false;
    
    //----------------------------------------------------
    void setup() 
    {
      size(300, 200);
      textSize(10);
    
      // Initialize LEDs as outputs.
      GPIO.pinMode(redLEDPin, GPIO.OUTPUT);
      GPIO.pinMode(yelLEDPin, GPIO.OUTPUT);
    
      // Default to drawing black lines around buttons.
      stroke(0, 0, 0);
      
      // Turn the LEDs off.
      GPIO.digitalWrite(redLEDPin, false);
      GPIO.digitalWrite(yelLEDPin, false);
    }
    
    //--------------------------------------------------------
    void draw()
    {
      //check flag, only do this once in beginning
      if (count == 0)
      {
        background(0, 0, 255);
        fill(255,255,255);
        text("BEGIN TEST:",5,10);
        text("WAIT FOR MOUSE CLICK",150, 10);
        count = 1;
      }
      
      //use mouse button as toggle to start/stop blinking
      if (mouseclk)                      
      {
        background(0, 0, 255);
        fill(255,255,255);
        text("BEGIN TEST:",5,10);
        text("WAIT FOR MOUSE CLICK",150, 10);
        text("TEST LOOP# " + i + " ",150,100);
    
        //blink
        redLEDicon();
        yelLEDicon();
        redLED = !redLED;
        yelLED = !yelLED;
        i++;
        delay(1000);
      }
      else
      {
        fill(255,255,255);
        text("END TEST:",150,150);
      }
    }
    
    //------------------------------------------------------
    void mousePressed() 
    {
      //count2 = 1;
      //i = 1;
      //redLED = true;
      //yelLED = false;
      mouseclk = !mouseclk;
    }
    
    //----------------------------------------------------
    void redLEDicon()
    {
      if (redLED)
      {
        fill(255, 0, 0);
        text("Red=ON",50, 80);
        rect(50, 20, 30, 30, 7);
        GPIO.digitalWrite(redLEDPin, true);
      }
      else
      {
        fill(255, 0, 0);
        text("Red=OFF",50, 80);
        fill(0, 0, 0);
        rect(50, 20, 30, 30, 7);
        GPIO.digitalWrite(redLEDPin, false);
      }
    }
    
    //----------------------------------------------------
    void yelLEDicon()
    {
      if (yelLED)
      {
        fill(255, 255, 0);
        text("Yel=ON",200, 80);
        rect(200, 20, 30, 30, 7);
        GPIO.digitalWrite(yelLEDPin, true);
      }
      else
      {
        fill(255, 255, 0);
        text("Yel=OFF",200, 80);
        fill(0, 0, 0);
        rect(200, 20, 30, 30, 7);
        GPIO.digitalWrite(yelLEDPin, false);
      }
    }
    //=====================================================
    
    
  • edited June 2016

    If it helps, here's some code that blinks an LED and doesn't use delay(). Delay does cause problems so it's better avoided if you can. Sorry, aware I'm not answering your question about drawing time for rect(), but let's remove the delays first!

        int blinkTime = 50; // ms between blink states
        boolean blinkOn = false;
        long lastBlink = millis();
        boolean mouseHeld = false;
    
        void setup() 
        {
          size(300, 200);
        }
    
        void draw() {
          if (mouseHeld) {
            blinkLED();
          } else {
            println("off");
            //  GPIO.digitalWrite(pin, false);
          }
        }
    
    
        void blinkLED() {
          if (millis() > (lastBlink + blinkTime)) {
            blinkOn = !blinkOn;
            println(blinkOn);
            // GPIO.digitalWrite(pin, blinkOn);
            lastBlink = millis();
          }
        }
    
        void mousePressed() {
          mouseHeld = true;
        }
    
        void mouseReleased() {
         mouseHeld = false; 
        }
    
  • edited June 2016

    To make it easier to have more than one pin blinking, this is the same sketch as an object. This lets you call blink for any pin, and set different blink rates.

        import processing.io.*;
    
        boolean mouseHeld = false;
        int redLEDpin = 22;
        int yellowLEDpin = 27;
    
        BlinkLED redLED, yellowLED;
    
        void setup() 
        {
          size(300, 200);
          redLED = new BlinkLED(redLEDpin, 100); // this calls the class BlinkLED, passing the pin to blink and the time
          yellowLED = new BlinkLED(yellowLEDpin, 1000);
        }
    
        void draw() {
          if (mouseHeld) {
            redLED.update();
            yellowLED.turnOff();
          } else {
            yellowLED.update();
            redLED.turnOff();
          }
        }
    
        void mousePressed() {
          mouseHeld = true;
        }
    
        void mouseReleased() {
          mouseHeld = false;
        }
    
        class BlinkLED {
          int pin;
          int blinkTime;
          long lastBlink;
          boolean blinkOn;
    
    
          BlinkLED(int LEDpin, int LEDblinkTime) {
            pin = LEDpin;
            blinkTime = LEDblinkTime;
            lastBlink = millis();
            blinkOn = false;
          }
          void update() {
            if (millis() > (lastBlink + blinkTime)) {
              blinkOn = !blinkOn;
              println(pin + " set to: " + blinkOn);
              // GPIO.digitalWrite(pin, blinkOn);
              lastBlink = millis();
            }
          }
          void turnOff() {
            // GPIO.digitalWrite(pin, GPIO.LOW);
          }
        }
    
  • forgive me , but this forum doesn't seem to let me reply to individual posts.

    Your post at 5:59am looks to be very helpful. I'll have to try that after work tonight. I like how you used the internal timer, "milli()" to keep track of time. I wasn't familiar with this function in Processing. I do this too on some retro projects when programming on the C64 with assembly code.

    Your last post at 7:53 also looks very helpful too. Again I have to wait til after work tonight and give it a try. I really like how you used the "Class" object. That's something I'm still practicing with as I was mostly a C coder on many projects - beside assembly. My background is hardware, but I still like to program since I was a kid - but back then it was only Basic, Fortran or Pascal.

  • Hope it works! If it's still slow I can test it for you on a pi zero, but hopefully optimising the code will speed it up.

  • ok, thanks again for the tips. I'll try this tonight and let you know

    Could I trouble you to look at my other post and get some suggestions[link below]. It's about the Servo-PWM Hat from Adafruit, made for the Raspberry PI. They only have libraries in python. I really would like to move everything over to Processing. As I read about the speed gains with Processing over python [interpeter] when using a lot of math in a project. I wish they had it already in C code. But I gained an interest in Processing several years ago and now that the news it's been ported to RPi was great to hear. https://forum.processing.org/two/discussion/17319/servo-pwm-pi-hat-how-to-convert-the-python-code-into-processing-code#latest

  • Sorry not to be able to help with that one. In the past I've managed by looking at the data sheet & bitbanging it, rather than using a library, meaning you can stay within processing, but it's complicated & needs a bit of tweaking.

  • ok, no prob. I'll keep looking for more info about that one. I'm getting ready to try those examples you posted tonight.

  • I tried your first example. It works great !!

    I merged your code with the millis() function together with mine[without the delay()]. So I can keep using the mouse toggle feature. And wouldn't you know it. The lag problem is gone. This really was a strange problem.

    Plus I changed the blinkTime to 500msec. I didn't want to push it so hard right now. I'll tinker with that value and see how fast both the graphics and the LEDs can really change.

    I'm going to try your 2nd example later too. below is the code

    //==================================================
    // LED Blink test
    //==================================================
    // Import hardware IO library.
    import processing.io.*;
    
    // Pin #'s for LEDs and Button:
    int blinkTime = 500; // ms between blink states
    boolean blinkOn = false;
    long lastBlink = millis();
    boolean mouseHeld = false;
    int redLEDPin   = 22;
    int yelLEDPin = 27;
    int count = 0;
    int count2 = 0;
    int i = 1;
    int endtest = 0;
    
    // LED state, on or off (true or false).
    boolean redLED = true;
    boolean yelLED = false;
    boolean mouseclk = false;
    
    //----------------------------------------------------
    void setup() 
    {
      size(300, 200);
      textSize(10);
    
      // Initialize LEDs as outputs.
      GPIO.pinMode(redLEDPin, GPIO.OUTPUT);
      GPIO.pinMode(yelLEDPin, GPIO.OUTPUT);
    
      // Default to drawing black lines around buttons.
      stroke(0, 0, 0);
      
      // Turn the LEDs off.
      GPIO.digitalWrite(redLEDPin, false);
      GPIO.digitalWrite(yelLEDPin, false);
    }
    
    //--------------------------------------------------------
    void draw()
    {
      //check flag, only do this once in beginning
      if (count == 0)
      {
        background(0, 0, 255);
        fill(255,255,255);
        text("BEGIN TEST:",5,10);
          text("WAIT FOR MOUSE CLICK",100,190);
        count = 1;
      }
      
      blinkLED();
      
    }
    
    //------------------------------------------------------ 
    void blinkLED() 
    {
      //use mouse button as toggle to start/stop blinking
      if (mouseclk)                      
      {
        if (millis() > (lastBlink + blinkTime)) 
        {
          lastBlink = millis();
          background(0, 0, 255);
          fill(255,255,255);
          text("BEGIN TEST:",5,10);
          text("TEST LOOP# " + i + " ",5,100);
      
          //blink
          redLEDicon();           //Change display
          yelLEDicon();           //Change display
          redLED = !redLED;       //toggle Red state
          yelLED = !yelLED;       //toggle Yellow state
          i++;                    //inc test counter
          endtest = 0;            //clear flag
        }
      }
      else
      {
        fill(255,255,255);
        if (endtest == 0)          //check flag, do only once
        {
          text("END TEST:",5,150);
          text("WAIT FOR MOUSE CLICK",100,190);
          endtest = 1;
        }
      }
    }
    
    //------------------------------------------------------
    void mousePressed() 
    {
      //count2 = 1;
      //i = 1;
      //redLED = true;
      //yelLED = false;
      mouseclk = !mouseclk;
    }
    
    //----------------------------------------------------
    void redLEDicon()
    {
      if (redLED)
      {
        fill(255, 0, 0);
        text("RED=ON",50, 80);
        rect(50, 20, 30, 30, 7);
        GPIO.digitalWrite(redLEDPin, true);
      }
      else
      {
        fill(255, 0, 0);
        text("RED=OFF",50, 80);
        fill(0, 0, 0);
        rect(50, 20, 30, 30, 7);
        GPIO.digitalWrite(redLEDPin, false);
      }
    }
    
    //----------------------------------------------------
    void yelLEDicon()
    {
      if (yelLED)
      {
        fill(255, 255, 0);
        text("YEL=ON",200, 80);
        rect(200, 20, 30, 30, 7);
        GPIO.digitalWrite(yelLEDPin, true);
      }
      else
      {
        fill(255, 255, 0);
        text("YEL=OFF",200, 80);
        fill(0, 0, 0);
        rect(200, 20, 30, 30, 7);
        GPIO.digitalWrite(yelLEDPin, false);
      }
    }
    //=====================================================
    
  • edited June 2016

    glad it's working. just for interest there are a few more optimisations you could make - for instance in yelLEDicon(), you have fill(255,255,0) and rect() on both sides of the if statement - this could go at the start of the function, which is easier to read & less code.

    I think the code in the if (count == 0) {} section will work in setup which means you don't need the count integer - but anyway a boolean would be more suitable here.

    None of these things have to be done, if it's working, but it's good practice to keep the code tight.

  • ok, I see what you mean. This little test was some practice to get acquainted with building some tools with Processing. Basically a kind of a gui instrument panel to receive telemetry data and transmit any commands for my next robot project. Next test was to add some sensors to check the response time of the software.

    Eventually I like to make this wireless via wifi. I see some more info about more libraries on the other website Openprocessing.org . I thought about using the udp networking libraries to transfer the telemetry data and run the instrument panel locally on a laptop to stay mobile.

    I tried this before with C coding on some old embedded projects with ethernet - it was a good experience. But a future problem exists when I'm somewhere that has no wifi. I didn't know how to get around this yet - maybe use a direct wireless connection instead of wifi.

Sign In or Register to comment.