A minimal protocol-agnostic communication framework and C library for in systems with diverse message types. BotSpeak produces and consumes raw byte arrays, so it can be used over serial, CAN, or any other byte-stream based protocol. The Physical Layer and Data Link Layer of the OSI model should be handled by the developer.
- Serialize: Convert a meaningful data-type (such as a
float) to a byte-array. - Deserialize: Convert a byte-array to a meaningful data-type (such as a
float). - Frame: A high-level data structure. This contains the data as an ID, a length, a timestamp, and a byte-array. See
DataFrame_TypeDef. - Pack frame: Convert a byte-array into a frame with metadata.
- Unpack frame: Convert a frame with metadata into a byte-array.
The data frame is adapted from the Serial Frame Format implemented in the Python CAN library. Source: https://python-can.readthedocs.io/en/stable/interfaces/serial.html#serial-frame-format
However, our implementation allows for a message longer than 8 bytes (up to 256 bytes). The frame structure is as follows:
| Byte index | Name | Length | Value |
|---|---|---|---|
| Start of Frame (SOF) | 1 byte | 0xAA |
|
|
|
Frame ID | 4 bytes | Unique identifier for the data type |
| Data Length | 1 byte | Length of data payload |
|
|
|
Timestamp | 4 bytes | Timestamp of packet inception, expressed as a Unix timestamp |
|
|
Data |
|
Actual data payload |
| End of Frame (EOF) | 1 byte | 0xBB |
This is realised in the software as a structure:
typedef struct {
uint32_t frameID;
uint32_t timestamp;
uint8_t dataLength;
uint8_t* data;
} DataFrame_TypeDef;BotSpeak handles the end-to-end conversion from useful data types (e.g., an array of floats) to a byte array directly usable for transmission, and vice versa. BotSpeak is designed to transmit receive Little-Endian data, and a separate header is provided for Big-Endian hosts.
It is recommended to define a set of IDs, and data sizes for your application. An example, implemented using Enums, is provided with this library. Please see Integrated Brain Conventions Documentation for more details.
Typical usage steps:
-
Serialize data: Convert useful data types to a byte array using the provided type-agnostic serialization function. If you're providing an array, you're required to provide the size of each element.
-
Generate a data frame: Create a
DataFrame_TypeDefstructure with the frame ID, timestamp, and serialized byte array. Simply populate an instance of typeDataFrame_TypeDef. -
Pack the frame into bytes: Generate a transmission-ready byte array from the
DataFrame_TypeDefstructure using the provided packing function. -
Transmit the byte array: Send the packed byte array over your chosen communication protocol (e.g., UART, CAN, USB).
-
Receive a byte array: Receive a byte array from your communication protocol.
-
Unpack the received byte array into a frame: Convert the received byte array back into a
DataFrame_TypeDefstructure using the provided unpacking function. -
Deserialize the data: Convert the byte array in the
DataFrame_TypeDefstructure back into useful data types using the provided deserialization function.
Make sure to include the BotSpeak header in your source files:
#include "bot_speak.h"Note
If you're working on a Big-Endian system, include the Big-Endian specific header instead:
#include "bot_speak_be.h"-
Navigate to your workspace root.
-
Build the package:
colcon build --packages-select botspeak
-
Source the workspace:
source install/setup.bash -
Run the executables:
ros2 run botspeak test_frame_ops ros2 run botspeak test_frame_ops_be ros2 run botspeak test_real_world
-
Create a build directory:
mkdir build && cd build
-
Configure and build:
cmake .. make
-
Run the executables from the
builddirectory:./test_frame_ops ./test_real_world
-
Optionally, install the library and executables (may require
sudo):sudo make install