The emitter and receiver are used to communicate with the Main Supervisor, Erebus’ game manager. The emitter can be used to score victims or hazard maps as well as signify the end of play to receive an exit bonus, while the receiver can be used to notify the robot controller in the event of a Lack of Progress.
First, set up the emitter and receiver:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from controller import Robot, Receiver, Emitter # Import Receiver and Emitterrobot = Robot()
receiver = robot.getDevice("receiver") # Retrieve the receiver and emitter by device nameemitter = robot.getDevice("emitter")
gps = robot.getDevice("gps") # Retrieve the gps by device nametimestep = int(robot.getBasicTimeStep())
receiver.enable(timestep) # Enable the receiver. Note that the emitter does not need to call enable()while robot.step(timestep) !=-1:
pass
#include<iostream>#include<webots/Robot.hpp>#include<webots/Receiver.hpp> // Include Receiver.hpp and Emitter.hpp#include<webots/Emitter.hpp>usingnamespace webots;
usingnamespace std;
intmain(int argc, char**argv) {
Robot *robot =new Robot();
Emitter* emitter = robot->getEmitter("emitter"); // Retrieve the receiver and emitter by device name
Receiver* receiver = robot->getReceiver("receiver");
GPS* gps = robot->getGPS("gps"); // Retrieve the gps by device name
int timeStep = (int)robot->getBasicTimeStep();
receiver->enable(timeStep); // Enable the receiver. Note that the emitter does not need to be enabled.
while (robot->step(timeStep) !=-1) {
}
delete robot;
return0;
}
Note: In contrast to other devices, the emitter does not have to be enabled.
Scoring Game Elements
To earn points for identifying victim letters and hazard maps, the emitter should be used to report the position and the type of the game element. The message to the Main Supervisor should be formatted as follows:
X Pos (integer), Z Pos (integer), Victim Type (character)
Note: The X position and Z Position should be in centimeters. Thus, it is important to multiply the position given by the GPS by 100 to convert meters to centimeters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from controller import Robot, Receiver, Emitter
import struct # Use the struct module in order to pack the message sent to the Main Supervisor...victimType = bytes('H', "utf-8") # The victim type being sent is the letter 'H' for harmed victimposition = gps.getValues() # Get the current gps position of the robotx = int(position[0] *100) # Get the xy coordinates, multiplying by 100 to convert from meters to cm y = int(position[2] *100) # We will use these coordinates as an estimate for the victim's positionmessage = struct.pack("i i c", x, y, victimType) # Pack the message.emitter.send(message) # Send out the message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<cstring>...
char message[9]; // Here we use a 9 byte array, since sizeof(int + int + char) = 9
constdouble* position = gps->getValues(); // Get the current gps position of the robot
int x = (int) position[0] *100; // Get the xy coordinates, multiplying by 100 to convert from meters to cm
int y = (int) position[2] *100; // We will use these coordinates as an estimate for the victim's position
int victim_pos[2] = {x, y};
memcpy(message, victim_pos, sizeof(victim_pos)); // Copy the victim position into the message array
message[8] ='H'; // The victim type is harmed
emitter->send(message, sizeof(message)); // Send out the message array. Note that the 2nd parameter must be the size of the message
Signaling Lack of Progress
To call of lack of progress autonomously (using your program), send the character ‘L’ using the emitter. The letter ‘L’ will be sent back to the robot’s receiver as per the Lack of Progress section below.
1
2
message = struct.pack('c', 'L'.encode()) # message = 'L' to activate lack of progressemitter.send(message) # Send message
1
2
char message[1] = { 'L' }; // message = 'L' to activate lack of progress
emitter->send(message, sizeof(message)); // Send out the message array. Note that the 2nd parameter must be the size of the message
Signaling End of Play
To signal to the Main Supervisor the end of play in order to receive an exit bonus, send the character ‘E’ using the emitter:
1
emitter.send(bytes('E', "utf-8")) # Send the letter 'E' to signify exit
1
2
char message ='E';
emitter->send(&message, 1); // Send the letter 'E' to signify exit
Lack of Progress
The receiver can be used to detect lack of progress messages sent by the Main Supervisor, so that the robot controller can respond accordingly:
1
2
3
4
5
6
if receiver.getQueueLength() >0: # If receiver queue is not empty receivedData = receiver.getBytes()
tup = struct.unpack('c', receivedData) # Parse data into characterif tup[0].decode("utf-8") =='L': # 'L' means lack of progress occurred print("Detected Lack of Progress!")
receiver.nextPacket() # Discard the current data packet
1
2
3
4
5
6
7
if(receiver->getQueueLength() >0) { // If receiver queue is not empty
char*message = (char*)receiver->getData(); // Grab data as a string
if (message[0] =='L') { // 'L' means a lack of progress occurred
cout <<"Detected Lack of Progress!"<< endl;
receiver->nextPacket(); // Discard the current data packet
}
}
Game Information
Your program can retrieve the robot’s current game score and the time remaining in your run. Use the emitter to send the character ‘G’ to the supervisor, and it will send back a package that starts with the letter ‘G’ and is followed by the score and time remaining:
1
2
3
4
5
6
7
8
9
10
11
message = struct.pack('c', 'G'.encode()) # message = 'G' for game informationemitter.send(message) # send message...if receiver.getQueueLength() >0: # If receiver queue is not empty receivedData = receiver.getBytes()
tup = struct.unpack('c f i', receivedData) # Parse data into char, float, intif tup[0].decode("utf-8") =='G':
print(f'Game Score: {tup[1]} Remaining time: {tup[2]}')
receiver.nextPacket() # Discard the current data packet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
char message[1] = { 'G' }; // message = 'G' for game information
emitter->send(message, sizeof(message)); // Send out the message array. Note that the 2nd parameter must be the size of the message
...
if(receiver->getQueueLength() >0) { // If receiver queue is not empty
char*receivedData = (char*)receiver->getData(); // Grab data as a string
float score =0.0;
int time =0;
if (receivedData[0] =='G') {
memcpy(&score, receivedData +4, 4); // Score stored in bytes 4 to 7
memcpy(&time, receivedData +8, 4); // Remaining time stored in bytes 8 to 11
cout <<"Game Score: "<< score <<" Remaining time: "<< time << endl;
receiver->nextPacket(); // Discard the current data packet
}
}