Optimizing sensor data collection

Howdy!

I've been working on a data collecting Arduino code. Its purpose is to take 2 thermocouples, 1 load cell, and 1 pressure sensor, format the data for PLX DAQ, add time/relevant data, then print it to the serial monitor.

However, I've run into a problem where the data being written to the serial monitor is extremely laggy. Though I have the delay set to run a loop about 5.7 times per second, the most it can do is 3 or 4 times per second. When adding or subtracting weight from the load cell, it can take up to 4 seconds to register the weight going from 0g to 131g, a far cry from the mere 3/4 second it takes in the example sketch. The application this is being used for requires near-instantaneous readings.

When I try to reduce the delay at the end of my code, the thermocouples stop collecting data altogether. The lowest delay usable without breaking them is 175.

I've tried adding and subtracting from delay, changing the baud rate, and optimizing how data is converted. Nothing seems to help.

Using an Arduino Uno (original), my thermocouples are running on MAX6675 modules, the load cell is running off an HX711 module. Do keep in mind I opened my first Arduino tutorial at 3pm, it's current 2am. For organization sakes, if I used any sort of variable, it's declared above setup or given a value before it's assigned an operational value. This code is guaranteed to look like a toddler with Parkinson's slept on a keyboard, so go easy on me.

TLDR: Input data takes an unreasonable amount of time to update in the serial monitor and the thermocouples outright break when the delay is lowered below 175.

Cheers!

//Load Cell Global Variables
const int HX711_dout = 8;
const int HX711_sck = 9;
const int calVal_eepromAdress = 0;
unsigned long t = 0;
int thrust = 0;
float i = 0;

//Clock Global Variables
int loopCount = 0;
int activated = activated;
unsigned long timer;
unsigned long millisUnmod;
unsigned long math;
unsigned long timerMS;

//Pressure Sensor Global Variables
const int pressureInput = A1;
const int pressureZero = 100;
const int pressureMax = 900;
const int pressuretransducermaxPSI = 300;
float pressureValue = 0;

#include <Thermocouple.h>
#include <MAX6675_Thermocouple.h>

#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
HX711_ADC LoadCell(HX711_dout, HX711_sck);

//Exhaust Thermocouple
#define SCK_PIN 2
#define CS_PIN 3
#define SO_PIN 4
Thermocouple* thermocoupleExhaust;

//Internal Thermocouple
#define SCK_PIN2 5
#define CS_PIN2 6
#define SO_PIN2 7
Thermocouple* thermocoupleInternal;

//---------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println("CLEARSHEET");
  Serial.println("RESETTIMER");
  Serial.println("LABEL,Sample No., Timer MS, Internal Celsius, Internal Fahrenheit, Exhaust Celsius, Exhaust Fahrenheit, Chamber Pressure PSI, Thrust Grams, ");

  thermocoupleExhaust = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);
  thermocoupleInternal = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);

  //Load Cell Setup
  LoadCell.begin();
  float calibrationValue;
  calibrationValue = 213.65;
#if defined(ESP8266)|| defined(ESP32)
#endif
  unsigned long stabilizingtime = 2000;
  boolean _tare = true;
  LoadCell.start(stabilizingtime, _tare);
  LoadCell.setCalFactor(calibrationValue);
}
//--------------------------------------
void loop() {
  timer = millis();
  millisUnmod = millis();
  loopCount = loopCount + 1;

  const double celsius = thermocoupleInternal->readCelsius();
  const double fahrenheit = thermocoupleInternal->readFahrenheit();
  const double celsius2 = thermocoupleExhaust->readCelsius();
  const double fahrenheit2 = thermocoupleExhaust->readFahrenheit();

  pressureValue = analogRead(pressureInput);
  pressureValue = ((pressureValue - pressureZero) * pressuretransducermaxPSI) / (pressureMax - pressureZero);

  Serial.print("DATA, ");
  Serial.print( (String)(loopCount) + (", "));
  if (timer >= 1000) {
    timer = timer / 1000;
    math = timer * 1000;
    timerMS = millisUnmod - math;
    Serial.print( (String)(timer) + ("s ") + (timerMS) + ("ms, "));
  }
  else {
    Serial.print( (String)(timer) + ("ms, "));
  }
  Serial.print( (String)(celsius) + (", "));
  Serial.print( (String)(fahrenheit) + (", "));
  Serial.print( (String)(celsius2) + (", "));
  Serial.print( (String)(fahrenheit2) + (", "));
  Serial.print( (String)(pressureValue) + (", "));

  float i = LoadCell.getData();
  Serial.println(i);

  delay(175);
}

