Liên kết nối tiếp#
Giới thiệu#
Lớp serial_link cho phép gửi một luồng byte thô giữa các robot. Nó được thiết kế cho giao tiếp giữa các robot, trong đó cả robot gửi và robot nhận đều hiểu nội dung của luồng dữ liệu.
Mỗi lần sử dụng send sẽ thêm dữ liệu vào hàng đợi của EXP Brain được liên kết và hàng đợi được đọc theo thứ tự vào trước ra trước (FIFO). Nếu nhiều tin nhắn được gửi trước khi EXP Brain khác nhận được, chúng sẽ được lưu trữ và trả về từng tin nhắn một theo thứ tự chúng được gửi. Vì tin nhắn có thể được xếp hàng đợi, việc liên tục gửi cùng một trạng thái trong mỗi vòng lặp có thể tạo ra tắc nghẽn; đối với logic cần xử lý nhanh, chỉ gửi khi giá trị thay đổi.
Quan trọng: Cả hai robot phải cùng lúc chạy các dự án sử dụng serial_link , nếu không sẽ không có dữ liệu nào được gửi/nhận.
Hàm tạo lớp#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Lớp Destructor#
Hủy đối tượng serial_link và giải phóng các tài nguyên liên quan.
~serial_link();
Thông số#
Tham số |
Kiểu |
Sự miêu tả |
|---|---|---|
|
|
Cổng thông minh mà liên kết tin nhắn được kết nối đến, được viết dưới dạng |
|
|
Tên của liên kết này. Nên sử dụng chuỗi ký tự duy nhất này đủ dài để khi được mã hóa bởi vexos sẽ tạo ra một ID duy nhất. Một tên liên kết không tốt sẽ là một cái tên chung chung như “vexlink” vì nó có thể đã được nhóm khác sử dụng. |
|
|
Loại liên kết, hoặc
|
|
|
Cho biết đối tượng serial_link có kết nối dây hay không (mặc định là
|
Ghi chú#
VEXlink hỗ trợ cả giao tiếp không dây và có dây, với kết nối có dây khuyến nghị sử dụng cáp thông minh đã được sửa đổi để tránh các sự cố về định tuyến nguồn.
Để liên lạc không dây, mỗi robot cần một bộ thu phát vô tuyến V5 Robot Radio được kết nối với một cổng thông minh Smart Port.
Bộ thu phát VEXlink có thể được sử dụng cùng với bộ thu phát VEXnet của bộ điều khiển EXP, cần được kết nối với Cổng thông minh có số hiệu cao nhất để tránh xung đột.
Để tạo VEXlink, cả hai EXP Brain phải được kết nối với Robot Radio V5.
Ví dụ#
Mã lệnh cho Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredMã lệnh cho Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Chức năng thành viên#
Lớp serial_link bao gồm các hàm thành viên sau:
isLinked— Kiểm tra xem EXP Brains có được ghép nối và giao tiếp trên liên kết này hay không.send— Gửi tin nhắn tới Brain được ghép nối.receive— Chờ và trả về tin nhắn đến tiếp theo.received— Đăng ký một hàm được gọi bất cứ khi nào nhận được tin nhắn mới.
Trước khi gọi bất kỳ hàm thành viên serial_link , cần phải tạo một thể hiện serial_link , như được hiển thị bên dưới:
Mã lệnh cho Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredMã lệnh cho Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Trả về trạng thái cho biết các EXP Brains trên liên kết nối tiếp có được ghép nối với nhau hay không.
Available Functionsbool isLinked();
Hàm này không có tham số nào.
Return ValuesTrả về giá trị Boolean cho biết liệu các EXP Brain có được liên kết với nhau hay không:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
Việc kiểm tra xem các EXP Brains đã được liên kết với nhau chưa trước khi chạy bất kỳ đoạn mã nào khác là một thực hành tốt ngay từ đầu dự án.
Mã lệnh cho 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));
Mã lệnh cho 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#
Gửi tin nhắn đến thiết bị Brain được ghép nối.
Available Functions1 — Gửi tin nhắn bằng cách sử dụng bộ đệm byte.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Gửi tin nhắn bằng cách sử dụng bộ đệm ký tự.
int32_t send( const char *buffer, int32_t length );
Tham số |
Kiểu |
Sự miêu tả |
|---|---|---|
|
|
Bộ đệm để gửi đến EXP Brain được liên kết khác. |
|
|
Độ dài của bộ đệm cần gửi. |
Trả về một giá trị int32_t biểu thị số byte đã gửi.
Mã lệnh cho 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); }
Mã lệnh cho 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#
Chờ và trả về tin nhắn đến tiếp theo.
Available FunctionsParameters1 — Nhận một thông báo vào bộ đệm ký tự với tùy chọn thời gian chờ.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Tham số |
Kiểu |
Sự miêu tả |
|---|---|---|
|
|
Bộ đệm để lưu trữ thông điệp đã nhận. |
|
|
Độ dài của vùng đệm. |
|
|
Thời gian chờ (tính bằng mili giây) |
Trả về một giá trị int32_t biểu thị số byte đã nhận được.
receivetrả về tin nhắn tiếp theo trong hàng đợi từ EXP Brain được liên kết khác.Các tin nhắn được đọc theo thứ tự FIFO (tin nhắn cũ nhất chưa được đọc trước).
Nếu hàng đợi trống khi lệnh
receiveđược gọi, nó sẽ đợi tối đa thời gian được chỉ định làtimeoutMsđể nhận tin nhắn mới.Nếu không có tin nhắn nào đến trong khoảng thời gian đó,
receivetrả về0, và bất kỳ tin nhắn nào được gửi sau đó vẫn nằm trong hàng đợi để được đọc vào lần tiếp theoreceiveđược sử dụng.
Mã lệnh cho 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); }
Mã lệnh cho 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#
Đăng ký một hàm để được gọi bất cứ khi nào EXP Brain nhận được một tin nhắn đã gửi.
Available Functions1 — Đăng ký một hàm gọi lại cho mỗi tin nhắn nhận được.
void received( void (* callback)(const char *, const char *, double) );
2 — Đăng ký một hàm gọi lại được thực thi cho mỗi tin nhắn nhận được có chứa thêm trường int32_t.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Đăng ký một hàm gọi lại chỉ được gọi đối với các tin nhắn đã nhận có tên trùng với tin nhắn.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Đăng ký một hàm gọi lại chỉ được gọi cho các tin nhắn đã nhận có tên khớp với tin nhắn, trong đó phần nội dung tin nhắn bao gồm một trường int32_t bổ sung.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Tham số |
Kiểu |
Sự miêu tả |
|---|---|---|
|
|
The message name (string) to match. When a received message’s name matches this value, the |
|
|
Một hàm đã được định nghĩa trước đó sẽ chạy khi EXP Brain nhận được một thông báo khớp với thông báo |
Hàm này không trả về giá trị nào.
Notesreceivedlệnh gọi lại được gọi với bốn đối số:
callback(message, linkname, index, value)
Lý lẽ |
Sự miêu tả |
|---|---|
|
Tên tin nhắn đã nhận được (ví dụ: |
|
Tên liên kết mà tin nhắn được nhận từ đó. |
|
Giá trị số nguyên được gửi kèm theo tin nhắn (nếu có). |
|
Giá trị số thực được gửi kèm theo tin nhắn (nếu có). |
Mã lệnh cho 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); }
Mã lệnh cho 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..."); }