CanBus for Beginners - Super Simple

From the messages I saw on the V-bus it will be possible to tell if steer has been disabled by the tractor as F0 doesn’t return target curve once the tractor disables steer.

Yea it’s something like that, but remember if speed is zero it returns zero so don’t really want to cut out at zero speed and may need to wait for 1 or 2 messages when engaging

Only 2 CAN interface and an arduino wifi UDP to control the tractor … Awesome! It only remains to draw a box that fits in the ashtray to put them … It would make a very sexy installation!

2 Likes

I am literally deciding where to put things now. Good idea!! As a simple retro fit component that would be really cool and perfectly possible. Switched power is already there right behind it for the lighter socket.

Just studying the 700 SCR BUS wiring diagrams. All three (K,V and ISO) busses are present in the roof connectors as far as I can see. This would mean the whole AOG setup could be mounted on the roof plate in the sun roof.

I’ll check this out this afternoon. It would make installation really easy as everything is there in one place.

2 Likes
name = [0x00, 0x00, 0xA0, 0x27, 0x00, 0x17, 0x02, 0x20]

IndentityNumber = name[0] | name[1] << 8 | (name[2] & 0x1f) << 16
ManufacturerCode = name[2] >> 5 | name[3] << 3
ECUInstance = name[4] & 0x07
FunctionInstance = name[4] >> 3
Funktion = name[5]
Reserved = name[6] & 0x01
VehicalSystem = name[6] >> 1
VehicalSystemInstance = name[7] & 0x0F
IndustryGroup = (name[7] >> 4) & 0x07
ArbitraryAddressCapable = name[7] >> 7

print(f"ManufacturerCode:    (0x{ManufacturerCode:03X}) {ManufacturerCode:8}")
print(f"Funktion:             (0x{Funktion:02X}) {Funktion:8}")
print(f"VehicalSystem:        (0x{VehicalSystem:02X}) {VehicalSystem:8}")
print(f"IndustryGroup:        (0x{IndustryGroup:02X}) {IndustryGroup:8}")

ManufacturerCode: (0x13D) 317 => Navtronics Bvba
Funktion: (0x17) 23 => Vehicle Navigation
VehicalSystem: (0x01) 1 => Tractor
IndustryGroup: (0x02) 2 => Agricultural Equipment

AddressClaim isnt Fendt specific, its essential for J1939 buses. A) to avoid SA duplicates B) to enumerate devices on the bus

In general the SA is hardcoded, ECU just expects it to be 0x2C. At least for me ECU didnt respond until i claimed the address. Maybe interface is disabled if no navigation controller is present.

Maybe its possible to gracefully disconnect after sending data[2] = 0 first??

3 Likes

Thanks for sharing your knowledge. This will be a fantastic way to implement Agopengps.

Which socket are you using to connect to the Claas tractor? The 9 pin connector by the power sockets on the right hand side of the cab or the socket behind the seat on the left? Does Claas work with the code from project 1?

That Claas was a real rough quick test the other day, Use Project 1 or “Show all messages” from Project 2 and see whats on the bus. If you see xxACxxxx that will be the WAS thats the first step.

3 Likes

Hello everyone,

Has anyone already sniffed the PTO speed and the tractor speed on a John deere via CAN bus?

Fendt wiring seems to be a reasonably simple operation. X4250 in the roof that is plugged into an empty male connector (X5052) has all the connections needed. VBUS,KBUS, ISOBUS, Constant power, Accessory power, Earth and three wires for serial that I think just go to the 9 pin D connector at the rear of the cab roof. I’ve populated that connector to give connections to evertything.

IMG_9090s

IMG_9091s

This is my prototyping setup on the sunroof GPS base plate. IF it works and when it’s configuration is more definite I’ll try to make a much neater installation with a custom PCB.

IMG_9097s

…anyone spot the very 80’s item amongst the build? :joy:

6 Likes

Perfect setup, it will work :ok_hand:

1 Like

If I continue with USB I’ll solder up the connections on the hub and possibly use the same 5v power unit used on the AOG standard PCB. I just happen to have loads of these adjustable buck converters lying around. The BNO085 isn’t wired up yet and I’ve never even looked at the machine arduino code.

USB makes code or receiver alterations easy and to be fair, despite lots saying they have issues and UDP is better, I’ve not had any trouble on my old 716.

Everything is either glued or tied down so this setup should be fine till I finalise it.

1 Like

Cassette box housing the F9p?

3 Likes

:joy: :+1:

That F9P board has been used for several different bits of evaluation so a housing was needed and it’s contents had long since ended up as spaghetti!!

I’m going to keep the go/end section code simple for a start but once it is working maybe keeping track of the fendt press/release counter would be good. This could then be coded to prevent AOG re pressing a button if you press go or end early manually. Double presses can bugger up timer events in the headland management procedures as every extra press advances the event chain one step regardless of distance or time. (so might not give a spool operation enough time for instance)

Hello,

So, I think I’ve understand why there is “32 bits CAN ID” displayed while SAE J1939 norm is 29 bits CAN ID.

SAE CAN2.0B arbitration field (32 bits), CAN ID and SAE J1939 CAN ID format:
Capture

First, we have to look at the MCP2515 datasheet:

