Using native protocol with Arduino


#1

I understand that the Arduino library makes use of the ascii protocol to communicate with ODrive.

I would like to modify the library to make use of the native protocol.

However, I’m having trouble finding a specification of the native protocol. I went through theprotocol interface, but I’m not sure what the content of the messages needs to be.

Is there any specification available? Alternatively, could anyone provide a simple example of using the native protocol outside the Python library?

Thank you.


#2

Not sure where, or if, it’s linked to in the doc index or similar, but here are details on the packet format: https://github.com/madcowswe/ODrive/blob/master/docs/protocol.md

Also keep in mind this particular workaround https://github.com/madcowswe/ODrive/blob/eb07260c3ea57e74c59432fd036b275b608d85d0/Firmware/fibre/python/fibre/protocol.py#L276 when writing your client code. e.g. if you’re sending message with sequence number “1”, the firmware is going to reply to that message with 129 instead of echoing back your “1”.

Although the sequence number is a short, you’ll need to treat it as a ushort since that bit is being used as a flag instead. That is, when you hit sequence number 32767 you’ll want to reset to 0 prior to your increment call.

I recommend looking at things with a USB packet inspector/monitor while using odrivetool and examining the payloads. I’d assume the UART packets will be the same. I didn’t even know you could use the native protocol with UART until this post.


#3

Hi @metanoic,

Thanks for your reply.

I’m aware of the document you linked, but what I’m looking for is the actual specifications of the message content.

Using a USB packet monitor is a good idea so I’ll try that and post back.

In the meantime, if anyone could provide some background on the messages content it would be a great help.


#4

Ah, I understand your question now I think. In short, the specification is dynamic.

The message contents themselves (both transmitted and received) will vary depending on the “endpoint” you’re dealing with (byte index 2 and 3 (3rd and 4th)) - though there is a CRC that should be sent with each message; that CRC is static between messages (it is not a CRC of the message itself, but rather a CRC of the schema). “Endpoint” not in the USB sense… think of it merely as the numeric address of a remote property, method or function.

You can get a list of endpoints by querying endpoint 0 and providing 1 for the CRC. That will return a JSON representation of all the other endpoints, their accepted parameters, their return type and flags for read and write. You can see a non-JSON version of the schema in this file: https://github.com/madcowswe/ODrive/blob/master/Arduino/ArduinoI2C/odrive_endpoints.h and an outdated JSON version here: https://pastebin.com/GF9M5Hu6 (this is what endpoint 0 returns, minus any whitespace)

For example: To set the Axis0 position setpoint, you’d use EndpointID 87 and provide a float value starting at the packet’s 7th byte followed by the CRC.

Note that all communication is Little Endian rather than network byte order / Big Endian. The CRC will change any time the firmware changes in a manner that alters the schema in any way. It’s basically just a safeguard against communicating with a different version of the protocol than your program is anticipating, which is fairly important since the order/number of endpoint is dictated by the execution order in the firmware and some users machines can kill or maim.

Hop on the discord and say hi in the development channel.


#5

Ah, that makes perfect sense. So a library using the binary protocol would query endpoint 0 and get an endpoint schema, whch would subsequently be used to get the ids of endpoints of interest to read from/write to.

Thanks a lot for the help! Will hop on discord soon :slight_smile:


#6

Correct. If it’s a private project then you can just read/write directly to endpoint X without querying for the schema. When the device stops accepting your commands after updating firmware then just ensure the endpoints you’re writing to haven’t changed their numbers or signatures and update your CRC and continue on. If it’s a public library or similar, you may want to use the schema to generate your library’s code or deal with it dynamically like odrivetool does.


#7

I started digging into this one but got stuck fairly early on while trying to get the JSON schema using UART. I’ve reflashed ODrive with CONFIG_UART_PROTOCOL=native and issued the following from Arduino:

unsigned char pk[] = {0x80, 0x00, 0x00, 0x01};
Serial1.write(pk, sizeof(pk));

But I get no response. A similar request using the ascii protocol works fine by the way, i.e. it returns the values as expected.

Obviously I got the packet formating/content wrong. So I’d greatly appreciate it if anyone could share an example of a simple schema request packet that works. Then I can take it from there for the rest.

Thanks!