This fixes mostly formatting issues so there is no longer any diff with things after rerunning the generation script. Yes, most of this can be fixed by running wpiformat but that doesn't exist as a pre-commit hook atm, so I think this is nicer. It also removes any reference to the java encode/decode within the python message gen
Photon Serde Autocode
Like Rosmsg. But worse.
Goals
- As fast as possible (only slightly slower than packed structs, ideally)
- Support for variable length arrays and optional types
- Allow deserialization into user-defined, possibly nested, types. See ResultList for an example of this.
Design
The code for a single type is split across 3 files. Let's look at PnpResult:
- The struct definition: This is the data the object holds. Auto-generated. The data this object holds can be primitives or other, fully-deserialized types (like Vec2)
- The user class: This is the fully-deserialized PnpResult type. This contains extra functions users might need to expose like
Amgiguity, or other computed helper things. - The serde interface: This is a template specialization for converting the user class to/from bytes
Prior art
- Protobuf: slow on embedded platforms (at least quickbuf is)
- Wpi's struct: no VLAs/optionals
- Rosmsg: I'm not using ros, but I'm stealing their message hash idea
Deviations from WPI's Struct Schema Typestrings
- Enum types are disallowed
- Bitfields and bit packing are disallowed
- Only variable length arrays are supported (no fixed-length arrays)
- Arrays must be no more than 127 elements long
- Members can be either VLAs or optional, but not both
- A top-level NT topic type shall be a single type (eg TargetCorner), and cannot an array of types (eg TargetCorner[] or TargetCorner[?])
floatanddoubletypes will be replaced with float32/float64 when generating message schema strings. This means thatfloat32 x;andfloat x;will result in the same message hash.
For example, this is a valid PhotonStruct schema. Note the WPILib Transform3d, the Photon-defined TargetCorner, optional prefix, and VLA suffix.
float64 poseAmbiguity;
optional Transform3d altCameraToTarget;
TargetCorner:16f6ac0dedc8eaccb951f4895d9e18b6 minAreaRectCorners[?];
Dynamic Decoding
Dynamic decoding is facilitated by publishing schemas to the .schema table in NT, and by encoding the message_uuid as a property on a photonstruct publisher. Schema names in the .schema table shall be formatted as photonstruct:{Type Name}:{Message UUID}. For example, here I've published Photon results to /photonvision/WPI2024/rawBytes. This topic has the typestring photonstruct:PhotonPipelineResult:ed36092eb95e9fc254ebac897e2a74df, with properties {message_uuid': 'ed36092eb95e9fc254ebac897e2a74df'}. It shall be legal to have published multiple versions of the same message, as long as their UUIDs are unique (which they'd better be).
| Topic Name | Type | Type String |
|---|---|---|
| /.schema/photonstruct:PhotonPipelineResult:ed36092eb95e9fc254ebac897e2a74df | kRaw | photonstructschema |
| /.schema/photonstruct:PhotonTrackedTarget:4387ab389a8a78b7beb4492f145831b4 | kRaw | photonstructschema |
| /.schema/photonstruct:TargetCorner:16f6ac0dedc8eaccb951f4895d9e18b6 | kRaw | photonstructschema |
| /.schema/photonstruct:MultiTargetPNPResult:af2056aaab740eeb889a926071cae6ee | kRaw | photonstructschema |
| /.schema/photonstruct:PnpResult:ae4d655c0a3104d88df4f5db144c1e86 | kRaw | photonstructschema |
| /.schema/photonstruct:PhotonPipelineMetadata:626e70461cbdb274fb43ead09c255f4e | kRaw | photonstructschema |
| /.schema/proto:geometry3d.proto | kRaw | proto:FileDescriptorProto |
| /.schema/proto:photon.proto | kRaw | proto:FileDescriptorProto |
The struct definition for PhotonPipelineResult we retrieved from the struct schema database shown above (via the command python.exe scripts/catnt.py --echo /.schema/photonstruct:PhotonPipelineResult:ed36092eb95e9fc254ebac897e2a74df) is:
PhotonPipelineMetadata:626e70461cbdb274fb43ead09c255f4e metadata;
PhotonTrackedTarget:4387ab389a8a78b7beb4492f145831b4[?] targets;
MultiTargetPNPResult:af2056aaab740eeb889a926071cae6ee? multitagResult;
If we were decoding this, we'd go retrieve the struct definitions for all our nested types. For example, PhotonTrackedTarget:4387ab389a8a78b7beb4492f145831b4 is defined by it's .schema table entry be the following. This type also demonstrates a mix of WPILib struct types (such as Transform3d), intrinsic types (such as float64), and Photon struct types (such as TargetCorner).
float64 yaw;
float64 pitch;
float64 area;
float64 skew;
int32 fiducialId;
int32 objDetectId;
float32 objDetectConf;
Transform3d bestCameraToTarget;
Transform3d altCameraToTarget;
float64 poseAmbiguity;
TargetCorner:16f6ac0dedc8eaccb951f4895d9e18b6[?] minAreaRectCorners;
TargetCorner:16f6ac0dedc8eaccb951f4895d9e18b6[?] detectedCorners;
