Millis vs Timestamp

Hello, I apologize for the basic question but I am wondering if this would be the preferred process for you all. I am just getting my feet wet and this forum has been super helpful in the past.

I have been using the serial timestamp with my data coming from the Nano 33 BLE, typically the readings are 17:46:27.316, 17:46:27.420, 17:46:27.529... etc. I am then exporting this into an excel spread sheet to calculate the exact time differences on consecutive data outputs to get .104, .109 etc.

I am using this time difference to calculate a few different things in excel but am looking to move all the calculations to the board and (hopefully) not use any excel tables for calculations.

One particular calculation is coming from an ultrasonic sensor, where I take the change in height divided by the change in time to find the velocity for that segment of data output.

I have seen online that the timestamp is actually coming from the serial monitor and not the Arduino so there could be discrepancies on when the data was recorded and the timestamp on the serial monitor (not to mention I cannot use the timestamp and store its time to then calculate). I am currently using delay(100).

Would adding Millis() be a suitable replacement for the time stamp? As I try a sample milli sketch, I see it is constantly printing at 100 milliseconds, but how can I be sure my data is coming in every millisecond? Based on the timestamps stated above sometimes it is .105 or .109, I would have some calculation error if I just divided each distance by 100 milliseconds.

Would there be an alternate way of doing this calculation on the board itself?

Here is the code I have now.


#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>
#define trigPin 10
#define echoPin 12

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
}

void loop() {
  float Ax, Ay, Az;
  float duration, distance;
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(Ax, Ay, Az);
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * .000343;

  if (Az*9.80665 >= 15 || distance <= 0) {
    Serial.println("Out of range");
  }
 else {
  
    Serial.print(Ax*9.80665);
    Serial.print(' ');
    Serial.print(Ay*9.80665);
    Serial.print(' ');
    Serial.print(Az*9.80665);
    Serial.print(' ');
    Serial.print("Distance = ");

 }
 if (distance >= 2 || distance <= 0) {
    Serial.println("Out of range");
 }
 else {
    Serial.print(distance);
    Serial.println(" m/s ");
 }
  
    delay(100);
  }
  }

Thank you for your time.

millis() is not always accurate. It depends largely on the type of Arduino that you use (crystal or ceramic resonator); a millisecond can actully be 998 microseconds or 1003 microseconds (thumbsuck numbers).

Having said that, you will eliminate the PC as a source of inaccuracy (due to e.g. buffering); I've seen timestamps posted here on the forum that are identical for data that was send a few millisconds apart.

I would prefer the millis() based approach.

Thank you sterretje,

I have put in the Millis() function but am wondering the cod switch I need to subtract the previous milli from the new one.

unsigned long myTime;

void setup() {
  Serial.begin(9600);
}
void loop() {
  Serial.print("Time: ");
  myTime = millis();

  Serial.println(myTime);
}

I am thinking I need another unsigned long variable to store the previous time, then switch the new time to the previous time to then subtract.

This example prints 4005 5005 6005 etc. How can I rewrite this code to show 1000 each print vs counting up?

unsigned long previousMillis;
. . .
void loop() 
{
  
if(millis() - previousMillis  > 1000)
{
    previousMillis = millis();

    Serial.print("Time: ");
    Serial.println(millis());
}

Thank you for the code Larry, unfortunately in my serial monitor I am still getting
Time: 72523
Time: 73524
Time: 74525

Do I need to be including a specific library or anything for this to run correctly?

It looks like the perfect correct output to my eyes. :roll_eyes:

Unfortunately this is not showing the change in time, it seems to be counting.

As I type this I am thinking maybe I am making this harder on my self then it needs to be. If my delay is set to 100, my outputs would be a millisecond apart, so I would know the change in time, and a timer might not be needed...

Using micros will help.

You may need to difference?
Why don't you subtract the previous value before printing? :roll_eyes:
Do we write of all the your code? :hushed:

the value given back by millis() is an unsigend long.
So all variables that deal somehow with millis() should all be unsigned longs

in case of unsigned longs a calculation
newValue - oldValue results to the right number even for the case
unsigned means always positive

+1 - 10 = +9

newValue = 1
oldValue = 4.294.967.296
1 - 4.294.967.296 = plus 4.294.967.295
that's why it is always working to code
if (newValue - oldValue >= 1000)

even with the case oldValue is a bigger number than newValue
best regards Stefan

Thanks for the feedback Chris

Thank you Stefan, I appreciate the response.

Try the below; it's a slight modification

uint32_t nextTime;

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  if (millis() > nextTime)
  {
    nextTime += 1000;

    Serial.print("Time: ");
    Serial.println(millis());
  }
}

