This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Seat Adjuster

The seat adjuster is an example to showcase how to create a vehicle application which senses and actuates signals in the vehicle for Eclipse Leda with help of Eclipse Velocitas and Eclipse Kuksa . The aim is not to build the best available seat adjuster application possible but to show how one can use the applied technologies to build a companion app for the interaction with a vehicle. If you are new to the concepts around Eclipse SDV and the mentioned projects we recommend to read the SDV Tutorial first.

Description

The idea of the seat adjuster application is to have a custom application to move the driver seat to positions defined in a driver profile hosted by a third-party web service.

Leda Seat Adjuster Use Case

The setup contains the following components:

  • Cloud or mobile trigger: not part of the Leda image, but we simulate it by issuing MQTT messages
  • Seat Adjuster : Developed with Eclipse Velocitas to be deployed by user
  • Eclipse Kuksa.val - KUKSA Databroker (pre-installed with Eclipse Leda)
  • Mock Service: Example provider for Eclipse Kuksa.VAL which mocks the behavior of the vehicle.
  • Seat ECU and the separate Seat Motor hardware can be emulated using a virtual CAN-Bus, which is beyond the scope of this guide.

In the following paragraphs, we next introduce the architecture and the assumed data flow before we explain the development and deployment steps. If you are more interested in the general development steps, you may directly jump to the develop seat adjuster.

1 - Architecture of Seat Adjuster

The seat adjuster application interacts with the vehicle through a Vehicle Abstraction Layer created by the KUKSA Databroker, which uses the Vehicle Signal Specification (VSS) to express the current value and in case of actuators also the desired state of the vehicle signal. By developing against the abstraction layer, the application becomes independent from the actual physical seat.

To control the position of the driver seat, the seat adjuster sets the target value of the Vehicle.Cabin.Seat.Row1.Pos1.Position signal in the KUKSA Databroker.

The architecture assumes so-called actuation providers that apply the changes to the actual vehicle as indicated in the target value, e.g., through interaction with the responsible ECUs. For this tutorial, we do not expect you to interface with an actual vehicle and thus abstract the vehicle by using the Kuksa.Val vehicle mock service. This vehicle mock service allows the definition of behavior toward the KUKSA Databroker like we would expect from the vehicle, for example, setting the current value after reacting to changes to the target value of a signal.

flowchart TB client[Client] anotherClient[Another Client] seatadjuster[Seat Adjuster] databroker[(KUKSA
Databroker)] mqttRequest[[MQTT topic
seatadjuster/setPosition/request]] mockservice[Provider: Mock Service] client -- "JSON Request: position, requestId" --> mqttRequest anotherClient -.-> mqttRequest mqttRequest --> seatadjuster seatadjuster -- "Set Target
Vehicle.Cabin.Seat.Row1.Pos1.Position
gRPC" --> databroker databroker <-- "Set Current
Vehicle.Cabin.Seat.Row1.Pos1.Position

Notify subscriber of changed target
Vehicle.Cabin.Seat.Row1.Pos1.Position" --> mockservice

As interface to the user, we assume a client that can, for example, be a local app in the infotainment domain with a user interface or an off-board application sending the request from a backend. Either way, the client controls our seat adjuster application through a JSON encoded message over MQTT using the topic setPosition/request.

An example request looks like this:

mosquitto_pub -t seatadjuster/setPosition/request 
    -m '{"position": 1000, "requestId": "12345"}'

The position parameter can be any value between 0 and 1000.

Getting Seat Position

When the seat moves, the provider gets this information, for example, from the seat ECU over the CAN-bus. We use the mock service as a provider and configure it to set the current value for the Vehicle.Cabin.Seat.Row1.Pos1.Position signal in the KUKSA Databroker after the target value for the signal changes.

To receive the changes to the seat position, the seat adjuster application already subscribed to the current value of the signals and thus gets notified. As a result, the seat adjuster constructs a JSON message and sends the new seat position to the MQTT-topic seatadjuster/currentPosition where any client can consume it.

