Kommunikation
Dein Programm kommuniziert mit dem Spiel über zwei Geräte, die jeder Roboter hat:
- Der Sender (Emitter) schickt Nachrichten an das Spiel. Er muss nicht aktiviert werden.
- Der Empfänger (Receiver) erhält Nachrichten vom Spiel. Aktiviere ihn wie einen Sensor.
Jeder Abschnitt unten ist ein vollständiges Programm für den Starter-Roboter. Alle Nachrichten sind in der Nachrichten-Referenz aufgelistet.
Punkte für Wandmarkierungen
Abschnitt betitelt „Punkte für Wandmarkierungen“Um für ein Buchstabenopfer (Letter victim) oder ein kognitives Ziel (Cognitive target) Punkte zu bekommen, muss der Roboter:
- Länger als 1 Sekunde in der Nähe der Markierung stehen bleiben. Erebus ignoriert die Meldung, wenn sich der Roboter in der letzten Sekunde bewegt hat.
- Position und Typ der Markierung senden: X und Z in Zentimetern und den Typ als einen Buchstaben.
| Wandmarkierung | Typ |
|---|---|
| Buchstabenopfer Φ (verletzt) | H |
| Buchstabenopfer Ψ (stabil) | S |
| Buchstabenopfer Ω (unverletzt) | U |
| Kognitives Ziel, Summe 0 (entzündbares Gas) | F |
| Kognitives Ziel, Summe 1 (Gift) | P |
| Kognitives Ziel, Summe 2 (ätzend) | C |
| Kognitives Ziel, Summe 3 (organisches Peroxid) | O |
Die Typen sind Buchstaben, obwohl die Opfer seit 2026 Symbole zeigen. Das GPS liefert Meter, also multipliziere mit 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;}Der Roboter muss auf derselben Seite der Wand sein wie die Markierung, und sowohl der Roboter als auch die gesendete Position müssen nah an ihr liegen. Die Regeln verlangen höchstens eine halbe Kachel, also ziele darauf. Erebus v26.1 prüft eine Entfernung von 9 cm.
Führe dieses Programm am Start von world1.wbt aus: Dort gibt es keine Markierung, also zeigt der Verlauf des Steuerfensters Misidentification of Victim -5. Eine falsche Meldung, auch die Meldung einer Fälschung, kostet 5 Punkte, und jede Markierung bringt nur einmal Punkte.

Fehlender Fortschritt
Abschnitt betitelt „Fehlender Fortschritt“Wenn der Roboter feststeckt, setzt ihn ein fehlender Fortschritt (Lack of Progress, LoP) zum letzten Checkpoint zurück und kostet 5 Punkte. Das passiert automatisch nach 20 Sekunden ohne Bewegung, und dein Programm kann ihn auch selbst auslösen, indem es L sendet. Jedes Mal sendet das Spiel L an den Roboter, damit dein Programm weiß, dass sich seine Position geändert hat.
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;}Der Empfänger kann verschiedene Nachrichten erhalten. Prüfe also die Länge jeder Nachricht, bevor du sie liest, wie im Beispiel.
Spielinformationen
Abschnitt betitelt „Spielinformationen“Sende G, um die Punktzahl und die verbleibende Zeit zu erhalten. Das Spiel antwortet mit einer 16 Byte langen Nachricht: dem Buchstaben G, der Punktzahl, der verbleibenden Spielzeit und der verbleibenden Echtzeit, in Sekunden.
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;}Die Spielzeit läuft in Sümpfen schneller ab, und das Spiel endet, wenn eine der beiden Zeiten abgelaufen ist. Nutze beide, um zu wissen, wann du zum Start zurückkehren solltest.
Das Spiel beenden
Abschnitt betitelt „Das Spiel beenden“Sende E, um das Spiel zu beenden. Steht der Roboter auf der Startkachel und hat mindestens eine Wandmarkierung erkannt, bekommt er den Ausgangsbonus (Exit bonus) von 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;}Als Nächstes lernst du unter Wandmarkierungen, die Markierungen zu unterscheiden.
