Skip to content
Snippets Groups Projects
Commit 7c074c1f authored by Constantin Christmann's avatar Constantin Christmann
Browse files

Upload of initial contribution from Vector.

parent 6403a38a
No related branches found
No related tags found
No related merge requests found
Showing
with 1849 additions and 0 deletions
# Hello VAF Demo
This `Hello, World!` style demo, introduces to the Vehicle Application Framework (VAF) with a simple
example. The figure below provides a schematic illustration to give an overview of its building
blocks:
![hello](../figures/hello.drawio.svg)
`AppModule1` provides a communication interface that is used by `AppModule2`.
The first application module periodically sends a message of format `Hello, VAF! - MsgID: <ID>`
to the second application module. The second module subscribes to message changes and prints new
messages on the terminal. It uses an operation to periodically change the MsgID of the first
application module, which is part of the message above.
## Prerequisites
### Docker setup
All steps in this tutorial are executed from within a container. Recipe and build script for the
appropriate VAF image are provided in the [Container](../../Container/README.md) folder of this
project repository.
Execute `docker images` to check if a REPOSITORY named `vaf` with TAG `latest` is available in the
list before moving on to the next steps.
### Workspace
The Vehicle Application Framework (VAF) supports three different project types, *interface project*,
*app-module project*, and *integration project*. These project types are useful for the organization
of small and large projects but especially helpful, when working with distributed development teams.
To group projects that belong together, it is recommended to create a so-called *workspace*. This
parent folder contains for example a devcontainer file to facilitate the work with VS Code.
To create a workspace, navigate to the target location, then use the below command to start a VAF
container and finally, create a VAF workspace there and enter the new directory.
``` bash
cd <some-dir>
docker run -it --rm --network=host -v$PWD:$PWD -w$PWD vaf:latest /bin/bash
vaf workspace init
Enter your workspace name: VafWorkspace
cd VafWorkspace
```
The following steps of the tutorial can either be executed in this already open terminal window or
directly from VS Code as described below.
### VS Code setup
To work with the VS Code container extension, enter a VAF workspace directory and make sure to
re-open the folder in the container:
* Open a remote window (bottom-left corner)
![remote-window](../figures/vscode-remote-window.png)
* Re-open project in container
![reopen-container](../figures/vscode-reopen-container.png)
In the bottom-left corner you find also a task runner extension that supports with the individual
steps of the VAF workflow. Commands can be clicked instead of using the command line interface.
>**ℹ️ Note**
> The execution path gets derived from the current working directory based on the currently opened
> file in editor area of the IDE.
## Project setup
First step is to create an integration project. This type of project deals with the integration of
an application, which includes instantiation and wiring of application modules, configuration of the
executable(s), and finally, the build of the binaries for execution on the target machine.
Application module projects can either be created in place, i.e., as sub-project of an integration
project, or imported from some external location. For the sake of simplicity, this demo makes use of
the first option.
First step is to create the required projects by using the following CLI commands:
``` bash
vaf project init integration
Enter your project name: HelloVaf
? Enter the directory to store your project in .
cd HelloVaf
vaf project create app-module
Enter the name of the app-module: AppModule1
Enter the namespace of the app-module: demo
? Enter the path to the project root directory .
vaf project create app-module
Enter the name of the app-module: AppModule2
Enter the namespace of the app-module: demo
? Enter the path to the project root directory .
```
The above commands create the structure of the corresponding projects. The application module
sub-projects are stored in the `HelloVaf/src/application_modules` directory, i.e., directly in the
integration project.
## Definition of interfaces
Communication between application modules is defined by means of communication interfaces. The
Configuration as Code (CaC) file for this step is part of the project template and located in the
`model` folder of each app-module sub-project. Extend the `app_module1.py` file of the first
app-module located in `HelloVaf/src/application_modules/app_module1/model` as follows:
``` python
interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo")
interface.add_data_element("Message", datatype=BaseTypes.STRING)
interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T})
```
This snippet defines a simple interface containing one data element (`Message`) and one operation
(`SetMsgId`).
As this interface definition is also used by the other app-module, make sure to copy the above
definition to the corresponding CaC file of the second app-module.
## Configuration of application modules
Next step is the configuration of both app-modules. For `AppModule1`, modify the generated template
of the CaC file to add a provider instance of the above interface and a periodically executed task:
``` python
app_module1.add_provided_interface("HelloWorldProvider", interface)
periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=500))
app_module1.add_task(task=periodic_task)
```
The configuration snippet for `AppModule2` is almost similar. Only the interface instance is a
consumed one in this case:
``` python
app_module2.add_consumed_interface("HelloWorldConsumer", interface)
periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=1000))
app_module2.add_task(task=periodic_task)
```
With this, the Configuration as Code part is complete. Next step is to start the code generation for
both app-modules. Change to the appropriate project directories
`HelloVaf/src/application_modules/app_module1` and `HelloVaf/src/application_modules/app_module2` to
run:
``` bash
vaf project generate
```
This step provides the implementation stubs in the `implementation` subdirectory of the app-module
projects. It also configures CMake with a release and debug preset to enable support by the VS Code
CMake Tools extension as well as IntelliSense features.
## Implementation of business logic
Now, some business logic can be added according to the demo description in the introduction of this
tutorial. For that, the periodic tasks of both app-modules need to be implemented. Further, an
operation handler needs to be registered in `AppModule1`. In `AppModule2` a data element handler is
needed.
In the first app-module, add the following snippet to the constructor
(see `HelloVaf/src/application_modules/app_module1/implementation/src/app_module1.cpp`):
``` cpp
HelloWorldProvider_->RegisterOperationHandler_SetMsgId(
[this](const std::uint8_t& msg_id) { msg_id_ = static_cast<uint8_t>(msg_id); }
);
```
Next, extend the periodic task with a simple method:
``` cpp
std::string myMsg = "Hello, VAF! - MsgID: " + std::to_string(msg_id_);
HelloWorldProvider_->Set_Message(myMsg.c_str());
```
Additionally, a member attribute must be defined in the corresponding header file of AppModule1:
``` cpp
private:
uint8_t msg_id_;
```
In the constructor of the second app-module, register a data element handler as follows:
``` cpp
HelloWorldConsumer_->RegisterDataElementHandler_Message(
GetName(),
[](const auto& hello_text) { std::cout << "Received: " << *hello_text << std::endl; }
);
```
Further, modify the periodic task to include the following snippet:
``` cpp
static uint8_t msg_id = 0;
HelloWorldConsumer_->SetMsgId(msg_id++);
```
Also, extend the include directives, for example with `#include <iostream>` in `app_module2.cpp`.
>**ℹ️ Note**
> To check for compilation errors, you can compile the app-modules into static libraries using `vaf
> make build` inside of the app-module project directory.
## Executable configuration
Returning to the integration project, both application modules can now be instantiated. Those
instances are then mapped to some executable, and finally, connected among each other. First,
however, the model changes from the application module projects above must be updated as to be
present on the level of the integration project. To do so, run the following command from the
integration projects' root directory, i.e. `HelloVaf`:
``` bash
vaf model update
```
Select both application modules in the appearing interactive dialog.
Now, the CaC file of the integration project in `HelloVaf/model/vaf/hello_vaf.py` can be extended:
``` python
# Create executable instances
executable = Executable("HelloVaf")
# Add application modules to executable instances
executable.add_application_module(AppModule1, [(Instances.AppModule1.Tasks.PeriodicTask, timedelta(milliseconds=10), 0)])
executable.add_application_module(AppModule2, [(Instances.AppModule2.Tasks.PeriodicTask, timedelta(milliseconds=10), 1)])
```
The above config snippet adds one instance of each app-module to the `HelloVaf` executable, enables
the periodic tasks, and sets them with a time budget of 10 ms and a preferred execution order.
Next step is the connection of the two application modules:
``` python
# Connect the internal application module instances
executable.connect_interfaces(
AppModule1,
Instances.AppModule1.ProvidedInterfaces.HelloWorldProvider,
AppModule2,
Instances.AppModule2.ConsumedInterfaces.HelloWorldConsumer,
)
```
Now, the project configuration is complete. The source code on executable-level can be generated
and the executable can be built as listed below:
``` bash
vaf project generate
vaf make install
```
>**ℹ️ Note**
> If something changes in any sub-project of the integration project, the entire integration project
> with all it's dependencies can be regenerated using `vaf project generate --mode ALL`. This also
> includes the `vaf model update` command as mentioned at the beginning of this section.
## Running the application
After the successful install step, the binary executable is located in the
`HelloVaf/build/<build_type>/install` directory and can be executed from there as follows:
``` bash
cd build/Release/install/opt/HelloVaf/
./bin/HelloVaf
```
You should see the following output on your terminal:
```
UserController::PreInitialize
ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kNotOperational
ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kNotOperational
ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kNotOperational
UserController::PostInitialize
UserController::PreStart
ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kStarting
ExecutableControllerBase::ChangeStateOfModule: name HelloWorldIfModule state: kOperational
ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kStarting
ExecutableControllerBase::ChangeStateOfModule: name AppModule1 state: kOperational
UserController::PostStart
ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kStarting
ExecutableControllerBase::ChangeStateOfModule: name AppModule2 state: kOperational
Received: Hello, VAF! - MsgID: 0
Received: Hello, VAF! - MsgID: 0
Received: Hello, VAF! - MsgID: 1
Received: Hello, VAF! - MsgID: 1
Received: Hello, VAF! - MsgID: 2
Received: Hello, VAF! - MsgID: 2
Received: Hello, VAF! - MsgID: 3
...
```
## Introduction to interface projects
In the above example, the interface definition is needed in both application module projects and
had to be copied. This works for small projects but even there, it can easily happen that
definitions diverge from each other. In consequence, consolidation or merging is needed.
To avoid such situations, *interface projects* in the VAF can be used to define communication
interfaces in a central location. Application module projects can then import these interfaces to
the Configuration as Code level for further use.
The following steps illustrate, how an interface project can be added to the above example.
At first, create a new interface project in your workspace, i.e., next to the `HelloVaf` folder:
``` bash
vaf project init interface
Enter your project name: HelloInterfaces
? Enter the directory to store your project in .
```
The interface definitions that earlier got directly added to the configuration in the app-module
projects can now go here. To specify the `HelloWorldIf`, extend the generated `hello_interfaces.py`
file as follows:
``` python
interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo")
interface.add_data_element("Message", datatype=BaseTypes.STRING)
interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T})
```
Next, generate the corresponding data exchange format of this interface definition:
``` bash
cd HelloInterfaces
vaf model generate
```
Switch to the directory of each application module project and run the following command to import
the interface project. Choose the path to the `HelloInterfaces/export/HelloInterfaces.json` file
in the interactive prompt:
``` bash
vaf project import
```
The original interface definition can now be removed from both app-module configurations. Instead,
the following line must be uncommented:
``` python
from .imported_models import *
```
The interface can now be used through the imported CaC helper as illustrated below:
``` python
app_module1.add_provided_interface("HelloWorldProvider", hello_interfaces.Demo.hello_world_if)
```
Apply those changes for both application modules.
Finally and due to changes in both app-modules, the executable can be rebuilt by navigating to the
integration project directory and running the following commands:
``` bash
vaf project generate --mode ALL
vaf make install
```
from datetime import timedelta
from vaf import vafpy, BaseTypes
interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo")
interface.add_data_element("Message", datatype=BaseTypes.STRING)
interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T})
app_module1 = vafpy.ApplicationModule(name="AppModule1", namespace="demo")
app_module1.add_provided_interface("HelloWorldProvider", interface)
periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=500))
app_module1.add_task(task=periodic_task)
from datetime import timedelta
from vaf import vafpy, BaseTypes
interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo")
interface.add_data_element("Message", datatype=BaseTypes.STRING)
interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T})
app_module2 = vafpy.ApplicationModule(name="AppModule2", namespace="demo")
app_module2.add_consumed_interface("HelloWorldConsumer", interface)
periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=1000))
app_module2.add_task(task=periodic_task)
from vaf import BaseTypes, vafpy
interface = vafpy.ModuleInterface(name="HelloWorldIf", namespace="demo")
interface.add_data_element("Message", datatype=BaseTypes.STRING)
interface.add_operation("SetMsgId", in_parameter={"MsgId": BaseTypes.UINT8_T})
from datetime import timedelta
from .application_modules import Instances, AppModule1, AppModule2
from vaf import *
# Create executable instances (or configure existing ones from the platform configuration)
executable = Executable("HelloVaf")
# Add application modules to executable instances
executable.add_application_module(
AppModule1,
[(Instances.AppModule1.Tasks.PeriodicTask, timedelta(milliseconds=10), 0)],
)
executable.add_application_module(
AppModule2,
[(Instances.AppModule2.Tasks.PeriodicTask, timedelta(milliseconds=10), 1)],
)
# Connect the internal application module instances
executable.connect_interfaces(
AppModule1,
Instances.AppModule1.ProvidedInterfaces.HelloWorldProvider,
AppModule2,
Instances.AppModule2.ConsumedInterfaces.HelloWorldConsumer,
)
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file app_module1.cpp
* \brief
*
*********************************************************************************************************************/
#include "demo/app_module1.h"
namespace demo {
/*
Generated based on configuration in ../../model/app_module1.py
Provider interfaces
===================
Data element API example for Message of type vaf::string
- ::vaf::Result<::vaf::DataPtr<vaf::string>> Allocate_Message()
- ::vaf::Result<void> SetAllocated_Message(::vaf::DataPtr<vaf::string>&& data)
- ::vaf::Result<void> Set_Message(const vaf::string& data)
- HelloWorldProvider_ : demo::HelloWorldIfProvider
- Data elements
- Message : vaf::string
- Operations
- void RegisterOperationHandler_SetMsgId(std::function<void(const std::uint8_t&)>&& f)
*/
/**********************************************************************************************************************
Constructor
**********************************************************************************************************************/
AppModule1::AppModule1(ConstructorToken&& token)
: AppModule1Base(std::move(token))
{
HelloWorldProvider_->RegisterOperationHandler_SetMsgId(
[this](const std::uint8_t& msg_id) { msg_id_ = static_cast<uint8_t>(msg_id); }
);
}
/**********************************************************************************************************************
1 periodic task(s)
**********************************************************************************************************************/
// Task with name PeriodicTask and a period of 500ms.
void AppModule1::PeriodicTask() {
std::string myMsg = "Hello, VAF! - MsgID: " + std::to_string(msg_id_);
HelloWorldProvider_->Set_Message(myMsg.c_str());
}
} // namespace demo
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file app_module1.h
* \brief
*
*********************************************************************************************************************/
#ifndef DEMO_APP_MODULE1_H
#define DEMO_APP_MODULE1_H
#include "demo/app_module1_base.h"
namespace demo {
class AppModule1 : public AppModule1Base {
public:
AppModule1(ConstructorToken&& token);
void PeriodicTask() override;
private:
uint8_t msg_id_;
};
} // namespace demo
#endif // DEMO_APP_MODULE1_H
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file app_module2.cpp
* \brief
*
*********************************************************************************************************************/
#include "demo/app_module2.h"
#include <iostream>
namespace demo {
/*
Generated based on configuration in ../../model/app_module2.py
Consumer interfaces
===================
Data element API example for Message of type vaf::string
- ::vaf::Result<::vaf::ConstDataPtr<const vaf::string>> GetAllocated_Message()
- vaf::string Get_Message()
- void RegisterDataElementHandler_Message(std::string owner, std::function<void(const ::vaf::ConstDataPtr<const vaf::string>)>&& f)
- HelloWorldConsumer_ : demo::HelloWorldIfConsumer
- Data elements
- Message : vaf::string
- Operations
- ::vaf::Future<void> SetMsgId(const std::uint8_t& MsgId)
*/
/**********************************************************************************************************************
Constructor
**********************************************************************************************************************/
AppModule2::AppModule2(ConstructorToken&& token)
: AppModule2Base(std::move(token))
{
HelloWorldConsumer_->RegisterDataElementHandler_Message(
GetName(),
[](const auto& hello_text) { std::cout << "Received: " << *hello_text << std::endl; }
);
}
/**********************************************************************************************************************
1 periodic task(s)
**********************************************************************************************************************/
// Task with name PeriodicTask and a period of 1000ms.
void AppModule2::PeriodicTask() {
static uint8_t msg_id = 0;
HelloWorldConsumer_->SetMsgId(msg_id++);
}
} // namespace demo
# Demo
Three examples are provided to illustrate the usage of the Vehicle Application Framework (VAF).
1. [HelloVaf](./HelloVaf/) is a simple one and the ideal starting point with the framework. It
introduces to the three different project types and the Configuration as Code user front-end.
Two application modules exchange information internal to one executable.
2. [Vss](./Vss) extends the previous example and illustrates how imported datatype and interface
information from the [COVESA Vehicle Signal Specification (VSS)](https://covesa.global/project/vehicle-signal-specification/)
can be used.
3. [SilKit](./SilKit/) is an example project with two executables that communicate via the [Vector
SIL Kit](https://github.com/vectorgrp/sil-kit). This illustrates the concept of middleware
abstraction and how to do system-level tests with a distributed application in the VAF.
This diff is collapsed.
from datetime import timedelta
from vaf import vafpy, BaseTypes
from .imported_models import *
collision_detection = vafpy.ApplicationModule(
name="CollisionDetection", namespace="NsApplicationUnit::NsCollisionDetection"
)
collision_detection.add_provided_interface(
"BrakeServiceProvider", interfaces.Af.AdasDemoApp.Services.brake_service
)
collision_detection.add_consumed_interface(
"ObjectDetectionListModule",
interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface,
)
periodic_task = vafpy.Task(name="PeriodicTask", period=timedelta(milliseconds=200))
collision_detection.add_task(task=periodic_task)
from vaf import BaseTypes, vafpy
# Brake Service
brake_pressure = vafpy.datatypes.Struct(name="BrakePressure", namespace="datatypes")
brake_pressure.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T)
brake_pressure.add_subelement(name="value", datatype=BaseTypes.UINT8_T)
brake_service = vafpy.ModuleInterface(
name="BrakeService", namespace="af::adas_demo_app::services"
)
brake_service.add_data_element(name="brake_action", datatype=brake_pressure)
brake_service.add_operation(
name="SumTwoSummands",
in_parameter={"summand_one": BaseTypes.UINT16_T, "summand_two": BaseTypes.UINT16_T},
out_parameter={"sum": BaseTypes.UINT16_T},
)
# Object Detection List
od_struct = vafpy.datatypes.Struct(name="ObjectDetection", namespace="adas::interfaces")
od_struct.add_subelement(name="x", datatype=BaseTypes.UINT64_T)
od_struct.add_subelement(name="y", datatype=BaseTypes.UINT64_T)
od_struct.add_subelement(name="z", datatype=BaseTypes.UINT64_T)
od_list = vafpy.datatypes.Vector(
name="ObjectDetectionList",
namespace="adas::interfaces",
datatype=od_struct,
)
od_interface = vafpy.ModuleInterface(
name="ObjectDetectionListInterface",
namespace="nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist",
)
od_interface.add_data_element(name="object_detection_list", datatype=od_list)
# ImageService
uint8_vector = vafpy.datatypes.Vector(
name="UInt8Vector", namespace="datatypes", datatype=BaseTypes.UINT8_T
)
image = vafpy.datatypes.Struct(name="Image", namespace="datatypes")
image.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T)
image.add_subelement(name="height", datatype=BaseTypes.UINT16_T)
image.add_subelement(name="width", datatype=BaseTypes.UINT16_T)
image.add_subelement(name="R", datatype=uint8_vector)
image.add_subelement(name="G", datatype=uint8_vector)
image.add_subelement(name="B", datatype=uint8_vector)
image_service = vafpy.ModuleInterface(
name="ImageService", namespace="af::adas_demo_app::services"
)
image_service.add_data_element(name="camera_image", datatype=image)
image_service.add_operation(
name="GetImageSize",
out_parameter={"width": BaseTypes.UINT16_T, "height": BaseTypes.UINT16_T},
)
# VelocityService
velocity = vafpy.datatypes.Struct(name="Velocity", namespace="datatypes")
velocity.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T)
velocity.add_subelement(name="value", datatype=BaseTypes.UINT16_T)
velocity_service = vafpy.ModuleInterface(
name="VelocityService", namespace="af::adas_demo_app::services"
)
velocity_service.add_data_element(name="car_velocity", datatype=velocity)
# Steering Angle
steering_angle = vafpy.datatypes.Struct(name="SteeringAngle", namespace="datatypes")
steering_angle.add_subelement(name="timestamp", datatype=BaseTypes.UINT64_T)
steering_angle.add_subelement(name="value", datatype=BaseTypes.UINT16_T)
steering_angle_service = vafpy.ModuleInterface(
name="SteeringAngleService", namespace="af::adas_demo_app::services"
)
steering_angle_service.add_data_element(name="steering_angle", datatype=steering_angle)
from datetime import timedelta
from vaf import vafpy, BaseTypes
from .imported_models import *
sensor_fusion = vafpy.ApplicationModule(
name="SensorFusion", namespace="NsApplicationUnit::NsSensorFusion"
)
sensor_fusion.add_provided_interface(
"ObjectDetectionListModule",
interfaces.Nsapplicationunit.Nsmoduleinterface.Nsobjectdetectionlist.object_detection_list_interface,
)
sensor_fusion.add_consumed_interface(
"ImageServiceConsumer1", interfaces.Af.AdasDemoApp.Services.image_service
)
sensor_fusion.add_consumed_interface(
"ImageServiceConsumer2", interfaces.Af.AdasDemoApp.Services.image_service
)
sensor_fusion.add_consumed_interface(
"SteeringAngleServiceConsumer",
interfaces.Af.AdasDemoApp.Services.steering_angle_service,
)
sensor_fusion.add_consumed_interface(
"VelocityServiceConsumer", interfaces.Af.AdasDemoApp.Services.velocity_service
)
p_200ms = timedelta(milliseconds=200)
step1 = vafpy.Task(name="Step1", period=p_200ms, preferred_offset=0)
step2 = vafpy.Task(name="Step2", period=p_200ms, preferred_offset=0)
step3 = vafpy.Task(name="Step3", period=p_200ms, preferred_offset=0)
sensor_fusion.add_task(task=step1)
sensor_fusion.add_task_chain(tasks=[step2, step3], run_after=[step1])
sensor_fusion.add_task(
vafpy.Task(name="Step4", period=p_200ms, preferred_offset=0, run_after=[step1])
)
from datetime import timedelta
from .application_modules import TestModule, SensorFusion, Instances, CollisionDetection
from vaf import *
# Create executable instances (or configure existing ones from the platform configuration)
executable = Executable("AdasDemoExecutable", timedelta(milliseconds=20))
tester = Executable("AdasDemoTester", timedelta(milliseconds=20))
# Add application modules to executable instances
b_10ms = timedelta(milliseconds=10)
executable.add_application_module(
SensorFusion,
[
(Instances.SensorFusion.Tasks.Step1, b_10ms, 0),
(Instances.SensorFusion.Tasks.Step2, b_10ms, 0),
(Instances.SensorFusion.Tasks.Step3, b_10ms, 0),
(Instances.SensorFusion.Tasks.Step4, b_10ms, 0),
],
)
executable.add_application_module(
CollisionDetection,
[(Instances.CollisionDetection.Tasks.PeriodicTask, timedelta(milliseconds=1), 1)],
)
tester.add_application_module(
TestModule,
[
(Instances.TestModule.Tasks.BrakeTask, b_10ms, 0),
(Instances.TestModule.Tasks.ImageTask, b_10ms, 0),
(Instances.TestModule.Tasks.SteeringAngleTask, b_10ms, 0),
(Instances.TestModule.Tasks.VelocityTask, b_10ms, 0),
],
)
# Connect the application module instances internally
executable.connect_interfaces(
SensorFusion,
Instances.SensorFusion.ProvidedInterfaces.ObjectDetectionListModule,
CollisionDetection,
Instances.CollisionDetection.ConsumedInterfaces.ObjectDetectionListModule,
)
# Connect the application module instances with middleware
executable.connect_consumed_interface_to_silkit(
SensorFusion,
Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer1,
"Silkit_ImageService1",
)
executable.connect_consumed_interface_to_silkit(
SensorFusion,
Instances.SensorFusion.ConsumedInterfaces.ImageServiceConsumer2,
"Silkit_ImageService2",
)
executable.connect_consumed_interface_to_silkit(
SensorFusion,
Instances.SensorFusion.ConsumedInterfaces.SteeringAngleServiceConsumer,
"Silkit_SteeringAngleService",
)
executable.connect_consumed_interface_to_silkit(
SensorFusion,
Instances.SensorFusion.ConsumedInterfaces.VelocityServiceConsumer,
"Silkit_VelocityService",
)
executable.connect_provided_interface_to_silkit(
CollisionDetection,
Instances.CollisionDetection.ProvidedInterfaces.BrakeServiceProvider,
"Silkit_BrakeService",
)
tester.connect_consumed_interface_to_silkit(
TestModule,
Instances.TestModule.ConsumedInterfaces.BrakeServiceConsumer,
"Silkit_BrakeService",
)
tester.connect_provided_interface_to_silkit(
TestModule,
Instances.TestModule.ProvidedInterfaces.ImageServiceProvider1,
"Silkit_ImageService1",
)
tester.connect_provided_interface_to_silkit(
TestModule,
Instances.TestModule.ProvidedInterfaces.ImageServiceProvider2,
"Silkit_ImageService2",
)
tester.connect_provided_interface_to_silkit(
TestModule,
Instances.TestModule.ProvidedInterfaces.SteeringAngleServiceProvider,
"Silkit_SteeringAngleService",
)
tester.connect_provided_interface_to_silkit(
TestModule,
Instances.TestModule.ProvidedInterfaces.VelocityServiceProvider,
"Silkit_VelocityService",
)
from datetime import timedelta
from vaf import vafpy, BaseTypes
from .imported_models import *
test_module = vafpy.ApplicationModule(
name="TestModule", namespace="NsApplicationUnit::NsTestModule"
)
test_module.add_consumed_interface(
instance_name="BrakeServiceConsumer",
interface=interfaces.Af.AdasDemoApp.Services.brake_service,
)
test_module.add_provided_interface(
instance_name="ImageServiceProvider1",
interface=interfaces.Af.AdasDemoApp.Services.image_service,
)
test_module.add_provided_interface(
instance_name="ImageServiceProvider2",
interface=interfaces.Af.AdasDemoApp.Services.image_service,
)
test_module.add_provided_interface(
instance_name="SteeringAngleServiceProvider",
interface=interfaces.Af.AdasDemoApp.Services.steering_angle_service,
)
test_module.add_provided_interface(
instance_name="VelocityServiceProvider",
interface=interfaces.Af.AdasDemoApp.Services.velocity_service,
)
test_module.add_task(
task=vafpy.Task(name="BrakeTask", period=timedelta(milliseconds=100))
)
test_module.add_task(
task=vafpy.Task(name="ImageTask", period=timedelta(milliseconds=100))
)
test_module.add_task(
task=vafpy.Task(name="SteeringAngleTask", period=timedelta(milliseconds=1000))
)
test_module.add_task(
task=vafpy.Task(name="VelocityTask", period=timedelta(milliseconds=1000))
)
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file collision_detection.h
* \brief
*
*********************************************************************************************************************/
#ifndef NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H
#define NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H
#include "nsapplicationunit/nscollisiondetection/collision_detection_base.h"
namespace NsApplicationUnit {
namespace NsCollisionDetection {
class CollisionDetection : public CollisionDetectionBase {
public:
CollisionDetection(ConstructorToken&& token);
void PeriodicTask() override;
::datatypes::BrakePressure ComputeBrakePressure(
vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list);
void OnError(const vaf::Error& error) override;
void OnObjectList(vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list);
private:
};
} // namespace NsCollisionDetection
} // namespace NsApplicationUnit
#endif // NSAPPLICATIONUNIT_NSCOLLISIONDETECTION_COLLISION_DETECTION_H
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file collision_detection.cpp
* \brief
*
*********************************************************************************************************************/
#include "nsapplicationunit/nscollisiondetection/collision_detection.h"
namespace NsApplicationUnit {
namespace NsCollisionDetection {
/*
Generated based on configuration in ../../model/collision_detection.py
Consumer interfaces
===================
Data element API example for object_detection_list of type adas::interfaces::ObjectDetectionList
- ::vaf::Result<::vaf::ConstDataPtr<const adas::interfaces::ObjectDetectionList>>
GetAllocated_object_detection_list()
- adas::interfaces::ObjectDetectionList Get_object_detection_list()
- void RegisterDataElementHandler_object_detection_list(std::string owner, std::function<void(const
::vaf::ConstDataPtr<const adas::interfaces::ObjectDetectionList>)>&& f)
- ObjectDetectionListModule_ :
nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceConsumer
- Data elements
- object_detection_list : adas::interfaces::ObjectDetectionList
Provider interfaces
===================
Data element API example for brake_action of type datatypes::BrakePressure
- ::vaf::Result<::vaf::DataPtr<datatypes::BrakePressure>> Allocate_brake_action()
- ::vaf::Result<void> SetAllocated_brake_action(::vaf::DataPtr<datatypes::BrakePressure>&& data)
- ::vaf::Result<void> Set_brake_action(const datatypes::BrakePressure& data)
- BrakeServiceProvider_ : af::adas_demo_app::services::BrakeServiceProvider
- Data elements
- brake_action : datatypes::BrakePressure
- Operations
- void
RegisterOperationHandler_SumTwoSummands(std::function<af::adas_demo_app::services::SumTwoSummands::Output(const
std::uint16_t&, const std::uint16_t&)>&& f)
*/
/**********************************************************************************************************************
Constructor
**********************************************************************************************************************/
CollisionDetection::CollisionDetection(ConstructorToken&& token) : CollisionDetectionBase(std::move(token)) {
ObjectDetectionListModule_->RegisterDataElementHandler_object_detection_list(
GetName(), [this](vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList> object_detection_list) {
OnObjectList(object_detection_list);
});
BrakeServiceProvider_->RegisterOperationHandler_SumTwoSummands(
[](std::uint16_t const& summand_one, std::uint16_t const& summand_two) {
af::adas_demo_app::services::SumTwoSummands::Output output{};
output.sum = summand_one + summand_two;
return output;
});
}
/**********************************************************************************************************************
1 periodic task(s)
**********************************************************************************************************************/
// Task with name PeriodicTask and a period of 200ms.
void CollisionDetection::PeriodicTask() { std::cout << "Collision detection is active\n"; }
::datatypes::BrakePressure CollisionDetection::ComputeBrakePressure(
vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list) {
static_cast<void>(object_list);
return ::datatypes::BrakePressure{11, 22};
}
void CollisionDetection::OnError(const vaf::Error& error) {
static_cast<void>(error);
ReportError(vaf::ErrorCode::kDefaultErrorCode, "Unknown error", true);
}
void CollisionDetection::OnObjectList(vaf::ConstDataPtr<const ::adas::interfaces::ObjectDetectionList>& object_list) {
std::cout << "Collision onObjectList\n";
::datatypes::BrakePressure brake_pressure = ComputeBrakePressure(object_list);
BrakeServiceProvider_->Set_brake_action(brake_pressure);
}
} // namespace NsCollisionDetection
} // namespace NsApplicationUnit
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file sensor_fusion.h
* \brief
*
*********************************************************************************************************************/
#ifndef NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H
#define NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H
#include "nsapplicationunit/nssensorfusion/sensor_fusion_base.h"
namespace NsApplicationUnit {
namespace NsSensorFusion {
class SensorFusion : public SensorFusionBase {
public:
SensorFusion(ConstructorToken&& token);
void Step1() override;
void Step2() override;
void Step3() override;
void Step4() override;
void OnError(const vaf::Error& error) override;
void OnVelocity(vaf::ConstDataPtr<const ::datatypes::Velocity> velocity);
::adas::interfaces::ObjectDetectionList DoDetection(const ::datatypes::Image&, const ::datatypes::Image&,
::datatypes::SteeringAngle, ::datatypes::Velocity);
private:
constexpr static uint16_t kMaxVelocity{100};
bool is_enabled_{true};
};
} // namespace NsSensorFusion
} // namespace NsApplicationUnit
#endif // NSAPPLICATIONUNIT_NSSENSORFUSION_SENSOR_FUSION_H
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file sensor_fusion.cpp
* \brief
*
*********************************************************************************************************************/
#include "nsapplicationunit/nssensorfusion/sensor_fusion.h"
namespace NsApplicationUnit {
namespace NsSensorFusion {
/*
Generated based on configuration in ../../model/sensor_fusion.py
Consumer interfaces
===================
Data element API example for camera_image of type datatypes::Image
- ::vaf::Result<::vaf::ConstDataPtr<const datatypes::Image>> GetAllocated_camera_image()
- datatypes::Image Get_camera_image()
- void RegisterDataElementHandler_camera_image(std::string owner, std::function<void(const
::vaf::ConstDataPtr<const datatypes::Image>)>&& f)
- ImageServiceConsumer1_ : af::adas_demo_app::services::ImageServiceConsumer
- Data elements
- camera_image : datatypes::Image
- Operations
- ::vaf::Future<af::adas_demo_app::services::GetImageSize::Output> GetImageSize()
- ImageServiceConsumer2_ : af::adas_demo_app::services::ImageServiceConsumer
- Data elements
- camera_image : datatypes::Image
- Operations
- ::vaf::Future<af::adas_demo_app::services::GetImageSize::Output> GetImageSize()
- SteeringAngleServiceConsumer_ : af::adas_demo_app::services::SteeringAngleServiceConsumer
- Data elements
- steering_angle : datatypes::SteeringAngle
- VelocityServiceConsumer_ : af::adas_demo_app::services::VelocityServiceConsumer
- Data elements
- car_velocity : datatypes::Velocity
Provider interfaces
===================
Data element API example for object_detection_list of type adas::interfaces::ObjectDetectionList
- ::vaf::Result<::vaf::DataPtr<adas::interfaces::ObjectDetectionList>> Allocate_object_detection_list()
- ::vaf::Result<void> SetAllocated_object_detection_list(::vaf::DataPtr<adas::interfaces::ObjectDetectionList>&&
data)
- ::vaf::Result<void> Set_object_detection_list(const adas::interfaces::ObjectDetectionList& data)
- ObjectDetectionListModule_ :
nsapplicationunit::nsmoduleinterface::nsobjectdetectionlist::ObjectDetectionListInterfaceProvider
- Data elements
- object_detection_list : adas::interfaces::ObjectDetectionList
*/
/**********************************************************************************************************************
Constructor
**********************************************************************************************************************/
SensorFusion::SensorFusion(ConstructorToken&& token) : SensorFusionBase(std::move(token)) {
VelocityServiceConsumer_->RegisterDataElementHandler_car_velocity(
GetName(), [this](vaf::ConstDataPtr<const ::datatypes::Velocity> velocity) { OnVelocity(std::move(velocity)); });
}
/**********************************************************************************************************************
4 periodic task(s)
**********************************************************************************************************************/
// Task with name Step1 and a period of 200ms.
void SensorFusion::Step1() {
if (is_enabled_) {
std::cout << "SensorFusion::step\n";
bool no_new_image{false};
auto image1 = ImageServiceConsumer1_->GetAllocated_camera_image().InspectError(
[&no_new_image](const vaf::Error&) { no_new_image = true; });
auto image2 = ImageServiceConsumer2_->GetAllocated_camera_image().InspectError(
[&no_new_image](const vaf::Error&) { no_new_image = true; });
auto steering_angle = SteeringAngleServiceConsumer_->Get_steering_angle();
auto velocity = VelocityServiceConsumer_->Get_car_velocity();
if (!no_new_image) {
std::cout << "Received new images" << "\n";
::adas::interfaces::ObjectDetectionList object_list =
DoDetection(*image1.Value(), *image2.Value(), steering_angle, velocity);
std::cout << "SensorFusion sending detection list\n";
ObjectDetectionListModule_->Set_object_detection_list(object_list);
}
}
}
// Task with name Step2 and a period of 200ms.
void SensorFusion::Step2() {
// Insert your code for periodic execution here...
}
// Task with name Step3 and a period of 200ms.
void SensorFusion::Step3() {
// Insert your code for periodic execution here...
}
// Task with name Step4 and a period of 200ms.
void SensorFusion::Step4() {
// Insert your code for periodic execution here...
}
void SensorFusion::OnVelocity(vaf::ConstDataPtr<const ::datatypes::Velocity> velocity) {
std::cout << "Received Velocity: " << velocity->value << "\n";
is_enabled_ = (velocity->value < kMaxVelocity);
}
::adas::interfaces::ObjectDetectionList SensorFusion::DoDetection(const ::datatypes::Image& image1,
const ::datatypes::Image& image2,
::datatypes::SteeringAngle, ::datatypes::Velocity) {
static_cast<void>(image1);
static_cast<void>(image2);
vaf::Future<af::adas_demo_app::services::GetImageSize::Output> answer = ImageServiceConsumer1_->GetImageSize();
if (vaf::is_future_ready(answer)) {
auto result = answer.GetResult();
if (result.HasValue())
std::cout << "GetImageSize() yields: " << result.Value().width << "x" << result.Value().height << "\n";
}
return ::adas::interfaces::ObjectDetectionList{};
}
void SensorFusion::OnError(const vaf::Error& error) {
std::cout << "Error in sensor fusion: " << error.Message() << ", " << error.UserMessage() << "\n";
ReportError(vaf::ErrorCode::kDefaultErrorCode, "Unknown error", true);
}
} // namespace NsSensorFusion
} // namespace NsApplicationUnit
/*!********************************************************************************************************************
* COPYRIGHT
* -------------------------------------------------------------------------------------------------------------------
* \verbatim
* Copyright (c) 2025 by Vector Informatik GmbH. All rights reserved.
*
* This software is copyright protected and proprietary to Vector Informatik GmbH.
* Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
* All other rights remain with Vector Informatik GmbH.
* \endverbatim
* -------------------------------------------------------------------------------------------------------------------
* FILE DESCRIPTION
* -----------------------------------------------------------------------------------------------------------------*/
/*! \file test_module.h
* \brief
*
*********************************************************************************************************************/
#ifndef NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H
#define NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H
#include "nsapplicationunit/nstestmodule/test_module_base.h"
namespace NsApplicationUnit {
namespace NsTestModule {
class TestModule : public TestModuleBase {
public:
TestModule(ConstructorToken&& token);
void BrakeTask() override;
void ImageTask() override;
void SteeringAngleTask() override;
void VelocityTask() override;
private:
datatypes::Image image{};
};
} // namespace NsTestModule
} // namespace NsApplicationUnit
#endif // NSAPPLICATIONUNIT_NSTESTMODULE_TEST_MODULE_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment