通信
プログラムは、すべてのロボットに付いている 2 つのデバイスを通じてゲームとやり取りします。
- エミッター(emitter) は、ゲームにメッセージを送ります。有効にする必要はありません。
- レシーバー(receiver) は、ゲームからメッセージを受け取ります。センサーと同じように有効にします。
以下の各セクションは、スターターロボット用の完全なプログラムです。すべてのメッセージはメッセージリファレンスに載っています。
壁のトークンで得点する
Section titled “壁のトークンで得点する”文字の被災者(Letter victim)やコグニティブターゲット(Cognitive target)で得点するには、ロボットは次のことをする必要があります。
- トークンの近くで 1 秒より長く停止する。直前の 1 秒間にロボットが動いていると、Erebus は報告を無視します。
- トークンの 位置と種類を送る。X と Z は センチメートル 単位で、種類は 1 文字で表します。
| 壁のトークン | 種類 |
|---|---|
| 文字の被災者 Φ(harmed) | H |
| 文字の被災者 Ψ(stable) | S |
| 文字の被災者 Ω(unharmed) | U |
| コグニティブターゲット、合計 0(Flammable Gas、可燃性ガス) | F |
| コグニティブターゲット、合計 1(Poison、毒物) | P |
| コグニティブターゲット、合計 2(Corrosive、腐食性物質) | C |
| コグニティブターゲット、合計 3(Organic Peroxide、有機過酸化物) | 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 点の減点になり、各トークンで得点できるのは 1 回だけです。

競技進行停止
Section titled “競技進行停止”ロボットが動けなくなったとき、競技進行停止(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;}レシーバーはさまざまなメッセージを受け取るので、例のように、読み取る前に各メッセージの長さを確認してください。
ゲームの情報
Section titled “ゲームの情報”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;}沼地ではゲーム時間が速く進み、どちらかの時間がなくなるとゲームは終了します。両方を使って、スタートに戻り始めるタイミングを判断しましょう。
ゲームを終了する
Section titled “ゲームを終了する”E を送るとゲームが終了します。ロボットがスタートタイルにいて、壁のトークンを 1 つ以上識別していれば、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;}次は、壁のトークンでトークンの見分け方を学びましょう。
