I recently started integrating Google's Protocol Buffer for the communication of more complex data structures in a robotic network (e.g. matrices, internal state arrays, device info).
While I'm still at the prototyping phase, I've begun wondering how specific I should make the proto messages for long-term support. I see three possible approaches (very simple examples):
1) Medium specificity: Make the messages specific to each type of robot. Ex:
// RobotA.proto
optional int32 commandID
repeated double positionData //ex: this robot has many joints
// RobotB.proto
optional int32 commandID
optional int32 subCommandID //ex: this robot has subcommands
optional double positionData //ex: this robot has only one joint
2) Low specificity: Make the messages very general. Ex:
// GeneralRobotMessage.proto
optional int32 commandID //switch-case which other potential data is needed
optional int32 potentialIntData
repeated double potentialDoubleArray
optional string potentialStringData
optional bool potentialBoolData
3) High specificity: Each type of message has a protobuf. Ex:
// NAKMessage.proto
// ACKMessage.proto
// RobotAGetPosition.proto
From past experience, I usually employ a low specificity approach and use command IDs (aka a packet header) to designate the approach to parsing the message. But with protobufs, the whole concept of a predesignated .proto seems to act as a header concept.
Is there a recommended approach to message specificity? Coding standards? Rule of thumb?
Cheers,
I guess it's mostly a matter of taste (makes this Q borderline off-topic.)
I would read, and follow, the proto3 guide and style guide.
As a tip I would recommend specifying fields and messages that you use to distinguish the messages on a specific recipient specifically so that parsing gets easier.
Also keep all entities optional if possible, then you can change the format later and it will still be backwards compatible.
Nested messages might also be an alternative, you can make a hierarchy like:
message Robot{
optional uint32 id = 1;
optional RobotTypeA robo_type_a = 2;
optional RobotTypeB robo_type_b = 3;
message RobotTypeA {
optional uint32 a = 1;
optional uint32 b = 2;
optional uint32 c = 3;
optional uint64 d = 4;
optional int32 command_id = 5;
optional string ip_address = 6 [default = "10.10.10.10"];
}
message RobotTypeB {
optional uint32 a = 1;
optional uint32 b = 2;
optional uint32 c = 3;
optional uint64 d = 4;
optional int32 command_id = 5;
optional string ip_address = 6 [default = "10.10.10.10"];
}
}