Jump to content

Transmitting CAN data to OEM modules


DerekAE86

Recommended Posts

I'm trying to figure out how to use the Link to generate usable CAN data to communicate to an OEM computer module.

Specifically a Toyota EPS computer that requires Wheel Speed and Engine RPM to engage and then provide variable assistance.

I know the format, but I'm just not sure how to accurately recreate it - most notably the Checksum Toyota uses.

The RPM signal is CAN Id HEX 02C4 (Decimal 708) 500kps & 20hz rate
It's an 11 byte message with 8 bytes of data.
The first two bytes are the RPM data and the last byte is the Checksum

It would look something like this:
     (02 C4)           (08)    (0B B8)   (00 00)    (00 00)      (00)             (??)
     (id 708)            (8)      (3000)       (0)           (0)           (0)               (?)
Engine Speed    Length     rpm    unknown unknown unknown  Checksum

Now the Checksum can be calculated by the following formula:
ID+Length+Sum(Data[1]:Data[Length-1]) & 0xFF

To provide some clarity, Data[1] = the first byte of data. So in the above example is 0B
And we want to add from Data[1] to Data[7], because the 8th byte is going to be the Checksum
Which is why Data[7] is written as Data[Length-1] because the same formula can be used on shorter Length messages.

So for the above example it would be: 02+C4+08+(0B+B8+00+00+00+00+00) = 191

Then we see the issue is the answer is larger than the size of 1 byte.
Which is why the "& 0xFF" mask is applied to bring it down to the size of 1 byte.

So the Checksum is 91.

Meaning this full CAN message will be: (02 C4) (08) (0B B8) (00 00) (00 00) (00) (91)

And if the RPM decreased from 3000 to 1250rpm the new message would be: (02 C4) (08) (04 E2) (00 00) (00 00) (00) (B4)

You could generate the Checksum in decimal with a Math Block since the ID and Length are known values and all you would have to do is convert the RPM value to the appropirate decimal to span 2 bytes.

But in order to guarantee accuracy you'd have to use the floor() function and the forumla would go over the character limit very quickly.

What I put together so far was;

Label = Math Block 1
Parameter a = Engine Speed
Equation = (((floor(a)/256)-floor(a/256))*256)+floor(a/256)+206

To explain;
This takes RPM (for example 7000rpm) and divides it by 256 (max number of bits)
This gives you 27.34375
Using the floor() function we know we've got a value of 27 in the 1st byte. aka HEX 1B
Now we take the RPM/256 (27.34375) and subtract floor(RPM/256) (27) which leaves us with 0.34375
We then multiply this by 256. (0.34375*256=88) to give us the value of the 2nd byte. aka HEX 58

We have now converted 7000rpm into HEX (1B 58) or Decimal (27, 88)

Then we can add the known fixed values. HEX (02 C4) (08) aka Decimal (2, 196) (8)

So the final value is 2+196+8+27+88 = 321

321 is larger than 1 byte (256) so you'd use the floor() function again in another Math Block
Parameter a = Math Block 1
Equation = a-(floor(a/256)*256)

This just works out how many times 256 goes into Parameter a and removes that total.

Which in the example is 321 - 256 = 65

So our Checksum is Decimal 65 / HEX 41

Meaning the final CAN message would be: (02 C4) (08) (1B 58) (00 00) (00 00) (00) (41)

I'd love to know if there was an easier or more elegent way of doing this. Since currently I can't fit this formula in the Math Block Equation field anyway...

Link to comment
Share on other sites

An EPAS wont even need real RPM will it?  Just send a constant message of effectively 0 RPM when not running and a constant 1000RPM when you want the steering to wake up.  Only speed will be needed to vary assist.

 

Link to comment
Share on other sites

52 minutes ago, Adamw said:

An EPAS wont even need real RPM will it?  Just send a constant message of effectively 0 RPM when not running and a constant 1000RPM when you want the steering to wake up.  Only speed will be needed to vary assist.

 

Yeah it only uses RPM to start assistance before it detects wheel speed.

But I'm up against the same issue with providing wheel speed via CAN and I was just using RPM as an example.

There are 4 IDs that provide speed, 2 are Front R/L and Rear R/L which don't appear to have a Checksum so that shouldn't be an issue.
But the other 2 do require a Checksum like RPM. I'm not sure which ones the EPS wants so I want to make sure I can emulate all of them before fully committing to this.

Link to comment
Share on other sites

1 hour ago, Adamw said:

