رابط تسلسلي#
مقدمة#
تتيح فئة serial_link إرسال سلسلة من البايتات الخام بين الروبوتات. وهي مصممة للتواصل بين الروبوتات حيث يفهم كل من الروبوت المُرسِل والمُستقبِل محتوى سلسلة البيانات.
كل استخدام للدالة send يُضيف بيانات إلى قائمة انتظار وحدة المعالجة المنطقية المرتبطة، وتُقرأ هذه القائمة وفقًا لأسلوب “الوارد أولًا يُخرج أولًا” (FIFO). إذا تم إرسال عدة رسائل قبل أن تستقبلها وحدة المعالجة المنطقية الأخرى، فسيتم تخزينها وإعادتها واحدة تلو الأخرى بالترتيب الذي أُرسلت به. نظرًا لإمكانية تراكم الرسائل في قائمة الانتظار، فإن إرسال الحالة نفسها بشكل متكرر في كل دورة قد يُؤدي إلى تراكمها؛ لذا، بالنسبة للمنطق الحساس للوقت، يُنصح بالإرسال فقط عند تغيير القيم.
هام: يجب أن يقوم كلا الروبوتين بتشغيل مشاريع تستخدم 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، والذي يجب توصيله بالمنفذ الذكي ذي الرقم الأعلى لتجنب التعارضات.
لإنشاء 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 مقترنة وتتواصل عبر هذا الرابط.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 Brains الموجودة على وصلة تسلسلية مقترنة ببعضها البعض.
Available Functionsbool isLinked();
لا تحتوي هذه الدالة على أي معلمات.
Return Valuesيُرجع قيمة منطقية تشير إلى ما إذا كانت عقول EXP مرتبطة ببعضها البعض أم لا:
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 );
المعلمة |
يكتب |
وصف |
|---|---|---|
|
|
المخزن المؤقت لإرساله إلى الدماغ التجريبي المرتبط الآخر. |
|
|
طول المخزن المؤقت المراد إرساله. |
Returns an int32_t representing the number of bytes sent.
كود للروبوت 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);
المعلمة |
يكتب |
وصف |
|---|---|---|
|
|
المخزن المؤقت لتخزين الرسالة المستلمة. |
|
|
طول المخزن المؤقت. |
|
|
كم من الوقت بالمللي ثانية |
Returns an int32_t representing the number of bytes received.
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 — يسجل رد نداء يتم استدعاؤه فقط للرسائل المستلمة التي يتطابق اسمها مع الرسالة، حيث تتضمن حمولة الرسالة حقل int32_t إضافي.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
المعلمة |
يكتب |
وصف |
|---|---|---|
|
|
اسم الرسالة (نص) المراد مطابقته. عند مطابقة اسم الرسالة المستلمة مع هذه القيمة، يتم استدعاء دالة رد الاتصال |
|
|
دالة مُعرَّفة مسبقًا يتم تشغيلها عندما يتلقى الدماغ التجريبي رسالة مطابقة للرسالة |
هذه الدالة لا تُرجع قيمة.
Notesتم استلام
receivedدالة رد نداء بأربعة وسائط:
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..."); }