making decent headway on the DIY route. i have a few PIDs decoded for G8X m3/m4
50hz RPM
50hz ACCELERATOR PEDAL
50hz BRAKE PRESSURE
25hz GEAR
25hz STEERING ANGLE
RPM and PEDAL come in at 100hz but the Bluetooth LE drivers on all the Arduino devices are terrible. nRF52 or ESP32!
My basic design is an Adafruit Feather ESP32s3 (or Adafruit Huzzah32 ESP32) with Feather Wing CAN bus transceiver (ESP32 has a SJA1000-like CAN controller built into the chip) The ESP32s3 is newer chip with Bluetooth 5.0, but drivers are so terrible, there is not real gains, I just prefer the USB-C vs USB micro B.
I started out with a nRF52 chip, but its performance was maybe 100 frames / second total. The ESP32s3 I can get about 350 frames / second before the Bluetooth stack starts dying.
I have developed my own CAN bus driver, so i can take lots of shortcuts since i only care about reading data. I can get over 2500 frames / second (the max my car broadcasts over the PT-CAN bus) without issue.
The ESP32 is dual-core, so i have CAN bus on one core, Bluetooth on the other, use a FreeRTOS Queue to pass data from the CAN bus interrupt handler to the bluetooth core and send that over Bluetooth LE to racechrono.
RaceChrono screenshot:
https://photos.app.goo.gl/Kbn5eceCnLTmVuXQ9ESP32 build:
https://photos.app.goo.gl/yBsnSb2GYug3SNcv7Next steps are to see if i can write my own BLE slimmed down driver with the ESP32 SDK and get past that 350 frames / second mark.
It would be nice to have a WiFi interface to RaceChrono for DIY devices, as that I feel is much more stable / performance drivers in the arduino world, vs trying to use BLE for performance path. BLE is fine for basic communication, but none of the Arduino drivers are hardened for performance on the BLE side.
Comments
could also just reduce the BLE payload to PID + value, instead of sending all the extra CAN data so each BLE message would be 4 bytes for PID and 1-2 bytes for data. that would reduce the data payload in each BLE from 12 bytes total to 5-6 bytes total
email me at magnust@gmail.com if you are interested in trying out my integrated ESP32-S3 CAN board with built in 12V power support from car/bike
https://github.com/MagnusThome?tab=repositories
ππ
A WiFi interface is available, and I have been using it for a year or so -- streaming $RC3 and GPS data via an old ESP8266 serial/WiFi interface at insane speeds. It is definitely faster and more stable than the Bluetooth SPP I used before.
> send_string( "AT+CWSAP_CUR=\"\",\"\",5,3\r\n" );
> delay(1000);
> send_string( "ATE0\r\n" ); // Echo off
> send_string( "AT+UART_CUR=1000000,8,1,0,0\r\n" ); // 1Mbps, 8 bits, 1 stop bit, no parity, flow control
> LL_USART_Disable( RC_dev ); // disable to change baud rate
> LL_USART_SetBaudRate( RC_dev, 96000000U, LL_USART_OVERSAMPLING_16, 1000000 );
> LL_USART_Enable( RC_dev );
> send_string( "AT\r\n");
> send_string( "AT+GMR\r\n");
> send_string( "AT+CWMODE_CUR=2\r\n"); // 2 = softAP mode (allow phone to connect via WiFi)
> send_string( "AT+CIPMODE=0\r\n" ); // Prepare normal mode
> send_string( "AT+CIFSR\r\n" ); // Query IP address
> send_string( "AT+CIPMUX=1\r\n"); // Enable multiple connections.
> send_string( "AT+CIPSERVER=1\r\n"); // Create a TCP server. Default port = 333
> delay(1000); // wait for connection
The serial port "RC_dev" is connected to the ESP8266 . You might need to insert some delays to let the ESP process the AT-commands -- check via a logic probe! This function sends data to RaceChrono:
> void send_AT(char* str) {
> size_t len = strlen(str);
> if ( len > 0 )
> {
> char at_com[]="AT+CIPSEND=0,xxx\r\n";
> sprintf(&at_com[13],"%03u\r\n",len);
> send_string(at_com); // Book the transmission and length
> delay(1); // wait for ">" ToDo: Read and check the response
> send_string(str);
> }
>}
> void send_string(char* str) {
> size_t len = strlen(str);
> for (; len > 0; --len, ++str) {
> LL_USART_TransmitData8( RC_dev, *str );
> while (!LL_USART_IsActiveFlag_TXE(RC_dev)) {} // Blocking mode
> }
> *(str-len)=0; // clear the buffer, strlen=0
>}
since all CAN bus packets would fit in UDP packet, it would be interesting to test WiFi + UDP, and interesting to pack more than 1 CAN bus data frame into a UDP packet as well, but the dual core ESP32 with CAN bus interrupts on one core and networking on another core seem to do well enough.
But racechrono does not ever attempt to connect, i have tried the diy UUID,
and the elm327 UUID, but i am stuck, here's my latest attempt,
#include
#include
#include
#include
// UUIDs for the BLE service and characteristics of your ELM327 device
#define SERVICE_UUID "0000fff0-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_RX "0000fff1-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_TX "0000fff2-0000-1000-8000-00805f9b34fb"
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
Serial.println("Device connected");
};
void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
Serial.println("Device disconnected");
}
};
class CharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
}
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("VEEPEAK");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pRxCharacteristic->setCallbacks(new CharacteristicCallbacks());
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE
);
pTxCharacteristic->addDescriptor(new BLE2902());
pService->start();
pServer->getAdvertising()->start();
Serial.println("Waiting for a client connection to notify...");
}
void loop() {
// Handle connection status changes
if (deviceConnected != oldDeviceConnected) {
if (!deviceConnected) {
pServer->startAdvertising();
}
oldDeviceConnected = deviceConnected;
}
// Read data from Serial and send over BLE
if (Serial.available()) {
String data = Serial.readStringUntil('\n'); // Read the incoming data until newline
if (deviceConnected) {
pTxCharacteristic->setValue(data.c_str()); // Set the value to the Tx Characteristic
pTxCharacteristic->notify(); // Notify the connected device
Serial.print("Transmitted Value: ");
Serial.println(data); // Print the transmitted data
}
}
}
Any chance you can tell me whats wrong please, or have an example to get BLE working?
I am making a Yamaha datalogger for pre 2016 kline,
// RaceChrono BLE service UUID
static constexpr uint16_t racechrono_service_uuid = 0x1ff8;
// RaceChrono uses two BLE characteristics:
// 0x01 to be notified of data received for those PIDs
// 0x02 to request which PIDs to send and how frequently
static constexpr uint16_t can_bus_characteristic_uuid = 0x1;
static constexpr uint16_t pid_characteristic_uuid = 0x2;
you can certainly look at my bluetooth setup https://github.com/joeroback/racechrono-canbus/tree/trunk
but racechrono is specifically looking for 0x1ff8 so the UUIDs you have listed, its certainly never going to be seen by racechrono
I have taken the BLE section of your code and now racechrono is connected,
Thanks!
You can make the ESP32 work as a very basic ELM327 copy with this code
https://github.com/collin80/ESP32RET
or for ESP32-S3
https://github.com/MagnusThome/ESP32S3RET
I assumed it was a UUID issue, but the DIY UUID was the only current way i could ever get working with racechrono.
The S3 does not have Bluetooth Serial which is what ESP32RET is coded for. So to be able to compile for the S3 i made a quick hack removing it. Anyone with some time on their hands can add serial over BLE to the code but I do wonder what phone apps for ELM327 would support that?
I believe torque also supports BLE odb, as does harrys lap timer.
I will build up on my code and be sure to update my github soon
Thanks to @MagnusThome and @dirtyfreebooter
Your github url?
Here @MagnusThome. I have finished decoding the yds, and I have lots to add to my repo, I am currently just working on the ble side now,
Uses could be complete dash removal of a pre 2016 yamaha, whilst supporting the yamaha protocol, or alternative dash,
There's still a lot of people who track pre 2016 r6, and with a simple esp32s3 and an L9637D people are able to produce a cost effective piece of kit.
Most of the community is locked onto can bus. And provides only support for such.
But there are many who have contributed to the motorcycle scene, whilst not as common as cars, bikes are still a largely enjoyed sport, bringing the yamaha up to date with an esp32s3 makes sense.
Thx for url.
By coincidence I did this last week
https://github.com/MagnusThome/RejsaCAN-ESP32/tree/main/Code%20Examples/RejsaCAN%20v3.x%20-%20ESP32-S3%20-%20read%20rpm%20over%20BLE
My test board is an UM feather s3.
But i have a UM nano s3 ready to go when I have finished up.
My personal plan is to adjust the 5v reg on the dash to support the UM nanos3, tap the RX,TX pads on the dash (which removes the need for the L9637D),
I can also double up with a decent immo (as the k-line handles immobox/ecu), Yamaha allows ECU flashing via k-line, which would fully disable the bike with a null flash when tampered, added in the fact of open haystack. ( DIY Airtags) You should have a pretty much bulletproof way of getting your bike back if stolen, (Unless the thief thinks to BLE scan)
https://github.com/seemoo-lab/openhaystack
Yamaha is Pwned by a simple immobox emulator, which, I won't mention how it's done, is pretty basic, jamming the k-line or null flashing the ecu will solve that issue.
I also thought of using the s3 devkit as it has USB host, that way a simple USB KKL cable can be converted to function as a data logger, Plenty of options.
Its winter here in the UK and whilst the weather is too cold to ride for pleasure, i set to study the YDS bus. The AIM kit is too expensive and we all know the possibilities with a simple MCU
End result is to study and reverse my ECU, custom ECUs are always about, but with a datasheet for my ecu, and fully unlocked flashing, its not needed, just time a dedication to the cause
https://github.com/terrafirma2021/ESP32-S3-BLE-ELM327
This is my base, i have lots to do, but soo far torque works without configuration to show speed.