CANWrapper

The CANWrapper is C++ class which is capable of sending CAN messages. A CAN message can be defined as a CAN ID with some data (described in more detail below). The CANWrapper is used to read and write from the CAN bus. Below is some documentation written by @Colin Toft including a background on CAN, but mainly the CAN Wrapper.

What is CAN?

Check out [this page](CAN ) for more information on what the CAN protocol is, how it works and how it is used to connect different parts of our rover.

CAN Setup

To be able to send and receive commands from the command line you will need the can-utils package: sudo apt install can-utils

Testing with VirtualCAN

Check out this page for a guide on setting up a virtual CAN interface:

https://www.pragmaticlinux.com/2021/10/how-to-create-a-virtual-can-interface-on-linux/

Sending messages over CAN

cansend <interface name>  <recipient, 3 hex characters>#<message, 8 hex characters>

Ex:

cansend vcan0 003#01343DB1

Note: the recipient is 3 hex characters but actually is only 11 bits, so it only would go up to 0x7FF. In many cases, like ODrive and our team’s hardware bridge, these 11 bits are further divided, for example into 6 bits and 5 bits (again, check out the CAN wiki page for more info about how this works on our team; lower 5 bits are command ID, upper 6 bits are node ID). These two groups represent the recipient and the actual command/instruction to be sent, respectively.

Shows all messages passing through the CAN interface:

candump <interface name>

Ex:

candump vcan0

CAN Wrapper

The CAN wrapper is the interface responsible for sending and reading messages to and from the CAN bus. It reads and writes from the Jetson CAN ports in order to communicate with the rest of the robot.

Setup Code for Using CAN Wrapper

First, construct the CAN wrapper. It takes in a name for the wrapper, the name of the CAN interface to write to (this is usually something like “can0” or “vcan0”) and the endianness (true for big endian).

can_wrapper_int = uwrt_mars_rover_utilities::UWRTCANWrapper("can_test_int", "can0", true);

Then, we initialize the CAN wrapper. This takes a vector of uint32_t, which are the IDs the wrapper will be reading from. For example, to set up a wrapper reading from IDs 0x001 and 0x002:

 

How to Use

Both reading and writing are templated, meaning you can choose any type to write and read from the CAN bus. Note that frames are only 8 bytes, so pick a type that is at most 8 bytes large. Smaller types like int and float also work.

Writing is pretty straightforward, data that you pass to the wrapper is directly sent to the specified ID. Reading is a little more complicated, since the wrapper uses a separate thread that is always checking to see if anything new has arrived from one of the IDs (the ones you give in the init method). Then, we can call the getLatestFromID method to read the most recent message from that ID. Note that you can only read a message from an ID once, if you attempt to read twice before the ID sends another message then the read method will return false signifying that no data is available. This is to avoid reading stale information.

Reading from the can bus takes in two parameters, a variable (passed by reference) to store the data in, and the ID to read from. The method returns true if the read was successful. In this example, we are reading a 64-bit unsigned integer from ID 0x001.

Writing to the bus takes in the same two parameters: data and an ID. Again, it returns true if the write is successful. This example writes the float 5.0f to ID 0x002:

 

You can look at the CAN test node file for a more detailed example of how to use the wrapper to read and write to IDs.

 

Endianness

One common cause of errors when using the CAN wrapper is endianness. Most recently, we have been using big endian (pass true into the CAN wrapper constructor) but be aware that endianness can cause messages to be different than you expect. Endianness simply refers to the order of the bytes. For example, to store the number 5 in two bytes, you would write 0x0005. However, on some systems, the order of the bytes is backwards: 0x0500. This is just another possible pitfall to look out for when using the CAN wrapper.

 

CAN Test Node

Run the test node (make sure that the CAN interface is running first, use candump and cansend to test this):

The test node should automatically read and log messages it receives over CAN, try sending it some with cansend to the IDs that it reads from (001 to 004)

You can also publish events which the test node will read, and then send over the CAN bus

ID is hardcoded and is set in the test node cpp file

The frame is encoded as a uint64 (or float64)