Communication between robots
Each of the robots is equipped with two Receivers and one Emitter. One of the Receivers is used for receiving data from Supervisor. The Emitter and the second Receiver can be used for sending and receiving data between robots from the same team. We are going to describe what needs to be done in order to make use of it.
Definition in the world file
Our world file defines one Emitter and one Receiver for team communication for
each robot. Blue team is assigned channel 2, while yellow team is assigned
channel 3. Webots supports changing channels, but we turned this feature off so teams
are not able to spam the opponent with a bunch of messages.
The name of the Emitter is set to team emitter
, while the Receiver can be found
under name team receiver
.
Initializing the communication
The first thing we need to do in order to setup the communication is initialize the Emitter and Receiver. To do so, just call following commands. We are going to use the OOP approach here as well (see our sample robot controllers).
self.team_emitter = self.robot.getDevice("team emitter")
self.team_receiver = self.robot.getDevice("team receiver")
self.team_receiver.enable(TIME_STEP)
Before using the Receiver, we must enable it with enable(TIME_STEP)
command,
where TIME_STEP
is the same value we use in our controller when calling
self.robot.step(TIME_STEP)
.
Sending a message
Each time we send a message via a channel, all the receivers listening on
this channel are going to receive it. So, if robot1
sends a message,
robot2
and robot3
from the same team can read it.
Converting the message into a packet
Webots supports sending the packet in different formats (string, bytes, list of doubles...). Since our example controllers as well as supervisor use strings, let's describe how to send it.
JSON (JavaScript Object Notation) is an
open standard file format and data interchange format that uses human-readable
text to store and transmit data objects consisting of attribute–value pairs and
arrays (or other serializable values).
In short, it is very similar to the dict
data structure that Python uses.
Starting from version 3.0, Python contains a built-in library called json. It
offers encoding Python's dictionaries into JSON string and later decoding it back to a dictionary.
This is very useful in our case because by reading the keys the receiver already knows what the
value means.
Let's create a simple message that we would like to send:
data = {"robot_id": 1, "my_array": [1, 1.0, 2]}
Before sending the data, we must convert it to the string so the emitter is able to
encode it. As mentioned above, json
library contains a method dumps
that takes care
of that.
packet = json.dumps(data)
The only thing we need to do is emit the packet by the Emitter. It is as easy as just calling
self.team_emitter.send(packet)
and the message is succesfully sent to the channel.
Receiving a message
When a Receiver receives a message, it adds it to the queue. We are then able to pull the oldest message out of the queue.
To check the number of messages waiting in the queue, we can call
self.team_receiver.getQueueLength()
If the there are new messages, the number of messages will be greater than 0 and we can proceed with reading the message.
packet = self.team_receiver.getString()
self.team_receiver.nextPacket()
In the first row we call the getString()
method, which returns the packet and assigns
it to the packet
variable. The nextPacket()
method is used to move the pointer
to the next packet in the queue, so next time we are calling getString()
, we are going
to read next packet in the queue.
Okay, now we have packet. How do we decode it? Well, remember our cool json
library? We are going to use it for decoding the packet, too.
data = json.loads(packet)
The variable data
now contains the same dictionary we sent by the emitter and can be
accessed as normal dictionary object.
WARNING: There are 3 robots within the team running asynchronously. If all of them
are sending messages, it is always good to empty the queue before moving on, otherwise
the queue might grow and you will be reading old messages. You can use
a while
loop for example
while self.team_receiver.getQueueLength() > 0:
packet = self.team_receiver.getString()
self.team_receiver.nextPacket()
# Do something with the packet
WARNING: Webots does not guarantee the order of messages. Your robot controllers should not rely on the order. Instead, we recommend sending robot identifier in the message payload so the receiving robots clearly know which robot originally sent the message.