The seat adjuster also sends responses to each request received at the MQTT-topic seatadjuster/request with a message to the MQTT-topic seatadjuster/response indicating whether it accepted the incoming request and set the target value or whether there was an error like the vehicle currently moving.

flowchart TD client[Client] anotherClient[Another Client] seatadjuster[Seat Adjuster] databroker[(KUKSA
Databroker)] mqttResponse[[MQTT topic
seatadjuster/setPosition/response]] mqttCurrent[[MQTT topic
seatadjuster/currentPosition]] mockservice[Provider: Mock Service] mockservice -- "Feed/Set
Vehicle.Cabin.Seat.Row1.Pos1.Position
(Sensor)" --> databroker databroker -- "Notify Subscriber
Vehicle.Cabin.Seat.Row1.Pos1.Position" --> seatadjuster seatadjuster -- "Once after processing
/setPosition/request
message" --> mqttResponse seatadjuster -- "While seat is moving" --> mqttCurrent mqttResponse -- "SetPosition Response
(Accepted / Error)" --> client mqttCurrent --> client mqttCurrent -.-> anotherClient mqttResponse -.-> anotherClient

The next step is to develop the seat adjuster with the help of Eclipse Velocitas.

2 - Develop Seat Adjuster

The following pages show how to execute the explained setup using Eclipse Velocitas and Eclipse Leda 0.1.0-M2:

On a high level, you need to perform the following steps described in more detail in this guide:

  1. Use the Eclipse Velocitas template repository to develop, build and deploy your version of the seat adjuster example.

  2. Run Eclipse Leda, for example, as container or with other options like QEMU, physical hardware, etc..

  3. Manage the Eclipse Kanto container runtime to deploy your seat adjuster application.

  4. Test the deployed setup by interacting with the seat adjuster to change the seat position.

Setup Eclipse Velocitas from template repository

We use Eclipse Velocitas to develop the seat application against the API of the Kuksa.val Databroker:

In the first step, you create a copy of the Eclipse Velocitas template repository. You create the copy by opening the repository in GitHub and selecting: Use this template -> Create a new repository. In the next step, you choose under which organization to place the created repository and whether it should be public. If you set the repository to private, you have to perform additional configuration steps mentioned below.

The template repository contains skeleton code for the application, test and release workflows for GitHub actions, and the configuration of a development environment in a container.

In addition to the Python template used in this guide, there is a C++ template available.

Execute Development Container in VSCode

You then checkout the repository on your development machine and open it in VSCode. From VSCode you can execute the development container (DevContainer) configured in the repository. For this to function, you need to install the following tools on your computer:

In the best case, VSCode may detect that the repository contains a DevContainer configuration and ask you whether to execute it. Alternatively, you can press F1 in VSCode and then enter DevContainers: Reopen in container to start the DevContainer. In either case, VSCode should reopen and then connect to the DevContainer. Because of the DevContainer, we do not need to make further modifications to the developer machine.

Develop the application

In the next step, we work on the actual application. You find the skeleton code in /app/src/main.py of the Eclipse Velocitas template and thus the DevContainer.

Eclipse Velocitas provides the code to realize the described seat adjuster application. One way to get the code is to use a pre-configured task in VSCode by pressing ‘F1’ and then typing ‘Run Task’.

As an alternative, you can check the latest version of the seat adjuster example code in the Eclipse Velocitas SDK repository in the Velocitas SDK directory.

There is a chance that the latest code for the seat-adjuster example in the main-branch of the Eclipse Velocitas SDK is a bit different compared to the code snippets below.

Let us walk through some lines of the code where the logic is in the vapp.py while the entry point is in main.py.

In the on_start(self) function we subscribe to any changes of the current value of the VSS signal Vehicle.Cabin.Seat.Row1.Pos1.Position in the KUKSA Databroker.

async def on_start(self):
        """Run when the vehicle app starts"""
        await self.Vehicle.Cabin.Seat.Row1.Pos1.Position.subscribe(
            self.on_seat_position_changed
        )

