Последовательное соединение#
Введение#
Класс serial_link serial_link позволяет передавать поток необработанных байтов между роботами. Он предназначен для связи между роботами, где и передающий, и принимающий роботы понимают содержимое потока данных.
Каждое использование send добавляет данные в очередь связанного EXP Brain, и очередь читается по принципу «первым пришел — первым вышел» (FIFO). Если несколько сообщений отправлены до того, как другие EXP Brain получат их, они будут сохранены и возвращены по одному в порядке отправки. Поскольку сообщения могут стоять в очереди, многократная отправка одного и того же статуса в каждом цикле может создавать задержку; для критически важной по времени логики отправляйте сообщения только тогда, когда значения изменяются.
Важно: Оба робота должны одновременно выполнять проекты, использующие последовательный канал serial_link , иначе данные не будут отправляться/получаться.
Конструкторы классов#
serial_link(
int32_t index,
const char *name,
linkType type,
bool isWired = false );
Деструктор класса#
Уничтожает объект serial_link serial_link и освобождает связанные с ним ресурсы.
~serial_link();
Параметры#
Параметр |
Тип |
Описание |
|---|---|---|
|
|
Интеллектуальный порт, к которому подключен канал связи, обозначается как |
|
|
Название этой ссылки. Рекомендуется, чтобы эта уникальная строка была достаточно длинной, чтобы при хешировании с помощью Vexos был создан уникальный идентификатор. Плохим названием ссылки будет что-то общее, например, «vexlink», поскольку оно может быть использовано другой командой. |
|
|
Тип соединения: либо
|
|
|
Является ли объект serial_link проводным (по умолчанию
|
Примечания#
VEXlink поддерживает как беспроводную, так и проводную связь, при этом для проводных соединений рекомендуется использовать модифицированный интеллектуальный кабель, чтобы избежать проблем с распределением питания.
Для беспроводной связи каждому роботу необходим радиомодуль V5 Robot Radio, подключенный к интеллектуальному порту.
Радиомодуль VEXlink можно использовать совместно с радиомодулем VEXnet контроллера EXP, который следует подключать к интеллектуальному порту с самым высоким номером во избежание конфликтов.
Для создания VEXlink оба блока EXP Brain должны быть подключены к роботизированной радиосистеме V5.
Пример#
Код для робота 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredКод для робота 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
Функции участников#
Класс serial_link включает следующие функции-члены:
isLinked— Проверяет, связаны ли EXP Brains парой и обмениваются ли данными по этой связи.send— Отправляет сообщение в парный мозг.receive— Ожидает и возвращает следующее входящее сообщение.received— Регистрирует функцию, которая будет вызываться при получении нового сообщения.
Перед вызовом любых функций-членов serial_link serial_link необходимо создать экземпляр serial_link serial_link , как показано ниже:
Код для робота 1
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::manager, // type true); // isWiredКод для робота 2
// Create a wireless link in Port 1 serial_link link = serial_link( PORT1, // index "VEXRoboticsLink123456789", // name linkType::worker, // type true); // isWired
isLinked#
Возвращает значение, указывающее, сопряжены ли модули EXP Brains, подключенные по последовательному каналу связи, друг с другом.
Available Functionsbool isLinked();
Эта функция не имеет параметров.
Return ValuesВозвращает логическое значение, указывающее, связаны ли EXP-мозги:
true— The two EXP Brains are paired and communicating on this link.false— The two EXP Brains are not paired on this link.
Перед запуском любого дальнейшего кода рекомендуется всегда проверять правильность подключения модулей EXP Brains в начале проекта.
Код для робота 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));
Код для робота 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#
Отправляет сообщение в сопряженный мозг.
Available Functions1 — Отправляет сообщение, используя буфер байтов.
int32_t send( uint8_t *buffer, int32_t length );
Parameters2 — Отправляет сообщение, используя буфер символов.
int32_t send( const char *buffer, int32_t length );
Параметр |
Тип |
Описание |
|---|---|---|
|
|
Буфер для отправки на другой связанный модуль EXP Brain. |
|
|
Длина буфера для отправки. |
Возвращает значение int32_t , представляющее количество отправленных байтов.
Код для робота 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); }
Код для робота 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#
Ожидает и возвращает следующее входящее сообщение.
Available FunctionsParameters1 — Принимает сообщение в символьный буфер с возможностью установки таймаута.
int32_t receive( char *buffer, int32_t length, int32_t timeoutMs = 500);
Параметр |
Тип |
Описание |
|---|---|---|
|
|
Буфер для хранения полученного сообщения. |
|
|
Длина буфера. |
|
|
Время ожидания в миллисекундах |
Возвращает значение int32_t , представляющее количество полученных байтов.
receiveвозвращает следующее сообщение из очереди от другого связанного модуля EXP Brain.Сообщения читаются в порядке FIFO (сначала самые старые непрочитанные).
Если очередь пуста при вызове функции
receive, она ожидает нового сообщения в течение указанного времениtimeoutMs).Если в этом окне не поступает ни одного сообщения, команда
receiveвозвращает0, и любое сообщение, отправленное после этого, остается в очереди для чтения при следующем использовании командыreceive.
Код для робота 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); }
Код для робота 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#
Регистрирует функцию, которая будет вызываться всякий раз, когда EXP Brain получает отправленное сообщение.
Available Functions1 — Регистрирует функцию обратного вызова для каждого полученного сообщения.
void received( void (* callback)(const char *, const char *, double) );
2 — Регистрирует функцию обратного вызова, вызываемую для каждого полученного сообщения, содержащего дополнительное поле типа int32_t.
void received( void (* callback)(const char *, const char *, int32_t, double) );
3 — Регистрирует функцию обратного вызова, которая вызывается только для полученных сообщений, имя которых совпадает с именем сообщения.
void received( const char *message, void (* callback)(const char *, const char *, double) );
Parameters4 — Регистрирует функцию обратного вызова, вызываемую только для полученных сообщений, имя которых совпадает с message, где полезная нагрузка сообщения включает дополнительное поле int32_t.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
Параметр |
Тип |
Описание |
|---|---|---|
|
|
Имя сообщения (строка), которое нужно сопоставить. Если имя полученного сообщения совпадает с этим значением, вызывается функция обратного вызова |
|
|
Ранее определенная функция, которая запускается, когда EXP Brain получает сообщение, соответствующее |
Эта функция не возвращает значения.
NotesПолучено
receivedобратный вызов с четырьмя аргументами:
callback(message, linkname, index, value)
Аргумент |
Описание |
|---|---|
|
Имя полученного сообщения (например, |
|
Название ссылки, с которой было получено сообщение. |
|
Целочисленное значение, отправляемое вместе с сообщением (если указано). |
|
Значение с плавающей запятой, отправляемое вместе с сообщением (если оно предоставлено). |
Код для робота 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); }
Код для робота 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..."); }