Custom CAN Device Programming

Hi Everyone,

I have been trying to find an answer to this and so far have been unsuccessful. I know we can add custom circuits to the CAN BUS as rule R80 A states this can be done. What I am having issues finding is how do I communicate with these devices over the network? I have found in the WPILib that there are a few different CAN specific Classes.

Examples would be:

CAN
CANData
CANStatus
CANJNI
along with a few others.

Has anyone tried this so far? If so what do you need to do? I am just looking for some guidance on at least what these Classes might do so I can try and work on interfacing with some custom ideas we as a team have. I so far have a base understanding and almost have the custom parts ready but we are not sure how to connect them to the whole system properly. Thanks for you time!

2 Likes

At the lowest level, anything on an “FRC CAN” network must conform to this spec: https://media.screensteps.com/attachment_assets/assets/002/527/448/original/FRC_CAN_Device_Specifications.docx. At a shared-object level, you can hook the FRCNetComm interface according to CANSessionMux. That’s the most basic way to access CAN messages from robot code.

Thanks CarlosGJ do you know if the CANSessionMux is also available in JAVA? Secondly once we are able to access CAN messages on the network how do we define the data being sent? Example is if we want to make a device that handles sensors for a specific part of our robot and then it needs to report when to shut down a motor at a certain point based on an encoder or a limit switch being hit. How do we transmit that back to the RoboRio? I am still learning everything on CAN so I kinda understand how these objects see each other on the network but unsure how they pass information fully.

Thanks again!

You can get access to a subset of the CANSessionMux functions via CANJNI: https://first.wpi.edu/FRC/roborio/beta/docs/java/edu/wpi/first/wpilibj/can/CANJNI.html

As to the second part of your question, CANbus is a low-level communications spec. It basically allows you to send some bytes (up to 8) across the network. Interpreting those bytes, and responding accordingly (such as controlling a motor), is up to you to implement in your software.

1 Like

I would very much recommended avoiding the low level jni calls with the session mux, and instead just using the CAN class. As long as your IDs conform to the doc that was postest above, with using the team use manufacturer id, the CAN class will be the easiest way to get communication. You will then have to implement the can IDs on your client device, but it’s not too hard.

Thanks I saw that api and was not sure it was the same thing. But with the following line I can send info out and there is another for receive.

FRCNetCommCANSessionMuxSendMessage(int messageID,
byte[] data,
int periodMs).

public static byte[] FRCNetCommCANSessionMuxReceiveMessage(java.nio.IntBuffer messageID,
int messageIDMask,
java.nio.ByteBuffer timeStamp)

Another question I have is the messageID since I am looking at the CAN Device Specs sheet you linked I want to clarify that the messageID is just the 10 bit value needed to id a particular command or message type. Is this correct? If so how would you ID a second device that is similar? or is the messageID the whole 28bit arbitration ID? Lastly what would the messageIDMask be? Same with bytebuffer timestamp and the int Periodms? I just want to make sure I am fully understanding all the terms. It seems like we have multiple terms that mean the same thing and I just want to fully grasp the information provided.

Now I look at the CAN Class and its a lot easier but maybe not as granular for working with. But that maybe easier to work with since the granular side of it might get to complex.

1 Like

CAN Messages do not contain the address of a specific device connected to the CAN network.
All messages are seen and read by every device on the network.
If you want to address a specific device, you will have to make provisions for it in the data you send. This means the device you are sending the data to must also be able to extract and interpret the address info from the message.

Well, the messages do in fact contain the address of a specific device on the bus, but they’re also received by all of the nodes. Specifically, FRC CAN devices use the 29-bit ID field, with an FRC-specific segmentation of the 29 bits into things like device ID and manufacturer.

1 Like