When the seat position changes, the on_seat_position_changed function is triggered and publishes the new seat position value as MQTT-message to the topic seatadjuster/currentPosition.

 async def on_seat_position_changed(self, data: DataPointReply):
        response_topic = "seatadjuster/currentPosition"
        await self.publish_event(
            response_topic,
            json.dumps(
                {"position": data.get(self.Vehicle.Cabin.Seat.Row1.Pos1.Position).value}
            ),
        )

In addition, we have the function on_set_position_request_received which is triggered for every MQTT-message to the topic seatadjuster/setPosition/request.

 @subscribe_topic("seatadjuster/setPosition/request")
    async def on_set_position_request_received(self, data_str: str) -> None:
        data = json.loads(data_str)
        (...)
        vehicle_speed = (await self.Vehicle.Speed.get()).value

        position = data["position"]
        if vehicle_speed == 0:
                try:
                    await self.Vehicle.Cabin.Seat.Row1.Pos1.Position.set(position)
        (...)

If the vehicle speed is zero, meaning that the vehicle does not move, we set the target value in the KUKSA Databroker for the position signal of the seat to the value requested in the incoming MQTT message.

The get() and set() functions are created based on a VSS model, and we assume that the KUKSA Databroker instance uses the same VSS model. In many cases, like the default Eclipse Leda, one may rely on the upstream VSS model, but some scenarios require further signals, e.g., by applying an overlay.

You can configure the used VSS model in the app/AppManifest.json file. This file includes an interface definition with the entry for the default vehicle_signal_interface. The VSS signals in this guide are part of VSS in version 3.0.0. The DevContainer generates the respective Eclipse Velocitas SDK based on this configuration. For more details see the Eclipse Velocitas Model Generator.

At this point, you may wonder how the application actually knows to which MQTT broker to connect and where to find the correct instance of the KUKSA Databroker. This service discovery is abstracted within the Velocitas SDK and involves the usage of so-called middleware to find and call the other components. As of writing this page, Eclipse Velocitas supports DAPR as middleware or uses the native approach to configure the correct address directly. The details of how to set and configure the used middleware are part of the deployment.

Signal Description: The signal indicates the seat position on the vehicle x-axis, where the value 0 is the frontmost position supported by the seat.

The value is the distance measured in millimeters.

The example implementation supports values between 0 and 1000 millimeters.

Note: This range of valid values is not reflected in the standard Vehicle Signal Specification. OEMs would overlay the VSS tree with actual Min/Max values, depending on the seat hardware available in the vehicle model.

Start Runtime in DevContainer to test application

You may skip the application testing since we already provide the example code. But it still makes sense to get a general idea of how to test and debug the code with the tooling in the DevContainer.

As mentioned before, the execution and, thus, the testing of the application requires a set of other components to be available like the KUKSA Databroker or an MQTT-broker. Furthermore, the deployment, the configuration, and the behavior of the application may change depending on the used (container) management solution. Therefore, Eclipse Velocitas allows the deployment of the required components and the application with the container management approach of choice inside the DevContainer.

The different runtimes are maintained in a separate Eclipse Velocitas repository. To start a runtime, we use the Eclipse Velocitas CLI:

velocitas exec runtime-kanto up

We use the Eclipse Kanto runtime here since we later deploy the seat adjuster application to Eclipse Leda, which uses Eclipse Kanto for container management.

Once the runtime is available, we add our application by executing:

velocitas exec deployment-kanto build-vehicleapp
velocitas exec deployment-kanto deploy-vehicleapp

You can now test the application by interacting with it through the local MQTT broker. To send and receive MQTT messages, use the VSMQTT plugin with a cloud icon in the left side of the VSCode instance connected to the DevContainer. We do not get into details for the topics and messages here since we will run the application in Eclipse Leda again later in this guide.

Once you finish the application testing and development, you can shutdown the runtime with:

velocitas exec runtime-kanto down

Eclipse Velocitas provides Tasks to abstract the mentioned calls of the velocitas CLI. As an alternative you can thus press F1 -> Run Task and scroll for the respective task like Kanto runtime Up.

