ลิงก์อนุกรม#
การแนะนำ#
คลาส 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 ชื่อลิงก์ที่ไม่ดีคือชื่อทั่วไป เช่น “vexlink” เพราะอาจมีทีมอื่นใช้งานอยู่แล้ว |
|
|
ประเภทของลิงก์ อาจเป็น
|
|
|
ตรวจสอบว่าอ็อบเจ็กต์ serial_link เชื่อมต่อแบบใช้สายหรือไม่ (ค่าเริ่มต้นคือ
|
หมายเหตุ#
VEXlink รองรับทั้งการสื่อสารแบบไร้สายและแบบมีสาย โดยสำหรับการเชื่อมต่อแบบมีสาย แนะนำให้ใช้สายเคเบิลอัจฉริยะแบบดัดแปลงเพื่อป้องกันปัญหาการเดินสายไฟ
สำหรับการสื่อสารแบบไร้สาย หุ่นยนต์แต่ละตัวจำเป็นต้องมีวิทยุหุ่นยนต์ V5 ที่เชื่อมต่อกับสมาร์ทพอร์ต
วิทยุ VEXlink สามารถใช้งานร่วมกับวิทยุ VEXnet ของคอนโทรลเลอร์ EXP ได้ โดยควรเชื่อมต่อเข้ากับ Smart Port ที่มีหมายเลขสูงสุดเพื่อหลีกเลี่ยงปัญหาความขัดแย้ง
ในการสร้าง VEXlink จำเป็นต้องเชื่อมต่อ EXP Brain ทั้งสองตัวเข้ากับ V5 Robot Radio
ตัวอย่าง#
รหัสสำหรับหุ่นยนต์ตัวที่ 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 Brains จับคู่และสื่อสารกันผ่านลิงก์นี้หรือไม่send— ส่งข้อความไปยังสมองที่จับคู่กันreceive— รอและส่งคืนข้อความขาเข้าถัดไปreceived— ลงทะเบียนฟังก์ชันที่จะถูกเรียกเมื่อใดก็ตามที่ได้รับข้อความใหม่
ก่อนเรียกใช้ฟังก์ชันสมาชิก serial_link 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 Brains ที่เชื่อมต่อผ่านลิงก์อนุกรมนั้นจับคู่กันหรือไม่
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 — ลงทะเบียนฟังก์ชันเรียกกลับที่จะถูกเรียกใช้เฉพาะเมื่อได้รับข้อความที่มีชื่อตรงกับข้อความนั้น
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — ลงทะเบียนฟังก์ชันเรียกกลับที่จะถูกเรียกใช้เฉพาะกับข้อความที่ได้รับซึ่งมีชื่อตรงกับข้อความ โดยที่ส่วนข้อมูลของข้อความจะมีฟิลด์ 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 ได้รับข้อความที่ตรงกับข้อความ |
ฟังก์ชันนี้ไม่ส่งค่ากลับ
Notesได้รับ
receivedฟังก์ชัน โดยมีอาร์กิวเมนต์ 4 ตัว:
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..."); }