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 
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:
|