Commit and Release Application

When you are confident about the application, you want to be able to distribute it. Here, pre-configured workflows from Eclipse Velocitas for GitHub Actions are helpful.

You now commit your changes and push them to your copy of the Eclipse Velocitas template repository in GitHub. Before you create the commit, we recommend running the pre-commit task, which performs similar checks and linting as the CI workflow from Eclipse Velocitas. You can trigger the pre-commit as a task in VSCode:

  1. Press F1
  2. Write Tasks: Run Task and press enter
  3. Write Pre Commit Action and press enter

The pre commit action should start in a terminal inside VSCode.

You can check the available tasks configured by Eclipse Velocitas in .vscode/tasks.json.

If the pre-commit was successful, you may push your changes and open the repository in the browser. In the meantime, the push should trigger the CI workflow and the Build multiarch image workflow, which you can track in the Actions tab.

If you set your copy of the template repository to private, the CI workflow may fail due to missing permissions to write container images to GitHub packages. You can grant more Workflow permissions in the Settings tab of the repository under Actions-> General.

To deploy your application to a target and if the two workflows have finished successfully, you can perform a release in GitHub. The subsequent release workflow will make the application available as a built container in the container registry of GitHub (Code -> Packages). To do the release in GitHub, go to the Code tab and click Releases on the right side of the page. Then you can Draft a new release, create a new tag and title for the release, and click Publish Release, which triggers the Release workflow.

The next step is to deploy the seat adjuster in Eclipse Leda

3 - Deploy Seat Adjuster

We now want to deploy the application to a target device. You may follow the remainder of this guide on a separate device like a RaspberryPi, but you can emulate such a device on your development machine too. Either way, we use Eclipse Leda in version 0.1.0-M2 as the target system, which is a Linux-based distribution with pre-installed SDV components like the KUKSA Databroker and Eclipse Kanto for container management. For more details on how to download and run Eclipse Leda, follow the respective guides:

We recommend to get started with the QEMU setup. In any case, you now need to configure Eclipse Kanto to execute the application. For this, it helps to get an overview of which containers are currently running in Eclipse Kanto. You can get this either through the command:

kantui

or

kanto-cm list

From this list, ensure that at least the KUKSA Databroker runs, which should be the case since it is are pre-configured with the Eclipse Leda release.

In Eclipse Kanto, you can manage a container with the command line application kanto-cm or container manifest files describing a desired container execution. The advantage of using the container manifests is that the configuration is persisted across a reboot of the system and is easier to use to describe a desired software state for the overall vehicle.

Eclipse Leda has the kanto-auto-deployer systemd service, which applies any changes to the manifests in /data/var/containers/manifests to Eclipse Kanto. Thus, the typical way to add or adapt containers is to modify the corresponding container manifest.

Disable other containers

The release 0.1.0-M2 of Eclipse Leda comes with a number of pre-configured and automatically executed containers. One of these containers is the feedercan that feeds changing values from a recording for signals such as Vehicle.Speed to the KUKSA Databroker. These values interfere with the seat adjuster application, which only moves the seat if the vehicle speed is zero. Another interfering container is the seatservice-example which reacts to changes in the signal Vehicle.Cabin.Seat.Row1.Pos1.Position and which we replace later with the mock service.

Therefore, we need to stop the feedercan and the seatservice-example container. This is possible in kantui by selecting the respective entry and pressing R. In addition, you need to remove the corresponding container manifests in /data/var/containers/manifests to avoid that the Eclipse Kanto auto-deployer re-deploys these containers. Another approach is to change the ending of the not-needed manifests to something other than .json.

If the feedercan container still runs, the seat adjuster application app will later respond with the following error message:

seatadjuster/setPosition/response
 {"requestId": "12345", "result": {"status": 1, "message": "Not allowed to move seat because vehicle speed is 9.0 and not 0"}}

Since they consume resources and are not needed for the seat adjustment, you may remove the containers and manifests for cloudconnector, hvacservice-example, sua, or vum as well.

Starting of container