Standart CAN ID and extanded CAN ID are store in 4 registers:

  • Two registers for standard CAN ID:
    image

  • Two registers for extanded CAN ID:
    image

Then, take a look at the “MCP_CAN Library for Arduino” function that read and treat these registers: mcp2515_read_id.
Here is the code of this function:

void MCP_CAN::mcp2515_read_id( const INT8U mcp_addr, INT8U* ext, INT32U* id )
{
INT8U tbufdata[4];

*ext = 0;
*id = 0;

mcp2515_readRegisterS( mcp_addr, tbufdata, 4 );

*id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5);

if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) ==  MCP_TXB_EXIDE_M ) 
{
                                                                    /* extended id                  */
   *id = (*id<<2) + (tbufdata[MCP_SIDL] & 0x03);
    *id = (*id<<8) + tbufdata[MCP_EID8];
    *id = (*id<<8) + tbufdata[MCP_EID0];
    *ext = 1;
}

}

So this function read these 4 registers, treat them and store the CAN ID in a 32 bits variable.

Here is a visual summary of what this function does to store CAN ID in the 32 bits variable (hop this is clear):
Capture2

To test if this is a extanded CAN ID, the library just test the status if the EXIDE bit of SIDL buffer. CAN norm is: IDE bit is 0 for a standart arbitration fiel and 1 for an extended arbitration field.

So at the end of this function, we have:

  • 32bits variable “ID” containing the 29 bits of CAN ID. As the 3 MSB will always be 0, if we diplay it, we will have the 29bits CAN ID
  • a variable “EXT” set to 1 for an extanded CAN ID (important for the following).

So apparently here, if we print our CAN ID, we should have our 29bits CAN ID limited to a max value of 0x1FFF FFFF.

But in the library README file, we can read this: “If the ID AND 0x80000000 EQUALS 0x80000000, the ID is of the Extended type, otherwise it is standard.”.

0x80000000 = 1000 0000 0000 0000 0000 0000 0000 0000 (bin).

So if we applied this treament of our previous variable with the extanded CAN ID, the test of the README doesn’t work:
image

So I assume that, somewhere in the library (but don’t find where, lot of function and pointers), when the “EXT” variable meaning that we have an extanded CAN ID is set to 1, the MSB of our 32 bits “ID” variable containing the extanded CAN ID is flip to 1. And then, the test work like discribed in the README:
image

So the library used the MSB bit of the 32 bits “ID” variable to indicate if this is a standart ID or an extended CAN ID.

And when I look to the example of the library (for exemple, “CAN_receive.ino” library exemple), before using the CAN ID (to display it by exemple), they applied a 0x1FFFFFFF mask to flip again the 3 MSB of the 32bits “ID” variable to 0:

if((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
  sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (rxId & 0x1FFFFFFF), len);

image

So with this mask, we goes back to you 29 bits CAN ID confoming to the CAN norm.

@CommonRail : I look on the .ino of project 1: before using the 32 bits variable “ID” containing the 29 bits CAN ID (to display it by example), you don’t applied this 0x1FFFFFFF mask. So you keep the MSB of this variable to 1, while it’s not a bit of CAN ID, it just a bit used for library function.
It also why you display CAN ID superior to 1FFF FFFF which is not possible in accordance to CAN standard.

Specifically your last number of your CAN ID in hex form will always be 9 or 8 (instead of 0 or 1):
image

One improvment that can be done on your code @CommonRail is to keep this mask before displaying the CAN ID: the CAN ID displayed will conform to a standard 29bits (and not a mix of CAN ID + library cheat).
Hop it makes sens.

Math

1 Like

That’s a very good explanation of how it all works :+1:. And explains very well how the library / CAN module can understand each other easily.

So there’s two ways to look at it I guess.

  1. Keep the filter so the library / CAN module add-ons are removed.
  2. Don’t worry about the filter and just remember / know how the CAN module works witch you have just explained very well.

Only for extended ID’s if the far left HEX number is 8 or 9 that means someone (myself) deleted the code to make the BIN bit32 = zero. So it really means 0 or 1.

And on the sending examples it only uses the 1st bit of HEX 8/9 (1000/1001) so doesn’t matter if you enter as 0/1 or 8/9 it’s the same thing.

1 Like

So you’re using the steer angle output from AOG right? Is the CAN message you’re sending to the steering in the machine the target curvature, that you could get directly from the pure pursuit algorithm in AOG and just feed that to the machine?

Sorry if it’s been addressed earlier in the thread but I was just too excited to read everything through before asking, will do the homework later :grin:

1 Like

The message to & from machine contains the target curve, actual curve, plus parts to engage / disengage.

The target curve is from AOG but not only from pure pursuit, that’s just one option AOG has to work it out.

You also need to use the Arduino WAS counts per degree to scale the CAN message output. Also in some machines they are super fast lock to lock witch is good but you need to limit the speed / change of the target curve this is also done in the Arduino department.

Hello,

Yes I agree, now that we have understood how it’s work, it is not a necessity to edit already shared INO.
We just have keep in mind the far left number:

  • 8 = 0 for CAN ID
  • 9 = 1 for CAN ID

As @g33k and @flipper80 was also questionning this strange CAN ID, now we have the answer.

Perhaps just have this in mind to reintroduce the 1FFFFFF mask in the upcomming INO.

Math

1 Like