직렬 링크#
소개#
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();
매개변수#
매개변수 |
유형 |
설명 |
|---|---|---|
|
|
메시지 링크가 연결된 스마트 포트는 |
|
|
이 링크의 이름입니다. 이 고유한 문자열은 Vexos에서 해시될 때 고유 ID가 생성될 수 있도록 충분히 길어야 합니다. “vexlink”와 같이 일반적인 이름은 다른 팀에서 이미 사용하고 있을 수 있으므로 좋지 않습니다. |
|
|
링크 유형은
|
|
|
serial_link 객체가 유선인지 여부(기본값:
|
메모#
VEXlink는 무선 및 유선 통신을 모두 지원하며, 유선 연결 시에는 전원 배선 문제를 방지하기 위해 특수 개조된 스마트 케이블을 사용하는 것이 좋습니다.
무선 통신을 위해서는 각 로봇에 스마트 포트에 연결된 V5 로봇 라디오가 필요합니다.
VEXlink 라디오는 EXP 컨트롤러의 VEXnet 라디오와 함께 사용할 수 있으며, 충돌을 방지하기 위해 가장 높은 번호의 스마트 포트에 연결해야 합니다.
VEXlink를 생성하려면 두 개의 EXP 브레인을 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 Brain이 이 링크에서 페어링되고 통신하는지 확인합니다.send— 쌍을 이룬 Brain에 메시지를 보냅니다.receive— 다음 수신 메시지를 기다리고 반환합니다.received— 새 메시지가 수신될 때마다 호출될 함수를 등록합니다.
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 Brain이 서로 페어링되었는지 여부를 반환합니다.
Available Functionsbool isLinked();
이 함수는 매개변수가 없습니다.
Return ValuesEXP 브레인이 연결되어 있는지 여부를 나타내는 부울 값을 반환합니다.
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 브레인으로 보낼 버퍼입니다. |
|
|
전송할 버퍼의 길이입니다. |
전송된 바이트 수를 나타내는 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 브레인에서 대기 중인 다음 메시지를 반환합니다.메시지는 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 브레인이 전송된 메시지를 수신할 때마다 호출될 함수를 등록합니다.
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 — 메시지 페이로드에 추가적인 int32_t 필드가 포함된, 이름이 message와 일치하는 수신 메시지에 대해서만 호출되는 콜백을 등록합니다.
void received( const char *message, void (* callback)(const char *, const char *, int32_t, double) );
매개변수 |
유형 |
설명 |
|---|---|---|
|
|
일치시킬 메시지 이름(문자열). 수신된 메시지의 이름이 이 값과 일치하면 |
|
|
EXP 브레인이 |
이 함수는 값을 반환하지 않습니다.
Notesreceived인수를 받아 호출되었습니다.
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..."); }