The NUbots are in favour of a standard communication protocol.
We feel that a protobuf based implementation is preferable as this allows for a standard set of message fields to be enforced while also allowing teams to add to this set without breaking conformance.
Teams can utilise the standard protocol buffer definition which can be used by all teams, and then add their own fields on top of this as extensions to allow better communication between teams.
This protocol should be communicated over a UDP channel with a single message per packet. UDP is desirable because it’s an unreliable protocol which prevents old data from building up, allows single sender multiple receiver via either multicast or broadcast and it is easier to process each packet as a message meaning it will not require a streaming protocol with synchronisation bytes.
Ideally this proposal should be more about the communication protocol (how we communicate) and less about what is said (the contents of the message). We feel at this time it would be better to get a message protocol defined with a minimalist set of fields. This way the league as a whole can try out new ideas of what needs to be shared between teams, and if a majority of the teams begin to adopt these custom messages they can be added to the standard protocol buffer later. This will promote a more organic evolution of communication and only the fields that are used will end up in every team. If we attempt to define every possible scenario now the protocol buffer will be burdensome to implement for teams and will inevitably fail to cover all scenarios.
In terms of enforcing, this becomes quite difficult. If we require all communication to be broadcasted/multicasted on the network then the game controller could implement a packet sniffer and decode all received packets to ensure conformance, but this doesn’t prevent teams from sending direct communication between their own players, thereby avoiding this conformance check. We feel that this is the best we could hope for in terms of conformance, unless we want to implement the conformance checks at the router level.
Adding encryption seems like it would be more of a headache than it is worth and also seems like it would provide little gain. We also feel that these messages would be akin to speaking and we see no need to prevent the opposition from hearing it. However, if we really want to separate team communications we can assign a multicast group IP to each team (with the game controller in both groups), in this way each team can see their own multicast packets, but they can’t see the other teams packets.
In terms of message content, we propose the following information initially:
- Player ID + Team ID (same as the game controller packet)
- Robot position measured from center of field (x, y, theta)
- Ball position measured from center of field (x, y, z)
- Game mode, phase, and penalty reason (taken from game controller data)
- Current walk command (x velocity, y velocity, turning velocity)
Both robot and ball position should be measured in SI units and should (optionally) be accompanied with a covariance measurement. If we add a “message” field (PENALISE, UNPENALISE, ALIVE) to this then we can use this protobuf message to replace the current game controller reply packets allowing teams to only need to implement a single message for sending data to the game controller.
With all of this information we could create a display that looks like this NUbots dashboard display
The circles with the wedges on the field are robot positions and orientations, the curved black arc is the robots walk command, the orange circle is where that robot thinks the ball is, and the arrow leaving the ball is the direction the robot intends to the kick ball in (kick direction could be left out of the message).
The bottom panels are specifics of each robot. “Mode”, “Phase”, and “Penalty” are repeats of game controller data (this data could be used as a minor check for teams implementing the protocol - send the robot game state information and have it repeat it to you). “Walk Command” is the numerical version of the black arc on the field. “Behaviour” and the battery percentage would be removed in this scenario. The camera, ball, and goal images at the very bottom are indications of how long it has been since the robot last saw those things.
A possible implementation of our proposed protobuf message could be
package robocup.humanoid;
/// Needed in proto3 to handle extensions
import "google/protobuf/any.proto";
/// A vector of three floats
message fvec3 {
float x = 1;
float y = 2;
float z = 3;
}
/// A matrix of three vectors
message fmat3 {
fvec3 x = 1;
fvec3 y = 2;
fvec3 z = 3;
}
/// The current playing state of the robot
enum State {
UNKNOWN = 0;
UNPENALISED = 1;
PENALISED = 2;
}
message Message {
/// ID of the team that is sending this message
uint32 team_id = 1;
/// ID of the player that is sending this message
uint32 player_id = 2;
/// The position of the robot on the field according to the following convention
/// x meters along the field with 0 at the centre of the field and positive towards opponent goals
/// y meters across the field with 0 at the centre of the field and positive to the left
/// θ orientation of the robot (anti-clockwise from the x axis from above the field)
fvec3 field_position = 3;
/// The covariance measure of the robots [x, y, θ] values or NaN if not available
fmat3 field_covarinace = 4;
/// The position of the ball on the field according to the following convention
/// x meters (along the field with 0 at the centre of the field)
/// y meters (across the field with 0 at the centre of the field)
/// z meters (up from the field with 0 at ground level)
fvec3 ball_position = 5;
/// The covariance measure of the balls [x, y, z] values or NaN if not available
fvec3 ball_covariance = 6;
/// The current walk speed of the robot in it's local [x, y, θ] coordinates
/// positive x being forwards, positive y being strafing to the left, and positive θ being anti-clockwise
fvec3 walk_command = 7;
/// The robots current state
State state = 7;
/// extensions is only available in proto2
extensions 100 to 1000;
/// in proto3 we could do something like
repeated google.protobuf.Any extras = 100;
}
EDIT: Alternatively, rather than using Any
or extensions
, we could just use parsePartial
.