COVESA / vehicle_signal_specification

Vehicle Signal Specification - standardized way to describe automotive data
Mozilla Public License 2.0
320 stars 164 forks source link

:construction: Model, structs, branches and the world #775

Open sschleemilch opened 1 week ago

sschleemilch commented 1 week ago

I was thinking recently a lot about structs and branches. Especially about how they differ. In general I would say that structs are pretty much the same as branches but just a different tree entry point (Types). If we exchange struct with branch and property with just a normal child having a datatype then we have the same as modelling it in the initial tree. Only difference like I said is having a separate Tree for it.

Also in context of https://github.com/COVESA/vss-tools/pull/405 I noticed that in terms of types there is no difference in modelling it as a struct or as a branch.

Essentially it leads to the fact that we could model everything using structs and multiple root elements in one or several yaml files. It then is just someting similar to a class diagram. In the same run we would get rid of needing for includes as well as instances. Two features that are often discussed. I did not think this completely until then end but I wanted to share my thoughts.

Here is an example model of some elements that just came into my mind. The only downside I can see for now is that you cannot directly reference list elements (Vehicle.Cabin.Door.Row1.PassengerSide) Maybe this is the crucial point where VSS shines but I am not sure how much we gain with that.

Example:

Vehicle:
  type: struct
  description: Vehicle

Vehicle.Cabin:
  type: property
  description: Cabin
  datatype: Cabin

Vehicle.Speed:
  type: property
  description: Speed
  datatype: uint16

Cabin:
  type: struct
  description: Cabin

Cabin.Doors:
  type: property
  description: Door
  datatype: Door[]

Door:
  type: struct
  description: Door

Door.Position:
  type: property
  description: Door Position
  datatype: string
  allowed:
  - Row[1,2]
  - "[Driver, Passenger]Side"

Door.Window:
  type: property
  description: Window
  datatype: Window

Window:
  type: struct
  description: Window

Window.Position:
  type: property
  datatype: uint8
  description: Percentage of position
  min: 0
  max: 100

Like I said, all definitions could be sharded across different files and all you need to know is the entrypoint. So an example cli call for this imaginary construct would be:

vspec export foo --model main.vspec --model cabin.vspec --model  door.vspec --entry Vehicle

Of course the cli call could get quite long doing it like that but we could have just a config file for instance. The question is if yaml is then still the right tool for the job. I think it goes into the same direction that has been discussed already a bit regarding modelling vss with GraphQL.

This would align quite well with programming languages where you can have roughly a file for each class. What we would have in the end is a language agnostic model of something. This would not be at all limited to Vehicle anymore (I know, the current solution also would work just fine with other root node names).

Anyway, I just wanted to share that thought as I myself struggled a bit with the struct/branch difference and when to apply what.

:clinking_glasses:

erikbosch commented 1 week ago

MoM: Please read/discuss, to be further discussed after AMM

erikbosch commented 1 week ago

If you want to dig in the old branch discussion you can find quite a lot on subpages at https://github.com/COVESA/vehicle_signal_specification/wiki, see also https://covesa.github.io/vehicle_signal_specification/rule_set/data_entry/data_types_struct/index.html

Some background

VSS as of today has no real good mechanism to handle "struct-like data", data that always shall be handled as an atomic unit, like Lat/Lon for GPS position and possibly obstacle information (distance + direction + ...). We support arrays but only of primitive types, and we support instances for branches. I.e you can put Lat+Lon in a branch and hope that people shall update them as a pair, but it is difficult to represent something like "TenLastPositions" (array of 10 Lat/Lon pairs).

Struct then came up as an alternative to offer reusable types. This is somewhat similar to reusable branches with #include. But there are some differences. In the hypothetical example below we want Vehicle.Position to be a signal (i.e. sensor/actuator) and not a branch, i.e. it shall be possible to do read/write on it and as response you should get the pair lat+lon as an atomic pair. It shall not be possible to do a write on Vehicle.Position.Lat only, it must always be written/provided in a pair with Lon.

Vehicle.Cabin.Sunroof shall on the other hand be possible to set independent from Vehicle.Cabin.Trunk. It is maybe not even relevant for an API to offer a method "set_Vehicle_Cabin(...)" as Vehicle.Cabin contains a mix of sensors and actuators.

Vehicle -Branch
Vehicle.Speed - sensor
Vehicle.Position - Sensor
Vehicle.Position.Lat - Property
Vehicle.Position.Lon -Property
Vehicle.Cabin - Branch
Vehicle.Cabin.Sunroof Actuator
Vehicle.Cabin.Trunk Actuator

Concerning instance addressing like Vehicle.Cabin.Door.Row1.PassengerSide. Some model guys has proposed that instance information not shall be part of the "core" model, as that rather reflects deployment. See for example https://wiki.covesa.global/display/WIK4/Data+Models+and+Ontologies?preview=/53510159/78840002/VSS%20Extensions%20and%20Ford%20Signal%20Ontology.pptx

That you somewhere should have deployment info that says that you define an instance of Vehicle.Cabin.Door with the identifier Vehicle.Cabin.Door.Row1.PassengerSide, or MyYellowDoor or some other identifier. The core model shall only define what a Vehicle.Cabin.Door contain and possibly state that there might be multiple instances of them, but not state which instances.

UlfBj commented 1 week ago

Erik points to what I think is the main argument arguments for using structs, that it provides a solution to handle complex data as an atomic unit. This should in my view also be the only usage of it, it should not be used to define a group of assorted signals. Defining the structs in a separate tree provides a clean model for the reuse case.

As a general comment I think that when it comes to changes in the model (rule set) this is more likely to have a significant impact on downstream users than changes to the content of the tree. Removing the struct concept would e. g. have a direct impact on VISS.