Output:

Time: 1
Time: 1001
Time: 2001
Time: 3001
Time: 4001
Time: 5001
Time: 6001
Time: 7001
Time: 8001
Time: 9001

And a more luxury version that shows how to calculate the delta between two samples

uint32_t nextTime;
uint32_t lastTime;

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  uint32_t currTime = millis();
  
  if (currTime > nextTime)
  {
    nextTime += 1000;
    uint32_t deltaTime = currTime - lastTime;
    lastTime = currTime;
    
    Serial.print("Time: ");
    Serial.println(currTime);
    Serial.print("Delta: ");
    Serial.println(deltaTime);
    
  }
}

With output

Time: 1
Delta: 1
Time: 1001
Delta: 1000
Time: 2001
Delta: 1000
Time: 3001
Delta: 1000
Time: 4001
Delta: 1000
Time: 5001
Delta: 1000
...
...
Time: 157001
Delta: 1000
Time: 158001
Delta: 1000
Time: 159001
Delta: 1000

Awesome, thank you very much sterretje! This was exactly what I was hoping to find, the delta time!

Hello again sterretje,

is there a way to modify this code to take the difference between two consecutive readings from an ultrasonic sensor?

I have tried to modify on my own but have had no such luck.

The code I have tried

#include <Arduino_LSM6DS3.h>
#define trigPin 10
#define echoPin 12

void setup(){
  Serial.begin(9600);
   while (!Serial);
  Serial.println("Started");
  }


void loop(){
  float duration, distance;
  float lastDist;
  float currDist = distance;
  float deltaDist = currDist - lastDist;
  
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
    
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

    duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * .000343;

    Serial.print(" Delta: ");
    Serial.println(deltaDist);
    Serial.print("distance: ");
    Serial.print(distance);
    
    lastDist = currDist;
    
    delay(1000);
  }

The output

distance: 0.04 Delta: 0.00
distance: 0.08 Delta: 0.00
distance: 0.04 Delta: 0.00
distance: 0.06 Delta: 0.00
distance: 0.07 Delta: 0.00
distance: 0.07 Delta: 0.00
distance: 0.07 Delta: 0.00
distance: 11.91 Delta: 0.00

Something is incorrect, obviously on my end because two consecutive data points subtracted are no what the delta is showing

standard output format for floats is two digits

here is a code version that makes visible what values your variables have.
IMHO printing all this to the serial monitor is easier because it
relieves the brain of the work of having to simulate everything in the head

my guess is the sequence you have chosen to calculate, print and update variables is wrong

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVar,myInterval);
// myVar can be any variable or expression that is defined in scope
// myInterval is the time-interval which must pass by before the next
// print is executed


// your code starts here your code starts here your code starts here
#include <Arduino_LSM6DS3.h>
#define trigPin 10
#define echoPin 12

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");
}


void loop() {
  float duration, distance;
  float lastDist;
  float currDist = distance;
  dbg("0:", distance);
  dbg("1:", currDist);
  float deltaDist = currDist - lastDist;
  dbg("2:", deltaDist);

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * .000343;
  dbg("3:", distance);

  Serial.print(" Delta: ");
  Serial.println(deltaDist);
  Serial.print("distance: ");
  Serial.print(distance);
  dbg("4:right before last=curr", lastDist);
  lastDist = currDist;
  dbg("5:right afterlast=curr", lastDist);

  delay(1000);
}

the additional serial.prints are numbered to clearly indicate from where in the code comes this output. This is an important detail to use.

The macros itself used in this code are somehow tricky.
A macro does pre-programmed automated keyboard typing into your source-code
just right after starting the compiling-process. But before the real compiling.

This means a macro is adding lines of code to the code you see in the editor.
very simple example you might have seen before:

#define myLED_Pin 13

The macro's name is "myLED_Pin" and what it does is replacing "myLED_Pin" with number 13
So if you code

pinMode(myLED_Pin,OUTPUT);`
the macro does

pinMode(13,OUTPUT);`
of course myLED_Pin is easier to understand than "13"

Macros can do much more. You can even use "macro-variables"
This is what the debug-macro does

best regards Stefan

lastDistneeds to be a global (or a static local) variable so it will be remembered between successive calls to loop(). Currently it goes out of scope at the moment that the loop() function ends and hence the stored value is lost.

Placing float lastDist; before setup() instead of in loop() is one way to achieve this; the same as I did with uint32_t lastTime;

StefanL38, This is amazing, thank you so much. You were exactly right, the order was incorrect, I was able to play around with the order and get exactly what I was looking for!

Thank you sterretje, along with the reply above you I was able to add your suggestion in and it works! Thank you!