Go Down

Topic: OBD II Bike Connector - Pass via bluetooth (Read 83105 times) previous topic - next topic


Jul 05, 2016, 08:36 pm Last Edit: Jul 05, 2016, 08:49 pm by Scissor
Attached are the two excel sheets containing the data from a few minutes of datalogging. The datalogger is capable of logging at approximately 7 Hz to a microSD card, which could be increased by fine tuning the serial communication timing parameters.  


Jul 06, 2016, 10:10 am Last Edit: Jul 06, 2016, 12:00 pm by Trib
Thank you very much for your data! I will include it into my document.

In your excel sheet you mention "Supported PIDs" several times. I don't really understand how you obtain the available localIdentifiers based on that response message. At first I thought it just might be a bitmask i.e. convert the HEX values to bits, and assume every "1" corresponds to an available localIdentifier. However this does not correspond to the results I get.
It is exactly working like that!
You will receive a PID-List on
  • 00 (Supported PID´s  1-32)
  • 20 (Supported PID´s 33-65)
  • 40 (Supported PID´s 66-96)
  • ...

00 gives me Hex: DF F7 87 87
Which is in Binary: 1101 1111 1111 0111 1000 0111 1000 0111
Now you can overlay the binary to PID 1-32.
0x01 supported
0x02 supported
0x03 unsupported
0x04 supported

That´s what my sniffer-functionality does:
Code: [Select]

const uint8_t pidList[] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0};
const uint8_t pidListCount = (uint8_t)(sizeof(pidList));
void SniffEcu()
  //Get first PID List
  for (int i = 0; i < pidListCount; i++)
    //Copy Array  from last PID List before it will be overwritten:
    uint8_t ecuResponseCopy[7];
    memcpy(ecuResponseCopy, ecuResponse, 7);       
    //Result: PID List
    //80 F1 11 06 61 00 DF F7 87 87 CD
    //                  DF F7 87 87
    //0000 0000 0000 0000 0000 0000 0000 0000
    //01 02 XX 04 05 06 07 08 09...
    //For each Hex value in ECUresponse (4 bytes, without checksum)
    for (uint8_t j = 2; j < 6; j++)
      byte bin = ecuResponseCopy[j];
      //0x80 = 1000 0000 | Shift 1 to the right
      for (int mask=0x80; mask != 0; mask >>= 1)
        if (bin & mask)           

KWP2000 / ISO-14230 is a previous version of Unified Diagnostic Service, which gives you a small impression of what is possible.
As you an see there, it is not possible to upload the FW without a special token from Kawasaki. But there is enough to mess up :D So stay careful :)

7Hz is very good! Due to the BT connection, slow Serial2 and my bad code, mine is about ~4-5.


Jul 06, 2016, 06:54 pm Last Edit: Jul 06, 2016, 08:05 pm by Scissor
Using the bitmask method to find supported localIdentifiers does give some strange results. Whenever the bitmask is "1", the response method is not always positive, many general reject messages (0x7F 0x21 0x10) are given as well. You have got the same result in your excel sheet. Is it related to secured registers? Also the 0xBF seems not to be supported, yet I get a very long response message which at this point appears to be related to pressure measurements.

Soon I will take the motorcycle for a ride while datalogging. Do you know if it's safe to log at a high rate? I can imagine the ECU will spend most time controlling the ignition especially at high RPM, additional serial communication might block functions which could result in strange behaviour.

Edit: In the mean time I did a little calculation on the speed of the communication. From the ISO-14230 documents the minimum timing parameters are given as:

Inter byte time ECU response: 0 ms
Request-response delay: 25 ms
Response-request delay: 55 ms
Inter byte time request: 5 ms

Using these parameters in combination with a baudrate of 10400 bits/s = 1300 bytes/s, the resulting maximum request-response rate is about 7.8 Hz (assuming a request of 7 bytes and a response of 9 bytes) and a data rate of approximately 125 bytes/s. This is very close to my datalogging rate at approximately 116 bytes/s (3138 bytes in about 27 seconds). Note that over 50% of the time the response-request and request-response delay are active.

Sending one byte in a request takes at least 5.8 ms (5 ms delay + 0.8 ms due to the baudrate), whereas the response byte can be send in just 0.8 ms. Therefore to achieve very high data rate we should try to use periodic transmission (send 80 11 F1 02 10 82 (instead of 80 for regular diagnostic session) 16). In this case, the rate increases to rougly 16 response messages per second. Additionally we can try to see if it's possible to reduce the Response-request delay and the inter byte time for requests in order to obtain higher datalogging speed.


The bitmask is fine. But some values like Injector timing, CO² Adjust timing, ect. are only working during a diagnostic session. It has to be initialized separately (somehow).
I don´t expect it is related to a security layer. There are testing scenarios for exhaust or injection, which can be run and I´d expect they will activate these sensors.

