Serial Link#
Introduction#
The serial_link class allows for a stream of raw bytes to be sent between robots. It’s designed for robot-to-robot communication where the transmitting and receiving robot both understand the contents of the data stream.
Every usage of send adds data to the linked V5 Brain’s queue, and the queue is read first-in, first-out (FIFO). If multiple messages are sent before the other V5 Brain uses receive, they will be stored and returned one at a time in the order they were sent. Because messages can queue, repeatedly sending the same status every loop may create backlog; for time-critical logic, send only when values change.
Important: Both robots must be running projects that use serial_link at the same time, or no data will be sent/received.
Class Constructors#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Class Destructor#
Destroys the serial_link object and releases associated resources.
~serial_link();
参数#
范围 |
Type |
描述 |
|---|---|---|
|
|
The Smart Port that the message link is connected to, written as |
|
|
The name of this link. It is recommended that this unique string is long enough that when hashed by vexos it will create a unique ID. A bad link name would be something generic such as “vexlink” as it may be used by another team. |
|
|
The type of link, either
|
|
|
Whether the serial_link object is wired (defaults to
|
Notes#
VEXlink supports both wireless and wired communication, with wired connections recommending a modified smart cable to prevent power routing issues.
For wireless communication, each robot needs a V5 Robot Radio connected to a Smart Port.
The VEXlink Radio can be used alongside a V5 Controller’s VEXnet radio, which should be connected to the highest numbered Smart Port to avoid conflicts.
要创建 VEXlink,两个 V5 主控模块都必须连接到 V5 机器人无线电模块。
Example#
Code for Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCode for Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Member Functions#
The serial_link class includes the following member functions:
isLinked— Checks if the V5 Brains are paired and communicating on this link.send— Sends a message to the paired Brain.receive— Waits for and returns the next incoming message.received— Registers a function to be called whenever a new message is received.
Before calling any serial_link member functions, a serial_link instance must be created, as shown below:
Code for Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCode for Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Returns whether the V5 Brains on a serial link are paired with one another.
Available Functionsbool isLinked();
This function does not have any parameters.
Return ValuesReturns a Boolean indicating whether the V5 Brains are linked:
true— The two V5 Brains are paired and communicating on this link.false— The two V5 Brains are not paired on this link.
It is good practice to always check to ensure the V5 Brains are linked at the start of a project before running any further code.
Code for Robot 1
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::manager, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.print("Robot 1 - Manager"); Brain.Screen.newLine(); Brain.Screen.print("Sending message..."); // Message to send const char* message = "Hello Robot 2"; // Send the message link.send((uint8_t*)message, strlen(message));
Code for Robot 2
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::worker, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); Brain.Screen.print("Waiting..."); // Buffer to store incoming bytes uint8_t buffer[32] = {0}; int32_t n = link.receive(buffer, sizeof(buffer) - 1); // Null-terminate if (n > 0) { buffer[n] = 0; // Display the message that was sent Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); Brain.Screen.print((char*)buffer); } else { Brain.Screen.newLine(); Brain.Screen.print("No message received"); }
send#
Sends a message to the paired Brain.
Available Functions1 — Sends a message using a byte buffer.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Sends a message using a character buffer.
int32_t send( const char *buffer, int32_t length );
范围 |
Type |
描述 |
|---|---|---|
|
|
The buffer to send to the other linked V5 Brain. |
|
|
The length of the buffer to send. |
Returns an int32_t representing the number of bytes sent.
Code for Robot 1
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::manager, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 1 - Manager"); // Track last sent state uint8_t lastState = 255; // impossible initial value // Tell Robot 2 when the screen is being pressed while (true) { uint8_t state = Brain.Screen.pressing() ? 1 : 0; // Only send if state changed if (state != lastState) { link.send(&state, 1); lastState = state; } wait(0.02, seconds); }
Code for Robot 2
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::worker, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); Brain.Screen.print("Waiting..."); // Track the last state uint8_t lastShown = 255; while (true) { // Variable stores 1 - pressed, 0 - not pressed uint8_t state = 0; int32_t n = link.receive(&state, 1, 200); // Only update screen if state changes if (n == 1 && state != lastShown) { Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); // Display text if Robot 1's screen is being pressed if (state == 1) { Brain.Screen.print("Manager IS being pressed!"); } else { Brain.Screen.print("Manager is NOT being pressed"); } lastShown = state; } wait(0.02, seconds); }
receive#
Waits for and returns the next incoming message.
Available FunctionsParameters1 — Receives a message into a character buffer with optional timeout.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
范围 |
Type |
描述 |
|---|---|---|
|
|
The buffer to store the received message. |
|
|
The length of the buffer. |
|
|
How long in milliseconds |
Returns an int32_t representing the number of bytes received.
receivereturns the next queued message from the other linked V5 Brain.Messages are read in FIFO order (oldest unread first).
If the queue is empty when
receiveis called, it waits up to the specifiedtimeoutMsfor a new message.If no message arrives in that window,
receivereturns0, and any message sent afterward remains in the queue to be read the next timereceiveis used.
Code for Robot 1
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::manager, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 1 - Manager"); // Track last sent state uint8_t lastState = 255; // impossible initial value // Tell Robot 2 when the screen is being pressed while (true) { uint8_t state = Brain.Screen.pressing() ? 1 : 0; // Only send if state changed if (state != lastState) { link.send(&state, 1); lastState = state; } wait(0.02, seconds); }
Code for Robot 2
// Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::worker, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); Brain.Screen.print("Waiting..."); // Track the last state uint8_t lastShown = 255; while (true) { // Variable stores 1 - pressed, 0 - not pressed uint8_t state = 0; int32_t n = link.receive(&state, 1, 200); // Only update screen if state changes if (n == 1 && state != lastShown) { Brain.Screen.clearScreen(); Brain.Screen.setCursor(1, 1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); // Display text if Robot 1's screen is being pressed if (state == 1) { Brain.Screen.print("Manager IS being pressed!"); } else { Brain.Screen.print("Manager is NOT being pressed"); } lastShown = state; } wait(0.02, seconds); }
received#
Registers a function to be called whenever the V5 Brain receives a sent message.
Available Functions1 — Registers a callback function for every received messages.
void received( void (* callback)(const char *, const char *, double) );
2 — Registers a callback invoked for every received message that includes an additional int32_t field.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Registers a callback invoked only for received messages whose name matches message.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Registers a callback invoked only for received messages whose name matches message, where the message payload includes an additional int32_t field.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
范围 |
Type |
描述 |
|---|---|---|
|
|
The message name (string) to match. When a received message’s name matches this value, the |
|
|
A previously defined function that runs when the V5 Brain receives a message matching |
This function does not return a value.
Notesreceivedcallbacks are called with four arguments:
callback(message, linkname, index, value)
Argument |
描述 |
|---|---|
|
The message name that was received (for example, |
|
The link name the message was received from. |
|
The integer value sent with the message (if provided). |
|
The float value sent with the message (if provided). |
Code for Robot 1
// Send left or right when pressed void screen_pressed() { if (Brain.Screen.xPosition() < 240) { link.send((uint8_t*)"left", 4); } else { link.send((uint8_t*)"right", 5); } } int main() { /* vexcodeInit() is only required when using VEXcode. Remove vexcodeInit() if compiling in VS Code. */ vexcodeInit(); // Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::manager, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } Brain.Screen.print("Robot 1 - Manager"); Brain.Screen.pressed(screen_pressed); }
Code for Robot 2
// Called when message received void received_callback(uint8_t *buffer, int32_t length) { char msg[32]; // Copy safely and null terminate int n = (length < 31) ? length : 31; memcpy(msg, buffer, n); msg[n] = '\0'; Brain.Screen.clearScreen(); Brain.Screen.setCursor(1,1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); // Display if Robot 1's screen is pressed on left or right if (strcmp(msg, "left") == 0) { Brain.Screen.print("Manager pressed LEFT"); } else if (strcmp(msg, "right") == 0) { Brain.Screen.print("Manager pressed RIGHT"); } } int main() { /* vexcodeInit() is only required when using VEXcode. Remove vexcodeInit() if compiling in VS Code. */ vexcodeInit(); // Create the link serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::worker, true); // Do not run code UNTIL the Brains are linked while (!link.isLinked()) { wait(0.1, seconds); } link.received(received_callback); Brain.Screen.clearScreen(); Brain.Screen.setCursor(1,1); Brain.Screen.print("Robot 2 - Worker"); Brain.Screen.newLine(); Brain.Screen.print("Waiting..."); }