Use kanto-cm

kanto-cm create \
    --name seatadjuster-app \
    --e="SDV_SEATSERVICE_ADDRESS=grpc://seatservice-example:50051" \
    --e="SDV_MQTT_ADDRESS=mqtt://mosquitto:1883" \
    --e="SDV_VEHICLEDATABROKER_ADDRESS=grpc://databroker:55555" \
    --e="SDV_MIDDLEWARE_TYPE=native" \
    --hosts="databroker:container_databroker-host, mosquitto:host_ip, seatservice-example:container_seatservice-example-host" \
    ghcr.io/<YOUR_ORG>/seat-adjuster-app:latest

kanto-cm start --name seatadjuster-app
kanto-cm logs --name seatadjuster-app

Add manifest for seat adjuster

As an alternative to using kanto-cm, you can add a container manifest to the directoy watched by the kanto-auto-deployer (data/var/containers/manifests).

To add the container manifest, create a new file inside this folder.

touch seat-adjuster.json
nano seat-adjuster.json

and copy the manifest from below. You can save the file with strg+s and close the window with strg+q. You can create the file on the development machine and copy it via scp too:

scp -P 2222 myapp.json root@localhost:/data/var/containers/manifests/

The example deployment descriptor below is available in meta-leda-components too. An interesting aspect of the snippet is the config.env section at the bottom of the container manifest. There, we define a number of environment variables for the container which configures the Eclipse Velocitas SDK to use the native middleware and where to find the MQTT-broker and the KUKSA Databroker to use. We did the same in kanto-cm call behind the parameter --e=.

More details on the general deployment approach can be found in Leda Vehicle Applications

If the GitHub packages in which you stored the container image are private, Eclipse Kanto needs a valid access token to download the container image. You can create a personal access token in the Developer Settings of your GitHub account. Select Personal access token -> Tokens (classic) and generate a new token that at least has the read:packages permission. Copy the generated token to a secure location or to Eclipse Kanto because GitHub will not show it again. You can now configure Eclipse Kanto in Eclipse Leda to use the token by executing: sdv-kanto-ctl add-registry -h <registryhostname> -u <your_username> -p <your_password>. In the case of GitHub, the registryhostname is ghcr.io , the username is your GitHub handle, and the password is the generated token. See Container Registries for more details.

To make sure that Eclipse Kanto detects the changes in the manifests folder, you can restart the respective system services:

systemctl restart kanto-auto-deployer

Mock Service

As explained in the description of the code, the seat adjuster application sets the target value for the seat positions in the KUSKSA Datbroker and waits for the current position to update.

For this to function, there needs to be a component that reacts to this change by moving the seat and updating the current value accordingly. Because we cannot assume that you have an actual ECU availabe for running this guide, we mock the vehicle behavior with the vehicle mock service from the Eclipse Kuksa project.

The mock service allows the definition of custom interaction sequences with the KUKSA Databroker. For instance, one can react to changes to specific signals or update signals with a time trigger. You can define the sequences in a Python file like the example mock.py below. The snippet shows how to use a change to the target value for the seat position signal as a trigger to update the current value to the target value step-wise over a duration of 10 seconds.

For the deployment, you create another container manifest in /data/var/containers/manifest with the content from below. The container manifest also mounts a custom mock.py into the container to replace the configuration of the default mock.py. With the container manifest below, Eclipse Kanto instead mounts from /data/var/mock/mock.py. Therefore, you need to create this directory and the file with the content from below.

You may now check with kantui or kanto-cm list whether all components (databroker, seatadjuster-app, and mock-service) are running well. The next step is to interact with the seat adjuster.

seat-application.json

This is the Eclipse Kanto container manifest for the seat adjuster application.