So what does the other speed message with the checksum look like, and what is its transmit rate?  Is there a counter byte? 

(00 B4) (08) (00 00) (00 00) (00) (1B 58) (2F)

(180) (8) (0) (0) (0) (7000) (47)

Speed, 8 Bytes, Unknown, Unknown, Distance, Speed, Checksum (calculated the same as the RPM example)

7000 in this case is actually 70.00km/h

Still 500kbit, could be 20hz, could be 10hz not sure yet.

Link to comment
Share on other sites

In this case if the speed has a resolution of 0.01kmh, then the largest speed that byte 6 can represent is only 2.55kmh.  If we are only using that to vary steering assist level then I don't see a need for that kind of resolution.  I think it would be satisfactory to just leave byte 6 as a zero all the time which will simplify the checksum.  So effectively the epas would see a speed in increments of 2.56 instead of 0.01.  - so accelerating from standstill it would see: 0, 2.56kmh,  5.12kmh etc.  

You dont need to do the floor etc to truncate the checksum to one byte since we are already telling the ecu to send it out as 8bits width it will just roll over automatically above ff/255.  

I didnt spend much time thinking about it but it appears correct to me.  

JEfhD4h.png

 

 

Link to comment
Share on other sites

Ignoring Byte6 and only looking at Byte7 to see "some" movement opposed to an accurate representaiton of actual speed isn't ideal since EPS needs to vary(decrease) the assist as speed increases.

In this example it will only ever think the car is at car-park speeds and continue to give full assist even if you're going 100km/h+

Really need to use both Byte6 and 7 to give the full picture for Speed.

Link to comment
Share on other sites

Sorry, I just edited my post as I meant the 7th byte rather than byte 7.  So what Im suggesting is to leave the LSB (byte 6) at zero and using only the MSB (byte 5) to represent speed.  The smallest speed your EPAS will see is 0x0100 which according to your sample would be 2.56kmh and the largest speed would be 0xFF00 or 652.80kmh and you can vary that speed in 2.5kmh increments.  

The only reason they would be using very high resolution speed on the bus originally would be for the odometer calculation.  

Link to comment
Share on other sites

Ah yes I understand where you're coming from now.

Could do similar with RPM, it would be slightly more crude since you'd be seeing steps of 256rpm. But it'd be an improvement over just transmitting a static rpm.

Link to comment
Share on other sites

2 hours ago, DerekAE86 said:

But it'd be an improvement over just transmitting a static rpm.

Not really.  The EPAS will not use it, it will only be looking for a certain bit to activate or for the RPM to exceed a fixed threshold.  So for example send 0RPM anytime you dont want it running and 1000RPM when you want it running, there is no need for anything in between as there are only two states - on or off.  You could even use something like idle status to activate it so for example it only activates after the startup decay had finished and idle ign control is working.  

Link to comment
Share on other sites

On 7/6/2023 at 9:56 PM, Adamw said:

You dont need to do the floor etc to truncate the checksum to one byte since we are already telling the ecu to send it out as 8bits width it will just roll over automatically above ff/255.  

Thinking about this further. Do you even need the Math Block to work out the Checksum?
Could you achieve the same thing by doing Paramater="Driving Wheel Speed" and Offset of +188 for Byte 8?

Link to comment
Share on other sites

  • 2 months later...

G’day, trying to incorporate a Yaris EPAS with my FuryX. I’ve copied Adam’s stream for the vehicle speed, but would like to confirm I’ve got the RPM stream right. Single frame of 8 bytes, none for ID position, set Ignition Idle Status as the parameter on start position 0, width 16, multiplier of 1024. With this, the sum of 708 + 8 + 1024 &FF will always be 0xCC (dec 204). So second parameter I’ve just chucked in the same ignition idle status, given it multiplier of 0 and offset of 204. 
 

Am I correct that this will give the desired result of turning the steering on when the motor is running?

Link to comment
Share on other sites

In theory this should work for sending the RPM signal when the engine is actually running, then nothing when the engine isn't running:

image.png.d9b2f5913d275a3035f9623e8105cac7.png

Setup on a Transmit User Stream @ 500kbit/s 20hz rate on ID 708.

Also if the speed doesn't work, you can try sending speed via ID 176 and 178 (@ 500kbit/s 10hz) with the following for both:

image.png.9ce307f88bd25cd583864a07e4d1127f.png

176 has Front R and Front L, 178 has Rear R and Rear L. This is the ABS wheel speed data before it's processed by other modules.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...