Link serial#
Introdução#
A classe serial_link permite o envio de um fluxo de bytes em bruto entre robots. Foi concebida para a comunicação robô-a-robô, onde tanto o robô transmissor como o recetor compreendem o conteúdo do fluxo de dados.
Cada utilização de send adiciona dados à fila do V5 Brain ligado, e a fila é lida pela ordem de chegada (FIFO). Se forem enviadas várias mensagens antes de o outro V5 Brain utilizar o método receive, estas serão armazenadas e devolvidas uma de cada vez, pela ordem em que foram enviadas. Como as mensagens podem ser colocadas em fila, enviar repetidamente o mesmo estado a cada iteração do ciclo pode criar uma acumulação; para a lógica crítica em termos de tempo, envie apenas quando os valores se alteram.
Importante: Ambos os robôs devem estar a executar projetos que utilizem serial_link em simultâneo, caso contrário, não serão enviados/recebidos quaisquer dados.
Construtores de Classes#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Destrutor de classes#
Destrói o objeto serial_link serial_link recursos associados.
~serial_link();
Parâmetros#
Parâmetro |
Tipo |
Descrição |
|---|---|---|
|
|
A Smart Port à qual a ligação da mensagem está ligada, escrita como |
|
|
O nome deste link. Recomenda-se que esta sequência única seja suficientemente longa para que, ao ser processada pelo Vexos, gere um ID único. Um nome de link inadequado seria algo genérico como “vexlink”, pois pode estar a ser utilizado por outra equipa. |
|
|
O tipo de ligação, seja
|
|
|
Indica se o objeto serial_link é cablado (o predefinido é
|
Notas#
O VEXlink suporta comunicação sem fios e com fios, sendo que para ligações com fios recomenda-se a utilização de um cabo inteligente modificado para evitar problemas de encaminhamento de energia.
Para comunicação sem fios, cada robô necessita de um rádio V5 Robot ligado a uma porta inteligente.
O rádio VEXlink pode ser utilizado em conjunto com o rádio VEXnet de um controlador V5, que deve ser ligado à porta Smart de número mais elevado para evitar conflitos.
Para criar um VEXlink, ambos os módulos V5 Brain devem estar ligados a um rádio V5 Robot.
Exemplo#
Código para o 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 o Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Funções de membro#
A classe serial_link inclui as seguintes funções membro:
isLinked— Verifica se os V5 Brains estão emparelhados e a comunicar neste link.send— Envia uma mensagem para o Brain emparelhado.receive— Aguarda e devolve a próxima mensagem recebida.received— Regista uma função a chamar sempre que uma nova mensagem é recebida.
Antes de chamar qualquer função membro de serial_link , deve ser criada uma instância de serial_link ), como se mostra abaixo:
Código para o 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 o Robot 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Retorna se os módulos V5 numa ligação série estão emparelhados entre si.
Available Functionsbool isLinked();
Esta função não tem parâmetros.
Return ValuesRetorna um valor booleano indicando se os V5 Brains estão ligados:
true— The two V5 Brains are paired and communicating on this link.false— The two V5 Brains are not paired on this link.
É uma boa prática verificar sempre se os módulos V5 estão ligados no início de um projeto, antes de executar qualquer outro código.
Código para o 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 o 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#
Envia uma mensagem para o cérebro emparelhado.
Available Functions1 — Envia uma mensagem utilizando um buffer de bytes.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Envia uma mensagem utilizando um buffer de caracteres.
int32_t send( const char *buffer, int32_t length );
Parâmetro |
Tipo |
Descrição |
|---|---|---|
|
|
O buffer a enviar para o outro V5 Brain ligado. |
|
|
O tamanho do buffer a enviar. |
Retorna um int32_t int32_t que representa o número de bytes enviados.
Código para o 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 o 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#
Aguarda e devolve a próxima mensagem recebida.
Available FunctionsParameters1 — Recebe uma mensagem num buffer de caracteres com tempo limite opcional.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Parâmetro |
Tipo |
Descrição |
|---|---|---|
|
|
O buffer para armazenar a mensagem recebida. |
|
|
O comprimento do buffer. |
|
|
Tempo em milissegundos |
Retorna um int32_t int32_t que representa o número de bytes recebidos.
receivee devolve a próxima mensagem em fila do outro V5 Brain ligado.As mensagens são lidas pela ordem FIFO (da mais antiga não lida para a primeira).
Se a fila estiver vazia quando
receiveé chamado, espera até ao tempo limite especificadotimeoutMspor uma nova mensagem.Se nenhuma mensagem chegar a esta janela,
receiveretorna0, e qualquer mensagem enviada posteriormente permanece na fila para ser lida na próxima vez quereceivefor utilizado.
Código para o 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 o 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#
Regista uma função a ser chamada sempre que o V5 Brain receber dados.
Available FunctionsParameters1 — Regista uma função de callback para cada buffer de bytes recebido.
void received( void (* callback)(uint8_t *, int32_t) );
Parâmetro |
Tipo |
Descrição |
|---|---|---|
|
|
Uma função previamente definida que é executada quando o V5 Brain recebe dados. |
Esta função não devolve qualquer valor.
NotesAs funções de callback
receivedsão invocadas com dois argumentos: um buffer de bytes e o número de bytes recebidos.Os dados recebidos podem não estar terminados com um caractere nulo. Se a função de retorno de chamada tratar os dados como uma string, copie os bytes recebidos para um array de caracteres e adicione um terminador nulo.
callback(buffer, length)
Discussão |
Descrição |
|---|---|
|
Um ponteiro para o buffer de bytes recebido. |
|
Número de bytes recebidos. |
Código para o Robot 1
// Create the link. serial_link link(PORT1, "VEXRoboticsLink123456789", linkType::manager, true); // 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(); // 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); while (true) { wait(10, msec); } }
Código para o 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..."); while (true) { wait(10, msec); } }