Problem Measuring RPM - way to less data per second

Hey there,

I couldn't find anything helpful using the forum search, so I'm starting this thread.

I'm working on a project where I want to measure the rotational speed of multiple wheels of a RC car. I'm using the Arduino Mega with a sensor combined with a magnetic pole ring from sensitec. The sensor is equipped with a microprocessor that produces a digital signal.

The final program is supposed to be programmed with Matlab but for troubleshooting reasons I tried Arduino software aswell. The maximum for the expected angular frequency is going to be around 555 1/s. A magnetic ring with 90 poles is resulting in over 5000 changes per second.

With slow rotational speed the sensor works perfectly fine. But as soon as I tried to get a signal more than 1 time per 10 ms the simulation didn't work properly in Matlab Simulink, i.e. having a simulation time of 10 seconds with a sample time of 1 ms is resulting in the program running for about 100 s (here the Arduino Mega is connected via USB).

To test the maximum amount of data I can gather per second I tried to log the Data with a time stamp onto a SD Card. But surprisingly I only got one entry every 10 ms.

The sensor can be excluded as an error source. I did test it with an oscilloscope where it was working even with a higher frequency. Is the Arduino Mega processor too slow to execute the loop more than every 10 ms? Is opening/closing the file on the SD card or the transfer rate of USB a problem?

Here is the code for writing data on the SD card:

#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

void setup()
{
  Serial.begin(19200);
  Serial.print("SD Karte initialisieren. \n");
  pinMode(53, OUTPUT);
  pinMode(19, INPUT);
  
  if (!SD.begin(4)) {
    Serial.println("Karte nicht vorhanden. \n");
    return;
  }
  
  if (!card.init(SPI_HALF_SPEED, 4)) {
    Serial.println("Initialisierung fehlgeschlagen. \n");
    return;
  } else {
   Serial.println("Initialisierung erfolgreich. \n"); 
  }
  
  Serial.print("Karte: ");
  
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1 \n");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2 \n");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC \n");
      break;
    default:
      Serial.println("Unbekannt \n");
  }

  if (!volume.init(card)) {
    Serial.println("Keine Partition gefunden.");
    return;
  }
  
  uint32_t volumesize;
  Serial.print("Datentyp: FAT");
  Serial.print(volume.fatType(), DEC);
  Serial.print("\n");
  Serial.print("\n");
  
  volumesize = volume.blocksPerCluster();
  volumesize *= volume.clusterCount();
  volumesize *= 512;
  
  Serial.print("Speicherplatz (Bytes): ");
  Serial.print(volumesize);
  Serial.print("\n");
  
  Serial.print("Speicherplatz (Kilobytes): ");
  volumesize /= 1024;
  Serial.print(volumesize);
  Serial.print("\n");
  
  Serial.print("Speicherplatz (Megabytes): ");
  volumesize /= 1024;
  Serial.print(volumesize);
  Serial.print("\n");
  
  Serial.print("Dateien auf SD Karte: ");
  
  root.openRoot(volume);
  
  root.ls(LS_R | LS_DATE | LS_SIZE);

  if(SD.remove("data.txt")) {
    Serial.print("Datei geloescht.");
  }
  else {
    Serial.print("Datei konnte nicht geloescht werden.");
  }
  
}

void loop(void) {
  
  File data = SD.open("data.txt", FILE_WRITE);
  
  if (data) {
    data.print("Value: ");
    data.print(digitalRead(19));
    data.print("Time: ");
    data.print(millis());
    data.print("\n");
    data.close();
  }

}

Thanks a lot in advance

Is opening/closing the file on the SD card or the transfer rate of USB a problem?

It is opening/closing the file on the SD card.
At these sorts of speeds you need to use interrupts. Using serial print statements will also slow things down a lot.

Thanks for your help! I built the model with interrupts and it does work eventhough not perfect yet. But when I checked the help it seemed like there's only two pins that support interrupts. Is that correct? I do need a total of 8 inputs to work with. Is it not possible to work with interrupts as a result?

Look into using the Pin Change Interrupts.

You're also writing the result of EVERY digitalRead to the file! Is that even worthwhile?

Here's the way I'd probably tackle it.

Open the file ONCE only in setup

Have an interrupt routine that just updates a counter.

Have a global array of 10 integers. This array can hold the RPM for each tenth of a second.
Keep an index into that array

Within your loop every 10th of a second:
write the current RPM count to the current array[index]
reset RPM counter
Increment the index;
if index > 9
Write array to file
reset index

As you are writing out the 10 values to the file, you could also note if any of them are above zero. If none are (ie it has been stationary for over a second), you could then close the file.

Don't crosspost and don't don't use old dead threads to do it!

Mark