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:
- Boarduino
- TypK Amp & Mux
- LM35
- SD Card Adapter
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