Running custom apps on HemiStereo devices

Base images

Full root access enables you to run your own applications on HemiStereo NX. While it is possible to run your app directly on the host OS, it is preferred to use containers for developing and deploying apps. We provide some pre-configured container images which can be used as base for your custom application:

Image

Description

3dvl/l4t-base

Ubuntu 18.04 image with Nvidia repositories enabled.

3dvl/l4t-cuda-base

3dvl/l4t-base + CUDA runtime packages installed.

3dvl/l4t-cuda-dev

3dvl/l4t-cuda-base + CUDA development packages installed.

3dvl/hemistereo-base

3dvl/l4t-cuda-base + jetson-multimedia-api, Boost, gRPC, OpenCV, TensorRT, VisionWorks runtime libraries.

3dvl/hemistereo-base-dev

3dvl/l4t-cuda-dev + CMake, jetson-multimedia-api, Boost, gRPC, OpenCV, TensorRT, VisionWorks development libraries.

Depending on your needs, choose on of the *-dev images above for development. Compiled binaries can then be used in the corresponding runtime images to deploy it to other devices. The image tags are defined by the following scheme:

<MACHINE>-<L4T-VERSION>[-<IMAGE_VERSION>]

Set MACHINE depending on your device to jetson-xavier-nx for the HemiStereo NX***-X or jetson-nano for the HemiStereo NX***-N. At the moment L4T-VERSION must be set to r32.4. IMAGE_VERSION can be set to latest to get the latest version of the base images.

Note

The l4t-* images do not have an image version. So this part of the image tag has to be omitted.

Container networking

Internal docker network

Containers can communicate with each other over network communication protocols. To see each other, they have to be in the same docker network. By default, a docker network hemistereo_backend exists which can be used for internal communication. For example, adding your container to the hemistereo_backend allows you to access the stereo application directly using the hostname stereo_backend and port 51346.

Note

Because in this case, the stereo application is access directly, the app field in the HTTP header can also be omitted.

Note

To make a service running in your container accessible from outside, you have to publish its ports.

Host network

Another possible solution for accessing other services is to enable host networking for your container. In this case you can only access the published ports of other containers. For example, to access the stereo application from your container, you have to connect to localhost:8888 and set the app field in the HTTP header to stereo. See Setup client context.

Note

All ports that are opened inside the container will be opened also on the host which can lead to conflicts.

Example

In this section we want to have a look at the grpc_cpp_sample. In this sample, stereo frames are read from the stereo application by using its gRPC interface. In this section, we focus on making the sample running on the device. For the usage of the gRPC application service, please read the chapter Application service.

Besides the C++ sources of the application, the repository contains also the following files:

File

Description

docker/<MACHINE>/Dockerfile

Contains the build instructions for container image.

docker/<MACHINE>/docker-compose.yml

The Docker Compose file containing the app configuration, e.g. volumes, ports, networks…

Dockerfile

For different machines, different Dockerfile`s exist under :code:`docker/<MACHINE>. Let’s have a look at the Dockerfile for the Jetson Xavier NX:

FROM 3dvl/hemistereo-base-dev:jetson-xavier-nx-r32.4-latest AS builder

COPY . /src
WORKDIR /build
RUN cmake -DCMAKE_GENERATOR=Ninja /src && ninja


FROM 3dvl/hemistereo-base:jetson-xavier-nx-r32.4-latest

COPY --from=builder /build/grpc_cpp_sample /app/
ENTRYPOINT [ "/app/grpc_cpp_sample" ]

The Dockerfile contains the build instructions for our docker image. As you can see, a multi-stage build is used. First we use the 3dvl/hemistereo-base-dev image to build the example code using CMake and Ninja, then we copy the binary to a smaller runtime image based on 3dvl/hemistereo-base. The runtime images will execute the binary automatically when it is started.

docker-compose.yml

The docker-compose.yml is used for defining the application itself. Multiple containers can be defined in the service section of the docker-compose.yml. In our case, we have only need to have one definition for the grpc_cpp_example container:

version: "3.0"
services:
    grpc_cpp_sample:
        image: grpc_cpp_sample:latest
        build:
            context: ../../
            dockerfile: ./docker/jetson-xavier-nx/Dockerfile
        networks:
            - hemistereo_backend
        volumes:
            - ./record:/record
        command: stereo_backend:51346

networks:
    hemistereo_backend:
        external: true

Let’s have a closer look at our service description:

image

The image name is set to grpc_cpp_sample and the tag to latest. When the file is executed by Docker Compose, Docker will run the image if it exists or build it if not.

build

build contains some information that is necessary to build the container. The context is set to the root directory of the repository. dockerfile points to the corresponding Dockerfile.

networks

The container is added to the hemistereo_backend network. Note that this network is also defined in the network section of the docker-compose.yml.

volumes

The sample application records images to the /record directory in the container. To access the images from host, we mount the /record directory as volume from a local folder ./record.

command

The last entry in the service section of the docker-compose.yml is the command. In the Dockerfile the entrypoint was set to the application executable. The application requires the service address of the stereo application. The command is appended to the entrypoint by Docker, so the address is provided here. Because the stereo_backend container is part of the same network, we can use its name for addressing. The service port for the direct connection is 51346. If the connection is established from an external network, the device’s IP and port 8888 have to be used.

Building the image and running the container

To build the image, go to the docker directory of your machine and run docker-compose build and docker-compose run:

cd docker/jetson-xavier-nx
docker-compose build
docker-compose run

A record folder will be created under the current directory and the application will start writing images into it.

Start the application automatically

If you want to run you application automatically after booting the device, you can set a restart policy in the docker-compose.yml. For example, you could set restart to unless-stopped to restart the container alway unless you stop it manually.

Stopping the application

To stop the application, navigate to the machine’s docker directory and call docker-compose stop:

cd docker/jetson-xavier-nx
docker-compose stop

This will stop the application but does not remove the containers. If you also want to remove the containers, use docker-compose down instead.