{
    "container_id": "seatadjuster-app",
    "container_name": "seatadjuster-app",
    "image": {
        "name": "ghcr.io/<identifier-for-container>:<tag-for-container>"
    },
    "host_config": {
        "devices": [],
        "network_mode": "bridge",
        "privileged": false,
        "restart_policy": {
            "maximum_retry_count": 0,
            "retry_timeout": 0,
            "type": "unless-stopped"
        },
        "runtime": "io.containerd.runc.v2",
        "extra_hosts": [        
                "mosquitto:host_ip",
                "databroker:container_databroker-host",
                "seatservice-example:container_seatservice-example-host"
        ],
        "port_mappings": [
            {
              "protocol": "tcp",
              "container_port": 30151,
              "host_ip": "localhost",
              "host_port": 50151,
              "host_port_end": 50151
            }
        ],
        "log_config": {
            "driver_config": {
                "type": "json-file",
                "max_files": 2,
                "max_size": "1M",
                "root_dir": ""
            },
            "mode_config": {
                "mode": "blocking",
                "max_buffer_size": ""
            }
        },
        "resources": null
    },
    "config": {
        "env": [
           "SDV_SEATSERVICE_ADDRESS=grpc://seatservice-example:50051",
           "SDV_VEHICLEDATABROKER_ADDRESS=grpc://databroker:55555",
           "SDV_MQTT_ADDRESS=mqtt://mosquitto:1883",
           "SDV_MIDDLEWARE_TYPE=native",
           "RUST_LOG=info",
           "vehicle_data_broker=info"
        ],
        "cmd": []
    }
}

mock.py

This is the example mock.py for mocking a seat provider:

from lib.animator import RepeatMode
from lib.dsl import (
    create_animation_action,
    create_behavior,
    create_event_trigger,
    create_set_action,
    get_datapoint_value,
    mock_datapoint,
)

from lib.trigger import ClockTrigger, EventType

mock_datapoint(
    path="Vehicle.Cabin.Seat.Row1.Pos1.Position",
    initial_value=0,
    behaviors=[
        create_behavior(
            trigger=create_event_trigger(EventType.ACTUATOR_TARGET),
            action=create_animation_action(
                duration=10.0,
                values=["$self", "$event.value"],
            ),
        )
    ],
)

mockservice.json

The container manifest for the mockservice may look like the following snippet. Note, that the files referenced in the source of the mount_points needs to be present in the file system of your Eclipse Leda instance.

{
    "container_id": "mockservice",
    "container_name": "mockservice",
    "image": {
        "name": "ghcr.io/eclipse/kuksa.val.services/mock_service:latest"
    },
    "mount_points": [
        {
            "source": "/data/var/mock/mock.py",
            "destination": "/mock.py",
            "propagation_mode": "rprivate"
        }
    ],
    "host_config": {
        "network_mode": "bridge",
        "privileged": false,
        "restart_policy": {
            "maximum_retry_count": 0,
            "retry_timeout": 0,
            "type": "unless-stopped"
        },
        "runtime": "io.containerd.runc.v2",
        "extra_hosts": [
            "databroker:container_databroker-host"
        ],
        "log_config": {
            "driver_config": {
                "type": "json-file",
                "max_files": 2,
                "max_size": "1M",
                "root_dir": ""
            },
            "mode_config": {
                "mode": "blocking",
                "max_buffer_size": ""
            }
        }
    },
    "config": {
        "env": [
           "VDB_ADDRESS=databroker:55555"
        ]
    }
}

4 - Interact with Seat Adjuster

