RC Boat Datalogger

The RC boat of a friend had some problems with the nitro engine, but without data its not easy to adjust it.

 

So a Arduino with some thermocouples got installed logging data onto a SD card.

Just imagine driving around and then pull out the SD card from your boat and analyze the data on a notebook cool

 

 

 

Hardware:

 

Software:

 

The Arduino logs the TypK and Throttle servo values on the SD card, and saves the file every 2 seconds.

So you can just pop the SD card out loosing maximal the last 2 seconds.

When starting again it makes a new file. Making the handling easy!

 

This is how the Data looks:

 

And the Arduino Code:

 

#include "Fat16.h"
#include "SdCard.h"
#include   //for PROGMEN

#define LOG_INTERVAL  200  // mills between entries
#define START_SENSOR 5     // z.b. starte bei sensor 6
#define MAX_SENSOR_COUNT 8 // number of analog pins to log
#define ECHO_TO_SERIAL   0 // echo data to serial port
#define WAIT_TO_START    0 // Wait for serial input in setup()
#define SYNC_INTERVAL 2000 // mills between calls to sync()
#define Runs  1000        // Anzahl der Testläufe
#define CaseTempPin 1      // LM 35 EIngang
#define AGTPin 2           // Typ K eingang
#define S0 2               // Mux select
#define S1 3               // Mux select
#define S2 4               // Mux select
#define tempTypKReadings 28    //how many entrys are in the Lookup Table
#define Spannung 3          //Spannung Check Eingang
#define LED_interval  50   //Blinkinterval

 //Lookup Table for the TypK:
 //from 0-1350°C in steps of 50°C, the list is in µV according to that Temp.
 const unsigned int tempTypK[] PROGMEM =
 { 
  0,
  2023,
  4096,
  6138,
  8138,
  10153,
  12209,
  14293,
  16397,
  18516,
  20644,
  22776,
  24905,
  27025,
  29129,
  31213,
  33275,
  35313,
  37326,
  39314,
  41276,
  43211,
  45119,
  46995,
  48838,
  50644,
  52410,
  54138
};
int U; //Variable für Spannungs Check Pin
int ledPingut = 7; // Status LED gut
int ledPinschlecht =6; //Status LED Schlecht
int Pulseingang=5; //für Servo stellung
uint32_t syncTime = 0;       // time of last sync()
int vari=0; //aktueller Run
int CalAGT[9]; //All Typ K Values will be stored inside this array => für 2 Sensoren
unsigned long pulse; //gezählte Pulse
int Tempvar; //hilfsvariable
unsigned int Temp; //hilfsvariable
int TempvarLM35; //hilfsvariable
SdCard card;
Fat16 file;
float CalCaseTemp; //hilfsvariable
/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
void blink() // run over and over again
{
  digitalWrite(ledPingut, HIGH); // sets the LED on
  delay(LED_interval*2); // waits for a second
  digitalWrite(ledPingut, LOW); // sets the LED off
  delay(LED_interval); // waits for a second
}
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
void error(char *str) //error Meldungen
{
  digitalWrite(ledPinschlecht, HIGH);
  Serial.print("error: ");
  Serial.println(str);
  while(1);
}
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
void setup(void)
{
      pinMode(S0, OUTPUT);
      pinMode(S1, OUTPUT);
      pinMode(S2, OUTPUT);
      pinMode(ledPingut, OUTPUT);
      pinMode(ledPinschlecht, OUTPUT);
      Serial.begin(19200);
      Serial.println();
  
          #if WAIT_TO_START
              Serial.println("Type any character to start");
              while (!Serial.available());
          #endif //WAIT_TO_START
  if (!card.init()) error("card.init"); // initialize the SD card
  if (!Fat16::init(card)) error("Fat16::init"); // initialize a FAT16 volume
   
  char name[] = "LOGGERII.CSV"; // create a new file
  for (uint8_t i = 0; i < 100; i++) {
      name[6] = i/10 + '0';
      name[7] = i%10 + '0';
       if (file.create(name)) break;
  }
  if (!file.isOpen()) error ("file.create");
      Serial.print("Logging to: ");
      Serial.println(name);
  // write header
          file.writeByteError = 0;  // clear print error
          file.print("millis");
          #if ECHO_TO_SERIAL 
              Serial.print("millis");
          #endif //ECHO_TO_SERIAL

          #if MAX_SENSOR_COUNT > 8
              #error MAX_SENSOR_COUNT too large
          #endif //MAX_SENSOR_COUNT

       file.print(";Zylinder [°C];Vergaser [°C];Auspuff [°C]");
          #if ECHO_TO_SERIAL
              Serial.print(";Zylinder [°C];Vergaser [°C];Auspuff [°C]");
         #endif //ECHO_TO_SERIAL
 
  
  /*file.print(";Spannung")*/;file.print(";Trottle");file.print(";Runs"); file.println();
          #if ECHO_TO_SERIAL
              /*Serial.print(";Spannung")*/;Serial.print(";Pulse");Serial.print(";Runs");Serial.println();
          #endif  //ECHO_TO_SERIAL
  if (file.writeByteError || !file.sync()) {
          error("write header");
  }
}
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
void loop() // run over and over again
{
    digitalWrite(ledPingut, HIGH); // sets the LED on
    /*for (vari; vari < Runs; vari++)
    {*/
        file.writeByteError = 0;  // clear print error
        delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL)); //Wartezeit für Daten loggen
        vari++;
        uint32_t m = millis(); // log time
        file.print(m);
            #if ECHO_TO_SERIAL
                Serial.print(m);
            #endif //ECHO_TO_SERIAL
        // add sensor data
           Tempvar = analogRead(CaseTempPin);
           CalCaseTemp = 500.0*Tempvar/1024.0;  //thats how to get °C out from a LM35 with 10Bit ADW
           FetchTypK();
              for (uint8_t ia = START_SENSOR; ia < MAX_SENSOR_COUNT; ia++)
              {
                  uint16_t data = CalAGT[ia];
                  file.print(';'); file.print(data);
                      #if ECHO_TO_SERIAL
                          Serial.print(';'); Serial.print(data);
                      #endif //ECHO_TO_SERIAL
              }  
          // U= analogRead(Spannung);
           pulse = pulseIn(Pulseingang,HIGH,20000);pulse=pulse-860;pulse=pulse/12.7;
           /*file.print(";");file.print(U,DEC)*/;file.print(";");file.print(pulse,DEC);file.print(";");file.print(vari, DEC);
                     #if ECHO_TO_SERIAL
                        /*Serial.print(";");Serial.print(U,DEC)*/; Serial.print(";");Serial.print(pulse, DEC);Serial.print(";");Serial.print(vari, DEC);
                     #endif //ECHO_TO_SERIAL
           // if (file.writeByteError) error("write data");
           if (file.writeByteError) file.print(";write Byte Error;");
           file.writeByteError = 0;// clear print error
           file.println();
                    #if ECHO_TO_SERIAL
                        Serial.println();
                    #endif //ECHO_TO_SERIAL
          //don't sync too often - requires 2048 bytes of I/O to SD card
          if ((millis() - syncTime) < SYNC_INTERVAL) return;
          syncTime = millis();
          //if (!file.sync()) error("sync");
          if (!file.sync()) file.print("\nerror sync\n");
    //}
    if (!file.sync()) file.print("\nerror sync\n");
    //blink();
digitalWrite(ledPingut, HIGH); // sets the LED on
}
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
void FetchTypK()
 {
 //This will read in all the needed Analog values, convert them to °C, and make the calibration with the LM35
 //so it must be called after the AnaConversion!
 for (int i=0; i < 8; i++)
 { 
 //int i = 0;
 //there are 8 connections, so i have to set the 3 pins according to all channels

  switch(i){
   case 0:
    digitalWrite(S0, LOW);
    digitalWrite(S1, LOW);
    digitalWrite(S2, LOW);
    break;
   case 1:
    digitalWrite(S0, LOW);
    digitalWrite(S1, LOW);
    digitalWrite(S2, HIGH);
    break;
   case 2:
    digitalWrite(S0, LOW);
    digitalWrite(S1, HIGH);
    digitalWrite(S2, LOW);
    break;
   case 3:
    digitalWrite(S0, LOW);
    digitalWrite(S1, HIGH);
    digitalWrite(S2, HIGH);
    break;
   case 4:
    digitalWrite(S0, HIGH);
    digitalWrite(S1, LOW);
    digitalWrite(S2, LOW);
    break;
   case 5:
    digitalWrite(S0, HIGH);
    digitalWrite(S1, LOW);
    digitalWrite(S2, HIGH);
    break;
   case 6:
    digitalWrite(S0, HIGH);
    digitalWrite(S1, HIGH);
    digitalWrite(S2, LOW);
    break;
   case 7:
    digitalWrite(S0, HIGH);
    digitalWrite(S1, HIGH);
    digitalWrite(S2, HIGH);
    break;
   default:
    break;
   }
     delay(10); //Due to the 0.1 µF cap this is needed. The Cap should be there to get a stable reading!
    //then read in the value from the ADW, and feed them into the averaging
    TempvarLM35=analogRead(AGTPin);
       Temp = ((5.0*TempvarLM35)/1024.0)*10000;   //gets the Volts and makes µV out of it (100 is already added from the Amp)
       Temp = GetTypKTemp(Temp);                       //Converts the µV into °C
       Temp += int(CalCaseTemp); //apply the Correction
       CalAGT[i] = Temp;              //Save it into the array
 //repeat for all 8 channels.
 }
}
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
//This converts the thermocouple µV reading into some usable °C
int GetTypKTemp(unsigned int microVolts)
{
  int LookedupValue;
  //This searches the 2 surrounding values, and then linear interpolates between them.
  for(int i = 0; iif(microVolts >= pgm_read_word(&tempTypK[i]) && microVolts <= pgm_read_word(&tempTypK[i+1]))
   {
    LookedupValue = ((i)*50) + ((50L *(microVolts - pgm_read_word(&tempTypK[i]))) / ((pgm_read_word(&tempTypK[i+1]) - pgm_read_word(&tempTypK[i]))));
    break;
   }
  }
  return LookedupValue;
 }
/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/


Related Links:

 

Comments powered by CComment