There is more than one way to do this. For this specific application, I expect that pretty much any approach will yield a satisfactory result (bikes are usually simpler than aircraft), but if you are interested in following good design principles, consider reading the Interface Design Guidelines:
Specifically, in this case, one important idea to internalize is that good interfaces are designed based on their business objective rather than the available means of implementation. The state variables you listed here may be coming from the same node but it doesn’t imply that they are sufficiently semantically related to be bundled into the same data transaction on the bus (that is, packed into the same topic):
The strategy for segregating your states into different topics depends on the overall architecture of your system so I am unable to describe the one best way to do this, but based on the information you provided, you may attain good results by using one topic per state with standard data types as follows:
Topics | Data type |
---|---|
throttle | uavcan.primitive.scalar.Real16.1.0 |
ignition | uavcan.primitive.scalar.Bit.1.0 |
brake front/rear | uavcan.primitive.scalar.Bit.1.0 |
turn signal left/right | uavcan.primitive.scalar.Bit.1.0 |
headlight lo/hi/alt | uavcan.primitive.scalar.Bit.1.0 |
horn | uavcan.primitive.scalar.Bit.1.0 |
Related signals could be grouped into bitmasks using either primitive integer types or custom types. Some of the rough examples to give you an idea:
# bike.BrakeLeverState.1.0
# The flag is true when the corresponding brake is active.
bool front
bool rear
@sealed
# bike.TurnSignalCtrl.1.0
int2 LEFT = -1
int2 NONE = 0
int2 RIGHT = +1
int2 state
@sealed
# bike.PropulsionCtrl.1.0
# This is a discriminated union, also known as a sum type.
@union
uavcan.primitive.Empty.1.0 ignition_off # This option indicates that the ignition is OFF.
float16 throttle # This option indicates that the ignition is ON and sets the throttle.
@sealed
I recommend starting with standard data types at first.