This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
 
Manual Vehicle Model Creation
Learn how to manually create a vehicle model to access vehicle data or execute remote procedure calls.
    
      
Info
    With the release of our new 
model lifecycle approach
on Friday, 2023-03-03, the model is now automatically generated with the instantiation of the devContainer from a model source referenced in the app manifest.
The approach described here, using pre-generated model repositories, is deprecated as of now. But it is still available and must be used if you need access to vehicle services. Please be aware, that you would either have to use template versions before the above mentioned release, or you need to adapt the newer versions of the template using the old approach.
 
This tutorial will show you how to:
- Create a Vehicle Model
 
- Add a Vehicle Service to the Vehicle Model
 
- Distribute your Python Vehicle Model
 
Note
    A Vehicle Model should be defined in its own package. This makes it possible to distribute the Vehicle Model later as a standalone package and to use it in different Vehicle App projects.
The creation of a new vehicle model is only required if the vehicle signals (like sensors and actuators) defined in the current version of the 
COVESA Vehicle Signal Specification
(VSS) is not sufficient for the definition of your vehicle API. Otherwise you could use the default vehicle model we already generated for you, see
Python Vehicle Model
and
C++ Vehicle Model
.
 
Create a Vehicle Model from VSS specification
A Vehicle Model can be generated from a 
COVESA Vehicle Signal Specification
 (VSS). VSS introduces a domain taxonomy for vehicle signals, in the sense of classical attributes, sensors and actuators with the raw data communicated over vehicle buses and data. The Velocitas 
vehicle-model-generator
 creates a Vehicle Model from the given specification and generates a package for use in Vehicle App projects.
Follow the steps to generate a Vehicle Model.
- 
Clone the 
vehicle-model-generator
 repository in a container volume.
 
- 
In this container volume, clone the 
vehicle-signal-specification
 repository and if required checkout a particular branch:
git clone https://github.com/COVESA/vehicle_signal_specification
cd vehicle_signal_specification
git checkout <branch-name>
In case the VSS vspec doesn’t contain the required signals, you can create a vspec using the 
VSS Rule Set
.
 
- 
Execute the command
python3 gen_vehicle_model.py -I ./vehicle_signal_specification/spec ./vehicle_signal_specification/spec/VehicleSignalSpecification.vspec -l <lang> -T sdv_model -N sdv_model
or if you want to generate it from a .json file
python3 gen_vehicle_model.py <path_to_your_json_file> -l <lang> -T sdv_model
Depending on the value of lang, which can assume the values python and cpp, this creates a sdv_model directory in the root of repository along with all generated source files for the given programming language.
Here is an overview of what is generated for every available value of lang:
| lang | 
output | 
python | 
Python sources and a setup.py ready to be used as Python package | 
cpp | 
C++ sources, headers and a CMakeLists.txt ready to be used as a CMake project | 
To have a custom model name, refer to README of 
vehicle-model-generator
 repository.
 
- 
For Python: Change the version of package in setup.py manually (defaults to 0.1.0).
 
- 
Now the newly generated sdv_model can be used for distribution. (See 
Distributing your Vehicle Model
)
 
Create a Vehicle Model Manually
Alternative to the generation from a VSS specification you could create the Vehicle Model manually. The following sections describing the required steps.
Distributing your Vehicle Model
Once you have created your Vehicle Model either manually or via the Vehicle Model Generator, you need to distribute your model to use it in an application. Follow the links below for language specific tutorials on how to distribute your freshly created Vehicle Model.
 
 
  
  
  
  
  
  
  
    
    
	
    
    
	1 - C++ Manual Vehicle Model Creation
    Learn how to create a Vehicle Model manually for C++
	Not yet done for C++
 
    
	
  
    
    
	
    
    
	2 - Python Manual Vehicle Model Creation
    Learn how to create a Vehicle Model manually for Python
	Setup a Python Package manually
A Vehicle Model should be defined in its own Python Package. This allows to distribute the Vehicle Model later as a standalone package and to use it in different Vehicle App projects.
The name of the Vehicle Model package will be my_vehicle_model for this walkthrough.
- 
Start Visual Studio Code
 
- 
Select File > Open Folder (File > Open… on macOS) from the main menu.
 
- 
In the Open Folder dialog, create a my_vehicle_model folder and select it. Then click Select Folder (Open on macOS).
 
- 
Create a new file setup.py under my_vehicle_model:
from setuptools import setup
setup(name='my_vehicle_model',
    version='0.1',
    description='My Vehicle Model',
    packages=['my_vehicle_model'],
    zip_safe=False)
This is the Python package distribution script.
 
- 
Create an empty folder my_vehicle_model under my_vehicle_model.
 
- 
Create a new file __init__.py under my_vehicle_model/my_vehicle_model.
 