We interact with the seat application through MQTT messages to emulate the behavior of an offboard application. To see the responses from the seat adjuster app, subscribe to the MQTT topic `seatadjuster/#``.

mosquitto_sub -t 'seatadjuster/#' -v

To initiate the moving of the seat, publish an MQTT message for the seat adjuster application to set the position to 1000 (which is the equivalent of 100%):

mosquitto_pub -t seatadjuster/setPosition/request -m '{"position": 1000, "requestId": "12345"}'

You may need to open a second terminal session to send the message. In the QEMU setup, you can do this through an SSH connection from the host machine by running ssh -p 2222 root@localhost.

After publishing the setPosition-message, the expected output for the seatadjuster/# subscription should look like this:

seatadjuster/setPosition/request {"position": 1000, "requestId": "12345"}
seatadjuster/setPosition/response {"requestId": "12345", "result": {"status": 0, "message": "Set Seat position to: 1000"}}
seatadjuster/currentPosition {"position": 00}
seatadjuster/currentPosition {"position": 10}
seatadjuster/currentPosition {"position": 20}
seatadjuster/currentPosition {"position": 30}
seatadjuster/currentPosition {"position": 40}
seatadjuster/currentPosition {"position": 50}
...

If you encounter an issue or want to look deeper into the state of the container, you can check the logs by executing:

kanto-cm --name <container-name> logs

Run Kuksa Client

Besides trusting the log information and the MQTT messages that the seat position in the KUKSA Databroker has changed you can read the values directly from the KUKSA Databroker with the KUKSA Client. Through the sdv-ctr-exec it becomes possible to interact with the CLI of the Eclipse KUKSA Client:

kanto-cm create --i --t --network=host --name=kuksa-client ghcr.io/eclipse/kuksa.val/kuksa-client:master
kanto-cm start --name=kuksa-client
sdv-ctr-exec -n kuksa-client /kuksa-client/bin/kuksa-client --port 30555 --protocol grpc --insecure

Congratulations, you have reached the end of the seat adjuster guide. Based on the used code, you can now continue to realize other applications by using other signals. You may need to adapt your mock.py accordingly. In addition, you can connect the seat service to a CAN-environment.

References

5 - CAN Setup for Seat Adjuster

Within the seat adjuster guide, we so far mocked the behavior of the actual vehicle. In the following, we give an overview of how to create a virtual CAN-bus and interact with it to send CAN-frames for moving a seat.

Instead of the mock service you use the seat service as a provider, which is another pre-installed container acting as the connection between the KUKSA Databroker and the underlying hardware. More specifically, it subscribes to the target value of the Vehicle.Cabin.Seat.Row1.Pos1.Position signal, can send CAN-frames, and updates the current value of the signal in small steps until it is equal to the target value. For more details, visit the Kuksa.val.services repository, which hosts the code for the seat service.

With a new installation of Eclipse Leda, the seat adjuster comes by default. If you performed the steps from the deploy the seat adjuster in Eclipse Leda guide, you need to re-add the seatadjuster container manifest and remove the mockservice. More details on how to do this are available in that guide.

The setup then looks as follows:

flowchart TB client[Client] anotherClient[Another Client] seatadjuster[Seat Adjuster] databroker[(KUKSA
Databroker)] mqttRequest[[MQTT topic
seatadjuster/setPosition/request]] %% mqttResponse[[MQTT topic
seatadjuster/setPosition/response]] %% mqttCurrent[[MQTT topic
seatadjuster/currentPosition]] seatservice[Seat Service] canbus[CAN-Bus and Seat ECU] client -- "JSON Request: position, requestId" --> mqttRequest anotherClient -.-> mqttRequest mqttRequest --> seatadjuster seatadjuster -- "Set Target
Vehicle.Cabin.Seat.Row1.Pos1.Position
gRPC" --> databroker databroker <-- "Set Current
Vehicle.Cabin.Seat.Row1.Pos1.Position

Notify subscriber of changed target
Vehicle.Cabin.Seat.Row1.Pos1.Position" --> seatservice seatservice -- "CAN Frame: SECU1_CMD1
CAN-ID 0x705" --> canbus

Virtual CAN-Bus

To set upa virtual CAN-Bus

  1. You will have to generate initial CAN frames that will emulate the car ECU responding to the service:

    $ cangen -v can0 -L 8 -I 712 -D r -n 5
    can0  712#4F.BF.B0.6B.5F.2D.54.09
    can0  712#13.2E.98.7E.77.11.99.5B
    can0  712#15.70.87.07.73.24.3A.7A
    can0  712#99.7F.F5.3F.FB.99.00.04
    can0  712#FE.1C.D5.55.22.86.3A.1F
    
  2. You can now start tracing CAN frames written to the bus with candump can0

  3. From now on when a request to change the seat position is issued you will be able to see the corresponding CAN frames in the trace.

Note: On QEMU you can tunnel the host CAN bus to the guest: Tunneling a CAN Interface from the Host.

Hardware CAN-Bus

The default configuration of the Seat Service is using simulated VCAN. If you want to switch to a physical CAN-Bus interface, the container needs to have access to the CAN-Bus hardware.

Such a CAN-Bus device might be a Raspberry Pi setup with an MCP251x-based CAN-Hat extension or a QEMU image with an emulated kvaser_pci device (enabled on the Leda QEMU Quickstart images by default).

This setup would require some adjustments to the container manifest in order for the container to have access to the physical CAN-Bus.

  1. Make Seat Service container privileged and run on the host network interface:

    "host_config": {
    ...
    "network_mode": "host",
    "privileged": true,
    ...
    }
    
  2. Remove all port mappings and extra hosts (set "extra_hosts": [] and "port_mappings": []) for the container as it’s now running in host-networking mode (host_ip variable no longer available) and all ports are directly exposed.

  3. Set the address to the databroker to localhost:30555:

        "config": {
        "env": [
           ...
            "BROKER_ADDR=127.0.0.1:30555",
           ...
        ],
        ...
        }
    
  4. Reconfigure the seat controller application to use the physical CAN interface,please see Eclipse Kuksa.VAL seat_controller/README.md for details:

    SC_CAN=can0
    CAN=can0
    

    All the necessary changes combined for clarity as a single diff can be found below:

    --- ../meta-leda-fork/meta-leda-components/recipes-sdv/eclipse-leda/kanto-containers/example_dev/seatservice.json	2023-03-06 11:32:00.771754434 +0200
    +++ seatservice-new.json	2023-03-06 11:37:12.967182044 +0200
    @@ -14,26 +14,16 @@
        "hooks": [],
        "host_config": {
            "devices": [],
    -        "network_mode": "bridge",
    -        "privileged": false,
    +        "network_mode": "host",
    +        "privileged": true,
            "restart_policy": {
                "maximum_retry_count": 0,
                "retry_timeout": 0,
                "type": "unless-stopped"
            },
            "runtime": "io.containerd.runc.v2",
    -        "extra_hosts": [
    -            "databroker-host:host_ip"
    -        ],
    -        "port_mappings": [
    -            {
    -              "protocol": "tcp",
    -              "container_port": 50051,
    -              "host_ip": "localhost",
    -              "host_port": 30051,
    -              "host_port_end": 30051
    -            }
    -        ],
    +        "extra_hosts": [],
    +        "port_mappings": [],
            "log_config": {
                "driver_config": {
                    "type": "json-file",
    @@ -58,9 +48,11 @@
        },
        "config": {
            "env": [
    -           "BROKER_ADDR=databroker-host:30555",
    -           "RUST_LOG=info",
    -           "vehicle_data_broker=info"
    +            "CAN=can0",
    +            "SC_CAN=can0",
    +            "BROKER_ADDR=127.0.0.1:30555",
    +            "RUST_LOG=info",
    +            "vehicle_data_broker=info"
            ],
            "cmd": []
        },
    

Safety Considerations

Attention: Safety considerations are not in scope for this example tutorial. This example is for demonstrating the general approach. Actual safety requirements must be handled within the Seat ECU as the lowest level component to guard against non-safe use of the seat motors. Non-ASIL domains are not certified for safety requirements. Please pay attention when following the physical CAN tutorial and attaching physical actuators to not harm anybody by accidental movements of seat motors or any other actuator.

However, the Seat Adjuster example application contains a rudimentary “Safe State” condition check: it will only allow to move the seat when the vehicle is not moving.

The condition is using VSS path notation: Vehicle.Speed == 0 (see main.py#L82 in v0.9.0)

Note: The Kuksa.VAL CAN Feeder, which is deployed by default on Eclipse Leda is constantly updating the Vehicle.Speed You need to disable the feedercan container (see step 7 of Getting started), otherwise the Seat Adjuster application will decline the request and not move the seat.