通信
你的程序通过每个机器人都有的两个设备与比赛通信:
- 发射器(emitter)向比赛发送消息。它不需要启用。
- 接收器(receiver)接收来自比赛的消息。像传感器一样启用它。
下面每一节都是一个适用于入门机器人的完整程序。所有消息都列在消息参考中。
为墙面标识得分
Section titled “为墙面标识得分”要为一个字母受害者(Letter victim)或认知目标(Cognitive target)得分,机器人必须:
- 在标识附近停止超过 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,LoP)会把它移回最后一个检查点,并扣 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% 的离场奖励(Exit bonus)。
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;}接下来,在墙面标识中学习如何区分各种标识。
