Enlace serie#
Introducción#
La clase serial_link permite enviar un flujo de bytes sin procesar entre robots. Está diseñado para la comunicación de robot a robot, donde tanto el robot transmisor como el receptor entienden el contenido del flujo de datos.
Cada uso de send agrega datos a la cola del cerebro EXP vinculado, y la cola se lee primero en entrar, primero en salir (FIFO). Si se envían varios mensajes antes de que el otro EXP Brain utilice receive, se almacenarán y devolverán uno a la vez en el orden en que se enviaron. Debido a que los mensajes pueden ponerse en cola, enviar repetidamente el mismo estado en cada bucle puede crear retraso; para la lógica de tiempo crítico, envíe solo cuando cambien los valores.
Importante: Ambos robots deben estar ejecutando proyectos que utilicen serial_link al mismo tiempo, o no se enviarán/recibirán datos.
Constructores de clase#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Destructor de clase#
Destruye el objeto serial_link y libera los recursos asociados.
~serial_link();
Parámetros#
Parámetro |
Tipo |
Descripción |
|---|---|---|
|
|
El puerto inteligente al que está conectado el enlace del mensaje, escrito como |
|
|
El nombre de este enlace. Se recomienda que esta cadena única sea lo suficientemente larga como para que cuando sea hashada por vexos cree un ID único. Un nombre de enlace incorrecto sería algo genérico como “vexlink”, ya que puede ser utilizado por otro equipo. |
|
|
El tipo de enlace, ya sea
|
|
|
Si el objeto serial_link está cableado (por defecto es
|
Observaciones#
VEXlink es compatible con la comunicación inalámbrica y por cable, con conexiones por cable que recomiendan un cable inteligente modificado para evitar problemas de enrutamiento de energía.
Para la comunicación inalámbrica, cada robot necesita una radio robot V5 conectada a un puerto inteligente.
La radio VEXlink se puede utilizar junto con la radio VEXnet de un controlador EXP, que debe estar conectada al puerto inteligente con el número más alto para evitar conflictos.
Para crear un VEXlink, ambos cerebros EXP deben estar conectados a una radio robótica V5.
Ejemplo#
Código para Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCódigo para Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Funciones de los miembros#
La clase serial_link incluye las siguientes funciones de miembro:
isLinked— Comprueba si los cerebros EXP están emparejados y se comunican en este enlace.send— Envía un mensaje al cerebro emparejado.receive— Espera y devuelve el siguiente mensaje entrante.received— Registra una función que se llamará cada vez que se reciba un nuevo mensaje.
Antes de llamar a cualquier función de miembro serial_link, se debe crear una instancia serial_link, como se muestra a continuación:
Código para Robot 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredCódigo para Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Devuelve si los cerebros EXP en un enlace serie están emparejados entre sí.
Available Functionsbool isLinked();
Esta función no tiene ningún parámetro.
Return ValuesDevuelve un booleano que indica si los cerebros EXP están vinculados:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
Es una buena práctica verificar siempre para asegurarse de que los cerebros EXP estén vinculados al comienzo de un proyecto antes de ejecutar cualquier código adicional.
Código para 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));
Código para 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#
Envía un mensaje al cerebro emparejado.
Available Functions1 — Envía un mensaje usando un búfer de bytes.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Envía un mensaje usando un búfer de caracteres.
int32_t send( const char *buffer, int32_t length );
Parámetro |
Tipo |
Descripción |
|---|---|---|
|
|
El búfer para enviar al otro cerebro EXP vinculado. |
|
|
La longitud del búfer a enviar. |
Devuelve un int32_t que representa el número de bytes enviados.
Código para 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); }
Código para 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#
Espera y devuelve el siguiente mensaje entrante.
Available FunctionsParameters1 — Recibe un mensaje en un búfer de caracteres con tiempo de espera opcional.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Parámetro |
Tipo |
Descripción |
|---|---|---|
|
|
El búfer para almacenar el mensaje recibido. |
|
|
La longitud del búfer. |
|
|
El tiempo en milisegundos de |
Devuelve un int32_t que representa el número de bytes recibidos.
receivedevuelve el siguiente mensaje en cola del otro cerebro EXP vinculado.Los mensajes se leen en orden FIFO (los más antiguos no leídos primero).
Si la cola está vacía cuando se llama a
receive, espera hasta el tiempo de espera especificadotimeoutMspara un nuevo mensaje.Si no llega ningún mensaje en esa ventana,
receivedevuelve0, y cualquier mensaje enviado después permanece en la cola para ser leído la próxima vez que se usereceive.
Código para 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); }
Código para 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#
Registra una función para ser llamada cada vez que el Cerebro EXP recibe un mensaje enviado.
Available Functions1 — Registra una función de devolución de llamada para cada mensaje recibido.
void received( void (* callback)(const char *, const char *, double) );
2 — Registra una devolución de llamada invocada por cada mensaje recibido que incluye un campo int32_t adicional.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Registra una devolución de llamada invocada solo para los mensajes recibidos cuyo nombre coincide con el mensaje.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Registra una devolución de llamada invocada solo para los mensajes recibidos cuyo nombre coincide con el mensaje, donde la carga útil del mensaje incluye un campo int32_t adicional.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Parámetro |
Tipo |
Descripción |
|---|---|---|
|
|
The message name (string) to match. When a received message’s name matches this value, the |
|
|
Una función previamente definida que se ejecuta cuando el Cerebro EXP recibe un mensaje que coincide con |
Esta función no devuelve un valor.
Notesreceivedcallbacks are called with four arguments:
callback(message, linkname, index, value)
Argumento |
Descripción |
|---|---|
|
El nombre del mensaje que se recibió (por ejemplo, |
|
El nombre del enlace del que se recibió el mensaje. |
|
El valor entero enviado con el mensaje (si se proporciona). |
|
El valor flotante enviado con el mensaje (si se proporciona). |
Código para 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); }
Código para 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..."); }