序列鏈路#
介紹#
serial_link 類別允許在機器人之間發送原始位元組流。它專為機器人之間的通訊而設計,其中發送機器人和接收機器人都能理解資料流的內容。
每次使用 send 都會將資料加入到關聯的 EXP Brain 的佇列中,佇列採用先進先出 (FIFO) 的讀取方式。如果在另一個 EXP Brain 使用接收操作之前發送了多個訊息,這些訊息將被存儲,並按發送順序逐條返回。由於訊息可以排隊,因此在每次循環中重複發送相同的狀態可能會導致積壓;對於時間關鍵型邏輯,僅當值發生變化時才發送訊息。
重要提示:兩個機器人必須同時運行使用 serial_link 項目,否則將不會發送/接收任何資料。
類別建構函數#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
類別析構函數#
銷毀 serial_link 物件並釋放相關資源。
~serial_link();
參數#
範圍 |
類型 |
描述 |
|---|---|---|
|
|
訊息鏈路連接的智慧型端口,寫成 |
|
|
此連結的名稱。建議此唯一字串足夠長,以便 Vexos 對其進行哈希處理後能夠產生唯一的 ID。不建議使用“vexlink”之類的通用名稱,因為它可能被其他團隊使用。 |
|
|
The type of link, either
|
|
|
serial_link 物件是否為有線連接(預設為
|
筆記#
VEXlink 支援無線和有線通信,有線連接建議使用改良的智慧電纜,以防止電源路由問題。
對於無線通信,每個機器人都需要一個連接到智慧型連接埠的 V5 機器人無線電模組。
VEXlink 無線電可以與 EXP 控制器的 VEXnet 無線電一起使用,應連接到編號最高的智慧型連接埠以避免衝突。
要建立 VEXlink,兩個 EXP 大腦都必須連接到 V5 機器人無線電。
例子#
機器人 1 的程式碼
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWired機器人2的程式碼
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
成員功能#
serial_link 類別包含以下成員函數:
isLinked— 檢查 EXP Brain 是否已配對並透過此連結進行通訊。send— 向配對的大腦發送訊息。receive— 等待並傳回下一個傳入的訊息。received— 註冊一個函數,每當收到新訊息時呼叫函數。
在呼叫任何 serial_link 函數之前,必須先建立一個 serial_link ,如下所示:
機器人 1 的程式碼
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWired機器人2的程式碼
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
返回串行鏈路上的 EXP Brain 是否彼此配對。
Available Functionsbool isLinked();
此函數沒有任何參數。
Return Values傳回布林值,指示 EXP Brains 是否已連線:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
在專案開始時,運行任何其他程式碼之前,最好始終檢查 EXP Brains 是否已連接。
機器人 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));
機器人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#
向配對的大腦發送訊息。
Available Functions1 — 使用位元組緩衝區傳送訊息。
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — 使用字元緩衝區傳送訊息。
int32_t send( const char *buffer, int32_t length );
範圍 |
類型 |
描述 |
|---|---|---|
|
|
要傳送到另一個已連接的 EXP Brain 的緩衝區。 |
|
|
要傳送的緩衝區長度。 |
傳回 int32_t ,表示發送的位元組數。
機器人 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); }
機器人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#
等待並返回下一條傳入的訊息。
Available FunctionsParameters1 — 將訊息接收到字元緩衝區中,並可選擇設定逾時時間。
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
範圍 |
類型 |
描述 |
|---|---|---|
|
|
用於儲存接收到的訊息的緩衝區。 |
|
|
緩衝區長度。 |
|
|
|
傳回 int32_t ,表示接收到的位元組數。
receive返回來自另一個已連接的 EXP Brain 的下一個已排隊訊息。訊息以先進先出(FIFO)順序讀取(最舊的未讀訊息優先)。
如果在呼叫
receive時佇列為空,則最多等待指定的timeoutMs以接收新訊息。如果在該視窗中沒有訊息到達,
receive返回0,並且之後發送的任何訊息都將保留在佇列中,以便在下次使用receive時讀取。
機器人 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); }
機器人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#
註冊一個函數,當 EXP Brain 收到發送的訊息時,該函數將被呼叫。
Available Functions1 — 為收到的每個訊息註冊一個回呼函數。
void received( void (* callback)(const char *, const char *, double) );
2 — 註冊一個回呼函數,該函數會針對每個接收到的訊息調用,其中包含一個額外的 int32_t 欄位。
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — 註冊一個回呼函數,該回呼函數僅在接收到名稱與 message 相符的訊息時才會呼叫。
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — 註冊一個回呼函數,該回呼函數僅在接收到名稱與 message 匹配的訊息時調用,其中訊息有效負載包含一個額外的 int32_t 欄位。
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
範圍 |
類型 |
描述 |
|---|---|---|
|
|
The message name (string) to match. When a received message’s name matches this value, the |
|
|
當 EXP Brain 收到與 |
此函數不傳回值。
Notesreceived回呼被調用,並帶有四個參數:
callback(message, linkname, index, value)
爭論 |
描述 |
|---|---|
|
收到的訊息名稱(例如, |
|
收到該訊息的連結名稱。 |
|
訊息中發送的整數值(如果提供)。 |
|
訊息中發送的浮點值(如果提供)。 |
機器人 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); }
機器人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..."); }