The PID´s are valid globally. Some are available during current data 0x21, some by freezed data 0x12, some maybe only on testing purpose. If you take a look into the KDS3.0 Documentation(from page 21 on), you will see what is possible with the ECU.

0xBF is really curious! Can´t explain it right now. But due to it´s "hidden" location way at the end, it will be a undocumented testing feature, I guess.

Yes, you are safe! You cannot break anything. The diagnostic is on a very low layer. If you are to fast, it will just cut off the connection and that´s it.
It is not possible to use important capacity or block anything, everything is separated. That´s how a BUS works :)

Thanks, the timing calculations are very interesting! Currently I´m waiting 10ms between every byte. I´ll try to change that to 5. But I´m still limited by my Bluetooth communication :( I´m sure I can delete my request delay, because it´s already taken by BT! (I should measure that somehow)

The ISO Documentation also says how to manipulate these timings :D
  • Format 80
  • Target 11
  • Source F1
  • Length XX
  • AccessTimingParameter Request Service Id (0x83)
  • Timing Parameter Identifier (00 read limits, 01 set to default, 02 read active parameter, 03 set parameter)
  • P2min, P2 max, P3 min, ect.
  • Checksum

Response Timing works similar to that, but with SID 0xC3.

My goal was to make OBD II dongle compatible devices/apps work with my bike. So I will always loose time by converting requests, calculating values and converting responses.
Raising from ~4 to 5 or 6 messages per second would be amazing!

Right now I am designing a more straight sketch to be flexible with different SID´s and response/request length. Not very easy, because I need to convert, fake and redirect requests. Also constantly receiving?  :o
A challenge!


Thanks for your response! Maybe we can try to start a diagnostic session by sending 0x81 instead of 0x80 after the start communication request. If this works we might have access to the non functioning registers.

You should take a look at the library I wrote. It contains very simple functions to send and receive messages. I posted the link to my Github on the previous page.


Off course I took a look into your GitHub, as you responded to this thread :D
And I like the idea of not waiting for data responses with a delay. Simple wait for Serial.available() or timeout.

Reduced ISORequestByteDelay from 10 to 5.
Then removed all delays according to the receiver -> We will see if the ECU simply responds as fast as it can or stops due to ISO protocol breach...

The last thing, was to change the static delay between the messages to a dynamic value.
I´m storing the last K-Line Response milis and simply calc the time left:
Code: [Select]
delay(ISORequestDelay - millis() - lastKresponse);
My Emulator counts up to 10(!!!) messages per second, even via bluetooth! Sure, my PC is to fast and I should implement the byte & request delay there as well!

Can´t wait to test that on my bike! Sure, it will slow down to 6-7 responses a second. But that´s great!

0x81 is just a different format with no length information, because messages can only be 1 byte long.
There are two more formats without any source and target information but it seems they are not supported. After fast Init, we receive 0xEA + 0x8F as response. That describes:
Header with Target & Source Information. Additional Length. Normal Timing.
ISO14230 / KWP2000 Protocol.
The more often I read these documents, the more I understand what´s going on there ;)


Alright that sounds good! I just tested my datalogger with the inter byte request time delay of 0 ms instead of 5 ms, and it just worked fine, although the data rate did not increase much.

What I actually meant with sending 0x81 instead of 0x80 is this:
To establish communication you send:

Start communication:     81 11 F1 81 04
Start diagnostic session: 80 11 F1 02 10 80 14

According to the KWP2000 documents the available parameters for the start diagnostic request are:

0x80: ReservedByDocument
0x81: StandardSession

Hence I figured it might help to send 0x81 instead of 0x80 to get positive responses from the currently blocked PIDs. However I just gave it a try and communication could not be established. So probably for the KDS protocol the 0x80 parameter requests already a standard diagnostic session.

Furthermore I tried to requests localIdentifiers from 0x0 to 0xFF, and observed that no positive response were given after 0x62 except for the "Supported PIDs" and the long 0xBF message.


It really works! My Sniffer is amazingly fast  :o
Nearly doubled my requests from 4 to 7, sometimes 8 per Sec (Maybe rounded).

Good to know, that it doesn´t work. But somehow like that, it should change the mode. We will go on investigating :)


That's really good performance, good job! Today I'll try to adjust the timing paramerers. However I first have to do some reading because the timing paramers need to meet certain conditions.

Are there any other interesting requests I can send? Did you ever figure out how to control certain actuators? Btw, do you have access to actual KDS software?


Jul 08, 2016, 10:11 am Last Edit: Jul 08, 2016, 11:03 am by Trib
Today I'll try to adjust the timing paramerers. However I first have to do some reading because the timing paramers need to meet certain conditions.
Spare your time...
Out: 83 02
In:   7F 83 10
0x7F is a negative Response Message. Maybe it is related to the result of the init-sequence, which I explored 4 posts above. It just says "Normal Timing". Probably it also means "not editable"?!?

