Accurate event Timer?

Hi guys, I’d be grateful for your guidance. I would like to have a Timer that triggers an event every 20ms. with good accuracy. Every 20ms it will read a value from an arrayList and it will send it through Serial.

I have so far tested quite a few ways as found in the forums, including the Java Timer class, the TimedEvents library, etc.

They all seem to be a bit out, similar amount as in this basic bit of code enclosed below that uses delay(). So instead of 20ms between events, I am getting something like 20,23,21, 24, 20ms…and so on.

My question is, is it possible to get closer to the 20ms that I need with an even spacing , or am I being totally unrealistic? I’m on a Mac, in case it’s relevant. In any case, I am more after precision than accuracy i.e. , I rather get 23, 23, 23ms between delays than 20,21,19,23, etc…

The other problem is that the incremental counter (on which I rely to get the array element number) sometimes skips at these high frequencies, so for instance on a run of 250 counts, it may skip a couple counts, no good:). Although to be fair this skipping is shown in the println(),which is slow, so maybe in reality it doesn’t skip, I still have to check that.

Many thanks in advance.

int frequency = 20; // 20 milliseconds between events
int counter=0;
int startMillis;

void setup() {
}
void draw() {
}

void keyPressed() {

for (int i = 1; i > 0; i = i++) {
int millisDiff = millis() - startMillis;
startMillis = millisDiff + startMillis;
counter++;

println(“Counter: " + counter +” millis: " + millis() + "ms " + “frequency: " + millisDiff + " ms” );

delay(frequency);
if (counter>=250) {
  counter=0;
  break;
}

}
}

Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/util/Timer.html#scheduleAtFixedRate(java.util.TimerTask,long,long)

1 Like

Thank you for the suggestion, I looked into it but I am still a bit green on using Java classes in Processing.
However, I have come up with this and it seems to do the trick quite well:

int arraySize = 501;
int[] myTarget = new int[arraySize];

int counter= -1;
long startTiming;
long startNanos;
long currentNanos;
long frequency = 20000000; //units in ns.= 20ms. Event every 20 m/s
boolean threadON = true;

void setup() {
startNanos=System.nanoTime();
}

void draw() {

for (int i = 0; i < myTarget.length; i++) { //populate array with random numbers 100 to 999
int maxNumber = 999;
int minNumber = 100;
int populate = minNumber + (int)(Math.random() * ((maxNumber - minNumber) + 1));
myTarget[i] =populate;
}

}//draw

void keyPressed() {
threadON=true;
thread(“myThread”);
}

void myThread() {
startTiming=System.nanoTime();

while (threadON) {
currentNanos = System.nanoTime();
if (currentNanos-startNanos >= frequency) {
startNanos = currentNanos;
counter++;
println("Random value: " + myTarget[counter] + " currentNanos: " + currentNanos + " ns Counter: " + counter);

}

if (counter==500) {
  float totalTime = System.nanoTime()-startTiming;
  println("");
  println("Total time taken:   " + totalTime/1000000000 + " seconds");
  threadON=false;
  counter=-1;
}

}
}

1 Like

yes, works well, thanks for sharing

i try to replace the thread print with a array saving of the time, but no problem

first i got confused, but correct, 100 values need ( the sum of ) 99 delta T

( sorry for some renaming )

int arraySize  = 100;
int[] myTarget = new int[arraySize];
long[] myTime  = new long[arraySize];
int counter    = 0;
long startTime, lastNanos, currentNanos, dT = 20000000; //units in ns,  Event every 20 m/s
boolean threadON = false;

void setup() {
  for (int i = 0; i < myTarget.length; i++) myTarget[i] = 100 + i;   // (int)random(100,1000); // make a data array
  println("press any key to start");
}

void draw() {}

void keyPressed() {
  threadON=true;
  thread("myThreadTimer");
}

void myThreadTimer() {
  startTime=System.nanoTime();
  while (threadON) {
    currentNanos = System.nanoTime();
    if ( currentNanos-lastNanos >= dT ) {
      lastNanos = currentNanos;
      myTime[counter] = currentNanos;                   // store in array instead printing, but no problem
      //println("send myTarget["+counter+"] = " + myTarget[counter] + " at " + currentNanos+" ns");
      counter++;
    }
    if ( counter >= arraySize ) {
       for (int i = 0; i < myTarget.length; i++) 
          println("send myTarget["+i+"] = " + myTarget[i] + " at " + myTime[i]+" ns");
      float totalTime = (System.nanoTime()-startTime)/1000000.0; // already in ms
      println("\nTotal time:   " + nf(totalTime,0,1) + " ms for "+arraySize+" values every "+dT/1000000+" ms" );
      threadON=false;
      counter=0;
    }
  }
}
// Total time:   1981.9 ms for 100 values every 20 ms