I don't think a constant can be set from code and is set at compile time, also your setting a constant every time through loop that makes no sense.

  const double celsius = thermocoupleInternal->readCelsius();
  const double fahrenheit = thermocoupleInternal->readFahrenheit();
  const double celsius2 = thermocoupleExhaust->readCelsius();
  const double fahrenheit2 = thermocoupleExhaust->readFahrenheit();

Don't convert every value you print to a String first as this takes time. The print class is quite capable of printing numbers as ASCII.

  Serial.print( (String)(loopCount) + (", "));

Can you tell which libraries you use ? The trouble with the thermocouples might be in the library.
Can you show a photo, so I can check the wires of the I2C bus.

  delay(175);

this might WILL slow your code WAY down.

the proper way is to know the optimum rate for the sensors

then use "blink without delay"
and call the sensors in that time, while running the rest of your program.

Hello,
Your problem could be reading of HX711 scale. I had a similar problem.
The trick is in the code below marked in <====
The HX711 sends data at a low pace, and i you issue a read without data being present, the lib waits.
So check if there is a valid result first.

//------------------------------------------------------------
void loop()
{
  // read weight, if available:
  if (scale.is_ready())  // <=================== if no data, skip reading, 
  {
    // read weight
    weight = scale.get_units(1);
    // set watchdog:    
    tWdScale.setMs(1000);
    // process tare cmd if required:
    if (triggerTare)
    {
      // reset cmd to Tare:
      triggerTare=0;
      scale.tare();  
      WawiSrv.print("Scale tare operation completed. ");
    }
  }  
  
  // process watchdog status:
  if (scaleOk != !tWdScale.isZero())
  {
    scaleOk = !tWdScale.isZero();
    if (scaleOk)
      WawiSrv.println("Weight processing restarted, scale ok. ");
    else
      WawiSrv.println("Weight processing stopped, scale communication fault. ");
  }

  // loop part:
  tWdScale.loop();
  // wawilib communication update:
  WawiSrv.loop();
}

This is a small sample of a demo for a peristaltic pump dosing application I am preparing.
If you want more details, pm me.

Best Regards,
johi.

dave-in-nj:

  delay(175);

this might WILL slow your code WAY down.

the proper way is to know the optimum rate for the sensors

then use "blink without delay"
and call the sensors in that time, while running the rest of your program.

I know it's been a while, but unfortunately that delay is necessary. If the delay is removed or is lower that 175-180~ ms, the MAX6675 thermocouples stop functioning and output a static value. The temperature data is read on the first loop and every loop after that just spits out the first loop's value

Reading both the celsius and fahrenheit temperatures from the thermocouple is taking a lot of time. The library is reading the thermocouple in celsius, then calculating the fahrenheit temperature:

/**
        Returns a temperature in Fahrenheit.
        Reads a temperature in Celsius,
        converts in Fahrenheit and return it.

        @return temperature in degree Fahrenheit
*/
double MAX6675_Thermocouple::readFahrenheit() {
        return celsiusToFahrenheit(readCelsius());
}


inline double MAX6675_Thermocouple::celsiusToFahrenheit(const double celsius) {
        return (celsius * 1.8 + 32);
}

Take the temperature you have read in celsius and do the conversion yourself, that will save some time.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.