Are there any other interesting requests I can send? Did you ever figure out how to control certain actuators? Btw, do you have access to actual KDS software?
I´m still investigating the diagnostic fault codes but didn´t get further...
ClearDiag: SID 0x14 PID 0x01.
Read Freezed Data Frame:
Out: 12 01 01
In:   52 01 15 07 01 54

Out: 12 02 01
In:   52 02 10 02 01 54

Out: 12 03 01
In:   52 03 10 01 01 54
It does not fit to any known results in the Z750 diagnostic schema.

No, I have not access to KDS Diag. software :( that would make my life a lot easier! You could sniff the data which is being transferred to the COM-Port and all that guessing, try and error would be unnecessary.
[EDIT] Got it. But you cannot install it, without the specific driver. I´m not sure if I can find them and make my device compatible with that driver. Or rewrite the driver...
[EDIT 2] I could extract the Installer and got access to the executable. It starts but (understandable) could not find a connection. I´ll try to fake the driver somehow and see if I could make it work. This will solve all our problems and answer any question :D

Two things I found out yesterday:
The throttle maximum value is getting bigger and bigger. Started with 405 and currently I´m on 455.
It means, that I will not reach 100% again on full-throttle (works also with engine turned off).
Maybe I will stop storing it onto the EEPROM and adjust it on time.

And I got a little setback, also on throttle valve. In the past I could not see it, because of the slow reaction time.
Turning the gas tap slowly, it raises 5%, 10%, 15%, then it drops to 5% again and went on with 20% and upwards.
Maybe you can keep an eye on that. I don´t know what to change on my calculation...

Code: [Select]
     //201 = 0% = idle, 405 = 100%
      minimum = 201;
      value = ecuResponse[2] * 100 + ecuResponse[3];
      if(value > ThrottlePosMax)
        ThrottlePosMax = value;
        EEPROM.write(0, ThrottlePosMax - 255);       
      //((Value-Minimum) *100) / (Maximum - Minimum) = %     
      //OBD II Calculation: (100/255) * A [Backwards]: 100% = 255
      if(value > minimum)       
        ecuResponse[2] = ((value-minimum) *100) / (ThrottlePosMax - minimum) * 255/100;
        ecuResponse[2] = 0x00;
      //Reduce 2 byte answer to 1 byte:     
      ecuResponse[3] = 0x00;


Jul 08, 2016, 11:16 am Last Edit: Jul 08, 2016, 10:29 pm by Scissor
That's a shame that it's not a supported function. Nevertheless I'm going to give it a try, you never know! :)

Why don't you try to send 12 00 00 (Requests all data, according to chapter 8.4.1 of ISO-14230-3)? I did not read too much about decoding the DTC response message, but I'll take a look at it soon.

Regarding the KDS software, maybe you could take a look at the files with a hex editor to extract some useful data. Or it would be nice if there were some kind of database files which already contain many possible requests.

I still don't really understand the TPS as two bytes are returned (right?) however the TPS would just give a voltage between 0 and 5 V, such that 1 byte would be sufficient to describe the TPS reading. Anyway, I can imagine the sensor is subjected to noise and interference, such that sometimes you get spikes in the signal. I think it could work to incorporate either some kind of thresholding or a running average to minimize the effect of spikes.

Edit: I managed to get the timing down to 0 ms inter byte request delay instead of 5 ms, and 49 ms between a response-request delay instead of 55 ms. Probably the arduino takes 6 ms to execute the code such that overall the delay equals 55 ms. This implies that the maximum working delay is code specific i.e. you need to figure it out for your self. When I got below 49 ms the ECU did not respond to the request.

Edit2: I also got a general reject message when requesting the 0x83 serviceId to read the timing parameters.

Edit3: I tried to use ReadDataByCommonIdentifier (0x22 instead of 0x21 for localIdentifier), but I only got general rejects (7F 22 10) on all parameters I tried. Probably no data is stored in these registers for the '04 Z750.

Edit4: It looks like your DTC readFreezeFrame request is missing a byte.

12 = readFreezeFrameData
01 = freezeFrameNumber
01 = recordAccessMethodId=requestByLocalId
xx = recordIdentification

Seems like you are missing the last byte, of which the possible values are given in table of the ISO-14230-3 document. If you want to request all data from a single freezeframe number send: 12 NN 00, where NN is the freezeFrameNumber of your choice. And even better if you send 12 FF 00, this would send all the data from all freezeFrameNumbers in several response messages. I'm curious if this trick works for you!


Jul 11, 2016, 09:22 am Last Edit: Jul 11, 2016, 05:19 pm by Trib
Searching goes on: Just found another PDF, which seems like a combination of ISO-14230-1,2,3&4 documents.
There are SID´s below 10  explained :o
Like Powertrain diagnostic data 0x01, which for sure will contain the injector and ignition data.
Or Emission related data 0x03 for CO2 purpose.

We are starting the Diagnostic mode the "regular" way. By changing the SID, it should be possible also to manipulate values.

Constantly receiving data should be possible by adding parameters:
0x21, 0x0C, [0x00-0x04], [0xXX]
SID, Speed, Transmission Mode (single, slow, medium, fast, stop), Maximum number of responses

I tried to send 12 00 00 before your edit. Now it´s clear why it didn´t worked!
My ISO Document has only 8.4.4 as maximum 8th chapter... I´ll investigate!
My working solution was 12 X 01 54, where X is my counter. But I don´t understand the Answer.
Also I don´t know PID 54, but the healtech software asks that from startup.
On 0x21 it responds with 0 all the time.
There is a lot of black magic going on there ;)

