I am in the early planning stages of a project to record engine RPM, engine vacuum, and AFR data from an existing Autometer AFR gauge / O2 sensor. The car is carbureted and does not have an ECM so I have to measure the signals on my own.
This is my first ever Arduino project, so sorry for any dumb questions.
The UNO R4 with WIFI version that just came on the market has onboard Bluetooth and WIFI, I was wondering if anyone has an idea of how this will affect the logic / libraries needed to send data from the UNO to RaceChrono? Will it be limited to Bluetooth only, or would I be able to broadcast data faster using the embedded WIFI module?
Does anyone have any tips for the best way to read the RPM signal from an MSD 6AL ignition box? It is supposed to send out a 12v, 20% duty cycle square wave, and I'm debating between using a proto screw terminal type shield to make a voltage divider, and using some sort of optocoupler module, potentially one of the Mikroe Click boards, since I was planning on going with the Vacuum Click board to read manifold vacuum. I'm trying to make it as plug and play, and robust as possible, as this will be going in a fairly stiffly sprung HPDE car.
Comments
C:\Users\***\AppData\Local\Temp\arduino_build_889957\sketch\sketch_aug13_RaceChronoBLE_Example.ino.cpp.o: In function `waitForConnection()':
C:\Users\***\Documents\Arduino\sketch_aug13_RaceChronoBLE_Example/sketch_aug13_RaceChronoBLE_Example.ino:63: undefined reference to `RaceChronoBle'
C:\Users\***\AppData\Local\Temp\arduino_build_889957\sketch\sketch_aug13_RaceChronoBLE_Example.ino.cpp.o: In function `loop':
C:\Users\***\Documents\Arduino\sketch_aug13_RaceChronoBLE_Example/sketch_aug13_RaceChronoBLE_Example.ino:71: undefined reference to `RaceChronoBle'
C:\Users\***\AppData\Local\Temp\arduino_build_889957\sketch\sketch_aug13_RaceChronoBLE_Example.ino.cpp.o: In function `setup':
C:\Users\***\Documents\Arduino\sketch_aug13_RaceChronoBLE_Example/sketch_aug13_RaceChronoBLE_Example.ino:43: undefined reference to `RaceChronoBle'
collect2.exe: error: ld returned 1 exit status
Anyone have any suggestions? I did have to go through an exercise to load new firmware onto the ESP32 chip and downloaded an updated BLE library that has R4 Wifi support. I was able to run an example from one of those and the BLE working as far as being able to connect it to my phone.
Now, however, I would like to get the data into Racechrono.
Are there any examples out there of how to create the raw RC2/RC3 / NEMA messages using the print command so I can convert it over to WIFI? Or is there a better way to send data to RaceChrono over WIFI?
Here is the working code that I have so far (still in progess so ignore all the comments)
#include "WiFiS3.h" //WIFI LIBRARY FOR UNO R4 WIFI
#include "arduino_secrets.h" //WIFI SSID & PW FILE
//enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) USING WPA
int keyIndex = 0; // your network key index number (needed only for WEP)
int led = LED_BUILTIN; //LED ON ARDUINO BOARD, OUTPUT 13
int status = WL_IDLE_STATUS;
WiFiServer server(80); //USE THIS PORT ADDRESS (80) IN ANDROID APP WITH RAW DATA SETTING
const int RPMpin = 2; //input pin for RPM signal from ignition
char buffer[40];
volatile unsigned long last_microsec = 0;
volatile long period = 0; //was unsigned long 10/4/23
volatile float freq = 0.0; //FREQUENCY OF RPM SIGNAL IN Hz
volatile float Engine_RPM = 0.0;
volatile boolean RPM_flag = 0; //RPM INPUT PIN REGISTERED A PULSE AND EXECUTED INTERRUPT FUNCTION
volatile boolean RPM_invalid_flag = 0; //RPM INPUT TIME INVALID FOR CURRENT SAMPLE DUE TO INTERRUPTS BEING DISABLED
volatile boolean Print_flag = 0; //READY TO PRINT DATA FLAG
volatile unsigned long Tmr1 = 0;
volatile boolean Tmr1_dn = 0; //Tmr1 DONE / COMPLETE FLAG
volatile long period_prnt = 0; //was unsigned long 10/4/23
volatile float freq_prnt = 0.0; //FREQUENCY OF RPM SIGNAL IN Hz FOR PRINTING
volatile float Engine_RPM_prnt = 0.0; //CALCULATED RPM SIGNAL FOR PRINTING
volatile float vacuum =0.0; //CALCULATED INTAKE MANIFOLD VACUUM
volatile float AFR=0.0; //CALCULATED AIR FUEL RATIO FROM OXYGEN SENSOR
volatile int ambient_vac_int=0;
const unsigned int maxReadings = 60;
unsigned long period_array[maxReadings];
unsigned int i = 0;
WiFiClient client=0;
void RPM_Count() //RUN THIS FUNCTION WHEN RPM PULSE FROM IGNITION SYSTEM GOES HIGH
{
unsigned long t = micros();
//measure time between pulse and previous pulse
if (RPM_invalid_flag==0)
{
period = (t - last_microsec);
}
else
{
period = 1;
}
last_microsec = t;
RPM_flag=1;
}
void Data_Record() //logic for recording engine data (previously in loop routine)
{
if (((micros() - Tmr1) >= 100000) && Tmr1_dn==false) // 100,000uS = 100mS intervals
{
Tmr1_dn=true;
Tmr1=micros();
}
if ((period>=1500) && (RPM_flag==true) && (RPM_invalid_flag==false)) // && ((((period_prnt-period)>=-100) && ((period_prnt-period)<=100 )) || (period_prnt==0))) //fix period test logic, only runs once
{
Serial.println("Valid RPM period");
freq = (1000000.0/period); //1,000,000uS = 1 SECOND
}
else //INVALID DATA WAS DETECTED
{
RPM_flag=false;
RPM_invalid_flag=false;
period_prnt=period;
}
if ( Tmr1_dn==true) //RUN THIS EVERY TIME TMR1 IS DONE (100mS), client.print = wifi data transmission
{
vacuum = ((map(analogRead(A0), 0, ambient_vac_int,-3610,0))/100.0); //divide by 100 to get 2 decimal places
AFR = ((map(analogRead(A1), 0, 4095,1000,1800))/100.0);
Engine_RPM = ((freq * 60.0)/4.0);
Engine_RPM_prnt=Engine_RPM;
client.print(",");
client.print(Engine_RPM_prnt);
client.print(",RPM,");
client.print(vacuum);
client.print(",inHg,");
client.print(AFR);
client.println(",:1 AFR,");
Print_flag=false;
RPM_flag=false;
RPM_invalid_flag=true;
Tmr1_dn=false;
//interrupts(); //11/18/23:DO NOT USE, CAUSING CPU TO FREEZE. TURNS INTERRUPTS BACK ON TO RESUME CHECKING FOR RPM PULSES
}
}
void printWiFiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
}
void setup() {
// put your setup code here, to run once:
pinMode(RPMpin , INPUT);
//pinMode(3 , OUTPUT);
pinMode(A0, INPUT);
analogReadResolution(12);
delay(1000);
ambient_vac_int = analogRead(A0); //take reading of ambient pressure w/o engine running for barometric zero
pinMode(A1, INPUT);
analogReadResolution(12);
attachInterrupt(digitalPinToInterrupt(RPMpin), RPM_Count, RISING); //ASSIGNS INTERRUPT TO RPM_PIN ON RISING EDGE
Serial.begin(115200);
//analogWrite(3,75); //OUTPUT PWM ON PIN 3 FOR RPM_PIN TO MEASURE FOR TESTING PURPOSES
Tmr1 = micros();
//********** WIFI COMMS LOGIC: **********
pinMode(led, OUTPUT); // set the LED pin mode
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// by default the local IP address will be 192.168.4.1
// you can override it with the following:
WiFi.config(IPAddress(192,168,1,2));
// print the network name (SSID);
Serial.print("Creating access point named: ");
Serial.println(ssid);
// Create open network. Change this line if you want to create an WEP network:
status = WiFi.beginAP(ssid, pass);
delay(100); //PTP
if (status != WL_AP_LISTENING) {
Serial.println("Creating access point failed");
while (true);
}
delay(10000);
// start the web server on port 80
server.begin();
printWiFiStatus();
}
void loop() {
// main code here, to run repeatedly:
//********** WIFI COMMS LOGIC: **********
// compare the previous status to the current status
if (status != WiFi.status()) {
// it has changed update the variable
status = WiFi.status();
if (status == WL_AP_CONNECTED) {
// a device has connected to the AP
Serial.println("Device connected to AP");
} else {
// a device has disconnected from the AP, and we are back in listening mode
Serial.println("Device disconnected from AP");
}
}
client = server.available(); // listen for incoming clients, PTP removed WiFiClient declaration to make global variable
if (client) { // if you get a client,
Serial.println("new client");
client.println("Connected to UnoR4!");
Tmr1=micros();
while (client.connected()) { // loop while the client's connected
Data_Record(); //run data recording routine
} //while loop end
// close the connection:
client.stop();
Serial.println("client disconnected");
}
//Serial.println("client lost");
}
If you look at the files in the src/ directory of that library, you can see that there's an #ifdef trick to automatically pick the right implementation for the board you're compiling for. I can totally imagine those conditions to not handle a previously-unknown board correctly, so the code needs to be updated. Try changing the #if defined(ARDUINO_ARCH_ESP32) condition at the top of RaceChronoESP32.cpp to "#if true" ?
As for the Wi-Fi idea, I don't think RaceChrono has a protocol for DIY devices to connect via Wi-Fi, but I might be wrong.