Łącze szeregowe#
Wstęp#
Klasa serial_link umożliwia przesyłanie strumienia surowych bajtów między robotami. Jest ona przeznaczona do komunikacji między robotami, w której zarówno robot nadający, jak i odbierający rozumieją zawartość strumienia danych.
Każde użycie send dodaje dane do kolejki połączonego modułu EXP Brain, a kolejka jest odczytywana metodą FIFO (pierwszy wszedł, pierwszy wyszedł). Jeśli wiele wiadomości zostanie wysłanych przed użyciem funkcji Receive przez drugi moduł EXP Brain, zostaną one zapisane i zwrócone pojedynczo w kolejności wysłania. Ponieważ wiadomości mogą być kolejkowane, wielokrotne wysyłanie tego samego statusu w każdej pętli może powodować zaległości. W przypadku logiki krytycznej czasowo, wysyłaj tylko wtedy, gdy wartości się zmienią.
Ważne: Oba roboty muszą jednocześnie realizować projekty wykorzystujące serial_link , w przeciwnym razie żadne dane nie zostaną wysłane ani odebrane.
Konstruktory klas#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Destruktor klasy#
Niszczy obiekt serial_link i zwalnia powiązane zasoby.
~serial_link();
Parametry#
Parametr |
Typ |
Opis |
|---|---|---|
|
|
Inteligentny port, do którego podłączony jest link wiadomości, zapisany jako |
|
|
Nazwa tego linku. Zaleca się, aby ten unikalny ciąg znaków był wystarczająco długi, aby po hashowaniu przez vexos utworzył unikalny identyfikator. Zła nazwa linku to coś ogólnego, na przykład „vexlink”, ponieważ może być używana przez inny zespół. |
|
|
Typ łącza, albo
|
|
|
Czy obiekt serial_link jest przewodowy (domyślnie
|
Notatki#
VEXlink obsługuje zarówno komunikację bezprzewodową, jak i przewodową. W przypadku połączeń przewodowych zaleca się stosowanie zmodyfikowanego inteligentnego kabla, aby zapobiec problemom z zasilaniem.
Do komunikacji bezprzewodowej każdy robot potrzebuje radia V5 podłączonego do inteligentnego portu.
Radio VEXlink można stosować wraz z radiem VEXnet kontrolera EXP. Aby uniknąć konfliktów, należy je podłączyć do portu Smart Port o najwyższym numerze.
Aby utworzyć VEXlink, oba mózgi EXP muszą być podłączone do radia robota V5.
Przykład#
Kod dla Robota 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredKod dla Robota 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Funkcje członkowskie#
Klasa serial_link zawiera następujące funkcje członkowskie:
isLinked— Sprawdza, czy mózgi EXP są sparowane i komunikują się za pomocą tego łącza.send— Wysyła wiadomość do sparowanego Mózgu.receive— czeka na następną przychodzącą wiadomość i ją zwraca.otrzymano
received— Rejestruje funkcję, która ma zostać wywołana po otrzymaniu nowej wiadomości.
Przed wywołaniem jakiejkolwiek funkcji członkowskiej serial_link należy utworzyć instancję serial_link , jak pokazano poniżej:
Kod dla Robota 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredKod dla Robota 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Zwraca informację, czy mózgi EXP na łączu szeregowym są ze sobą sparowane.
Available Functionsbool isLinked();
Ta funkcja nie ma żadnych parametrów.
Return ValuesZwraca wartość logiczną wskazującą, czy mózgi EXP są połączone:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
Dobrą praktyką jest zawsze sprawdzenie na początku projektu, czy EXP Brains są połączone, zanim uruchomisz dalszy kod.
Kod dla Robota 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));
Kod dla Robota 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#
Wysyła wiadomość do sparowanego Mózgu.
Available Functions1 — Wysyła wiadomość używając bufora bajtów.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Wysyła wiadomość używając bufora znaków.
int32_t send( const char *buffer, int32_t length );
Parametr |
Typ |
Opis |
|---|---|---|
|
|
Bufor do wysłania do drugiego połączonego mózgu EXP. |
|
|
Długość bufora do wysłania. |
Zwraca wartość int32_t reprezentującą liczbę wysłanych bajtów.
Kod dla Robota 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); }
Kod dla Robota 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#
Oczekuje na następną przychodzącą wiadomość i zwraca ją.
Available FunctionsParameters1 — Otrzymuje wiadomość do bufora znaków z opcjonalnym limitem czasu.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Parametr |
Typ |
Opis |
|---|---|---|
|
|
Bufor do przechowywania odebranej wiadomości. |
|
|
Długość bufora. |
|
|
Jak długo (w milisekundach) |
Zwraca wartość int32_t reprezentującą liczbę odebranych bajtów.
receive, zwraca następną oczekującą wiadomość z innego połączonego mózgu EXP.Wiadomości są odczytywane w kolejności FIFO (najstarsze nieprzeczytane jako pierwsze).
Jeżeli kolejka jest pusta w momencie wywołania
receive, to czeka ona do określonego czasutimeoutMsna nową wiadomość.Jeżeli w tym oknie nie pojawi się żadna wiadomość, polecenie
receivezwraca0, a każda wiadomość wysłana później pozostaje w kolejce do odczytania przy następnym użyciu poleceniareceive.
Kod dla Robota 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); }
Kod dla Robota 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#
Rejestruje funkcję, która ma zostać wywołana za każdym razem, gdy EXP Brain otrzyma wysłaną wiadomość.
Available Functions1 — Rejestruje funkcję wywołania zwrotnego dla każdej odebranej wiadomości.
void received( void (* callback)(const char *, const char *, double) );
2 — Rejestruje wywołanie zwrotne wywoływane dla każdej odebranej wiadomości zawierającej dodatkowe pole int32_t.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Rejestruje wywołanie zwrotne wywoływane tylko dla odebranych wiadomości, których nazwa pasuje do message.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Rejestruje wywołanie zwrotne wywoływane tylko dla odebranych wiadomości, których nazwa pasuje do message, gdzie treść wiadomości zawiera dodatkowe pole int32_t.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Parametr |
Typ |
Opis |
|---|---|---|
|
|
Nazwa wiadomości (ciąg znaków) do dopasowania. Gdy nazwa odebranej wiadomości pasuje do tej wartości, wywoływana jest funkcja zwrotna |
|
|
Wcześniej zdefiniowana funkcja uruchamiana, gdy EXP Brain otrzyma wiadomość pasującą do |
Ta funkcja nie zwraca wartości.
NotesOtrzymano
receivedsą wywoływane z czterema argumentami:
callback(message, linkname, index, value)
Argument |
Opis |
|---|---|
|
Nazwa otrzymanej wiadomości (na przykład |
|
Nazwa łącza, z którego otrzymano wiadomość. |
|
Wartość całkowita wysyłana w wiadomości (jeśli podano). |
|
Wartość zmiennoprzecinkowa wysyłana w wiadomości (jeśli została podana). |
Kod dla Robota 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); }
Kod dla Robota 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..."); }