通訊
你的程式透過每台機器人都有的兩個裝置與比賽溝通:
- 發射器(emitter)會傳送訊息給比賽。它不需要啟用。
- 接收器(receiver)會接收來自比賽的訊息。請像感測器一樣啟用它。
以下每一節都是一個適用於入門機器人的完整程式。所有訊息都列在訊息參考中。
靠牆上的標記得分
Section titled “靠牆上的標記得分”要靠字母受害者或認知目標得分,機器人必須:
- 在標記附近停止超過 1 秒。如果機器人在最後一秒內移動過,Erebus 會忽略這次回報。
- 傳送標記的位置和類型:X 和 Z 以公分為單位,類型則是一個字母。
| 牆上的標記 | 類型 |
|---|---|
| 字母受害者 Φ(受傷) | H |
| 字母受害者 Ψ(穩定) | S |
| 字母受害者 Ω(未受傷) | U |
| 認知目標,總和 0(易燃氣體) | F |
| 認知目標,總和 1(毒性物質) | P |
| 認知目標,總和 2(腐蝕性物質) | C |
| 認知目標,總和 3(有機過氧化物) | O |
雖然從 2026 年起受害者顯示的是符號,類型仍然是字母。GPS 提供的是公尺,所以要乘以 100。
from controller import Robotimport struct
robot = Robot()timeStep = int(robot.getBasicTimeStep())
emitter = robot.getDevice("emitter") # Always on the robot. It does not need to be enabled.gps = robot.getDevice("gps")gps.enable(timeStep)leftWheel = robot.getDevice("left wheel motor")rightWheel = robot.getDevice("right wheel motor")leftWheel.setPosition(float("inf"))rightWheel.setPosition(float("inf"))
def wait(seconds): start = robot.getTime() while robot.step(timeStep) != -1: if robot.getTime() - start >= seconds: break
def report(tokenType): # 1. Stop for more than 1 second leftWheel.setVelocity(0) rightWheel.setVelocity(0) wait(1.2) # 2. Send the position in centimeters, and the type as one letter x, _, z = gps.getValues() message = struct.pack("i i c", int(x * 100), int(z * 100), tokenType.encode()) emitter.send(message) robot.step(timeStep)
report("H") # Reports a harmed victim (Φ) where the robot isprint("Reported")#include <iostream>#include <cmath>#include <cstring>#include <webots/Robot.hpp>#include <webots/Emitter.hpp>#include <webots/GPS.hpp>#include <webots/Motor.hpp>
using namespace webots;
Robot *robot;Emitter *emitter;GPS *gps;Motor *leftWheel, *rightWheel;int timeStep;
void wait(double seconds) { double start = robot->getTime(); while (robot->step(timeStep) != -1) { if (robot->getTime() - start >= seconds) break; }}
void report(char tokenType) { // 1. Stop for more than 1 second leftWheel->setVelocity(0); rightWheel->setVelocity(0); wait(1.2); // 2. Send the position in centimeters, and the type as one letter int position[2] = {(int)(gps->getValues()[0] * 100), (int)(gps->getValues()[2] * 100)}; char message[9]; memcpy(message, position, sizeof(position)); message[8] = tokenType; emitter->send(message, sizeof(message)); robot->step(timeStep);}
int main() { robot = new Robot(); timeStep = (int)robot->getBasicTimeStep();
emitter = robot->getEmitter("emitter"); // Always on the robot. It does not need to be enabled. gps = robot->getGPS("gps"); gps->enable(timeStep); leftWheel = robot->getMotor("left wheel motor"); rightWheel = robot->getMotor("right wheel motor"); leftWheel->setPosition(INFINITY); rightWheel->setPosition(INFINITY);
report('H'); // Reports a harmed victim (Φ) where the robot is std::cout << "Reported" << std::endl;
delete robot; return 0;}機器人必須和標記在牆的同一側,而且機器人和你傳送的位置都必須靠近標記。規則要求最多半個地塊,所以請以此為目標。Erebus v26.1 檢查的距離是 9 cm。
在 world1.wbt 的起點執行這個程式:那裡沒有標記,所以控制視窗的歷史紀錄會顯示 Misidentification of Victim -5。錯誤的回報(包括回報假目標)會扣 5 分,而且每個標記只能得分一次。

當機器人卡住時,缺乏進展(lack of progress)會把它移回最後一個檢查點,並扣 5 分。機器人 20 秒沒有移動就會自動發生,你的程式也可以傳送 L 主動宣告。每次發生時,比賽都會傳送 L 給機器人,讓你的程式知道它的位置改變了。
from controller import Robotimport struct
robot = Robot()timeStep = int(robot.getBasicTimeStep())
emitter = robot.getDevice("emitter")receiver = robot.getDevice("receiver")receiver.enable(timeStep) # The receiver must be enabled
askedAt = Nonewhile robot.step(timeStep) != -1: # Call a lack of progress once, after 2 seconds if askedAt is None and robot.getTime() > 2: emitter.send(struct.pack("c", b"L")) askedAt = robot.getTime()
# Listen for messages from the game while receiver.getQueueLength() > 0: data = receiver.getBytes() if len(data) == 1 and data == b"L": print("Lack of progress! The robot is back at the last checkpoint.") receiver.nextPacket()#include <iostream>#include <webots/Robot.hpp>#include <webots/Emitter.hpp>#include <webots/Receiver.hpp>
using namespace webots;using namespace std;
int main() { Robot *robot = new Robot(); int timeStep = (int)robot->getBasicTimeStep();
Emitter *emitter = robot->getEmitter("emitter"); Receiver *receiver = robot->getReceiver("receiver"); receiver->enable(timeStep); // The receiver must be enabled
bool asked = false; while (robot->step(timeStep) != -1) { // Call a lack of progress once, after 2 seconds if (!asked && robot->getTime() > 2) { char message = 'L'; emitter->send(&message, 1); asked = true; }
// Listen for messages from the game while (receiver->getQueueLength() > 0) { const char *data = (const char *)receiver->getData(); if (receiver->getDataSize() == 1 && data[0] == 'L') cout << "Lack of progress! The robot is back at the last checkpoint." << endl; receiver->nextPacket(); } }
delete robot; return 0;}接收器可能收到不同的訊息,所以請像範例一樣,在讀取之前先檢查每則訊息的長度。
傳送 G 可以取得分數和剩餘時間。比賽會回覆一則 16 位元組的訊息:字母 G、分數、剩餘比賽時間和剩餘實際時間,單位是秒。
from controller import Robotimport struct
robot = Robot()timeStep = int(robot.getBasicTimeStep())
emitter = robot.getDevice("emitter")receiver = robot.getDevice("receiver")receiver.enable(timeStep)
lastAsked = 0while robot.step(timeStep) != -1: # Ask for the game information once a second if robot.getTime() - lastAsked > 1: emitter.send(struct.pack("c", b"G")) lastAsked = robot.getTime()
while receiver.getQueueLength() > 0: data = receiver.getBytes() if len(data) == 16: # The game information is 16 bytes long _, score, timeLeft, realTimeLeft = struct.unpack("c f i i", data) print("Score:", round(score, 2), "Time left:", timeLeft, "s", "Real time left:", realTimeLeft, "s") receiver.nextPacket()#include <iostream>#include <cstring>#include <webots/Robot.hpp>#include <webots/Emitter.hpp>#include <webots/Receiver.hpp>
using namespace webots;using namespace std;
int main() { Robot *robot = new Robot(); int timeStep = (int)robot->getBasicTimeStep();
Emitter *emitter = robot->getEmitter("emitter"); Receiver *receiver = robot->getReceiver("receiver"); receiver->enable(timeStep);
double lastAsked = 0; while (robot->step(timeStep) != -1) { // Ask for the game information once a second if (robot->getTime() - lastAsked > 1) { char message = 'G'; emitter->send(&message, 1); lastAsked = robot->getTime(); }
while (receiver->getQueueLength() > 0) { const char *data = (const char *)receiver->getData(); if (receiver->getDataSize() == 16 && data[0] == 'G') { // The game information is 16 bytes long float score; int timeLeft, realTimeLeft; memcpy(&score, data + 4, 4); memcpy(&timeLeft, data + 8, 4); memcpy(&realTimeLeft, data + 12, 4); cout << "Score: " << score << " Time left: " << timeLeft << " s Real time left: " << realTimeLeft << " s" << endl; } receiver->nextPacket(); } }
delete robot; return 0;}比賽時間在沼澤中會流逝得更快,只要任一種時間用完,比賽就會結束。請同時利用兩者來判斷何時該返回起點。
傳送 E 可以結束比賽。如果機器人在起始地塊上,且已辨識出至少一個牆上的標記,就會獲得 10% 的出口加成。
from controller import Robotimport struct
robot = Robot()timeStep = int(robot.getBasicTimeStep())emitter = robot.getDevice("emitter")
robot.step(timeStep)print("Ending the game")# Ends the game. Send it on the starting tile, after identifying a token, to get the exit bonus.# The game stops your program right after this message.emitter.send(struct.pack("c", b"E"))robot.step(timeStep)#include <iostream>#include <webots/Robot.hpp>#include <webots/Emitter.hpp>
using namespace webots;
int main() { Robot *robot = new Robot(); int timeStep = (int)robot->getBasicTimeStep(); Emitter *emitter = robot->getEmitter("emitter");
robot->step(timeStep); std::cout << "Ending the game" << std::endl; // Ends the game. Send it on the starting tile, after identifying a token, to get the exit bonus. // The game stops your program right after this message. char message = 'E'; emitter->send(&message, 1); robot->step(timeStep);
delete robot; return 0;}接下來,在牆上的標記中學習如何分辨各種標記。
