Comunicación
Tu programa habla con la partida a través de dos dispositivos que tienen todos los robots:
- El emisor (
emitter) envía mensajes a la partida. No hace falta activarlo. - El receptor (
receiver) recibe mensajes de la partida. Actívalo como un sensor.
Cada sección siguiente es un programa completo para el robot inicial. Todos los mensajes están en la Referencia de mensajes.
Puntuar las marcas en las paredes
Sección titulada «Puntuar las marcas en las paredes»Para puntuar una víctima de letra (Letter victim) o un objetivo cognitivo (Cognitive target), el robot debe:
- Detenerse más de 1 segundo cerca de la marca. Erebus ignora el informe si el robot se ha movido en el último segundo.
- Enviar la posición y el tipo de la marca: X y Z en centímetros, y el tipo como una letra.
| Marca en la pared | Tipo |
|---|---|
| Víctima de letra Φ (herida) | H |
| Víctima de letra Ψ (estable) | S |
| Víctima de letra Ω (ilesa) | U |
| Objetivo cognitivo, suma 0 (gas inflamable) | F |
| Objetivo cognitivo, suma 1 (veneno) | P |
| Objetivo cognitivo, suma 2 (corrosivo) | C |
| Objetivo cognitivo, suma 3 (peróxido orgánico) | O |
Los tipos son letras, aunque desde 2026 las víctimas muestran símbolos. El GPS da metros, así que multiplica por 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;}El robot debe estar en el mismo lado de la pared que la marca, y tanto el robot como la posición que envías deben estar cerca de ella. Las reglas exigen como máximo media baldosa, así que apunta a eso. Erebus v26.1 comprueba una distancia de 9 cm.
Ejecuta este programa al inicio de world1.wbt: ahí no hay ninguna marca, así que el historial de la ventana de control muestra Misidentification of Victim -5. Un informe erróneo, incluido el informe de una marca falsa, cuesta 5 puntos, y cada marca solo se puede puntuar una vez.

Falta de progreso
Sección titulada «Falta de progreso»Cuando el robot está atascado, una falta de progreso (Lack of Progress, LoP) lo devuelve al último punto de control (checkpoint) y cuesta 5 puntos. Ocurre automáticamente tras 20 segundos sin moverse, y tu programa también puede declararla enviando L. Cada vez, la partida envía L al robot, para que tu programa sepa que su posición ha cambiado.
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;}El receptor puede recibir mensajes distintos, así que comprueba la longitud de cada uno antes de leerlo, como en el ejemplo.
Información de la partida
Sección titulada «Información de la partida»Envía G para obtener la puntuación y el tiempo restante. La partida responde con un mensaje de 16 bytes: la letra G, la puntuación, el tiempo de partida restante y el tiempo real restante, en segundos.
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;}El tiempo de partida corre más rápido en los pantanos, y la partida termina cuando se acaba cualquiera de los dos tiempos. Usa ambos para saber cuándo volver a la salida.
Terminar la partida
Sección titulada «Terminar la partida»Envía E para terminar la partida. Si el robot está en la baldosa de salida y ha identificado al menos una marca en la pared, consigue la bonificación de salida (Exit bonus) del 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;}A continuación, aprende a distinguir las marcas en Marcas en las paredes.