At this point the source tree of the Python package should look like this:
my_vehicle_model
├── my_vehicle_model
│   └── __init__.py
└── setup.py
To verify that the package is created correctly, install it locally:
The output of the above command should look like this:
Defaulting to user installation because normal site-packages is not writeable
Processing /home/user/projects/my-vehicle-model
Preparing metadata (setup.py) ... done
Building wheels for collected packages: my-vehicle-model
Building wheel for my-vehicle-model (setup.py) ... done
Created wheel for my-vehicle-model: filename=my_vehicle_model-0.1-py3-none-any.whl size=1238 sha256=a619bc9fbea21d587f9f0b1c1c1134ca07e1d9d1fdc1a451da93d918723ce2a2
Stored in directory: /home/user/.cache/pip/wheels/95/c8/a8/80545fb4ff73c974ac1716a7bff6f7f753f92022c41c2e376f
Successfully built my-vehicle-model
Installing collected packages: my-vehicle-model
Successfully installed my-vehicle-model-0.1
Finally, uninstall the package again:
pip3 uninstall my_vehicle_model
Add Vehicle Models manually
- 
Install the Python Vehicle App SDK:
pip3 install git+https://github.com/eclipse-velocitas/vehicle-app-python-sdk.git
The output of the above command should end with:
Successfully installed sdv-x.y.z
Now it is time to add some Vehicle Models to the Python package. At the end of this section you will have a Vehicle Model, that contains a Cabin model, a Seatmodel and has the following tree structure:
 Vehicle
 └── Cabin
     └── Seat (Row, Pos)
 
- 
Create a new file Seat.py under my_vehicle_model/my_vehicle_model:
from sdv.model import Model
class Seat(Model):
    def __init__(self, parent):
        super().__init__(parent)
        self.Position = DataPointFloat("Position", self)
This creates the Seat model with a single data point of type float named Position.
 
- 
Create a new file Cabin.py under my_vehicle_model/my_vehicle_model:
from sdv.model import Model
  class Cabin(Model):
      def __init__(self, parent):
          super().__init__(parent)
          self.Seat = SeatCollection("Seat", self)
  class SeatCollection(Model):
      def __init__(self, name, parent):
          super().__init__(parent)
          self.name = name
          self.Row1 = self.RowType("Row1", self)
          self.Row2 = self.RowType("Row2", self)
      def Row(self, index: int):
          if index < 1 or index > 2:
              raise IndexError(f"Index {index} is out of range")
          _options = {
              1 : self.Row1,
              2 : self.Row2,
          }
          return _options.get(index)
      class RowType(Model):
          def __init__(self, name, parent):
              super().__init__(parent)
              self.name = name
              self.Pos1 = Seat("Pos1", self)
              self.Pos2 = Seat("Pos2", self)
              self.Pos3 = Seat("Pos3", self)
          def Pos(self, index: int):
              if index < 1 or index > 3:
                  raise IndexError(f"Index {index} is out of range")
              _options = {
                  1 : self.Pos1,
                  2 : self.Pos2,
                  3 : self.Pos3,
              }
              return _options.get(index)
This creates the Cabin model, which contains a set of six Seat models, referenced by their names or by rows and positions:
- row=1, pos=1
 
- row=1, pos=2
 
- row=1, pos=3
 
- row=2, pos=1
 
- row=2, pos=2
 
- row=2, pos=3
 
 
- 
Create a new file vehicle.py under my_vehicle_model/my_vehicle_model:
from sdv.model import Model
from my_vehicle_model.Cabin import Cabin
class Vehicle(Model):
    """Vehicle model"""
    def __init__(self, name):
        super().__init__()
        self.name = name
        self.Speed = DataPointFloat("Speed", self)
        self.Cabin = Cabin("Cabin", self)
vehicle = Vehicle("Vehicle")
 
The root model of the Vehicle Model tree should be called Vehicle by convention and is specified, by setting parent to None. For all other models a parent model must be specified as the 2nd argument of the Model constructor, as can be seen by the Cabin and the Seat models above.
A singleton instance of the Vehicle Model called vehicle is created at the end of the file. This instance is supposed to be used in the Vehicle Apps. Creating multiple instances of the Vehicle Model should be avoided for performance reasons.
Add a Vehicle Service
Vehicle Services provide service interfaces to control actuators or to trigger (complex) actions. E.g. they communicate with the vehicle internal networks like CAN or Ethernet, which are connected to actuators, electronic control units (ECUs) and other vehicle computers (VCs). They may provide a simulation mode to run without a network interface. Vehicle Services may feed data to the Databroker and may expose gRPC endpoints, which can be invoked by Vehicle Apps over a Vehicle Model.
In this section, we add a Vehicle Service to the Vehicle Model.
- 
Create a new folder proto under my_vehicle_model/my_vehicle_model.
 
- 
Copy your proto file under my_vehicle_model/my_vehicle_model/proto
As example you could use the protocol buffers message definition 
seats.proto
 provided by the KUKSA services which describes a 
seat control service
.
 
- 
Install the grpcio tools including mypy types to generate the Python classes out of the proto-file:
pip3 install grpcio-tools mypy_protobuf
 
- 
Generate Python classes from the SeatService message definition:
python3 -m grpc_tools.protoc -I my_vehicle_model/proto --grpc_python_out=./my_vehicle_model/proto --python_out=./my_vehicle_model/proto --mypy_out=./my_vehicle_model/proto my_vehicle_model/proto/seats.proto
This creates the following gRPC files under the proto folder:
- seats_pb2.py
 
- seats_pb2_grpc.py
 
- seats_pb2.pyi
 
 
- 
Create the SeatService class and wrap the gRPC service:
from sdv.model import Service
from my_vehicle_model.proto.seats_pb2 import (
    CurrentPositionRequest,
    MoveComponentRequest,
    MoveRequest,
    Seat,
    SeatComponent,
    SeatLocation,
)
from my_vehicle_model.proto.seats_pb2_grpc import SeatsStub
class SeatService(Service):
    "SeatService model"
    def __init__(self):
        super().__init__()
        self._stub = SeatsStub(self.channel)
    async def Move(self, seat: Seat):
        response = await self._stub.Move(MoveRequest(seat=seat), metadata=self.metadata)
        return response
    async def MoveComponent(
        self,
        seatLocation: SeatLocation,
        component: SeatComponent,
        position: int,
    ):
        response = await self._stub.MoveComponent(
            MoveComponentRequest(
                seat=seatLocation,
                component=component,  # type: ignore
                position=position,
            ),
            metadata=self.metadata,
        )
        return response
    async def CurrentPosition(self, row: int, index: int):
        response = await self._stub.CurrentPosition(
            CurrentPositionRequest(row=row, index=index),
            metadata=self.metadata,
        )
        return response
Some important remarks about the wrapping SeatService class
shown above:
- The 
SeatService class must derive from the Service class provided by the Python SDK. 
- The 
SeatService class must use the gRPC channel from the Service base class and provide it to the _stub in the __init__ method. This allows the SDK to manage the physical connection to the gRPC service and use service discovery of the middleware. 
- Every method needs to pass the metadata from the 
Service base class to the gRPC call. This is done by passing the self.metadata argument to the metadata of the gRPC call. 
 
 
    
	
  
    
    
	
    
    
	3 - Vehicle Model Distribution
    Learn how to distribute a Vehicle Model.
	
 
    
      
  
  
  
  
  
  
  
    
    
	
    
    
	3.1 - C++ Vehicle Model Distribution
    Learn how to distribute a Vehicle Model written in C++.
	Now that you have created your own Vehicle Model, we can distribute it to make use of it in Vehicle Apps.
Copying the folder to your Vehicle App repo
The easiest way to get started quickly is to copy the created model, presumably stored in vehicle_model into your Vehicle App repository to use it. To do so, simply copy and paste the directory into the <sdk_root>/app directory and replace the existing model.
Using a git submodule
A similar approach to the one above but a bit more difficult to set up is to create a git repository for the created model. The advantage of this approach is that you can share the same model between multiple Vehicle Apps without any manual effort.
- Create a new git repository on i.e. 
Github
 
- Clone it locally, add the created 
vehicle_model folder to the git repository 
- Commit everything and push the branch
 
In your Vehicle App repo, add a new git submodule via
git submodule add <checkout URL of your new repo> app/vehicle_model
git submodule init
Now you are ready to develop new Vehicle Apps with your custom Vehicle Model!
 
    
	
  
    
    
	
    
    
	3.2 - Python Vehicle Model Distribution
    Learn how to distribute a Vehicle Model written in Python.
	Now you a have a Python package containing your first Python Vehicle Model and it is time to distribute it. There is nothing special about the distribution of this package, since it is just an ordinary Python package. Check out the 
Python Packaging User Guide
 to learn more about packaging and package distribution in Python.
Distribute to single Vehicle App
If you want to distribute your Python Vehicle Model to a single Vehicle App, you can do so by copying the entire folder my_vehicle_model under the /app/src folder of your Vehicle App repository and treat it as a sub-package of the Vehicle App.
- Create a new folder 
my_vehicle_model under /app/src in your Vehicle App repository. 
- Copy the 
my_vehicle_model folder to the /app/src folder of your Vehicle App repository. 
- Import the package 
my_vehicle_model in your Vehicle App: 
from <my_app>.my_vehicle_model import vehicle
...
my_app = MyVehicleApp(vehicle)
Distribute inside an organization
If you want to distribute your Python Vehicle Model inside an organization and use it to develop multiple Vehicle Apps, you can do so by creating a dedicated Git repository and copying the files there.
- 
Create new Git repository called my_vehicle_model
 
- 
Copy the content under my_vehicle_model to the repository.
 
- 
Release the Vehicle Model by creating a version tag (e.g., v1.0.0).
 
- 
Install the Vehicle Model package to your Vehicle App:
pip3 install git+https://github.com/<yourorg>/my_vehicle_model.git@v1.0.0
 
- 
Import the package my_vehicle_model in your Vehicle App and use it as shown in the previous section.
 
Distribute publicly as open source
If you want to distribute your Python Vehicle Model publicly, you can do so by creating a Python package and distributing it on the 
Python Package Index (PyPI)
. PyPi is a repository of software for the Python programming language and helps you find and install software developed and shared by the Python community. If you use the pip command, you are already using PyPI.
Detailed instructions on how to make a Python package available on PyPI can be found 
here
.