Problem with timer.

edited October 2014 in Questions about Code

Hi! I'm new to programming but last week we decided to make laser stopwatch system in our mtb competition.. so i decided to try. Making with Arduino (with photoresistor in analog input) with filled in Firmata, and trying to use processing to get rider's times on display. Our track is about 30sec, and starts every minute, so I need a timer, looped in a minute.. when rider cross laser - check the time and display it... As I said, I'm new in programming, so code may be stupid, but as is =) Now i have a problem with looping minute (60000ms), it just stopping the watch. Can't get it (((

    import processing.serial.*;
    import cc.arduino.*;
    PFont font;
    Arduino arduino;
    int a = 8; // sets switch threshold
    int bg = 200; //bg color
    String txt = "Waiting..."; 

    void setup() {
      size(displayWidth, displayHeight);
      background(bg);
      textAlign(CENTER);
      arduino = new Arduino(this, "COM3", 57600);

      font = createFont("Impact",60,true);
      textFont(font,80);
      fill(20);
      text(txt, displayWidth/2, displayHeight/2);
      StopWatch.start();
    }

    void draw() {

      if (arduino.analogRead(0)<a) { // shading trigger
        StopWatch.stop();
        String time = ("Time:\t  " + StopWatch.time()/1e3);
        background(bg);
        text(time, displayWidth/2, displayHeight/2);
            }
       if (StopWatch.time()>60000)
        {
                                                                ///////////lag????
          StopWatch.start();
         }
       if (keyPressed==true){  //restart to sync time
           StopWatch.reset();
           String res = ("Time:\t  " + StopWatch.time()/1e3);
          background(bg);
          text(txt, displayWidth/2, displayHeight/2);
          StopWatch.start();
         }

       // printArray(arduino.analogRead(0)); debug a

    }
    boolean sketchFullScreen() {
      return true;
    }

    static final class StopWatch {
      static long startTime, endTime;

      static void start() {
        startTime = System.currentTimeMillis();
      }

      static void stop() {
        endTime = System.currentTimeMillis();
      }

      static long time() {
        return endTime - startTime;
      }

      static void reset() {
        startTime = endTime = 0;
      }
    }

Answers

  • edited October 2014

    Little confusing... Perhaps making endTime = startTime inside start()? :-/

    static void start() {
      startTime = endTime = System.currentTimeMillis();
    }
    
  • i start program, pressing any key to sync with my stopwatch, than laser crossed and i see the time... till now its ok. i supose that timer continue 1 minute loop counting, but when next rider crossing laser it just starting timer from 0... thats the problem i cant guess..

  • edited October 2014 Answer ✓

    As said by GoToLoop (you haven't answered him), you need to have startTime = endTime in start(), otherwise endTime is 0, and computing in time() is just wrong. Do println(System.currentTimeMillis()) to see why.

    And I wonder why you use this instead of Processing's millis().

    Side note: since your problem has nothing to do with Arduino, you better make a different sketch without dependency on it, eg. replacing its event with a keyboard event, for example. Thus, anybody can run your code, it is easier to help you.

  • edited October 2014

    Thanks, trying to modify the code... I thought to display real time and track time with minutes first time i start to write this code, for now... maybe millis() only will work, just need to think about it... Thanks PhiLho, my brain a little hazed now with all this new programming) Also there is one more little problem... As soon as front wheel of the bike cross the laser, my timer checking times until his rear wheel pass (all details of bike shading laser) - so on dysplay i see rear wheel time. I think some delay after 28 string would work, but as I heard delay() function is not very good to use.

  • edited October 2014

    ... but as I heard delay() function is not very good to use.

    Actually it's disastrous. Although it's OK inside setup(), before draw() starts.
    If you need to use it, you're gonna need a separate Thread for it.

  • Hey, GoToLoop, PhiLho - thanks for advice! Modyfied code, using millis(). Here it is:

    import processing.serial.*;
    import cc.arduino.*;
    PFont font;
    Arduino arduino;
    int a = 30; // sets switch threshold
    int bg = 200; //bg color
    String txt = "Waiting..."; 
    String go = "Go! Go! Go!";
    int savedTime;
    int totalTime = 60000; //reset time
    
    void setup() {
      size(displayWidth, displayHeight);
      background(bg);
      arduino = new Arduino(this, "COM3", 57600);
      savedTime = millis();
    
      font = createFont("Impact",60,true);
      textFont(font,80);
      fill(20);
      text(txt, displayWidth/2, displayHeight/2);
    }
    
    void draw() {
      // Calculate how much time has passed
      int passedTime = millis() - savedTime;
     if (arduino.analogRead(0)<a) { // shading trigger
        String time = ("Time:\t  " + passedTime/1e3);
        background(bg);
        text(time, displayWidth/2, displayHeight/2);
            }
      // 
      if (passedTime > totalTime) {
        println("GoGoGo!");
        savedTime = millis(); //to restart timer every minute
        background(bg);
        text(go, displayWidth/2, displayHeight/2);
      }
      if (keyPressed==true){  //restart to sync time
           savedTime = millis();
           println("reset");
         }
        // println(arduino.analogRead(0)); debug a
    }
    //Fullscreen
    //boolean sketchFullScreen() {
    //  return true;
    //}
    

    It seems to work good for now) Still wondering of delay on finish. GoToLoop, should i create a new thread about it?

  • Callback draw() is invoked @ 60 FPS by default. Rather than using delay() to forcibly halt draw(),
    it's much better & correct to use frameRate(): http://processing.org/reference/frameRate_.html

    For example, frameRate(2) would set 2 FPS for draw(). Which is the same as delay(500). =:)

  • I thougth framerate would decrease timer accuracy, cause its checking analog read from photoresistor in draw() if (arduino.analogRead(0)<a){...} Isn't it?

  • edited October 2014

    Well, delay() would halt the whole "Animation Thread" too.
    While frameRate() establishes a constant delay for draw() callback.

    Question is, does analogRead() need to be hammered @ 60 FPS?
    Notice that millis() isn't affect neither by frameRate() nor delay() though.

  • Well, as I've checked using frameRate(2) displayed time was with 0.5sec accuracy (2 frames/sec) cause in the draw() arduino.analogRead() checking if laser shaded or not with this framerate. So its not suitable for me, accuracy should be 0.01sec so i set framerate to 100. But problem still exist - how to record only first event?

  • I have notice on some of these programs in the sample section. the milliseconds just keep counting upward. could you record the millis at the start of the program. And each trigger of the next millis rec event subtract it from the start millis?

  • edited October 2014 Answer ✓

    Declare a startMillis "global" variable.
    When millis() - startMillis >= LIMIT, do something and make startMillis = millis() again!

  • Works great! Big respect, GoToLoop!

Sign In or Register to comment.