A CAN message ID is 29 bits, and you need all 29 bits to identify a specific message. The 10-bit field is an API index, but it only makes sense in the context of a particular manufacturer and device type. An API index of 3 identifies a completely different message in the context of a Rev Spark Max as opposed to a CTRE PDP. The 6-bit Device Number field is used to differentiate identical devices (this is the “CAN ID” that you see in Phoenix Tuner, etc.).

This is a mask allowing you to capture multiple message IDs with the same statement. If your mask is 0x0, you will capture all CAN messages, regardless of ID. If your mask is 0x1FFFFFFF (i.e. 29 1s), you will only capture messages whose ID exactly matches the messageID field. See https://en.wikipedia.org/wiki/Mask_(computing) for more.

Agreed. But this is a FRC specific implementation and code is still required to pull-out the Device ID from the 29-bit Message ID.
You also need a device and its driver compatible with the FRC implementation of the Message ID breakdown.

You need code to pull out (and parse) all of the components of the 29-bit ID. While it’s not commonly done, it’s legal for different devices to have the same 6-bit device number. For example, a PDP and a Talon could both have a device number of 3. Only the complete 29-bit ID is required to be unique*.

Luckily, the CANSessionMux framework does some of the work for you. You can, for example, set the mask bits to only care about manufacturer, device type, and device number, and thereby receive only messages from that device, but with any API.

*Well, one-way uniqueness. A given 29-bit ID should indicate a particular device in most cases, but a given device will send messages with many different APIs.

1 Like

I see how the messageID is built in the 29 bits. I am guessing that the API Class and the API Index basically act as my message or my data that is being sent right? Because in the CAN Class you have a data amount of 8 bits that can be sent. Or is this a separate part of information that is sent over the network?

public void writePacket​(byte[] data, int apiId)

public boolean readPacketNew​(int apiId, [CANData])

Though reading through this now it sounds like from the constructor this is used to just send a set amount of data to the certain device as the Constructor takes care of most of the 29 bits and you are just finishing up the API portion of the message system and then providing specific data to the CAN device or receiving data from that device specifically if its not part of the normal WPI Library. Am I right?

The API class and index describe the data in the message. The actual data payload can be up to 8 bytes, and comes after the ID fields (see https://en.wikipedia.org/wiki/CAN_bus#Extended_frame_format). The API just specifies what data is in this particular message. Check out the CAN interface for the Jaguar, which was effectively the reference implementation of CAN for FRC: http://carlosgj.org/Lorentz/7870.SW-RDK-BDC24-UG-7243.pdf

1 Like

Ok I will look at that later today. With that being said has anyone ever been able to connect an Arduino to an FRC CAN Bus? If so how did you structure the code for the ID and data? I have the library for Arduino CAN but I’m looking at how to adapt the arduino to FRC needs. Any insight would be most appreciated!

I know 900 was able to connect their Jetson to the CANbus. There might be something helpful in their code.

There is example code for connecting the hero board to the roborio in the CTRE github examples (auton selector). I assume something similar could be done with an arduino. Example with both the hero code (C#) and the RoboRio code (JAVA) is found at: https://github.com/CrossTheRoadElec/Phoenix-Examples-Languages/tree/master/HERO%20C%23/FRC%20Auton%20Selector

Before we get any further, do you have a CAN shield for your arduino?

If you don’t, it’s going to be pretty difficult to get it to work. See https://stackoverflow.com/questions/22089689/is-it-possible-to-have-can-on-arduino-without-extra-hardware

Clayton_Yocom I do have the CAN Bus Shield and other CAN arduino adapters so I am there. Is there any other extra hardware needed beyond that? Or is it just code at this point?

Sounds like you’re headed in the right direction.

I think you just need code at this point. I’d check out the link from @wits (which is a great example of what you are trying to do) and try to use that as a reference to write some test communications for the arduino to see if you can get it talking that way.

While we’re happy to have people look at our code, we linked up WPI calls to the CAN bus with CTRE code which implemented them. We didn’t do anything with custom devices, just reused existing WPIlib PCM / PDP / etc. code, compiled to run on the Jetson.