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 EXP Brain ligado, e a fila é lida pela ordem de chegada (FIFO). Se forem enviadas várias mensagens antes de o outro EXP Brain utilizar 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 EXP, que deve ser ligado à porta Smart de número mais elevado para evitar conflitos.
Para criar um VEXlink, ambos os EXP Brains devem estar ligados a um rádio de robô V5.
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 cérebros EXP 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 EXP Brains 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 cérebros EXP estão ligados:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
É uma boa prática verificar sempre se os EXP Brains 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 EXP 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 EXP 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 EXP Brain receber uma mensagem enviada.
Available Functions1 — Regista uma função de chamada de retorno para cada mensagem recebida.
void received( void (* callback)(const char *, const char *, double) );
2 — Regista um callback invocado para cada mensagem recebida que inclui um campo int32_t adicional.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Regista um callback invocado apenas para mensagens recebidas cujo nome corresponda à mensagem.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Regista um callback invocado apenas para mensagens recebidas cujo nome corresponde à mensagem, em que a carga útil da mensagem inclui um campo int32_t adicional.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Parâmetro |
Tipo |
Descrição |
|---|---|---|
|
|
O nome da mensagem (string) a corresponder. Quando o nome de uma mensagem recebida corresponde a este valor, é chamada a função de retorno de chamada |
|
|
Uma função previamente definida que é executada quando o EXP Brain recebe uma mensagem que corresponde à mensagem |
Esta função não devolve qualquer valor.
Notesreceivedchamada de retorno com quatro argumentos:
callback(message, linkname, index, value)
Discussão |
Descrição |
|---|---|
|
O nome da mensagem recebida (por exemplo, |
|
O nome do link a partir do qual a mensagem foi recebida. |
|
O valor inteiro enviado com a mensagem (se fornecido). |
|
O valor float enviado com a mensagem (se fornecido). |
Código para o 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 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..."); }