The KDS Software is compiled in C, there is no way to look into it. But there is a KDSAdapter.dll which might be rewritten and connect to my device. The hope dies last, but I don´t expect to make it work.

Yes, you are right. It must be a value related to the current (operating) voltage. That will explain the different max values. But not the spikes :( I´ll keep an eye on that!
Most sensors are already calculated by the ECU due to the voltage oscillation.
=> After some testing, it has a really strange behaviour. Every 20% it breaks down to 0% very crazy... I have to analyse that.

Nice to know how fast you got it! I am calculating the delay every request. So the time, the code consumes should be irrelevant.
49ms + 6 for your code... I think I´ll stay on 55 :)

The next days I´ll be on a racetrack and go on testing!

[EDIT]: TPS seems like it is calculated different to all the other 2byte values...
Speed and RPM: A * 100 + B.
My only explanation for dropping values is: A * 255 + B. Every time I am passing the 255 mark, it calculates 155 less. That´s why it is dropping lower again.
That´s very bad, because I have to change my min & max calculation and the max-data storage... Both is at not suitable for values greater then 509, at the moment :(


Jul 11, 2016, 10:46 pm Last Edit: Jul 11, 2016, 11:02 pm by Scissor
There appear to be a bunch of documents about the KWP 2000 protocol, but I doubt if all are relevant. Nevertheless we can always try to see if some function works of course!  :)

If I understand you correctly, you send 12 00 00 54? Does the response also have 54 as last byte? Or did you make a typo? Do you have the healtech OBD software? If so, why don't you try to use your sniffer to reveal all the requests?

Regarding the TPS value, I see the same thing happening. I think it simply means that the value is a 16 bit integer e.g. a range of 0-65535. Now all we need to do is normalize it to fit the engineering unit.

TPS = ((256*A+B) / (256*256) )* C

Where C is the constant we are looking for. According to my Z750 manual:

0.99 ∼ 1.03 V DC (at idle throttle opening)
4.19 ∼ 4.39 V DC (at full throttle opening)

The minimal value I get is 213 (0x0 0xD5) and at full open in the range of 871 (0x03 0x67). What first comes to mind is a simple factor of 5 (C = 5*256*256, resulting in simply the 16 bit integer value mulitplied by 5). This yields: 0% open: 1065 mV and 100% 4355 mV. I cannot guarantee this is correct, as I did not check the 100% throttle output properly. Does this fit your readings?
In any case, I'm pretty sure you don't need to update your extreme TPS values during each run, as the output will always be between 0-5V. You could always do some post processing to get a value between 0 and 100%.


Yes, I was sending 12 00 00 54 which does not work. But call DTC group 01 is okay:

To ECU: 12 01 01 54
FrmECU: 52 01 15 07 01 54
To ECU: 12 01 02 54
FrmECU: 52 02 10 02 01 54
To ECU: 12 01 03 54
FrmECU: 52 03 10 01 01 54

If I would have the Software & the Healtech plug, I would have been already through ;)
But I know someone, who sent me some data in the past. That´s where I got the most known PID´s from.

TPS is (on my bike) a value from 00 D8 up to 03 7F, which I tested several times.
I was totally wrong with my dynamic adjustment, because with my old equation, I more or less took an eye on the last byte.
Calculation A*256+B means 201 - 895, which worked great, yesterday (Forgot to reset max value, so I only got max ~70%).

This is not very straight if you compare the calculation with RPM and Speed. But rather then have to fix voltage oscillation :D

Tomorrow start my trackdays. There, I´ll go on testing the data values. After that I´ll keep on going with the diagnostic.


I see, it is indeed a strange result. At this point I'm not sure how to analyse the response message. I agree that it's odd how the conversion formulas differ from each other. I think I did not see the same thing for the SDS protocol. Probably the Kawasaki engineers like to confuse us. :)

Have fun on your trackday, ride save ;)

Go Up