Serielle Verbindung#
Einführung#
Die Klasse serial_link ermöglicht den Austausch eines Datenstroms von Rohbytes zwischen Robotern. Sie ist für die Roboter-zu-Roboter-Kommunikation konzipiert, bei der sowohl der sendende als auch der empfangende Roboter den Inhalt des Datenstroms verstehen.
Jede Verwendung von send fügt Daten zur Warteschlange des verknüpften EXP Brain hinzu. Die Warteschlange wird nach dem FIFO-Prinzip (First-In, First-Out) gelesen. Werden mehrere Nachrichten gesendet, bevor der andere EXP Brain die Empfangsfunktion verwendet, werden diese in der Reihenfolge ihres Eingangs gespeichert und zurückgesendet. Da Nachrichten in einer Warteschlange landen können, kann das wiederholte Senden desselben Status in jeder Schleife zu einem Rückstau führen. Senden Sie daher für zeitkritische Logik nur dann Nachrichten, wenn sich Werte ändern.
Wichtig: Beide Roboter müssen gleichzeitig Projekte ausführen, die serial_link verwenden, sonst werden keine Daten gesendet/empfangen.
Klassenkonstruktoren#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Klassendestruktor#
Zerstört das Objekt serial_link serial_link 1) und gibt die zugehörigen Ressourcen frei.
~serial_link();
Parameter#
Parameter |
Typ |
Beschreibung |
|---|---|---|
|
|
Der Smart Port, mit dem die Nachrichtenverbindung hergestellt wird, wird als |
|
|
Der Name dieses Links. Es wird empfohlen, dass diese eindeutige Zeichenkette lang genug ist, damit sie beim Hashing durch Vexos eine eindeutige ID erzeugt. Ein ungeeigneter Linkname wäre beispielsweise „vexlink“, da er möglicherweise bereits von einem anderen Team verwendet wird. |
|
|
Der Verbindungstyp, entweder
|
|
|
Gibt an, ob das serial_link-Objekt kabelgebunden ist (Standardwert:
|
Anmerkungen#
VEXlink unterstützt sowohl drahtlose als auch kabelgebundene Kommunikation. Für kabelgebundene Verbindungen wird ein modifiziertes Smart-Kabel empfohlen, um Probleme mit der Stromversorgung zu vermeiden.
Für die drahtlose Kommunikation benötigt jeder Roboter ein V5-Roboterradio, das mit einem Smart Port verbunden ist.
Das VEXlink-Funkgerät kann zusammen mit dem VEXnet-Funkgerät eines EXP-Controllers verwendet werden. Um Konflikte zu vermeiden, sollte das VEXnet-Funkgerät an den Smart Port mit der höchsten Nummer angeschlossen werden.
Um eine VEXlink-Verbindung herzustellen, müssen beide EXP Brains mit einem V5 Robot Radio verbunden werden.
Beispiel#
Code für Roboter 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCode für Roboter 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Mitgliedsfunktionen#
Die Klasse serial_link enthält die folgenden Memberfunktionen:
isLinked— Prüft, ob die EXP Brains gepaart sind und über diese Verbindung kommunizieren.send— Sendet eine Nachricht an das gepaarte Gehirn.receive— Wartet auf die nächste eingehende Nachricht und gibt sie zurück.received— Registriert eine Funktion, die aufgerufen wird, sobald eine neue Nachricht empfangen wird.
Bevor Sie eine der Memberfunktionen von serial_link aufrufen, muss eine serial_link Instanz erstellt werden, wie unten gezeigt:
Code für Roboter 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCode für Roboter 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Gibt zurück, ob die EXP Brains an einer seriellen Verbindung miteinander gekoppelt sind.
Available Functionsbool isLinked();
Diese Funktion hat keine Parameter.
Return ValuesGibt einen booleschen Wert zurück, der angibt, ob die EXP-Gehirne miteinander verbunden sind:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
Es empfiehlt sich, zu Beginn eines Projekts immer zu überprüfen, ob die EXP Brains verknüpft sind, bevor weiterer Code ausgeführt wird.
Code für Roboter 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));
Code für Roboter 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#
Sendet eine Nachricht an das zugehörige Gehirn.
Available Functions1 — Sendet eine Nachricht mithilfe eines Byte-Puffers.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Sendet eine Nachricht mithilfe eines Zeichenpuffers.
int32_t send( const char *buffer, int32_t length );
Parameter |
Typ |
Beschreibung |
|---|---|---|
|
|
Der Puffer, der an das andere verbundene EXP Brain gesendet werden soll. |
|
|
Die Länge des zu sendenden Puffers. |
Gibt einen int32_t zurück, der die Anzahl der gesendeten Bytes darstellt.
Code für Roboter 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); }
Code für Roboter 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#
Wartet auf die nächste eingehende Nachricht und gibt diese zurück.
Available FunctionsParameters1 — Empfängt eine Nachricht in einen Zeichenpuffer mit optionalem Timeout.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Parameter |
Typ |
Beschreibung |
|---|---|---|
|
|
Der Puffer zum Speichern der empfangenen Nachricht. |
|
|
Die Länge des Puffers. |
|
|
Wie lange in Millisekunden |
Gibt einen int32_t zurück, der die Anzahl der empfangenen Bytes darstellt.
receivegibt die nächste in der Warteschlange befindliche Nachricht vom anderen verknüpften EXP Brain zurück.Nachrichten werden in der Reihenfolge FIFO gelesen (älteste ungelesene zuerst).
Wenn die Warteschlange leer ist, wenn
receiveaufgerufen wird, wartet sie bis zu den angegebenentimeoutMsauf eine neue Nachricht.Wenn in diesem Zeitfenster keine Nachricht eintrifft, gibt
receiveden Wert0zurück, und jede danach gesendete Nachricht bleibt in der Warteschlange, um beim nächsten Aufrufreceivegelesen zu werden.
Code für Roboter 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); }
Code für Roboter 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#
Registriert eine Funktion, die immer dann aufgerufen wird, wenn das EXP Brain eine gesendete Nachricht empfängt.
Available Functions1 — Registriert eine Callback-Funktion für jede empfangene Nachricht.
void received( void (* callback)(const char *, const char *, double) );
2 — Registriert eine Rückruffunktion, die für jede empfangene Nachricht aufgerufen wird, die ein zusätzliches int32_t-Feld enthält.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Registriert einen Callback, der nur für empfangene Nachrichten aufgerufen wird, deren Name mit der Nachricht übereinstimmt.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Registriert einen Callback, der nur für empfangene Nachrichten aufgerufen wird, deren Name mit message übereinstimmt, wobei die Nachrichtennutzlast ein zusätzliches int32_t-Feld enthält.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Parameter |
Typ |
Beschreibung |
|---|---|---|
|
|
Der Name der zu vergleichenden Nachricht (Zeichenkette). Wenn der Name einer empfangenen Nachricht mit diesem Wert übereinstimmt, wird die Rückruffunktion |
|
|
Eine zuvor definierte Funktion, die ausgeführt wird, wenn das EXP Brain eine Nachricht empfängt, die mit |
Diese Funktion gibt keinen Wert zurück.
NotesreceivedRückruffunktion wird mit vier Argumenten aufgerufen:
callback(message, linkname, index, value)
Argument |
Beschreibung |
|---|---|
|
Der Name der empfangenen Nachricht (z. B. |
|
Der Name des Links, von dem die Nachricht empfangen wurde. |
|
Der mit der Nachricht gesendete ganzzahlige Wert (falls angegeben). |
|
Der mit der Nachricht gesendete Gleitkommawert (falls angegeben). |
Code für Roboter 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); }
Code für Roboter 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..."); }