/*
31.07.2020
*/
#include <Audio.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <tvg.h> // an image in hex format
#include <EEPROM.h>
#include <NMEAGPS.h> // for the NMEA GPS sentences pharsing
#include <ResponsiveAnalogRead.h> // the library for smooth analog reads
#include <Adafruit_MAX31855.h> // for temparature read
/*
Make a ResponsiveAnalogRead object, pass in the pin, and either true or false depending on if you want sleep enabled
Enabling sleep will cause values to take less time to stop changing and potentially stop changing more abruptly,
where as disabling sleep will cause values to ease into their correct position smoothly and with slightly greater accuracy
*/
ResponsiveAnalogRead BRAKE(A0, true);
ResponsiveAnalogRead BATTERYRELAY(A1, true);
ResponsiveAnalogRead BATTERY(A8, true);
ResponsiveAnalogRead VOLUME(A12, true);
ResponsiveAnalogRead STEERING(A16, true);
ResponsiveAnalogRead ACCELERATION(A17, true);
/* ========= */
/* NRF24L01+ */
/* ========= */
RF24 radio(24, 25); // CE and CSN pins for the NRF24L01+
const uint64_t pipeaddress = 0xFA51AA55AFLL; // NRF pipe address must be the same for transmitter and receiver
bool wireless = true; // to know if the data should be sent to a wireless device HIGH=Yes, LOW=No
int NRFfail = 0; // number of failed NRF ack receives. Used to know when to display the WiFi sign
byte NRFfailRate = 10;// how many failed ack receives untill the WiFi sign stops showing
byte ackMsg;
/* ====== */
/* AUDIO */
/* ====== */
#define audiobuffersize 128 // one block in audio library has 128 values of 2 bytes
// GUItool: begin automatically generated code
AudioInputI2S i2s1;
AudioPlayQueue queue2;
AudioMixer4 mixer2;
AudioMixer4 mixer1;
AudioOutputI2S i2s2;
AudioRecordQueue queue1;
AudioConnection patchCord1(i2s1, 0, mixer1, 0);
AudioConnection patchCord2(i2s1, 1, mixer1, 1);
AudioConnection patchCord3(queue2, 0, mixer2, 0);
AudioConnection patchCord4(mixer2, 0, i2s2, 0);
AudioConnection patchCord5(mixer2, 0, i2s2, 1);
AudioConnection patchCord6(mixer1, queue1);
AudioControlSGTL5000 sgtl5000_1;
// GUItool: end automatically generated code
uint8_t bufr[audiobuffersize * 2]; // buffer to hold 256 bytes of audio data
uint8_t bufcount = 0; // received nrf24l01+ packet counter
bool setupR = true, setupT = true, setupN = true; // used to run the setup code only once
byte error = 0; // used to calculate the number of errors received when transmitting audio
byte maxErrors = 2; // the number of errors that show that the audio receiving has ended
unsigned long lastError = 0; // last time 50 ms have passed since the last Audio Receive
/* ========= */
/* VARIABLES */
/* ========= */
unsigned int accValue = 0, brkValue = 0, zeroAccValue = 0, zeroBrkValue = 0, fullAccValue = 0, fullBrkValue = 0, fullLeftValue = 0, fullRightValue = 0;
byte leds = 0; // Variable to hold the pattern of which LEDs are currently turn ed on or off for RPM
byte rpmCount = 0, spdCount = 0; // Variable used in the average of the interval between pulses for RPM and RPMW calculation
unsigned long interval = 0, intervalCount = 0, intervalSpd = 0, intervalCountSpd = 0, lastPulseTime = 0, lastPulseTimeSpd = 0, intervalAvg = 0, intervalSpdAvg = 0; // used for the RPM and SPD calculation
float nr = 0.0526657824; // for 11" wheel (rear) // number for the rpmW to speed calculation. Formula: wheelDiameter(m)/2*0.10472*18/5 for km/h
// float nr = 0.047877984; // for 10" wheel (front)
float rpmW = 0; // used in speed calculations
/* ===== */
/* GEARS */
/* ===== */
bool currentstateGP, currentstateGM; // The current state of the gear+, gear-, and sensors
bool prevstateGP = HIGH, prevstateGM = HIGH; // The state of gear+, gear-, and lap sensors in previous scan
unsigned long lastGearPlus = 0, lastGearMinus = 0; // for used for activating the relays for changing gears
byte gearImpuls = 50; // how long the gear change relay stays on (the time neded to actualy change the gear)
byte gearImpulsReturn = 10; // TESTING - for stopping the gear shift motor from turning too much when shifting gears.
bool geaP = false, geaM = false;
/* ======= */
/* LAPTIME */
/* ======= */
unsigned long lastLap = 0, bestLap = 599990; // Variables for the last and best lap
unsigned long lapMillis = 0; // How long has it been since the last time the lap has started
int bestLapReset = 0, bestLapLastReset = 0;// used to reset the stored best lap
byte sectors = 1; // the number of split/start/finish lines
byte line = 0; // the number of times you passed over the split/start/finish lines
bool bestLapFlag = false; // used to know when one lap is finished to calculate the bestLap
bool startLap = false; // used to know when a lap was started
bool firstLap = true; // used to not record the seconds from starting the device untill the first magentic line is corossed - first las is started
/* ======= */
/* MPU6050 */
/* ======= */
byte x = 0; // used as a counter for the average of MPU readings
float rawX = 0, rawY = 0; // the float where all the MPU readings are stored then divided by the number of entries (x);
int16_t acc_x, acc_y, acc_z;
/* =================== */
/* SERIAL TRANSMISSION */
/* =================== */
unsigned long lastTransmit = 0; // the last time the $RC2 string was transmitted via serial
byte transmitRate = 50; // transmit the $RC2 string every 50 milliseconds
String data; // this is the string that is going to be sent to the phone
/* === */
/* GPS */
/* === */
NMEAGPS gps;
gps_fix fix; // the structure that holds all the parsed pieces
/* see https://github.com/SlashDevin/NeoGPS/blob/master/extras/doc/Data%20Model.md for all fix members that can be accesed */
String GpsNmea1, GpsNmea2, GpsNmea1Buf, GpsNmea2Buf, GPScounter; // strings to hold the NMEA buffer and sentences
bool nmea = true; // flag to know when to write to which NMEA sentence string
/* ==== */
/* OLED */
/* ==== */
U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R2, /* ss=*/ 4, /* dc=*/ 3, /* reset=*/ 2);
unsigned long lastUpdateOled = 0;
byte updateRateOled = 100; // update the display once every 100 milliseconds
/* === */
/* BPM */
/* === */
int UpperThreshold = 518, LowerThreshold = 490, reading = 0;
bool IgnoreReading = false, FirstPulseDetected = false;
unsigned long FirstPulseTime = 0, SecondPulseTime = 0, PulseInterval = 0;
/* ================= */
/* dataNRF STRUCTURE */
/* ================= */
struct transmission {
float avgXx, avgYy, speed, BPM, lapTime; // 4 bytes
byte acceleration, brake, gear, SETUP = 0; // 1 byte
short int rpm, str; // 2 bytes
}; transmission dataNRF; // 28 bytes structure
/* ============= */
/* BUTTON STATES */
/* ============= */
bool currentstateBLUE;
bool currentstateGREEN;
bool currentstateTALK;
bool prevstateBLUE = LOW;
bool prevstateGREEN = LOW;
bool prevstateTALK = LOW;
/* ============= */
/* BATTERY LEVEL */
/* ============= */
int lastMillisSec = 0; // last time the battery level was taken
boolean startBat = true; // update the battery level only once when the Teensy starts. Every 5 seconds after that.
/* =========== */
/* TEMPERATURE */
/* =========== */
Adafruit_MAX31855 thermocouple1(16); // initialize the MAX31855 Thermocouple 1
Adafruit_MAX31855 thermocouple2(17); // initialize the MAX31855 Thermocouple 2
unsigned long lastTemp1Read = 0, lastTemp2Read = 0;// to know when the last temperature read was made for both thermocouples
double temp1, temp2; // variables to hold the temperatures
/* thermocouple1.readCelsius() // thermocouple2.readCelsius() */
/* ======= */
/* TESTING */
/* ======= */
bool go = true, goS = false, goG = false;
unsigned long lastGear = 0;
unsigned long startLoop, endLoop, showTime, startRPM, endRPM, startSPD, endSPD; // for calculating the time it takes for 1 loop of the program
/*==================================================================================================*/
/*=== ===*/
/*==================================================================================================*/
void setup() {
pinMode(2, OUTPUT); // Reset pin for the 2.42 inch Oled
pinMode(3, OUTPUT); // DC pin Oled
pinMode(4, OUTPUT); // CS Oled
pinMode(5, OUTPUT); // DS shift register (Steering wheel Oled) DATA
pinMode(6, OUTPUT); // ST-CP shift register (Steering wheel Oled) LATCH
pinMode(9, INPUT); // Lap
pinMode(10, OUTPUT); // SH-CP shift register (Steering wheel Oled) CLOCK
pinMode(16, OUTPUT); // CS for Temperature sensor 1
digitalWrite(16, HIGH); // do not read temperature now
pinMode(17, OUTPUT); // CS for Temperature sensor 2
digitalWrite(17, HIGH); // do not read temperature now
pinMode(27, INPUT); // Button GREEN - Right (Steering wheel Oled)
pinMode(28, INPUT); // Button Talk (Steering wheel Oled)
pinMode(29, INPUT); // Button BLUE - Left (Steering wheel Oled)
pinMode(30, OUTPUT); // Gear relay -
pinMode(31, OUTPUT); // Transistor for Relay Ground
pinMode(32, OUTPUT); // Gear relay +
pinMode(33, INPUT); // RPM
pinMode(36, INPUT); // SPD
pinMode(37, INPUT); // Gear - button
pinMode(38, INPUT); // Gear + button
//pinMode(A0, INPUT); // Brk
//pinMode(A1, INPUT); // Relay Battery level
//pinMode(A8, INPUT); // Battery level
//pinMode(A12, INPUT); // Vol
//pinMode(A15, INPUT); // HeartRate
//pinMode(A16, INPUT); // Steering angle
//pinMode(A17, INPUT);// Acc
Serial.begin(115200); // initialize the USB Serial port
Serial1.begin(115200); // initialize the Serial port to transmit the Bluetooth data
Serial8.begin(115200); // initialize the Serial port to receive GPS data
delay(50);
SPI.begin(); // initialize the SPI port
u8g2.begin(); // initialize the Oled
u8g2.setFlipMode(true); // flip the image on the Oled
Wire.begin(); // initialize the i2c port
Wire.setClock(400000); // set the i2c to 400 KHz
leds = B00000000; // turn off all the leds on the steering wheel
updateShiftRegister();// update the LEDs on the steering wheel. (turn them off)
Wire.beginTransmission(0x68); // Start communicating with the MPU
Wire.write(0x6B); // Start writing to this register (PWR_MGMT_1)
Wire.write(0x00); // Set register 0x6B to zero (wakes up the MPU)
Wire.endTransmission(); // Terminate the connection
delay(50);
Wire.beginTransmission(0x68); // Start communicating with the MPU
Wire.write(0x1C); // Start writing to this register (ACCEL_CONFIG)
Wire.write(0x00); // Set register 0x1C to 0 (sets the sensitivity of the accelerometer to 2g)
//Wire.write(0x01); // Set register 0x1C to 1 (sets the sensitivity of the accelerometer to 4g)
//Wire.write(0x10); // Set register 0x1C to 2 (sets the sensitivity of the accelerometer to 8g)
//Wire.write(0x11); // Set register 0x1C to 3 (sets the sensitivity of the accelerometer to 16g)
Wire.endTransmission(); // Terminate the connection
AudioMemory(64); // Give the Audio Library some memory to work with
sgtl5000_1.enable(); // Enable the SGTL5000
radio.begin(); // Initialize and configure the NRF24L01+ module
delay(50);
/* Attach interrupts for the RPM, SPEED and LAP sensors */
attachInterrupt(digitalPinToInterrupt(33), &ignitionIsr, FALLING);
attachInterrupt(digitalPinToInterrupt(36), &wheelRpm, FALLING);
attachInterrupt(digitalPinToInterrupt(9), &lap, FALLING);
//EEPROM.get(24, bestLap);// read the best lap from EEPROM to show on the Oled
u8g2.clearBuffer(); // Clear the oled buffer
u8g2.drawXBM(0, 0, 128, 64, tvg); // The TvG logo
u8g2.sendBuffer(); // Send the TvG image to the screen
delay(2000);
u8g2.clearBuffer(); // Clear the Oled buffer so that the next data can be written in
if (digitalReadFast(27)) { // if the GREEN button is pressed while powering on
radio.begin(); // initialize the NRF module
delay(50);
radio.setPALevel(RF24_PA_MAX); // set the NRF module in the maximum transmission/receiving power
radio.setDataRate(RF24_250KBPS); // set the lowest data rate (best for max distance)
radio.setAutoAck(true); // enable auto acknowledgement
radio.setRetries(3, 5); // set just 3 retries so time is not wasted on resends
radio.enableAckPayload(); // enable the ack payload
radio.stopListening(); // start transmitting data
delay(50);
radio.openWritingPipe(pipeaddress); //open the pipe for transmitting data
dataNRF.gear = 11; // tell the wireless device that the main boart is in SETUP mode
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
u8g2.setCursor(4, 40);
u8g2.print(F(">SETUP<"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(2000);
dataNRF.gear = 12;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(3000);
//ACCELERATION.update(); // update the Acc analog value in the ResponsiveAnalogRead library
//BRAKE.update(); // update the Brk analog value in the ResponsiveAnalogRead library
//EEPROM.put(0, ACCELERATION.getValue());// put the analog value in the EEPROM for released ACC
//EEPROM.put(4, BRAKE.getValue()); // put the analog value in the EEPROM for released BRK
delay(50);
dataNRF.gear = 13;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.drawBox(0, 0, 130, 20);
u8g2.setDrawColor(0); // Black font on white background
u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
u8g2.setCursor(15, 19);
u8g2.print(F(">Press<"));
u8g2.setDrawColor(1); // White font on black background
u8g2.setCursor(12, 39);
u8g2.setFont(u8g2_font_lubB14_tf);// 15 pixels high font
u8g2.print(F("Acc & Brk"));
u8g2.setCursor(30, 59);
u8g2.print(F("pedals"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(3000);
//ACCELERATION.update(); // update the Acc analog value in the ResponsiveAnalogRead library
//BRAKE.update(); // update the Brk analog value in the ResponsiveAnalogRead library
//EEPROM.put(8, ACCELERATION.getValue());// put the analog value in the EEPROM for pressed ACC
//EEPROM.put(12, BRAKE.getValue()); // put the analog value in the EEPROM for pressed BRK
delay(50);
dataNRF.gear = 14;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
u8g2.setCursor(15, 30);
u8g2.print(F("Release"));
u8g2.setCursor(25, 50);
u8g2.print(F("pedals"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(2000);
dataNRF.gear = 15;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
u8g2.setCursor(10, 25);
u8g2.print(F("Steering"));
u8g2.setCursor(10, 50);
u8g2.print(F("MAX LE"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(3000);
//STEERING.update(); // update the STR analog value in the ResponsiveAnalogRead library
//EEPROM.put(16, STEERING.getValue());// put the analog value in the EEPROM for max left STR
delay(50);
dataNRF.gear = 16;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
u8g2.setCursor(10, 25);
u8g2.print(F("Steering"));
u8g2.setCursor(11, 50);
u8g2.print(F("MAX RI"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(3000);
//STEERING.update(); // update the STR analog value in the ResponsiveAnalogRead library
//EEPROM.put(20, STEERING.getValue());// put the analog value in the EEPROM for max right STR
delay(50);
dataNRF.gear = 17;// used to know what to display on the wireless device
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
u8g2.setCursor(8, 40);
u8g2.print(F(">DONE<"));
u8g2.sendBuffer();
u8g2.clearBuffer();
delay(2000);
dataNRF.gear = 0; // tell the wireless device to enter normal mode
sendData(); // send the dataNRF.gear value
sendData(); // send the dataNRF.gear a second time just in case the first time failed
} else { /* end of TvG KDL setup */
/* read the stored values for the position of the pedals */
/*EEPROM.get(0, zeroAccValue);
EEPROM.get(4, zeroBrkValue);
EEPROM.get(8, fullAccValue);
EEPROM.get(12, fullBrkValue);
EEPROM.get(16, fullLeftValue);
EEPROM.get(20, fullRightValue);
*/
}
zeroAccValue = 517; //TESTING
fullAccValue = 785; //TESTING
zeroBrkValue = 527; //TESTING
fullBrkValue = 785;//TESTING
} /* end of Setup function */
void loop() {
startLoop = micros(); //TESTING
currentstateTALK = digitalRead(28); // see if the Talk Button is pressed
/* ========================================== */
/* CODE for AUDIO TRANSMITTING and RECEIVING */
/* ========================================== */
if (ackMsg == 1) { // if the Receiver transmits Audio Data
if (setupR) { // setup the NRF to receive (just once)
detachInterrupt(digitalPinToInterrupt(33)); // disable the interupt for RPM
detachInterrupt(digitalPinToInterrupt(36));// disable the interupt for SPD
leds = B00000000; // turn off the LEDs on the steering wheel
updateShiftRegister(); // turn off the LEDs on the steering wheel
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_crox4hb_tf); // 14 pixels high font
u8g2.setCursor(60, 40);
u8g2.print("R"); // display R to know the device is receiving Audio
u8g2.sendBuffer(); // send the buffer to the display
u8g2.clearBuffer(); // clear the buffer
/* code for setting up the NRF for audio receiving */
radio.begin(); // reinitialize the NRF module so that the settings reset to default
delay(50);
radio.setPayloadSize(32); // this is the maximum payload size for a packet transfer of nrf24
radio.setAutoAck(false); // no Ack
radio.disableCRC(); // no CRC
radio.setPALevel(RF24_PA_MAX); // set the NRF module in the maximum transmission/receiving power
radio.setDataRate(RF24_2MBPS); // set the maximum data rate
radio.openReadingPipe(0, pipeaddress);// open the pipe for receiving Audio
delay(50);
radio.startListening();
/* done setting up the NRF for audio receiving */
/* audio settings */
VOLUME.update(); // update the reading fot the volume analog read pin
sgtl5000_1.volume(VOLUME.getValue() / 1023.0/*0.4*/); // set the headphone volume from 0.0 to 1.0
setupR = false; // so that the setup is only done once
setupT = true; // perform the transmit setup next time you press the TRANSMIT the button
setupN = true; // perform the NORMAL setup after transmitting/receiving
}
/* code for the actual audio receiving */
if (radio.available()) {
error = 0; // reset the error count so the program knows when too many errors are present
if ((bufcount >= 0) && (bufcount < 8)) { // get 8 packets a 32 byte audio data
radio.read(&bufr[bufcount * 32], 32); // get 32 byte audio packet data
if (bufcount == 7) { // test if all 8 packets received
bufcount = 0; // reset the packets received count
int16_t *p = queue2.getBuffer();
memcpy(p, &bufr[0], (audiobuffersize * 2));
queue2.playBuffer();
} else {
bufcount++;
}
}
}/* end of code for the actual audio receiving */
/* code for exiting the Audio Receiver mode */
if (!radio.available()) { // if the radio signal is not available
if (millis() - lastError > 50) { // every 50 milliseconds
error += 1; // increment the number of errors received
lastError = millis(); // reset the last time an error was logged
}
if (error > maxErrors) { // if the number of errors is bigger than maxErrors it means that probably the receiving of audio stopped
ackMsg = 0; // exit receiving audio mode
}/* end of code for exiting the Audio Receiver mode */
}
/* end of code for Receiving Audio */
} else if (prevstateTALK != currentstateTALK && currentstateTALK == HIGH) { // if the Talk button is pressed and data should be sent to a wireless device
if (setupT) { // setup the NRF to transmit - just once
detachInterrupt(digitalPinToInterrupt(33)); // disable the interupt for RPM
detachInterrupt(digitalPinToInterrupt(36));// disable the interupt for SPD
leds = B00000000; // turn off the LEDs on the steering wheel
updateShiftRegister(); // turn off the LEDs on the steering wheel
u8g2.clearBuffer(); // clear the buffer
u8g2.setFont(u8g2_font_crox4hb_tf); // 14 pixel high font
u8g2.setCursor(60, 40);
u8g2.print("T"); // display T to know the device is receiving Audio
u8g2.sendBuffer(); // send the buffer to the display
dataNRF.SETUP = 1; // tell the Receiver that it is time to receive audio data
sendData(); // send the data containing the SETUP instruction to the receiver using the current NRF settings
/* setup the NRF for audio transmission */
radio.begin(); // reinitialize the NRF module so that the settings reset to default
delay(50);
radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
radio.setAutoAck(false); // no Ack
radio.disableCRC(); // no CRC
radio.setPALevel(RF24_PA_MAX); // set the NRF module in the maximum transmission/receiving power
radio.setDataRate(RF24_2MBPS); // set the maximum data rate
radio.openWritingPipe(pipeaddress);// open the pipe for transmitting Audio
delay(50);
radio.stopListening(); // start transmitting Audio data
/* done setting up the NRF for audio receiving */
/* audio settings */
sgtl5000_1.inputSelect(AUDIO_INPUT_MIC); //which input to use (MICROPHONE)
sgtl5000_1.adcHighPassFilterDisable();
queue1.begin(); // initialize the queue in which to put the Audio data
setupT = false; // perform the transmit setup only once
setupR = true; // perform the receive setup next time the conditions are met
setupN = true;// perform the normal setup next time the conditions are met
}
/* code for the actual audio transmitting */
Serial.println("BUTON");
if (queue1.available()) {
memcpy(bufr, queue1.readBuffer(), audiobuffersize * 2); // copy 256 byte audio data from audio library buffer to bufr
queue1.freeBuffer();
for (int i = 0; i < 8; i++) { // send audio data in 8 packages a 32 byte to the FIFO buffers
radio.writeFast(&bufr[i * 32], 32);
}
}
/* end of code for the actual audio transmitting */
} else {
if (setupN) { // if the TALK button is not pressed and the Receiver is not transmitting Audio
attachInterrupt(digitalPinToInterrupt(33), &ignitionIsr, FALLING);// enalbe the interrupt for RPM
attachInterrupt(digitalPinToInterrupt(36), &wheelRpm, FALLING); // enalbe the interrupt for SPD
dataNRF.SETUP = 0; // tell the Receiver that no more audio data will be transmitted
error = 0; // reset the number of Audio receive errors
radio.begin(); // reinitialize the NRF module so that the settings reset to default
delay(50);
radio.setPALevel(RF24_PA_MAX); // set the NRF module in the maximum transmission/receiving power
radio.setDataRate(RF24_250KBPS); // set the lowest data rate (best for max distance)
radio.setAutoAck(true); // enable auto acknowledgement
radio.setRetries(3, 5); // set just 3 retries so time is not wasted on resends
radio.enableAckPayload(); // enable the ack payload
radio.stopListening(); // start transmitting data
delay(50);
radio.openWritingPipe(pipeaddress); //open the pipe for transmitting data
setupN = false; // perform the normal operation setup only once
setupT = true; // perform the transmit setup next time the conditions are met
setupR = true; // perform the receive setup next time the conditions are met
}
prevstateTALK = currentstateTALK;
/* ==================================================================================== */
/* ==================================================================================== */
/* Beginning of the normal LOOP */
/* ==================================================================================== */
/* ==================================================================================== */
/* ======================== */
/* CALCULATE the HEART RATE */
/* ======================== */
bpm();
/* ====================== */
/* CALCULATE the G-forces */
/* ====================== */
gforce();
/* ========================= */
/* PHARSE THE GPS DATA */
/* ========================= */
gps_data();
/* ================================ */
/* CALCULATE the ACC and BRK values */
/* ================================ */
accBrk();
/* ======================= */
/* READ the STEERING ANGLE */
/* ======================= */
steering();
/* ===================== */
/* READ the TEMPERATURES */
/* ===================== */
if (millis() - lastTemp1Read > 2000){ // read the temperature on thermocouple 1 every 2 seconds
temp1 = thermocouple1.readCelsius();
lastTemp1Read = millis();
}
if (millis() - lastTemp2Read > 3000){ // read the temperature on thermocouple 2 every 3 seconds
temp2 = thermocouple2.readCelsius();
lastTemp2Read = millis();
}
/* ====================== */
/* CALCULATE THE BEST LAP */
/* ====================== */
if (bestLapFlag) { // if a lap was finished and the best lap has not been calculated yet
if (lastLap > 1 && lastLap <= bestLap) { // if the last lap wan not 1 second and was equal or faster than the best lap
bestLap = lastLap; // store the last lap as beeing the best lap
//EEPROM.put(24, bestLap); // store the best lap in EEPROM for later use
}
bestLapFlag = false; // reset the flag that was placed when a lap was finished so we can calculate the next best lap
}
/* ========================= */
/* CODE FOR THE BLUE BUTTON */
/* ========================= */
/*currentstateBLUE = digitalReadFast(29);// read the current button state (pressed or not / HIGH or LOW)
if (prevstateBLUE != currentstateBLUE && currentstateBLUE == HIGH ) {// if the GREEN button is pressed
if (startLap = false){
startLap = true;
} else if (startLap = true){
bestLapFlag = true;
}
}
prevstateBLUE = currentstateBLUE;
*/
/* ========================= */
/* CODE FOR THE GREEN BUTTON */
/* ========================= */
currentstateGREEN = digitalReadFast(27);// read the current button state (pressed or not / HIGH or LOW)
if (prevstateGREEN != currentstateGREEN && currentstateGREEN == HIGH ) {// if the GREEN button is pressed
if (wireless) {
wireless = LOW; // there is no wireless device to transmit/receive to/from
} else {
wireless = HIGH; // there is a wireless device to transmit/receive to/from
}
}
prevstateGREEN = currentstateGREEN;
if (digitalReadFast(27)){
bestLapReset = millis() - bestLapLastReset; // increment the bestLapReset value while the GREEN button is pressed
if (bestLapReset > 5000){ // if the GREEN button is pressed for more than 5 seconds
bestLap = 599990; // reset the best lap to 9:59.99
//EEPROM.put(24, bestLap);// reset the best Lap stored in EEPROM
}
} else {
bestLapReset = 0; // reset the bestLapReset value when the GREEN button is not pressed
bestLapLastReset = millis();// reset the time the button was not pressed
}
/* ==================== */
/* CALCULATIONS FOR RPM */
/* ==================== */
/* calculate the average interval between sparks every 10 sparks to calculate the rpm */
if (rpmCount >= 10) {
intervalAvg = intervalCount / rpmCount; /* =====!!!!! WARNING !!!!!===== probable error in calculation because the time is calculated every 10 impulses. It should be 1.*/
dataNRF.rpm = 60000000 / (intervalAvg * 1); // 1 = number of impulses per rotation
intervalCount = 0;
rpmCount = 0;
}
/*
if ((micros() - lastPulseTime) > 500000) { // if more than 0.5 sec has passed since the last engine revolution the engine is probably stopped so rpm=0
dataNRF.rpm = 0;
}*/
/* ====================== */
/* CALCULATIONS FOR SPEED */
/* ====================== */
/* calculate the average interval between wheel rotations every 5 wheel rotations to calculate the speed */
if (spdCount >= 5) {
intervalSpdAvg = intervalCountSpd / spdCount;
rpmW = 60000000 / intervalSpdAvg;
dataNRF.speed = nr * rpmW;
intervalCountSpd = 0;
spdCount = 0;
}
/*
if ((micros() - lastPulseTimeSpd) > 1500000) { // if more than 1.5 sec has passed since the last wheel revolution reset the speed to 0
dataNRF.speed = 0;
rpmW = 0;
}*/
/* ======================== */
/* CALCULATIONS FOR LAPTIME */
/* ======================== */
if (startLap){ // calculate the current laptime only if you started a lap - passed over at least one magnetic strip
dataNRF.lapTime = millis() - lapMillis; // update every loop how many milliseconds have passed in this lap - for live LapTime display
}
/* ======================= */
/* GEAR + */
/* ======================= */
currentstateGP = digitalReadFast(38); // Read hall sensor state (Gear +)
if (prevstateGP != currentstateGP) { // If there is change in input
if (currentstateGP == LOW ) { // If input changes from HIGH to LOW
dataNRF.gear += 1; // Increment the Gear number
if (dataNRF.gear > 6) { // if you are in 6th gear and trigger the gear+ sensor the display remains 6
dataNRF.gear = 6;
}
digitalWriteFast(32, LOW); // activate the relay to change the gear up
lastGearPlus = millis();
geaP = true;
}
prevstateGP = currentstateGP;
}
if (millis() - lastGearPlus >= gearImpuls) {
digitalWriteFast(32, HIGH); // after <gearImpuls> milliseconds turn the Gear+ relay off
delay(10);
if (geaP){
digitalWriteFast(30, LOW);
delay(20);
digitalWriteFast(30, HIGH);
geaP = false;
}
}
/* ======================= */
/* GEAR - */
/* ======================= */
currentstateGM = digitalReadFast(37); // Read hall sensor state (Gear -)
if (prevstateGM != currentstateGM) { // If there is change in input
if (currentstateGM == LOW ) { // If input only changes from HIGH to LOW
dataNRF.gear -= 1; // Decrement the Gear number
if (dataNRF.gear > 10 || dataNRF.gear == 0) { // if you are in 1st gear and trigger the gear- sensor the display remains 1
dataNRF.gear = 1;
}
digitalWriteFast(30, LOW); // activate the relay to change the gear down
lastGearMinus = millis();
geaM = true;
}
prevstateGM = currentstateGM;
}
if (millis() - lastGearMinus >= gearImpuls) {
digitalWriteFast(30, HIGH); // after <gearImpuls> milliseconds turn the Gear- relay off
delay(10);
if (geaM){
digitalWriteFast(32, LOW);
delay(20);
digitalWriteFast(32, HIGH);
geaM = false;
}
}
/*
if (dataNRF.rpm == 0 && dataNRF.speed == 0) { // if the engine is stopped and you are not moving, probably the kart is stopped so gear = 0
dataNRF.gear = 0;
}
*/
/* ================================= */
/* UPDATE THE DATA ON THE OLED */
/* ================================= */
if (millis() - lastUpdateOled >= updateRateOled) {
oled();
lastUpdateOled = millis();
}
/* ================================== */
/* DATA TRANSMIT TO BLUETOOTH AND NRF */
/* ================================== */
if (millis() - lastTransmit >= transmitRate) {
avgGforce(); // calculate the average of the g-forces
constructString(); // construct the string needed for RaceChrono
if (wireless) { // if data should be sent to a wireless device
sendData(); // transmit the data to the wireless device using the NRF module
}
Serial1.println(data); // print the data to serial (to the Bluetooth device)
Serial1.print(GpsNmea1); // print the first NMEA sentence to serial
Serial1.print(GpsNmea2); // print the second NMEA sentence to serial
//testData();
rpmLights(); // calculate how many leds to turn on the steering wheel based on the RPM
lastTransmit = millis();// reset the time when the last $RC2 string was transmitted
/*
if (count == 65535) { // Needed only when not using the GPS
count = 0; // reset the counter variable when it reaches 65535 (maximum an int can hold)
}
else {
count += 1; // increment the count variable
}*/
}
}
}
/* ==================================================================================== */
/* ==================================================================================== */
/* End of the normal LOOP */
/* ==================================================================================== */
/* ==================================================================================== */
void testData() { // TESTING
if (dataNRF.rpm <= 1000) {go = true;}
if (dataNRF.rpm >= 12500) {go = false;}
if (go) {dataNRF.rpm += 900;}
if (!go) {dataNRF.rpm -= 1000;}
if (dataNRF.speed <= 3.2) {goS = true;}
if (dataNRF.speed >= 141.5) {goS = false;}
if (goS) {dataNRF.speed += 3.2;}
if (!goS) {dataNRF.speed -= 3.2;}
if (millis() - lastGear >= 1000) {
if (dataNRF.gear <= 1) {goG = true;}
if (dataNRF.gear >= 6) {goG = false;}
if (goG) {dataNRF.gear += 1;}
if (!goG) {dataNRF.gear -= 1;}
lastGear = millis();
}
dataNRF.BPM += 1;
if (dataNRF.BPM >= 180) {
dataNRF.BPM = 1;
}
}
/* ========================================================================================= */
/* SEND DATA WITH NRF24L01+ */
/* ======================== */
void sendData() {
if (radio.write(&dataNRF, sizeof(dataNRF))) {
if (radio.isAckPayloadAvailable()) { // if the Receiver transmitted the ackMsg
radio.read(&ackMsg, sizeof(ackMsg));// read the ackMsg
NRFfail = 0;
} else {
NRFfail += 1;
}
/* display the WiFi sign on the top right corner */
if (NRFfail < NRFfailRate) { // if there are no more that <NRFfailRate> failed ack receives, display the WiFi sign
u8g2.drawLine(119, 4, 121, 2);
u8g2.drawLine(121, 2, 125, 2);
u8g2.drawLine(125, 2, 127, 4);
u8g2.drawLine(121, 5, 122, 4);
u8g2.drawLine(122, 4, 124, 4);
u8g2.drawLine(124, 4, 125, 5);
u8g2.drawPixel(123, 6); // the pixel at the bottom of the signal indicator
}
}
}
/* ========================================================================================= */
/* OLED DISPLAY */
/* ============ */
void oled() {
/* Values for the analogRead(A1) depending on voltage
5V - 240
6.6V - 320 minimum for operating the gear shift relays
9V - 450
12V - 620
*/
/* update the battery level once when the Teensy starts */
if (startBat == true) {
BATTERY.update(); // update the value read from pin A10
BATTERYRELAY.update();// update the analog read value for relay battery
startBat = false; // reset the flag so the battery level is updated only once every 5 seconds (below)
}
if (millis() - lastMillisSec > 5000) { // update the battery level indicator every 5 seconds
BATTERY.update(); // update the analog read value for battery
BATTERYRELAY.update(); // update the analog read value for relay battery
lastMillisSec = millis();
}
/* battery full/empty frames */
if (BATTERY.getValue() > 100){ // only show battery level if battery plugged in
u8g2.drawBox(/*x*/(map (BATTERY.getValue(), 240, 620, 22, 3)), /*y*/ 2, /*length*/ (/*remaining pixels outside the battery frame*/ 22 - (map (BATTERY.getValue(), 240, 620, 22, 3))), /*height*/ 4); // used to draw the rectangle that fills the battery :: battery full in 20 minutes @ USB
}
if (BATTERYRELAY.getValue() > 100){ // only show battery level if battery plugged in
u8g2.drawBox(/*x*/(map (BATTERYRELAY.getValue(), 240, 620, 56, 37)), /*y*/ 2, /*length*/ (/*remaining pixels outside the battery frame*/ 56 - (map (BATTERYRELAY.getValue(), 240, 620, 56, 37))), /*height*/ 4); // used to draw the rectangle that fills the battery for Relay board
}
/*MAIN BATTERY LEVEL INDICATOR*/
u8g2.drawFrame(2, 1, 21, 6); // empty battery frame
u8g2.drawVLine(1, 2, 4); // the tip of the battery frame
if (BATTERYRELAY.getValue() < 250) {
u8g2.setFont (u8g2_font_courR08_tf); // 6 pixels high font
u8g2.drawStr(58, 6, "X"); // display text indicating that gears will not change (voltage under 5V at the gear change relays)
} else {
u8g2.setCursor(58, 6); // FOR TESTING
u8g2.print(BATTERYRELAY.getValue());// FOR TESTING
}/*MAIN BATTERY LEVEL INDICATOR*/
/*RELAY BATTERY LEVEL INDICATOR*/
u8g2.drawFrame(36, 1, 21, 6); // empty relay battery frame
u8g2.drawVLine(36, 2, 4); // the tip of the relay battery frame
if (BATTERY.getValue() < 250) {
u8g2.setFont (u8g2_font_courR08_tf); // 6 pixels high font
u8g2.drawStr(25, 7, "X"); // display text indicating low main PCB battery
} else {
u8g2.setFont (u8g2_font_courR08_tf);// FOR TESTING 6 pixels high font
u8g2.setCursor(25, 7); // FOR TESTING
BATTERY.update(); // update the analog read value for battery
u8g2.print(BATTERY.getValue()); // FOR TENTING
}/*RELAY BATTERY LEVEL INDICATOR*/
/* if there is no wireless device to transmit/receive to/from, display an X instead of the Wifi signal */
if (!wireless) {
u8g2.setFont (u8g2_font_courR08_tf);// 6 pixels high font
u8g2.drawStr(122, 6, "X"); // display the X that indicates there is no wireless device
}
/* ----- */
/* FRAME */
/* ----- */
/* draw the horizontal and vertical lines on the display */
u8g2.drawHLine(0, 47, 127);
u8g2.drawVLine(93, 0, 42);
/* ------- */
/* LAPTIME */
/* ------- */
/*CURRENT LAP*/
u8g2.setFont(u8g2_font_crox4hb_tf); // 14 pixels high font
u8g2.setCursor(0, 25);
u8g2.print("C "); // display the C as in CURRENT lap
u8g2.print((int)dataNRF.lapTime / 60000); // display the minutes
u8g2.setCursor(32, 25);
u8g2.print(":"); // display the ":" between the minutes and seconds
if (((int) dataNRF.lapTime % 60000) < 10000) {// if less than 10 seconds should be displayed
u8g2.setCursor(39, 25);
u8g2.print("0"); //add a "0" in front of the seconds so it shows "X:0X.XX"
u8g2.setCursor(50, 25);
u8g2.print((int)dataNRF.lapTime % 60000 / 1000.0); // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
}
if (((int)dataNRF.lapTime % 60000) >= 10000){ // if there are more than 10 seconds to be displayed
u8g2.setCursor(39, 25);
u8g2.print((int)dataNRF.lapTime % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
}
/*LAST LAP*/
u8g2.setCursor(0, 43);
u8g2.print("L "); // display the L as in LAST lap
u8g2.setCursor(20, 43);
u8g2.print(lastLap / 60000); // display the full minutes
u8g2.setCursor(32, 43);
u8g2.print(":"); // diaplay the ":" between the minutes and seconds
if ((lastLap % 60000) < 10000) {// if less than 10 seconds should be displayed
u8g2.setCursor(39, 43);
u8g2.print("0"); //add a "0" in front of the seconds so it shows "0x"
u8g2.setCursor(50, 43);
u8g2.print(lastLap % 60000 / 1000.0); // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
} else {
u8g2.setCursor(39, 43);
u8g2.print(lastLap % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
}
/*BEST LAP*/
u8g2.setCursor(0, 64);
u8g2.print("B "); // display the B as in BEST lap
u8g2.setCursor(20, 64);
u8g2.print(bestLap / 60000); // display the full minutes
u8g2.setCursor(32, 64);
u8g2.print(":"); // diaplay the ":" between the minutes and seconds
if ((bestLap % 60000) < 10000.0) {// if less than 10 seconds should be displayed
u8g2.setCursor(39, 64);
u8g2.print("0"); //add a "0" in front of the seconds so it shows "0x"
u8g2.setCursor(50, 64);
u8g2.print(bestLap % 60000 / 1000.0); // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
} else {
u8g2.setCursor(39, 64);
u8g2.print(bestLap % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
}
/*TEMPERATURE*/
u8g2.setFont (u8g2_font_courR08_tf);// 6 pixels high font
u8g2.setCursor(95, 51);
u8g2.print(temp1, 1);
u8g2.setCursor(95, 64);
u8g2.print(temp2, 1);
/* ----- */
/* SPEED */
/* ----- */
//u8g2.setFont(u8g2_font_crox4hb_tf);// 14 pixels high font
/*if (dataNRF.speed < 10.0) {
u8g2.setCursor(37, 60); //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
u8g2.print(dataNRF.speed, 1);
}
if (dataNRF.speed >= 10.0 && dataNRF.speed <= 99.9) {
u8g2.setCursor(26, 60); //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
u8g2.print(dataNRF.speed, 1);
}
if (dataNRF.speed > 99.9) {
u8g2.setCursor(15, 60); //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
u8g2.print(dataNRF.speed, 1);
}
u8g2.setCursor(80, 60);
u8g2.print(F("Km/h"));
*/
/* ---- */
/* GEAR */
/* ---- */
u8g2.setFont(u8g2_font_fub35_tn);// 35 pixels high font
u8g2.setCursor(95, 43);
u8g2.print(dataNRF.gear); // display the current gear
u8g2.sendBuffer(); // send the buffer to the display
u8g2.clearBuffer(); // clear the buffer
}
/* ========================================================================================= */
/* CALCULATE NMEA CHECKSUM */
/* ======================= */
char checkSum(String chars) {
char check = 0;
for (int c = 0; c < chars.length(); c++) {
check = char(check ^ chars.charAt(c));
}
return check;
}
/* ========================================================================================= */
/* CALCULATE LAPTIME */
/* ================= */
void lap() {
if (sectors == 1) { // if the track has only 1 magnetic strip/sector
if (firstLap){ // if this is the begining of the first lap
lapMillis = millis(); // reset the time recorded from when the device was started
firstLap = false; // do this only once when the first lap is started
} else {
lastLap = millis() - lapMillis;// store the last lap
lapMillis = millis(); // reset the last time the sensor was triggered
}
startLap = true; // tell the microcontroller that a lap was started. Start recording time.
bestLapFlag = true; // used to know when a lap is finished to calculate the best lap and not waste time in the interrupt routine
}
if (sectors > 1) { // if the track has more than 1 magnetic strips/sectors
line += 1; // A split line was crossed
if (firstLap){ // if this is the begining of the first lap
lapMillis = millis(); // reset the time recorded from when the device was started
firstLap = false; // do this only once when the first lap is started
}
if (line == (sectors + 1)) { // If enough split lines have been crossed
lastLap = millis() - lapMillis;// store the last lap
lapMillis = millis(); // Reset the last time that the start/finish line was crossed
line = 0; // Reset the split lines
startLap = true; // tell the microcontroller that a lap was started. Start recording time.
bestLapFlag = true; // used to know when a lap is finished to calculate the best lap and not waste time in the interrupt routine
}
}
}
/* ========================================================================================= */
/* CALCULATE RPM */
/* ============= */
void ignitionIsr() {
startRPM = micros(); //TESTING
interval = micros() - lastPulseTime;
lastPulseTime = micros();
rpmCount += 1;
intervalCount += interval;
endRPM = micros(); //TESTING
}
/* ========================================================================================= */
/* CALCULATE SPEED */
/* =============== */
void wheelRpm() {
startSPD = micros(); //TESTING
intervalSpd = micros() - lastPulseTimeSpd;
lastPulseTimeSpd = micros();
spdCount += 1;
intervalCountSpd += intervalSpd;
endSPD = micros(); //TESTING
}
/* ========================================================================================= */
/* CONSTRUCT the $RC2 STRING */
/* ========================= */
void constructString() {
String buffer = "RC2," + GPScounter + ",," + String (dataNRF.avgXx, 1) + ',' + String (dataNRF.avgYy, 1) + ",," + dataNRF.rpm + ',' + dataNRF.gear + ',' + dataNRF.brake + ',' + dataNRF.acceleration + ',' + String(lastLap / 1000.0) + ',' + String(dataNRF.speed, 1) + ',' + String(dataNRF.BPM) + ',' + dataNRF.str + ",,"; // construct the $RC2 string using the variables and taking into account the format RaceChrono asks for
//String buffer = "RC2,," + String(count) + ',' + String (dataNRF.avgXx, 1) + ',' + String (dataNRF.avgYy, 1) + ",," + dataNRF.rpm + ',' + dataNRF.gear + ',' + dataNRF.brake + ',' + dataNRF.acceleration + ',' + String(lastLap / 1000.0) + ',' + String(dataNRF.speed, 1) + ',' + String(dataNRF.BPM) + ',' + dataNRF.str + ",,"; // construct the $RC2 string using the variables and taking into account the format RaceChrono asks for
String checksum = String (checkSum(buffer), HEX);// calculate the checksum of the RC2 string
char crc = checkSum (buffer);
data = "$" + buffer + "*";
if (crc < 16) { // if the HEX value of the checksum is only one character, add "0" in front
data = data + "0" + checksum;
} else {
data = data + checksum;
}
}
/* ========================================================================================= */
/* RPM LEDs */
/* ======== */
void rpmLights() {
if (dataNRF.rpm < 5000 ) {leds = B00000000;}
if (dataNRF.rpm > 5000 && dataNRF.rpm < 6000 ) {leds = B10000000;}
if (dataNRF.rpm > 6000 && dataNRF.rpm < 7000 ) {leds = B11000000;}
if (dataNRF.rpm > 7000 && dataNRF.rpm < 8000 ) {leds = B11100000;}
if (dataNRF.rpm > 8000 && dataNRF.rpm < 9000 ) {leds = B01110000;}
if (dataNRF.rpm > 9000 && dataNRF.rpm < 10000) {leds = B00111000;}
if (dataNRF.rpm > 10000 && dataNRF.rpm < 11000) {leds = B00011100;}
if (dataNRF.rpm > 11000 && dataNRF.rpm < 12000) {leds = B00001110;}
if (dataNRF.rpm > 12000 ) {leds = B00000111;}
updateShiftRegister(); //update the shift register to light up the corresponding LEDs
}
/* ========================================================================================= */
/* UPDATE SHIFT REGISTER */
/* ===================== */
void updateShiftRegister() {
digitalWriteFast(6, LOW); // (latchPin(ST), LOW);
shiftOut(5, 10, LSBFIRST, leds);// (dataPin(DS), clockPin(SH), LSBFIRST, leds)
digitalWriteFast(6, HIGH); // (latchPin(ST), HIGH);
}
/* ========================================================================================= */
/* CALCULATE THE BPM */
/* ================= */
void bpm() {
reading = analogRead(A15);
if (reading > UpperThreshold && IgnoreReading == false) { // Heart beat leading edge detected
if (FirstPulseDetected == false) {
FirstPulseTime = millis();
FirstPulseDetected = true;
} else {
SecondPulseTime = millis();
PulseInterval = SecondPulseTime - FirstPulseTime;
FirstPulseTime = SecondPulseTime;
}
IgnoreReading = true;
}
if (reading < LowerThreshold && IgnoreReading == true) { // Heart beat trailing edge detected
IgnoreReading = false;
}
dataNRF.BPM = round((1 / PulseInterval) * 60 * 1000);
}
/* ========================================================================================= */
/* PHARSE THE GPS DATA */
/* =================== */
void gps_data(){
while (Serial8.available()) {// if receiving data from GPS
char c = Serial8.read();
if (c == '\n') { // if the received character is the endline (\n or \r)
if (nmea) { // if the characters received have been appended to nmea string
nmea = false; // turn off the nmea flag so that the next characters are stored in the nmea2 string
}
if (!nmea) { // if the characters received have been appended to nmea2 string
nmea = true; // turn off the nmea2 flag so that the next characters are stored in the nmea string
}
}
if (nmea) {
GpsNmea1Buf += c; // add characters received in Serial7 to the NMEA 1 buffer
}
if (!nmea) {
GpsNmea2Buf += c; // add characters received in Serial7 to the NMEA 2 buffer
}
gps.handle(c); // parse the GPS data in the NeoGPS library
// Did 'handle' finish making a new fix structure?
if (gps.available() && (c == 0x0A)) { // wait for last LF char
fix = gps.read(); // yes, a fix structure is ready (10Hz)
GpsNmea1 = GpsNmea1Buf; // put the contents of the nmea buffer1 in the GPSNmea1 string that will be printed to serial
GpsNmea1Buf = ""; // empty the NMEA 1 buffer
GpsNmea2 = GpsNmea2Buf; // put the contents of the nmea buffer2 in the GPSNmea2 string that will be printed to serial
GpsNmea2Buf = ""; // empty the NMEA 2 buffer
GPScounter = fix.dateTime.hours + fix.dateTime.minutes + fix.dateTime.seconds + '.' + fix.dateTime_cs;
}
}
}
/* ========================================================================================= */
/* CALCULATE ACC and BRK VALUES */
/* ============================ */
void accBrk(){
ACCELERATION.update(); // update the ACC analog value to be smoothed out
BRAKE.update(); // update the BRK analog value to be smoothed out
accValue = ACCELERATION.getValue(); // used instead of the analogRead() function. returns much more stable readings.
brkValue = BRAKE.getValue(); // used instead of the analogRead() function. returns much more stable readings.
dataNRF.acceleration = ((accValue - zeroAccValue) * 100L) / (fullAccValue - zeroAccValue); //calculates the percentage the acc pedal is pressed
dataNRF.brake = ((brkValue - zeroBrkValue) * 100L) / (fullBrkValue - zeroBrkValue); //calculates the percentage the brk pedal is pressed
}
/* ========================================================================================= */
/* READ the STEERING ANGLE */
/* ======================= */
void steering(){
STEERING.update();
dataNRF.str = STEERING.getValue();
}
/* ========================================================================================= */
/* READ RAW MPU6050 DATA */
/* ===================== */
void gforce() {
Wire.beginTransmission(0x68); // start communicating with the MPU
Wire.write(0x3B); // set byte 0x3B to indicate start register
Wire.endTransmission(); // terminate the connection
Wire.requestFrom(0x68, 6); // request 6 bytes from MPU
acc_x = Wire.read() << 8 | Wire.read(); // Shift high byte left and add low and high byte to acc_x
acc_y = Wire.read() << 8 | Wire.read(); // Shift high byte left and add low and high byte to acc_y
acc_z = Wire.read() << 8 | Wire.read(); // Shift high byte left and add low and high byte to acc_z
rawX += acc_x;
rawY += acc_y;
x += 1;
/*
acc_x = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
acc_y = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
acc_z = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
*/
}
/* ========================================================================================= */
/* AVERAGE THE MPU6050 DATA */
/* ======================== */
void avgGforce() {
/* 2g sensitivity */
dataNRF.avgXx = (rawX / x) * 0.061 / 1000;
dataNRF.avgYy = (rawY / x) * 0.061 / 1000;
/* 4g sensitivity */
//dataNRF.avgXx = (rawX/x) * 0.122 / 1000;
//dataNRF.avgYy = (rawY/x) * 0.122 / 1000;
/* 8g sensitivity */
//dataNRF.avgXx = (rawX / x) * 0.244 / 1000;
//dataNRF.avgYy = (rawY / x) * 0.244 / 1000;
/* 16g sensitivity */
//dataNRF.avgXx = (rawX/x) * 0.732 / 1000;
//dataNRF.avgYy = (rawY/x) * 0.732 / 1000;
x = 0; // reset the counter for the average of MPU
rawX = 0;
rawY = 0;
}