├── .github
├── actions
│ └── generate-job-matrix
│ │ ├── action.yml
│ │ └── scripts
│ │ └── generate.sh
└── workflows
│ └── automated-testing.yml
├── CITATION.cff
├── LICENSE
├── README.md
├── automated-testing
├── README.md
├── evaluate-scenarios.sh
└── template.yml
├── data-driven-development
├── README.md
├── config
│ ├── data-driven-development-demo-permutation-execution.yml
│ ├── data-driven-development-demo-scenario-execution.yml
│ └── sensors
│ │ └── rgb_segmentation_camera.json
├── data_generation.py
├── docker-compose.yml
├── env
│ ├── environment.yml
│ └── requirements.txt
├── launch
│ └── demo.launch.py
└── scripts
│ ├── set_environment.py
│ ├── simulation_controller.py
│ ├── spawned_vehicle_check.py
│ └── time_controller.py
├── run-demo.sh
├── software-prototyping
├── README.md
├── carla-ros-bridge.launch.py
├── config.rviz
├── docker-compose.yml
└── sensors.json
└── utils
├── carla-essentials
├── README.md
└── carla-services.yml
├── images
├── architecture.png
├── automated-testing-cli.png
├── automated-testing-icon.png
├── automated-testing-workflow.png
├── data-driven-development-icon.png
├── logo.png
├── overview.gif
├── software-prototyping-icon.png
├── software-prototyping-image-segmentation.png
├── software-prototyping-rviz.png
├── teaser.png
├── tutorial-dynamic-weather.png
├── tutorial-pygame.png
└── tutorial-rviz-overview.png
├── requirements.md
├── scenarios
├── catalogs
│ └── VehicleCatalog.xosc
├── town01.xosc
├── town01.xosc.opt
├── town10.xosc
└── town10.xosc.opt
└── tutorial
├── README.md
├── config.rviz
└── docker-compose.yml
/.github/actions/generate-job-matrix/action.yml:
--------------------------------------------------------------------------------
1 | name: 'generate-job-matrix'
2 | description: 'Generates a matrix from files/directories selected by a query string to dynamically create jobs'
3 |
4 | inputs:
5 |
6 | starting-point:
7 | description: 'Location from which recursive search starts'
8 | default: '.'
9 |
10 | query-string:
11 | description: 'Shell pattern that is used for matching and selecting file/directory names'
12 | default: ''
13 |
14 | max-depth:
15 | description: 'How many levels to descend at most for selection of results (1 targets the directory of the starting-point)'
16 | default: 100
17 |
18 | exclude-string:
19 | description: 'Shell pattern that is used to exclude file/directory names from the final result'
20 | default: ''
21 |
22 | outputs:
23 |
24 | matrix:
25 | description: 'JSON string which can be turned to a matrix definition by using fromJson()'
26 | value: ${{ steps.generator.outputs.matrix }}
27 |
28 | runs:
29 |
30 | using: 'composite'
31 | steps:
32 | - id: generator
33 | run: ${GITHUB_ACTION_PATH}/scripts/generate.sh -d ${{ inputs.max-depth }} -e "${{ inputs.exclude-string }}" ${{ inputs.starting-point }} "${{ inputs.query-string }}"
34 | shell: bash
35 |
--------------------------------------------------------------------------------
/.github/actions/generate-job-matrix/scripts/generate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | usage() {
6 | echo "Usage: $0 [-d maxdepth] [-e exclude-path] STARTING-POINT QUERY-STRING"
7 | echo "STARTING-POINT : Location from where search should start"
8 | echo "QUERY-STRING : UNIX pattern used for matching and selecting results. Needs to be \"quoted\""
9 | echo "max-depth : Descend at most max-depth levels from STARTING-POINT"
10 | echo "exclude-string : Exclude paths matching this UNIX pattern from final result. Needs to be \"quoted\""
11 | echo "-----"
12 | echo "Example: $0 -d 3 . \"*.xosc\""
13 | }
14 |
15 | args=()
16 |
17 | while getopts "hd:e:" flag; do
18 | case "$flag" in
19 | h)
20 | usage
21 | exit 0
22 | ;;
23 | d) args=(-maxdepth "$OPTARG" "${args[@]}");;
24 | e) args+=(-not -path "$OPTARG");;
25 | esac
26 | done
27 |
28 | shift $(($OPTIND-1)) # return to usual handling of positional args
29 | if [ $# -lt 2 ]; then
30 | usage
31 | exit 1
32 | fi
33 | startingPoint=$1
34 | queryStr=$2
35 |
36 | matrixArray=$(find ~+/$startingPoint "${args[@]}" -name "$queryStr")
37 |
38 | printf %"s\n" "Selected paths:" "$matrixArray"
39 | echo "$matrixArray" | \
40 | jq --slurp --raw-input 'split("\n")[:-1]' | \
41 | jq "{\"filepath\": .[] }" | \
42 | jq -c '(.filepath / "/" | {filedir: (.[0:-1] | join("/")),filename: .[-1]})' | \
43 | jq -sc "{ \"include\": . }" \
44 | > matrix.tmp
45 | echo "MATRIX=$(cat ./matrix.tmp)" >> "$GITHUB_OUTPUT"
46 |
--------------------------------------------------------------------------------
/.github/workflows/automated-testing.yml:
--------------------------------------------------------------------------------
1 | name: automated-testing
2 | on: push
3 | jobs:
4 | generate-scenario-job-matrix:
5 | runs-on: [self-hosted]
6 | outputs:
7 | matrix: ${{ steps.generate.outputs.matrix }}
8 | name: generate scenario job matrix
9 | steps:
10 | - uses: actions/checkout@v4
11 | - id: generate
12 | uses: ./.github/actions/generate-job-matrix
13 | with:
14 | starting-point: ./utils/scenarios
15 | query-string: '*.xosc'
16 | exclude-string: '*/catalogs/*'
17 |
18 | evaluate-required-scenarios:
19 | needs: generate-scenario-job-matrix
20 | runs-on: [self-hosted]
21 | name: Run ${{ matrix.filename }}
22 | strategy:
23 | fail-fast: false
24 | matrix: ${{ fromJson(needs.generate-scenario-job-matrix.outputs.matrix) }}
25 | steps:
26 | - uses: actions/checkout@v4
27 | - shell: bash
28 | run: |
29 | xhost +local:
30 | - uses: ika-rwth-aachen/carlos-ci-action@v0.1.2
31 | with:
32 | scenario-folder-path: ${{ matrix.filedir }}
33 | scenario-file-name: ${{ matrix.filename }}
34 | - shell: bash
35 | run: |
36 | xhost -local:
37 |
38 | generate-opt-scenario-job-matrix:
39 | needs: evaluate-required-scenarios
40 | runs-on: [self-hosted]
41 | outputs:
42 | opt-matrix: ${{ steps.generate-opt.outputs.matrix }}
43 | name: generate optional scenario job matrix
44 | steps:
45 | - uses: actions/checkout@v4
46 | - id: generate-opt
47 | uses: ./.github/actions/generate-job-matrix
48 | with:
49 | starting-point: ./utils/scenarios
50 | query-string: '*.xosc.opt'
51 | exclude-string: '*/catalogs/*'
52 |
53 | evaluate-optional-scenarios:
54 | needs: generate-opt-scenario-job-matrix
55 | runs-on: [self-hosted]
56 | strategy:
57 | fail-fast: false
58 | matrix: ${{ fromJson(needs.generate-opt-scenario-job-matrix.outputs.opt-matrix) }}
59 | name: Run ${{ matrix.filename }}
60 | steps:
61 | - uses: actions/checkout@v4
62 | - shell: bash
63 | run: |
64 | xhost +local:
65 | - uses: ika-rwth-aachen/carlos-ci-action@v0.1.2
66 | continue-on-error: true
67 | with:
68 | scenario-folder-path: ${{ matrix.filedir }}
69 | scenario-file-name: ${{ matrix.filename }}
70 | - shell: bash
71 | run: |
72 | xhost -local:
73 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "We hope that our simulation framework CARLOS can help your research. If this is the case, please cite it using the following metadata."
3 |
4 | title: "CARLOS"
5 | type: software
6 | repository-code: "https://github.com/ika-rwth-aachen/carlos"
7 | date-released: 2024-02-01
8 | authors:
9 | - given-names: Christian
10 | family-names: Geller
11 | - given-names: Benedikt
12 | family-names: Haas
13 | - given-names: Amarin
14 | family-names: Kloeker
15 | - given-names: Jona
16 | family-names: Hermens
17 | - given-names: Bastian
18 | family-names: Lampe
19 |
20 | preferred-citation:
21 | title: "CARLOS: An Open, Modular, and Scalable Simulation Framework for the Development and Testing of Software for C-ITS"
22 | type: conference-paper
23 | conference:
24 | name: 2024 IEEE Intelligent Vehicles Symposium (IV)
25 | year: 2024
26 | doi: 10.1109/IV55156.2024.10588502
27 | url: "https://github.com/ika-rwth-aachen/carlos"
28 | authors:
29 | - given-names: Christian
30 | family-names: Geller
31 | orcid: "https://orcid.org/0000-0001-8655-3201"
32 | - given-names: Benedikt
33 | family-names: Haas
34 | orcid: "https://orcid.org/0009-0004-4842-9997"
35 | - given-names: Amarin
36 | family-names: Kloeker
37 | orcid: "https://orcid.org/0000-0003-4984-2797"
38 | - given-names: Jona
39 | family-names: Hermens
40 | orcid: "https://orcid.org/0009-0005-9193-3336"
41 | - given-names: Bastian
42 | family-names: Lampe
43 | orcid: "https://orcid.org/0000-0002-4414-6947"
44 | - given-names: Lutz
45 | family-names: Eckstein
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Institute for Automotive Engineering (ika), RWTH Aachen University
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # **CARLOS** - An Open, Modular, and Scalable Simulation Framework for the Development and Testing of Software for C-ITS
4 |
5 | This repository contains CARLOS, the official reference implementation of the open, modular and scalable simulation architecture presented in our [paper](https://ieeexplore.ieee.org/document/10588502). We provide a containerized simulation framework based on the open-source simulator [CARLA](http://carla.org/) and enable a simple integration of custom ROS applications. Find below a brief description of the architecture as well as configurations and instructions for demos of three example use cases:
6 | - [Software Prototyping](./software-prototyping/)
7 | - [Data-Driven Development](./data-driven-development/)
8 | - [Automated Testing](./automated-testing/)
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Notice
16 |
17 | > [!IMPORTANT]
18 | > This repository is open-sourced and maintained by the [**Institute for Automotive Engineering (ika) at RWTH Aachen University**](https://www.ika.rwth-aachen.de/).
19 | > **Simulation, Containerization and DevOps for Automated Driving** are some of many research topics within our [*Vehicle Intelligence & Automated Driving*](https://www.ika.rwth-aachen.de/en/competences/fields-of-research/vehicle-intelligence-automated-driving.html) domain.
20 | > If you would like to learn more about how we can support your automated driving or robotics efforts, feel free to reach out to us!
21 | > :email: ***opensource@ika.rwth-aachen.de***
22 |
23 | ## Overview
24 |
25 |
26 |
27 |
28 |
29 | ## Content
30 |
31 | - [**CARLOS** - An Open, Modular, and Scalable Simulation Framework for the Development and Testing of Software for C-ITS](#carlos---an-open-modular-and-scalable-simulation-framework-for-the-development-and-testing-of-software-for-c-its)
32 | - [Publication](#publication)
33 | - [Quick Start](#quick-start)
34 | - [Use Cases](#use-cases)
35 | - [Simulation Architecture](#simulation-architecture)
36 | - [Citation](#citation)
37 | - [Acknowledgements](#acknowledgements)
38 |
39 |
40 | ## Publication
41 |
42 | > **CARLOS: An Open, Modular, and Scalable Simulation Framework for the Development and Testing of Software for C-ITS**
43 | > > *([IEEEXplore](https://ieeexplore.ieee.org/document/10588502), [arXiv](http://arxiv.org/abs/2404.01836), [ResearchGate](https://www.researchgate.net/publication/379484629_CARLOS_An_Open_Modular_and_Scalable_Simulation_Framework_for_the_Development_and_Testing_of_Software_for_C-ITS))*
44 | >
45 | > [Christian Geller](https://www.ika.rwth-aachen.de/de/institut/team/fahrzeugintelligenz-automatisiertes-fahren/geller.html), [Benedikt Haas](https://github.com/BenediktHaas96), [Amarin Kloeker](https://www.ika.rwth-aachen.de/en/institute/team/vehicle-intelligence-automated-driving/kloeker-amarin.html), [Jona Hermens](TODO), [Bastian Lampe](https://www.ika.rwth-aachen.de/en/institute/team/vehicle-intelligence-automated-driving/lampe.html), [Till Beemelmanns](https://www.ika.rwth-aachen.de/en/institute/team/vehicle-intelligence-automated-driving/beemelmanns.html), [Lutz Eckstein](https://www.ika.rwth-aachen.de/en/institute/team/univ-prof-dr-ing-lutz-eckstein.html)
46 | > [Institute for Automotive Engineering (ika), RWTH Aachen University](https://www.ika.rwth-aachen.de/en/)
47 | >
48 | > *Abstract* – Future mobility systems and their components are increasingly defined by their software. The complexity of these cooperative intelligent transport systems (C-ITS) and the ever-changing requirements posed at the software require continual software updates. The dynamic nature of the system and the practically innumerable scenarios in which different software components work together necessitate efficient and automated development and testing procedures that use simulations as one core methodology. The availability of such simulation architectures is a common interest among many stakeholders, especially in the field of automated driving. That is why we propose CARLOS - an open, modular, and scalable simulation framework for the development and testing of software in C-ITS that leverages the rich CARLA and ROS ecosystems. We provide core building blocks for this framework and explain how it can be used and extended by the community. Its architecture builds upon modern microservice and DevOps principles such as containerization and continuous integration. In our paper, we motivate the architecture by describing important design principles and showcasing three major use cases - software prototyping, data-driven development, and automated testing. We make CARLOS and example implementations of the three use cases publicly available at [https://github.com/ika-rwth-aachen/carlos](https://github.com/ika-rwth-aachen/carlos).
49 |
50 | ---
51 |
52 |
53 | ## Quick Start
54 |
55 | > [!TIP]
56 | > Make sure your computer fulfills the [requirements](./utils/requirements.md) and feel free to first check out our comprehensive [tutorial](./utils/tutorial/README.md), which gives an overview of our simulation framework's main features, and describes how CARLA and ROS applications can be combined in a containerized composition.
57 |
58 | This repository provides demos for different use cases. The demos can be used as an example or initial starting point for your own variations for the use cases. A specific demo can be started using the provided [run-demo.sh](./run-demo.sh) script, for example:
59 |
60 | ```bash
61 | ./run-demo.sh software-prototyping
62 | ```
63 |
64 | Hitting CTRL + C twice stops a demo.
65 |
66 | ## Use Cases
67 |
68 | Each link below provides a detailed description of a provided use case and instructions on how to adjust it to your needs.
69 |
70 | | Use Case | Integrated Components | Description |
71 | | ------ | ------ | ------
72 | | [***software-prototyping***](./software-prototyping/README.md) | carla-server, carla-ros-bridge, rviz | Transfers simulation data into the ROS ecosystem. |
73 | | [***data-driven-development***](./data-driven-development/README.md) | carla-server, carla-ros-bridge, carla-scenario-runner | Automated simulation configuration to capture sensor data at large scale. |
74 | | [***automated-testing***](./automated-testing/README.md) | carla-server, carla-scenario-runner | Sequential simulation of multiple scenarios in OpenSCENARIO format with automated evaluation. |
75 |
76 | ## Simulation Architecture
77 |
78 |
79 |
80 | Our architecture consists of several *sub-layers* encapsulating different components that serve individual purposes:
81 |
82 | - **Simulation Layer** - simulation core equipped with low-level interfaces and capabilities;
83 | - **Control Layer** - tools for interactions with the simulation core;
84 | - **Application Layer** - software interacting with the simulation layer to achieve certain goals;
85 | - **Storage Layer** - persistent data used for or generated by the simulation layer;
86 | - **Orchestation Layer** - automated configuring, coordinating, and managing of all other layers.
87 |
88 | The *simulation layer* contains the core of a simulation software. It performs the simulation work via its graphics and physics engine, and manages the world state. It comes with low-level interfaces that are often specific to the used software. The *control layer* provides tools for interactions with the simulation core via preferably standardized interfaces and communication protocols. The *application layer* contains application-specific user iterfaces and user-defined functions interacting with the simulation. These computational layers are accompanied by the *storage layer* which can both provide data to the other layers or record data generated by the other layers during simulation. Last, the *orchestration layer* automates the configuring, coordinating, and managing of the other layers.
89 |
90 | The various layers are composed into a microservice architecture, fostering scalability, flexibility, reusability, maintainability. We achieve this through a very modular approach in which all major components are containerized.
91 |
92 | CARLOS is a framework that implements the described architecture. We make use of already established software, especially the [CARLA simulator](http://carla.org//). Some additional components from the rich CARLA ecosystem are crucial to our framework and available as specified GitHub forks. We extended these repositories by additional GitHub CI workflows to generate Docker images built with [docker-ros](https://github.com/ika-rwth-aachen/docker-ros). This approach enables an automatic and continual building of up-to-date container images with recent versions of, e.g., ROS, Python, and Ubuntu.
93 |
94 | ### Simulation Core: [***carla-simulator***](https://github.com/ika-rwth-aachen/carla-simulator)
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | The carla-simulator constitutes the central element of the framework and handles all graphics and physics calculations in the individual simulation time steps.
105 |
106 | ### Communication Actor: [***carla-ros-bridge***](https://github.com/ika-rwth-aachen/carla-ros-bridge)
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | The carla-ros-bridge is the component that facilitates the powerful combination of CARLA and ROS. It retrieves data from the simulation to publish it on ROS topics while simultaneously listening on different topics for requested actions, which are translated to commands to be executed in CARLA. It communicates via DDS to interact with ROS, and via RPC to interact with the CARLA Python API.
118 |
119 | ### Control Actor: [***carla-scenario-runner***](https://github.com/ika-rwth-aachen/carla-scenario-runner)
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | To enable scenario-based testing and evaluation, the carla-scenario-runner is used. It is a powerful engine that follows the [OpenSCENARIO standard](https://www.asam.net/standards/detail/openscenario-xml/) for scenario definitions. An additional ROS service allows other ROS nodes to dynamically issue the execution of a specified scenario using the carla-scenario-runner. For the creation of light-weight container images, a custom Dockerfile is used.
131 |
132 |
133 | > [!NOTE]
134 | > For all provided use case examples we use predefined Docker services, listed in [carla-services.yml](./utils/carla-essentials/carla-services.yml) and further described in the [carla-components overview](./utils/carla-essentials/README.md).
135 |
136 | ## Citation
137 | We hope that our simulation framework CARLOS can help your research. If this is the case, please cite it using the following metadata.
138 | ```
139 | @inproceedings{CARLOS24,
140 | author = {Geller, Christian and Haas, Benedikt and Kloeker, Amarin and Hermens, Jona and Lampe, Bastian and Beemelmanns, Till and Eckstein, Lutz},
141 | booktitle={2024 IEEE Intelligent Vehicles Symposium (IV)},
142 | title = {{CARLOS: An Open, Modular, and Scalable Simulation Framework for the Development and Testing of Software for C-ITS}},
143 | url = {https://ieeexplore.ieee.org/document/10588502},
144 | year = {2024},
145 | pages={3100-3106},
146 | doi={10.1109/IV55156.2024.10588502}
147 | }
148 | ```
149 |
150 | ## Acknowledgements
151 |
152 | This research is accomplished within the project [AUTOtech.*agil*](https://www.ika.rwth-aachen.de/en/competences/projects/automated-driving/autotech-agil-en.html) (FKZ 01IS22088A). We acknowledge the financial support for the project by the Federal Ministry of Education and Research of Germany (BMBF).
153 |
--------------------------------------------------------------------------------
/automated-testing/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Use Case: *Automated testing*
4 |
5 | >[!NOTE]
6 | > **Background**: In the *automated testing* demo, simulation is considered to systematically evaluate a large number of defined tests, potentially within the safety assurance process. A specific test configuration may encompass both a concrete scenario and well-defined test metrics for evaluation. Thus, a direct interface to a standardized scenario database is favorable, and custom pass-fail criteria need to be configurable to deduce objective test results. Scalability drastically improves efficiency when simulating multiple test configurations. Moreover, embedding the simulation architecture in a CI process further accelerates the entire safety assurance.
7 |
8 | The subsequent demonstration showcases *automated testing* and specifically addresses the following requirements:
9 | - predefined scenario metrics and **automatic evaluation**
10 | - automation and **scalability**
11 | - CI integration with **GitHub actions and workflows**
12 |
13 | ## Getting Started
14 |
15 | > [!IMPORTANT]
16 | > Make sure that all [system requirements](../utils/requirements.md) are fulfilled.
17 | > Additionally, the CI related part of this demo requires a [self-hosted GitHub Runner](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners) to execute scenarios within a [GitHub workflow](https://docs.github.com/en/actions/using-workflows/about-workflows). The specific requirements for such a runner are listed [below](#self-hosted-github-runner).
18 |
19 | This demo aims to automatically evaluate predefined test scenarios. For this purpose, a test catalog can be defined using OpenSCENARIO files as contained in the [scenarios](../utils/scenarios) folder. These scenarios can be simulated and evaluated using the [carla-scenario-runner](https://github.com/ika-rwth-aachen/carla-scenario-runner). Thus, a basic [docker-compose template](../.github/actions/evaluate-scenario/files/template.yml) only includes the `carla-server` and a `carla-scenario-runner` Docker service. So, in general, the demo enables the efficient execution of multiple scenario-based tests with CARLA, both in local environments and within an automated GitHub CI process.
20 |
21 | ### Manual Testing Pipeline
22 |
23 | In your local environment, you can evaluate multiple scenarios directly, using the provided [run-demo.sh](../run-demo.sh) script:
24 |
25 | ```bash
26 | # carlos$
27 | ./run-demo.sh automated-testing
28 | ```
29 | This executes the [evaluate-scenarios.sh](./evaluate-scenarios.sh) script with default settings. You can also run this script directly and provide custom overrides to the default values by using specific environment variables, flags and arguments. For a detailed overview, please check the script or run:
30 | ```bash
31 | # carlos/automated-testing$
32 | ./evaluate-scenarios.sh -h
33 | ```
34 | The script sequentially evaluates all scenario files in the selected folder. After each scenario run, a detailed evaluation based on the criteria specified in the scenario is presented. An example is shown below.
35 |
36 | 
37 |
38 |
39 | ### Automated CI Pipeline
40 |
41 | All scenarios within the test catalog are also simulated and evaluated in an automated [CI pipeline on GitHub](https://github.com/ika-rwth-aachen/carlos/actions/workflows/automated-testing.yml). A detailed look in the [scenarios folder](../utils/scenarios/) shows that some of them have the postfix `.opt` , marking them as optional. This means a failure in test evaluation is allowed for those specific scenarios and does not determine the success of the entire pipeline. The CI pipeline processes required scenarios first, followed by all optional scenarios. In both cases a job matrix is dynamically created based on the found scenarios, in which each job targets and evaluates a specific scenario. As an example, a workflow is shown below.
42 |
43 | 
44 |
45 | >[!NOTE]
46 | > Even though the complete pipeline appears to have succeeded, the annotations show that one of the optional scenarios has failed and thus should still be investigated
47 |
48 | #### Actions
49 |
50 | We provide two [GitHub actions](https://docs.github.com/en/actions/creating-actions/about-custom-actions) for CARLOS:
51 | - [generate-job-matrix](../.github/actions/generate-job-matrix/)
52 | - [carlos-ci-action](https://github.com/ika-rwth-aachen/carlos-ci-action)
53 |
54 | They can be used within a GitHub CI workflow to create a job list of simulation runs, and consecutively run all simulations. A demonstration of this is presented next.
55 |
56 | #### Workflow
57 |
58 | The workflow presented in [automated-testing.yml](../.github/workflows/automated-testing.yml) combines the different actions and performs simulation evaluation analog to the local `evaluation-scenarios.sh`. It leverages the modularity and customizability of the provided actions by reusing them and configuring them differently. For example, `generate-job-matrix` allows customizing the `query-string`, which is used for matching and collecting fitting scenarios as a job matrix for following pipeline steps.
59 |
60 | #### Self-Hosted GitHub Runner
61 |
62 | As mentioned before, a [self-hosted GitHub Runner](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners) needs to be set up in order to run the described CI pipeline in your custom repository fork. Apart from ensuring the [system requirements](../utils/requirements.md), the runner currently also needs to be started in a **local session** (i.e. not via SSH, RPD or other tools) and has to have access to the primary "display" (see [X window system](https://en.wikipedia.org/wiki/X_Window_System)). You can validate this by running the following command in the same session where you want to start the runner:
63 | ```bash
64 | echo $DISPLAY
65 | ```
66 | The result should be something simple like `:1` . If there is anything in front of the colon, the session is most likely not local and thus not suitable for this setup.
67 |
68 | ### Setup Your Own Simulation Testing Pipeline
69 |
70 | Follow these steps to setup your own simulation testing pipeline:
71 | 1. [Fork](https://docs.github.com/de/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the CARLOS repository on GitHub.
72 | 2. Add a self-hosted runner using the provided information [above](#self-hosted-github-runner).
73 | 3. Push additional OpenSCENARIO test files in the [scenarios](../utils/scenarios/) folder.
74 | 4. Observe the GitHub workflow and scenario test evaluations.
75 |
76 | You may now update the specific test metrics to enable comprehensive testing. In addition, custom ITS functions can be used to control the vehicle instead of the basic CARLA autopilot, enabling useful testing.
77 |
78 |
79 | ## Outlook - Scalability using Orchestration Tools
80 |
81 | The principles and workflows demonstrated here already show the effectiveness of automating the simulation processes. Certainly, a much higher grade of automation can be achieved by incorporating more sophisticated orchestration tools like [Kubernetes](https://kubernetes.io/docs/concepts/overview/), [Docker Swarm](https://docs.docker.com/engine/swarm/) or others. These tools allow for better scalability, while also simplifying the deployment and monitoring of the services.
82 |
--------------------------------------------------------------------------------
/automated-testing/evaluate-scenarios.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | DEFAULT_SIMULATOR_IMAGE="rwthika/carla-simulator:server"
6 | DEFAULT_SCENARIO_RUNNER_IMAGE="rwthika/carla-scenario-runner:latest"
7 | COMPOSE_TEMPLATE_PATH="./template.yml"
8 |
9 | usage() {
10 | echo "Usage: $0 [-o][-p][-n] [COMPOSE_TEMPLATE_PATH] [SCENARIO_FOLDER_PATH]"
11 | echo "COMPOSE_TEMPLATE_PATH : Location of Compose file which can be customized through environment variables"
12 | echo "SCENARIO_FOLDER_PATH : Location of folder containing scenario files ending with .xosc*"
13 | echo "o : Set the simulator to offscreen mode"
14 | echo "p : Pull/Update images before starting the simulation"
15 | echo "n : Do not restart the simulator after each scenario run"
16 | echo "-----"
17 | echo "Environment variables for customization:"
18 | echo "SIMULATOR_IMAGE : CARLA image that should be used"
19 | echo "SCENARIO_RUNNER_IMAGE : CARLA Scenario Runner image that should be used"
20 | echo "TIME_BETWEEN_EVALS" : Delay between each scenario run in seconds
21 | echo "-----"
22 | echo "Example:"
23 | echo "SIMULATOR_IMAGE=rwthika/carla:dev $0 -r ./template.yml ./scenarios"
24 | }
25 |
26 | restart-simulator() {
27 | echo "Restarting simulator..."
28 | docker compose -f $COMPOSE_TEMPLATE_PATH kill
29 | docker compose -f $COMPOSE_TEMPLATE_PATH down
30 | docker compose -f $COMPOSE_TEMPLATE_PATH up -d carla-server
31 | }
32 |
33 | update-simulator() {
34 | echo "Updating simulator..."
35 | docker compose -f $COMPOSE_TEMPLATE_PATH pull
36 | }
37 |
38 | while getopts "hopn" flag; do
39 | case "$flag" in
40 | h)
41 | usage
42 | exit 0
43 | ;;
44 | o)
45 | export SIMULATOR_OFFSCREEN=true
46 | ;;
47 | p)
48 | update-simulator
49 | ;;
50 | n)
51 | export RESTART_SIMULATOR=false
52 | ;;
53 | esac
54 | done
55 |
56 | shift $(($OPTIND-1)) # return to usual handling of positional args
57 |
58 | # default settings if no external overrides provided
59 | export SIMULATOR_IMAGE=${SIMULATOR_IMAGE:-$DEFAULT_SIMULATOR_IMAGE}
60 | export SCENARIO_RUNNER_IMAGE=${SCENARIO_RUNNER_IMAGE:-$DEFAULT_SCENARIO_RUNNER_IMAGE}
61 |
62 | export COMPOSE_TEMPLATE_PATH=$(realpath ${1:-$COMPOSE_TEMPLATE_PATH})
63 | export SCENARIO_FOLDER_PATH=$(realpath ${2:-"../utils/scenarios"})
64 |
65 | export RESTART_SIMULATOR=${RESTART_SIMULATOR:-true}
66 | export TIME_BETWEEN_EVALS=${TIME_BETWEEN_EVALS:-5}
67 |
68 | export SIMULATOR_FLAGS=""
69 | export SCENARIO_FILE_NAME=""
70 |
71 | trap cleanup EXIT
72 | trap cleanup 0
73 |
74 | cleanup() {
75 | echo "Cleaning up..."
76 | RESTART_SIMULATOR=false
77 | docker compose -f $COMPOSE_TEMPLATE_PATH kill
78 | docker compose -f $COMPOSE_TEMPLATE_PATH down
79 | xhost -local:
80 | echo "Done cleaning up."
81 | exit
82 | }
83 |
84 | echo "Searching for scenarios in $SCENARIO_FOLDER_PATH ..."
85 | scenarios=($(find $SCENARIO_FOLDER_PATH -maxdepth 1 -type f -name "*.xosc*" -exec basename {} \;))
86 |
87 | if [ ${#scenarios[@]} -eq 0 ]; then
88 | echo "No scenarios found. Exiting..."
89 | exit 1
90 | fi
91 |
92 | if [ "$SIMULATOR_OFFSCREEN" = true ]; then
93 | export SIMULATOR_FLAGS="-RenderOffScreen"
94 | fi
95 |
96 | xhost +local:
97 | echo "Starting simulator..."
98 | docker compose -f $COMPOSE_TEMPLATE_PATH up -d carla-server
99 |
100 | for scenario in "${scenarios[@]}"; do
101 | echo "Evaluating $scenario ..."
102 | export SCENARIO_FILE_NAME=$scenario
103 |
104 | docker compose -f $COMPOSE_TEMPLATE_PATH run --rm carla-scenario-runner || true
105 |
106 | if [ "$RESTART_SIMULATOR" = true ]; then
107 | restart-simulator
108 | fi
109 |
110 | sleep $TIME_BETWEEN_EVALS
111 | done
112 |
--------------------------------------------------------------------------------
/automated-testing/template.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | carla-server:
4 | deploy:
5 | resources:
6 | reservations:
7 | devices:
8 | - driver: nvidia
9 | count: 1
10 | capabilities: [gpu]
11 | privileged: True
12 | environment:
13 | DISPLAY: $DISPLAY
14 | volumes:
15 | - /tmp/.X11-unix:/tmp/.X11-unix
16 | image: $SIMULATOR_IMAGE
17 | command: bash -ic './CarlaUE4.sh -nosound $SIMULATOR_FLAGS 2>/dev/null'
18 |
19 | carla-scenario-runner:
20 | depends_on:
21 | carla-server:
22 | condition: service_healthy
23 | volumes:
24 | - $SCENARIO_FOLDER_PATH:/scenarios
25 | image: $SCENARIO_RUNNER_IMAGE
26 | command: bash -ic "python ./scenario_runner.py --host carla-server --openscenario /scenarios/$SCENARIO_FILE_NAME --output"
--------------------------------------------------------------------------------
/data-driven-development/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Use Case: *Data-Driven Development*
4 |
5 | >[!NOTE]
6 | > **Background**: The *data-driven development* use case covers development processes using large amounts of data, which are not effectively obtainable in real-world settings, thus motivating simulations. For many applications, simulative data can be sufficiently accurate to be integrated into the data-driven development process. This includes training data for machine learning algorithms but also closed-loop reinforcement learning. Potentially interesting data includes raw sensor but also dynamic vehicle data in a wide variety at large scale. Simulations additionally enable data generation beyond the physical limits of vehicle dynamics or sensor configurations. To accumulate large amounts of data, relevant simulation parameters can be automatically sampled along different dimensions. Subsequently, automation and parallelization empower a cost-effective execution of multiple simulations, especially when using already established orchestration tools.
7 |
8 | The subsequent demonstration showcases rapid *data driven development* and specifically addresses the following requirements:
9 | - high simulation **fidelity**
10 | - **flexibility** and containerization
11 | - automation and **scalability**
12 |
13 | ## Getting Started
14 |
15 | ### Requirements and Installation
16 | > [!IMPORTANT]
17 | > Make sure that all [system requirements](../utils/requirements.md) are fulfilled.
18 | > Additionally, a Python installation is required on the host for this use case. We recommend using [conda](https://docs.conda.io/projects/conda/en/stable/index.html).
19 |
20 | Install and activate the conda environment:
21 |
22 | ```bash
23 | conda env create -f env/environment.yml
24 | conda activate carlos_data_driven_development
25 | ```
26 |
27 | Alternatively, you can also use Pip:
28 |
29 | ```bash
30 | pip install -r env/requirements.txt
31 | ```
32 |
33 | In the initial demo [software-prototyping](../software-prototyping), we demonstrated the integration of a Function Under Test (FUT) with CARLOS, exploring its capabilities through practical experimentation. While these tests validated the general functionality of our image segmentation module, it became clear that there is considerable potential to improve its performance. Given that this module, like many AD functions, relies heavily on machine learning models trained with specific datasets, the quality and quantity of this training data are crucial.
34 |
35 | ### Permutation-based Data Generation
36 |
37 | Given that the specific nature of the data is less critical, the main objective is to generate as much and diverse data as possible. This can be effectively achieved through permutations of the simulation parameters, ensuring both quantity and diversity in the generated dataset.
38 |
39 | Run the demo for permutation-based data generation:
40 | ```bash
41 | # carlos/data-driven-development$
42 | python ./data_generation.py --config config/data-driven-development-demo-permutation-execution.yml
43 | ```
44 |
45 | or use the top-level `run-demo.sh` script:
46 | ```bash
47 | # carlos$
48 | ./run-demo.sh data-driven-development
49 | ```
50 |
51 | Data is generated by creating all possible permutations from a set of configuration parameters, managed through a YAML configuration file. This results in different simulation runs in several parameter dimensions, which are simulated in sequence. A comprehensive [example configuration](./config/data-driven-development-demo-permutation-execution.yml) is provided within the [config](./config/) folder. While the current implementation is limited to the settings specified [below](#configuration-table), the provided code is modular and can be easily customized to fit your requirements.
52 |
53 | ```yaml
54 | run_settings:
55 | num_executions: 1
56 | permutation_settings:
57 | sensors_file:
58 | - ./config/sensors/rgb_segmentation_camera.json
59 | spawn_point:
60 | - "1"
61 | - "2"
62 | - "3"
63 | town:
64 | - Town01
65 | - Town10HD
66 | vehicle_occupancy:
67 | - "0.5"
68 | walker_number:
69 | - "50"
70 | weather:
71 | - ClearSunset
72 | - WetCloudyNoon
73 | ```
74 |
75 | This exemplary demo configures 12 different simulation runs, by applying permutations in the CARLA town, the weather settings and the initial spawning point of the ego vehicle. All simulations run for a maximum simulation time of 60s and all relevant image segmentation data topics are recorded in dedicated ROS bags.
76 |
77 | Thus, data generation at large scale becomes possible and helps developers to achieve diverse and useful data for any application.
78 |
79 | ### Scenario-based Data Generation
80 |
81 | Assuming we improved our model, we are now aiming to evaluate its performance in targeted, real-world scenarios. Hence, we need to generate data in such concrete scenarios, for which the scenario-based data generation feature can be utilized. In this example, we demonstrate how a list of multiple OpenSCENARIO files can be integrated into the data generation pipeline as well to generate data under those specific conditions.
82 |
83 | ```bash
84 | # carlos/data-driven-development$
85 | python ./data_generation.py --config data-driven-development-demo-scenario-execution.yml
86 | ```
87 |
88 | All scenarios are executed sequentially and data is generated analogous to above. The respective configuration file contains mainly a list to specific predefined OpenSCENARIO files, but additionally enables variation in the sensors file:
89 | ```yaml
90 | run_settings:
91 | num_executions: 1
92 | scenario_settings:
93 | scenario_file:
94 | - ../utils/scenarios/town01.xosc
95 | - ../utils/scenarios/town10.xosc
96 | sensors_file:
97 | - ./config/sensors/rgb_segmentation_camera.json
98 | ```
99 |
100 | Following on that initial scenario-based simulation approach, we focus more on the automatic execution and evaluation of scenarios at large scale in the third, [automatic testing demo](../automated-testing/README.md). In addition, a full integration into a CI workflow is provided.
101 |
102 | ### Record Your Own Data
103 |
104 | Follow these steps to record your own data:
105 |
106 | 1. Specify [sensor configuration file(s)](https://carla.readthedocs.io/projects/ros-bridge/en/latest/carla_spawn_objects/#spawning-sensors) to provide sensor data within ROS.
107 | 2. Adjust the parameters in the data pipeline configuration file. A full list of supported parameters is given [below](#configuration-parameters).
108 | 3. Start the pipeline with `./data_generation.py --config `.
109 | 4. Observe the recorded ROS 2 bag files for further postprocessing.
110 |
111 | You may now adjust the configuration parameters to fit your specific use case. In addition, the pipeline code itself can be updated in the [data_generation.py](./data_generation.py) Python file.
112 |
113 | ## Configuration Parameters
114 |
115 | The YAML configuration file for the data generation pipeline consists of two main sections: `general_settings` and `run_settings`. The `general_settings` section specifies general parameters. The `run_settings` section must either contain `permutation_settings` for permutation-based simulations or `scenario_settings` for scenario-based simulations.
116 |
117 | ### General Settings (`general_settings`)
118 |
119 | | Name | Description | Note | required | default
120 | | --- | --- | --- | --- | --- |
121 | | `max_simulation_time` | Maximum simulation-time duration in seconds of one simulation run before it is terminated | | not required | 300 |
122 | | `max_real_time` | Maximum real-time duration in seconds of one simulation run before it is terminated | | not required | 300 |
123 | | `simulation_services` | List of all Docker services which should are executed during a simulation run | Names must match with the service names in [docker-compose.yml](./docker-compose.yml) | required | - |
124 | | `record_topics` | Dict of ROS 2 topics to be recorded | | not required | - |
125 | | `output_path` | Path for storing generated data | | not required | `./data/` |
126 |
127 | ### Run Settings (`run_settings`)
128 | | Name | Description | Note | required | default
129 | | --- | --- | --- | --- | --- |
130 | | `num_executions` | Number of times a simulation setup is executed | Must be an integer | not required | 1 |
131 | | `permutation_settings` | Struct to specify settings for permutation based simulation | See below | not required | - |
132 | | `scenario_settings` | Struct to specify settings for scenario based simulation | See below | not required | - |
133 |
134 | #### Permutation-based Settings (`permutation_settings`)
135 | | Name | Description | Note | required | default
136 | | --- | --- | --- | --- | --- |
137 | | `sensors_file` | Paths of sensor configuration files | | required | - |
138 | | `spawn_point` | List of spawnpoints for the data-generating-vehicle | Only numbers are allowed | required | - |
139 | | `town` | List of towns for the simulation environment | [Town list](https://carla.readthedocs.io/en/latest/core_map/#non-layered-maps), Town10 = Town10HD | required | Town01 |
140 | | `vehicle_number` | List of numbers that spawn a fixed number of vehicles | only used if `vehicle_occupancy` is not set, vehicles are spawned via generate_traffic.py | not required | - |
141 | | `vehicle_occupancy` | List of numbers between 0 and 1 that spawn vehicles proportionally to the number of available spawn points | vehicles are spawned via generate_traffic.py | not required | - |
142 | | `weather` | List of weather conditions | [Weather conditions list](https://github.com/carla-simulator/carla/blob/master/PythonAPI/docs/weather.yml#L158) | not required | depends on town, in general "ClearSunset" |
143 |
144 | #### Scenario-based Settings (`scenario_settings`)
145 | | Name | Description | Note | required | default
146 | | --- | --- | --- | --- | --- |
147 | | `scenario_file` | Paths of OpenSCENARIO files (.xosc) | | not required | - |
148 | | `sensors_file` | Paths of sensor configuration files | | not required | - |
149 |
--------------------------------------------------------------------------------
/data-driven-development/config/data-driven-development-demo-permutation-execution.yml:
--------------------------------------------------------------------------------
1 | general_settings:
2 | max_simulation_time: 60
3 | max_real_time: 300
4 | simulation_services:
5 | - carla-server
6 | - time-health-check
7 | - spawned-vehicle-check
8 | - carla-ros-bridge
9 | - carla-simulation-controller
10 | - rosbag-record
11 | convert_services: []
12 | record_topics:
13 | topic_rgb: /carla/ego_vehicle/rgb/image
14 | topic_segmentation: /carla/ego_vehicle/segmentation/image
15 | topic_tf: /tf
16 | topic_clock: /clock
17 | output_path: ./data/permutation-execution/
18 |
19 | run_settings:
20 | num_executions: 1
21 | permutation_settings:
22 | sensors_file:
23 | - ./config/sensors/rgb_segmentation_camera.json
24 | spawn_point:
25 | - "1"
26 | - "2"
27 | - "3"
28 | town:
29 | - Town01
30 | - Town10HD
31 | vehicle_occupancy:
32 | - "0.5"
33 | walker_number:
34 | - "50"
35 | weather:
36 | - ClearSunset
37 | - WetCloudyNoon
38 |
--------------------------------------------------------------------------------
/data-driven-development/config/data-driven-development-demo-scenario-execution.yml:
--------------------------------------------------------------------------------
1 | general_settings:
2 | max_simulation_time: 60
3 | max_real_time: 300
4 | simulation_services:
5 | - carla-server
6 | - time-health-check
7 | - spawned-vehicle-check
8 | - carla-ros-bridge
9 | - carla-scenario-runner
10 | - rosbag-record
11 | convert_services: []
12 | record_topics:
13 | topic_rgb: /carla/ego_vehicle/rgb/image
14 | topic_segmentation: /carla/ego_vehicle/segmentation/image
15 | topic_tf: /tf
16 | topic_clock: /clock
17 | output_path: ./data/scenario-execution/
18 |
19 | run_settings:
20 | num_executions: 1
21 | scenario_settings:
22 | scenario_file:
23 | - ../utils/scenarios/town01.xosc
24 | - ../utils/scenarios/town10.xosc
25 | sensors_file:
26 | - ./config/sensors/rgb_segmentation_camera.json
27 |
--------------------------------------------------------------------------------
/data-driven-development/config/sensors/rgb_segmentation_camera.json:
--------------------------------------------------------------------------------
1 | {
2 | "objects":
3 | [
4 | {
5 | "type": "vehicle.tesla.model3",
6 | "id": "ego_vehicle",
7 | "sensors":
8 | [
9 | {
10 | "type": "sensor.camera.rgb",
11 | "id": "rgb",
12 | "spawn_point": {"x": 1.0, "y": 0.0, "z": 1.7, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
13 | "fov": 90,
14 | "image_size_x": 1024,
15 | "image_size_y": 512
16 | },
17 | {
18 | "type": "sensor.camera.semantic_segmentation",
19 | "id": "segmentation",
20 | "spawn_point": {"x": 1.0, "y": 0.0, "z": 1.7, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
21 | "fov": 90,
22 | "image_size_x": 1024,
23 | "image_size_y": 512
24 | },
25 | {
26 | "type": "sensor.pseudo.tf",
27 | "id": "tf"
28 | },
29 | {
30 | "type": "sensor.pseudo.objects",
31 | "id": "objects"
32 | },
33 | {
34 | "type": "sensor.pseudo.odom",
35 | "id": "odometry"
36 | },
37 | {
38 | "type": "sensor.pseudo.speedometer",
39 | "id": "speedometer"
40 | },
41 | {
42 | "type": "actor.pseudo.control",
43 | "id": "control"
44 | }
45 | ]
46 | }
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/data-driven-development/data_generation.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import argparse
4 | import itertools
5 | import json
6 | import logging
7 | import os
8 | import sys
9 | import xml.etree.ElementTree as ET
10 | from pathlib import Path
11 | from typing import Any
12 |
13 | import yaml
14 | from python_on_whales import DockerClient, DockerException
15 |
16 | logging.basicConfig(level=logging.INFO,
17 | format='%(asctime)s - %(levelname)s - %(message)s')
18 |
19 |
20 | def parse_arguments() -> argparse.Namespace:
21 | parser = argparse.ArgumentParser()
22 | parser.add_argument(
23 | '--config',
24 | metavar='C',
25 | default='./config/data-driven-development-demo-permutation-execution.yml',
26 | help=('Config file which should be used (default:'
27 | './config/data-driven-development-demo-permutation-execution.yml)'))
28 | args = parser.parse_args()
29 | return args
30 |
31 |
32 | def load_config(
33 | config_file_path: Path) -> tuple[dict[str, Any], dict[str, Any]]:
34 | try:
35 | with config_file_path.open() as config_file:
36 | config = yaml.safe_load(config_file)
37 | return config["general_settings"], config["run_settings"]
38 | except FileNotFoundError:
39 | logging.error(f"Config file not found: {config_file_path}")
40 | sys.exit(1)
41 | except yaml.YAMLError as e:
42 | logging.error(f"Error reading YAML file: {e}")
43 | sys.exit(1)
44 | except KeyError as e:
45 | logging.error(f"The {e} key is missing in the config file")
46 | sys.exit(1)
47 |
48 |
49 | def prepare_general_settings(
50 | general_settings: dict[str, Any]
51 | ) -> tuple[dict[str, Any], list[str], list[str]]:
52 | # Convert required settings to CLI arguments
53 | cli_args = ["max_real_time", "max_simulation_time"]
54 | for key in cli_args:
55 | if key in general_settings:
56 | general_settings[key] = f"--{key} {general_settings[key]}"
57 | # Set default output path if required
58 | if "output_path" not in general_settings:
59 | general_settings["output_path"] = "./data/"
60 | if "record_topics" in general_settings:
61 | output_path = general_settings["output_path"]
62 | if not os.path.exists(output_path):
63 | os.makedirs(output_path)
64 | # Flatten all topics into a single argument
65 | general_settings["record_topics"] = " ".join(
66 | general_settings["record_topics"].values())
67 | # Separate simulation and convert services as they are required somewhere else
68 | simulation_services = general_settings.pop("simulation_services", None)
69 | convert_services = general_settings.pop("convert_services", None)
70 | return general_settings, simulation_services, convert_services
71 |
72 |
73 | def setup_docker_client(docker_compose_file: Path = Path(
74 | './docker-compose.yml')) -> DockerClient:
75 | if not docker_compose_file.exists():
76 | logging.error(f"Docker Compose file not found: {docker_compose_file}")
77 | sys.exit(1)
78 | return DockerClient(compose_files=[docker_compose_file])
79 |
80 |
81 | def check_run_settings(run_settings: dict[Any], simulation_services: list[str]) -> None:
82 | config_checks = {
83 | "permutation_settings": {
84 | "required_service": "carla-simulation-controller",
85 | "forbidden_service": "carla-scenario-runner",
86 | "error_message": "simulation-controller is required for permutation execution."
87 | },
88 | "scenario_settings": {
89 | "required_service": "carla-scenario-runner",
90 | "forbidden_service": "simulation-controller",
91 | "error_message": "carla-scenario-runner is required for scenario execution."
92 | }
93 | }
94 |
95 | for setting_key, config in config_checks.items():
96 | if setting_key in run_settings:
97 | if (config["required_service"] not in simulation_services or
98 | config["forbidden_service"] in simulation_services):
99 | logging.error(config["error_message"])
100 | sys.exit(1)
101 |
102 |
103 | def validate_file(file: str, suffix: str = None) -> str:
104 | if not file:
105 | logging.error("No file specified")
106 | sys.exit(1)
107 |
108 | file = Path(file)
109 | if not file.is_file():
110 | logging.error(f"File not found: {file}")
111 | sys.exit(1)
112 |
113 | if suffix and file.suffix != suffix:
114 | logging.error(f"Invalid file suffix: {file}")
115 | sys.exit(1)
116 |
117 | return str(file)
118 |
119 |
120 | def get_role_names(sensor_config_file: str) -> str:
121 | try:
122 | with open(sensor_config_file) as file:
123 | data = json.load(file)
124 | role_names = [actor["id"] for actor in data["objects"]
125 | if actor["type"].startswith("vehicle.")]
126 | role_names = " ".join(role_names)
127 | return role_names
128 | except json.JSONDecodeError as e:
129 | logging.error(f"Error reading sensors JSON file: {e}")
130 | sys.exit(1)
131 |
132 |
133 | def prepare_controller(simulation_setup: dict[str, Any]) -> dict[str, Any]:
134 | # Store relevant keys as simulation controller args
135 | controller_args = []
136 | argument_list = ["spawn_point", "town", "weather",
137 | "vehicle_number", "vehicle_occupancy", "walker_number"]
138 |
139 | for key in list(simulation_setup.keys()):
140 | if key in argument_list:
141 | controller_args.append(f"--{key} {simulation_setup[key]}")
142 |
143 | simulation_setup["controller_args"] = " ".join(controller_args)
144 | return simulation_setup
145 |
146 |
147 | def prepare_scenario(simulation_setup: dict[str, Any]) -> dict[str, Any]:
148 | if "scenario_file" in simulation_setup:
149 | scenario_file = simulation_setup.pop("scenario_file")
150 |
151 | # validate scenario_file
152 | validate_file(scenario_file, ".xosc")
153 |
154 | # split scenario_file in scenario_file and scenario_path
155 | simulation_setup["scenario_folder"] = os.path.dirname(scenario_file)
156 | simulation_setup["scenario_file"] = os.path.basename(scenario_file)
157 |
158 | # get town from scenario file
159 | tree = ET.parse(scenario_file)
160 | root = tree.getroot()
161 | elem = root.find('./RoadNetwork/LogicFile')
162 | simulation_setup["town"] = elem.get('filepath')
163 |
164 | return simulation_setup
165 |
166 |
167 | def simulate_setup(docker_client: DockerClient,
168 | general_settings: dict[Any],
169 | simulation_setup: dict[Any],
170 | simulation_services: list[str]) -> None:
171 | run_name = '_'.join(
172 | Path(str(value)).stem if Path(
173 | str(value)).parent != Path('.') else str(value)
174 | for value in simulation_setup.values()
175 | )
176 |
177 | simulation_setup["sensors_file"] = validate_file(
178 | simulation_setup["sensors_file"], ".json")
179 | simulation_setup["role_names"] = get_role_names(
180 | simulation_setup["sensors_file"])
181 |
182 | simulation_setup = prepare_controller(simulation_setup)
183 | simulation_setup = prepare_scenario(simulation_setup)
184 |
185 | simulation_args = {"run_name": run_name, **
186 | general_settings, **simulation_setup}
187 |
188 | os.environ.update(simulation_args)
189 | logging.info(f"Running simulation setup {run_name}")
190 | docker_client.compose.pull()
191 | docker_client.compose.up(abort_on_container_exit=True,
192 | services=simulation_services)
193 | docker_client.compose.down()
194 | logging.info(f"Simulation setup {run_name} completed")
195 |
196 |
197 | def main():
198 | args = parse_arguments()
199 | general_settings, run_settings = load_config(Path(args.config))
200 | general_settings, simulation_services, convert_services = prepare_general_settings(
201 | general_settings)
202 | docker_client = setup_docker_client()
203 |
204 | try:
205 | num_executions = int(run_settings.pop("num_executions", 1))
206 |
207 | check_run_settings(run_settings, simulation_services)
208 |
209 | simulation_setups = []
210 | for setting_key in ("permutation_settings", "scenario_settings"):
211 | if setting_key in run_settings:
212 | keys, values = zip(*run_settings[setting_key].items())
213 | setups = [dict(zip(keys, v))
214 | for v in itertools.product(*values)]
215 | simulation_setups.extend(setups)
216 |
217 | logging.info(
218 | f"Running {len(simulation_setups) * num_executions} different simulation setups..."
219 | )
220 |
221 | for _ in range(num_executions):
222 | for simulation_setup in simulation_setups:
223 | try:
224 | simulate_setup(docker_client,
225 | general_settings,
226 | simulation_setup,
227 | simulation_services)
228 | except DockerException:
229 | docker_client.compose.down()
230 |
231 | except KeyboardInterrupt:
232 | docker_client.compose.kill()
233 |
234 |
235 | if __name__ == "__main__":
236 | main()
237 |
--------------------------------------------------------------------------------
/data-driven-development/docker-compose.yml:
--------------------------------------------------------------------------------
1 | x-scenario-mount: &scenario-mount ./${scenario_folder}:/scenarios
2 | x-sensors-mount: &sensors-mount ./${sensors_file}:/sensors.json
3 |
4 | # ==============================================================================
5 |
6 | services:
7 |
8 | # --- core services ----------------------------------------------------------
9 |
10 | carla-server:
11 | extends:
12 | file: ../utils/carla-essentials/carla-services.yml
13 | service: carla-server-offscreen
14 |
15 | carla-ros-bridge:
16 | extends:
17 | file: ../utils/carla-essentials/carla-services.yml
18 | service: carla-ros-bridge
19 | volumes:
20 | - *sensors-mount
21 | - ./launch/demo.launch.py:/demo.launch.py
22 | command: bash -ic "ros2 launch /demo.launch.py town:=${town}"
23 |
24 | # ----------------------------------------------------------------------------
25 | # --- checking services ------------------------------------------------------
26 |
27 | time-health-check:
28 | extends:
29 | file: ../utils/carla-essentials/carla-services.yml
30 | service: carla-client
31 | depends_on:
32 | spawned-vehicle-check:
33 | condition: service_healthy
34 | volumes:
35 | - ./scripts/time_controller.py:/opt/carla/PythonAPI/time_controller.py
36 | command: bash -ic "python time_controller.py --host carla-server ${max_simulation_time} ${max_real_time}"
37 |
38 | spawned-vehicle-check:
39 | extends:
40 | file: ../utils/carla-essentials/carla-services.yml
41 | service: carla-client
42 | volumes:
43 | - ./scripts/spawned_vehicle_check.py:/opt/carla/PythonAPI/spawned_vehicle_check.py
44 | command: sleep infinity
45 | healthcheck:
46 | test: ["CMD-SHELL", "bash -ic \"python spawned_vehicle_check.py --host carla-server --role_name_list ${role_names}\""]
47 | interval: 1s
48 | start_period: 10s
49 | retries: 3
50 |
51 | # ----------------------------------------------------------------------------
52 | # --- Option A: apply random permutation setups ------------------------------
53 | carla-simulation-controller:
54 | extends:
55 | file: ../utils/carla-essentials/carla-services.yml
56 | service: carla-client
57 | depends_on:
58 | spawned-vehicle-check:
59 | condition: service_healthy
60 | volumes:
61 | - ./scripts/simulation_controller.py:/opt/carla/PythonAPI/simulation_controller.py
62 | - ./scripts/set_environment.py:/opt/carla/PythonAPI/set_environment.py
63 | - *sensors-mount
64 | command: bash -ic "python -u simulation_controller.py --host carla-server ${controller_args}"
65 |
66 | # --- Option B: apply concrete scenario setups -------------------------------
67 | carla-scenario-runner:
68 | extends:
69 | file: ../utils/carla-essentials/carla-services.yml
70 | service: carla-scenario-runner
71 | depends_on:
72 | spawned-vehicle-check:
73 | condition: service_healthy
74 | volumes:
75 | - *scenario-mount
76 | command: bash -ic "python ./scenario_runner.py --host carla-server --openscenario /scenarios/${scenario_file} --waitForEgo --output"
77 |
78 | # ----------------------------------------------------------------------------
79 | # --- recording services -----------------------------------------------------
80 | rosbag-record:
81 | extends:
82 | file: ../utils/carla-essentials/carla-services.yml
83 | service: ros-monitoring-offscreen
84 | depends_on:
85 | spawned-vehicle-check:
86 | condition: service_healthy
87 | volumes:
88 | - ${output_path}:/docker-ros/ws/data
89 | command: bash -ic "ros2 bag record --use-sim-time -o /docker-ros/ws/data/bags/${run_name}_$(date +%Y-%m-%d-%H-%M) ${record_topics}"
90 |
--------------------------------------------------------------------------------
/data-driven-development/env/environment.yml:
--------------------------------------------------------------------------------
1 | name: carlos_data_driven_development
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - python==3.12.1
6 | - python-on-whales==0.68.0
7 | - pyyaml==6.0.2
8 |
--------------------------------------------------------------------------------
/data-driven-development/env/requirements.txt:
--------------------------------------------------------------------------------
1 | python-on-whales==0.68.0
2 | pyyaml==6.0.2
--------------------------------------------------------------------------------
/data-driven-development/launch/demo.launch.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import launch
4 | from ament_index_python.packages import get_package_share_directory
5 |
6 | def generate_launch_description():
7 |
8 | # Args that can be set from CLI
9 |
10 | # CARLA Args
11 | host_launch_arg = launch.actions.DeclareLaunchArgument(
12 | name='host',
13 | default_value='carla-server'
14 | )
15 |
16 | port_launch_arg = launch.actions.DeclareLaunchArgument(
17 | name='port',
18 | default_value='2000'
19 | )
20 |
21 | timeout_launch_arg = launch.actions.DeclareLaunchArgument(
22 | name='timeout',
23 | default_value='5000'
24 | )
25 |
26 | passive_launch_arg = launch.actions.DeclareLaunchArgument(
27 | name='passive',
28 | default_value='False'
29 | )
30 |
31 | synchronous_mode_wait_launch_arg = launch.actions.DeclareLaunchArgument(
32 | name='synchronous_mode_wait_for_vehicle_control_command',
33 | default_value='False'
34 | )
35 |
36 | fixed_delta_seconds_launch_arg = launch.actions.DeclareLaunchArgument(
37 | name='fixed_delta_seconds',
38 | default_value='0.1'
39 | )
40 |
41 | town_launch_arg = launch.actions.DeclareLaunchArgument(
42 | name='town',
43 | default_value='Town10HD'
44 | )
45 |
46 | # Ego vehicle args
47 | objects_definition_file_launch_arg = launch.actions.DeclareLaunchArgument(
48 | name='objects_definition_file',
49 | default_value=os.path.join(
50 | '/sensors.json'
51 | )
52 | )
53 |
54 | role_name_launch_arg = launch.actions.DeclareLaunchArgument(
55 | name='role_name',
56 | default_value="ego_vehicle"
57 | )
58 |
59 | # Included launch files
60 |
61 | ros_bridge_launch_include = launch.actions.IncludeLaunchDescription(
62 | launch.launch_description_sources.PythonLaunchDescriptionSource(
63 | os.path.join(
64 | get_package_share_directory('carla_ros_bridge'),
65 | 'carla_ros_bridge.launch.py'
66 | )
67 | ),
68 | launch_arguments={
69 | 'host': launch.substitutions.LaunchConfiguration('host'),
70 | 'port': launch.substitutions.LaunchConfiguration('port'),
71 | 'town': launch.substitutions.LaunchConfiguration('town'),
72 | 'timeout': launch.substitutions.LaunchConfiguration('timeout'),
73 | 'passive': launch.substitutions.LaunchConfiguration('passive'),
74 | 'synchronous_mode_wait_for_vehicle_control_command': launch.substitutions.LaunchConfiguration('synchronous_mode_wait_for_vehicle_control_command'),
75 | 'fixed_delta_seconds': launch.substitutions.LaunchConfiguration('fixed_delta_seconds')
76 | }.items()
77 | )
78 |
79 | carla_spawn_objects_launch_include = launch.actions.IncludeLaunchDescription(
80 | launch.launch_description_sources.PythonLaunchDescriptionSource(
81 | os.path.join(
82 | get_package_share_directory('carla_spawn_objects'),
83 | 'carla_example_ego_vehicle.launch.py'
84 | )
85 | ),
86 | launch_arguments={
87 | 'objects_definition_file': launch.substitutions.LaunchConfiguration('objects_definition_file'),
88 | 'role_name': launch.substitutions.LaunchConfiguration('role_name'),
89 | 'spawn_sensors_only': 'False'
90 | }.items()
91 | )
92 |
93 | # Return full launch description
94 |
95 | return launch.LaunchDescription([
96 | host_launch_arg,
97 | port_launch_arg,
98 | timeout_launch_arg,
99 | passive_launch_arg,
100 | synchronous_mode_wait_launch_arg,
101 | fixed_delta_seconds_launch_arg,
102 | town_launch_arg,
103 | objects_definition_file_launch_arg,
104 | role_name_launch_arg,
105 | ros_bridge_launch_include,
106 | carla_spawn_objects_launch_include,
107 | ])
108 |
109 |
110 | if __name__ == '__main__':
111 | generate_launch_description()
112 |
--------------------------------------------------------------------------------
/data-driven-development/scripts/set_environment.py:
--------------------------------------------------------------------------------
1 | # System imports
2 | import glob
3 | import os
4 | import sys
5 | import time
6 | import yaml
7 |
8 | # Differentiate between windows and linux
9 | try:
10 | sys.path.append(
11 | glob.glob("../carla/dist/carla-*%d.%d-%s.egg" % (
12 | sys.version_info.major,
13 | sys.version_info.minor,
14 | "win-amd64" if os.name == "nt" else "linux-x86_64",
15 | ))[0])
16 | except IndexError:
17 | pass
18 |
19 | # Carla Import
20 | import carla
21 | from carla import VehicleLightState as vls
22 |
23 | # System imports
24 | import argparse
25 | import logging
26 | from numpy import random
27 |
28 | # Set Default Values for parameters that can not be set by arguments
29 | DFAULT_ACTOR_ACTIVE_DISTANCE = 1000.0
30 | DEFAULT_RESPAWN_LOWER_BOUND = 25.0
31 | DEFAULT_RESPAWN_UPPER_BOUND = 700.0
32 | DEFAULT_PHYSICS_ENABLE_RADIUS = 70.0
33 | DEFAULT_GLOBAL_DISTANCE_TO_LEADING_VEHICLE = 2.5
34 | DEFAULT_GLOBAL_PERCENTAGE_SPEED_DIFFERENCE = 0.0
35 | DEFAULT_PERCENTAGE_PEDESTRIANS_RUNNING = 0.0
36 | DEFAULT_PERCENTAGE_PEDESTRIANS_CROSSING = 0.0
37 |
38 |
39 | #########################################################
40 | ##################### Main Function #####################
41 | #########################################################
42 | def main():
43 | # Parse arguments
44 | args = parseArguments()
45 |
46 | # Parse config file
47 | if args.config_file != "":
48 | config = parseConfigFile(args.config_file)
49 | if config is None:
50 | logging.error("Can not parse config file")
51 | sys.exit()
52 |
53 | # As we removed any explicitly given arguments from the config, we can merge the config with the arguments without overwriting any intentional arguments
54 | args_dict = vars(args).copy()
55 | args_dict.update(config)
56 | args = argparse.Namespace(**args_dict)
57 |
58 | # Configure logging
59 | logging.basicConfig(format="%(levelname)s: %(message)s",
60 | level=logging.INFO)
61 |
62 | # Set up actor lists
63 | vehicles_list = []
64 | walkers_list = []
65 | all_id = []
66 |
67 | # Set up the carla client
68 | client = carla.Client(args.host, args.port)
69 | client.set_timeout(10.0)
70 | synchronous_master = False
71 | random.seed(args.seed if args.seed is not None else int(time.time()))
72 |
73 | ###########################################
74 | # Try to spawn the actors
75 | ###########################################
76 | try:
77 | # Get the world
78 | world = client.get_world()
79 |
80 | ###########################################
81 | # Set up the weather
82 | ###########################################
83 |
84 | # Get available weather presets from carla
85 | weather_presets = {
86 | name: getattr(carla.WeatherParameters, name)
87 | for name in dir(carla.WeatherParameters)
88 | if not name.startswith("_")
89 | }
90 |
91 | # Check if weather config is used (config file only)
92 | if hasattr(args, "generate_weather") and args.generate_weather:
93 | print("Generating weather...")
94 |
95 | # Save current weather conditions
96 | saved_weather = world.get_weather()
97 |
98 | # Set weather by preset
99 | if args.use_weather_preset:
100 | print("Setting weather to preset: " +
101 | args.weather_preset_name + "\n")
102 | selected_weather = weather_presets[args.weather_preset_name]
103 |
104 | # Set weather by parameters
105 | else:
106 | print("Setting Weather to custom parameters" + "\n")
107 | selected_weather = carla.WeatherParameters(
108 | cloudiness=args.cloudiness,
109 | precipitation=args.precipitation,
110 | precipitation_deposits=args.precipitation_deposits,
111 | sun_altitude_angle=args.sun_altitude_angle,
112 | sun_azimuth_angle=args.sun_azimuth_angle,
113 | wind_intensity=args.wind_intensity,
114 | fog_density=args.fog_density,
115 | fog_distance=args.fog_distance,
116 | wetness=args.wetness,
117 | fog_falloff=args.fog_falloff,
118 | dust_storm=args.dust_storm,
119 | )
120 |
121 | # Apply weather
122 | world.set_weather(selected_weather)
123 |
124 | ###########################################
125 | # Set up the traffic behavior
126 | ###########################################
127 |
128 | # Get the traffic manager
129 | traffic_manager = client.get_trafficmanager(args.tm_port)
130 |
131 | # All vehicles have to be at least a certain distance apart
132 | global_distance_to_leading_vehicle = getattr(
133 | args,
134 | "global_distance_to_leading_vehicle",
135 | DEFAULT_GLOBAL_DISTANCE_TO_LEADING_VEHICLE,
136 | )
137 | traffic_manager.set_global_distance_to_leading_vehicle(
138 | global_distance_to_leading_vehicle)
139 |
140 | # All vehicles can only differ a certain percentage from their set speed
141 | global_percentage_speed_difference = getattr(
142 | args,
143 | "global_percentage_speed_difference",
144 | DEFAULT_GLOBAL_PERCENTAGE_SPEED_DIFFERENCE,
145 | )
146 | traffic_manager.global_percentage_speed_difference(
147 | global_percentage_speed_difference)
148 |
149 | # Enable hybrid physics mode
150 | if args.hybrid:
151 | if not args.hero:
152 | logging.warning(
153 | "You are using hybrid physics mode. However none of the spawned"
154 | " vehicles is a hero vehicle. This will result in no vehicles being"
155 | " simulated, unless you define a separate hero vehicle.")
156 | traffic_manager.set_hybrid_physics_mode(
157 | True
158 | ) # Only actors in a given radius around a hero vehicle are simulated, if there is no hero vehicle, no actors are simulated.
159 |
160 | # Set the spawn radius
161 | traffic_manager.set_hybrid_physics_radius(
162 | getattr(args, "physics_enable_radius",
163 | DEFAULT_PHYSICS_ENABLE_RADIUS)
164 | ) # The radius in meters around the hero vehicle in which other actors are simulated
165 |
166 | # Set the actor active distance
167 | settings = world.get_settings()
168 | settings.actor_active_distance = getattr(
169 | args, "actor_active_distance", DFAULT_ACTOR_ACTIVE_DISTANCE)
170 | # Apply world settings
171 | world.apply_settings(settings)
172 |
173 | # Set Spawn Boundaries
174 | lower_bound = getattr(args, "respawn_lower_bound",
175 | DEFAULT_RESPAWN_LOWER_BOUND)
176 | upper_bound = getattr(args, "respawn_upper_bound",
177 | DEFAULT_RESPAWN_UPPER_BOUND)
178 | traffic_manager.set_boundaries_respawn_dormant_vehicles(
179 | lower_bound, upper_bound)
180 |
181 | # Respawn vehicles that are dormant (outside the range of the hero vehicle)
182 | if args.respawn:
183 | traffic_manager.set_respawn_dormant_vehicles(True)
184 |
185 | # Set the seed for the random
186 | if args.seed is not None:
187 | traffic_manager.set_random_device_seed(args.seed)
188 | msg = (
189 | "Random seed set to %s. This will result in the same traffic every"
190 | " time.")
191 | logging.warning(msg, str(args.seed))
192 |
193 | # Get world settings
194 | settings = world.get_settings()
195 |
196 | # Set synchronous or asynchronous mode
197 | if not args.asynch:
198 | logging.warning(
199 | "You are currently in synchronous mode. If you want to use the"
200 | " traffic manager alogside the ros-bridge (active ticking part)"
201 | " make sure to start this script with the --asynch argument.")
202 | traffic_manager.set_synchronous_mode(True)
203 | if not settings.synchronous_mode:
204 | synchronous_master = True
205 | settings.synchronous_mode = True
206 | settings.fixed_delta_seconds = 0.025
207 | else:
208 | synchronous_master = False
209 | else:
210 | logging.warning(
211 | "You are currently in asynchronous mode. If this is a traffic"
212 | " simulation, you could experience some issues. If it's not"
213 | " working correctly, switch to synchronous mode by using"
214 | " traffic_manager.set_synchronous_mode(True) or see documentation for"
215 | " help.")
216 |
217 | # Set render mode
218 | if args.no_rendering:
219 | settings.no_rendering_mode = True
220 | logging.info(
221 | "No rendering mode is enabled. The Scene will not be rendered."
222 | )
223 |
224 | # Apply world settings
225 | world.apply_settings(settings)
226 |
227 | # Get blueprints for vehicles and walkers TODO: More fine grained control over the blueprints
228 | blueprints = get_actor_blueprints(world, args.filterv,
229 | args.generationv)
230 | blueprintsWalkers = get_actor_blueprints(world, args.filterw,
231 | args.generationw)
232 |
233 | # Set safe spawning for vehicles
234 | if args.safe:
235 | blueprints = [
236 | x for x in blueprints if x.get_attribute("base_type") == "car"
237 | ]
238 |
239 | # Sort the blueprints by id
240 | blueprints = sorted(blueprints, key=lambda bp: bp.id)
241 |
242 | # Check if distribution is requested
243 | vehicle_distribution_absolute = dict()
244 | if hasattr(args, 'filter_by_type') and args.filter_by_type:
245 | # Check if distribution is valid
246 | if hasattr(args, 'vehicle_distribution'
247 | ) and args.vehicle_distribution is not None:
248 | if sum(args.vehicle_distribution.values()) != 100:
249 | logging.warning(
250 | "Your Vehicle distribution does not sum to 100%. Vehicles will be spawned in following Priority: Car, Truck, Motorcycle, Bicycle"
251 | )
252 |
253 | # Get the number of vehicles to spawn from the distribution
254 | vehicle_distribution_absolute.update(
255 | (x, round(float(y) / 100 * args.number_of_vehicles))
256 | for x, y in args.vehicle_distribution.items())
257 | else:
258 | raise ValueError(
259 | "You have specified a vehicle distribution, but no distribution"
260 | " was given. Please specify a distribution.")
261 |
262 | # Get spawn points for vehicles
263 | spawn_points = world.get_map().get_spawn_points()
264 | number_of_spawn_points = len(spawn_points)
265 |
266 | if args.number_of_vehicles < number_of_spawn_points:
267 | random.shuffle(spawn_points)
268 | elif args.number_of_vehicles > number_of_spawn_points:
269 | msg = "requested %d vehicles, but could only find %d spawn points"
270 | logging.warning(msg, args.number_of_vehicles,
271 | number_of_spawn_points)
272 | args.number_of_vehicles = number_of_spawn_points
273 |
274 | SpawnActor = carla.command.SpawnActor
275 | SetAutopilot = carla.command.SetAutopilot
276 | FutureActor = carla.command.FutureActor
277 |
278 | ###########################################
279 | # Spawn vehicles
280 | ###########################################
281 |
282 | # Set up the batch and hero
283 | batch = []
284 | hero = args.hero
285 |
286 | # Iterator for vehicle distribution
287 | current_type_id = 0
288 | current_type_count = 0
289 |
290 | # Iterate over the spawn points and spawn the vehicles
291 | for n, transform in enumerate(spawn_points):
292 | # Spawn only the requested number of vehicles
293 | if n >= args.number_of_vehicles:
294 | break
295 |
296 | # If Distribution is requested, get the blueprint from the class
297 | if hasattr(args, 'filter_by_type') and hasattr(
298 | args, 'vehicle_distribution'
299 | ) and args.filter_by_type and args.vehicle_distribution is not None:
300 |
301 | while current_type_id < len(args.vehicle_distribution):
302 | # Get the current type
303 | current_type = list(
304 | args.vehicle_distribution.keys())[current_type_id]
305 |
306 | # Check if the current type has been spawned enough
307 | if current_type_count >= vehicle_distribution_absolute[
308 | current_type]:
309 | current_type_id += 1
310 | current_type_count = 0
311 | else:
312 | break # Found a type that can be spawned
313 |
314 | # Filter Blueprints by Type
315 | selected_blueprints = [
316 | x for x in blueprints
317 | if x.get_attribute("object_type") == current_type
318 | ]
319 |
320 | if selected_blueprints == []:
321 | raise ValueError(
322 | "The vehicle distribution is not compatible with the filter."
323 | )
324 |
325 | # Increase the current type count
326 | current_type_count += 1
327 | else:
328 | # If no distribution is requested, select all blueprints
329 | selected_blueprints = blueprints
330 |
331 | # Chose a random blueprint and configure it
332 | blueprint = random.choice(selected_blueprints)
333 |
334 | if blueprint.has_attribute("color"):
335 | color = random.choice(
336 | blueprint.get_attribute("color").recommended_values)
337 | blueprint.set_attribute("color", color)
338 | if blueprint.has_attribute("driver_id"):
339 | driver_id = random.choice(
340 | blueprint.get_attribute("driver_id").recommended_values)
341 | blueprint.set_attribute("driver_id", driver_id)
342 | if hero:
343 | blueprint.set_attribute(
344 | "role_name", "hero"
345 | ) # ATTENTION: Role Name has to be set to hero for the hero to work
346 | hero = False
347 | else:
348 | blueprint.set_attribute("role_name", "generated_vehicle")
349 |
350 | # Spawn the cars and set their autopilot and light state all together
351 | batch.append(
352 | SpawnActor(blueprint, transform).then(
353 | SetAutopilot(FutureActor, True,
354 | traffic_manager.get_port())))
355 |
356 | # Apply the batch
357 | for response in client.apply_batch_sync(batch, synchronous_master):
358 | if response.error:
359 | logging.error(response.error)
360 | else:
361 | vehicles_list.append(response.actor_id)
362 |
363 | # Set automatic vehicle lights update if specified
364 | if args.car_lights_on:
365 | all_vehicle_actors = world.get_actors(vehicles_list)
366 | for actor in all_vehicle_actors:
367 | traffic_manager.update_vehicle_lights(actor, True)
368 |
369 | ###########################################
370 | # Spawn Walkers
371 | ###########################################
372 |
373 | # Specify pedestrian behavior
374 | percentagePedestriansRunning = getattr(
375 | args, "percentagePedestriansRunning",
376 | DEFAULT_PERCENTAGE_PEDESTRIANS_RUNNING
377 | ) # how many pedestrians will run
378 | percentagePedestriansCrossing = getattr(
379 | args,
380 | "percentagePedestriansCrossing",
381 | DEFAULT_PERCENTAGE_PEDESTRIANS_CROSSING,
382 | ) # how many pedestrians will walk through the road
383 |
384 | # Set Random seed if specified
385 | if args.seedw:
386 | world.set_pedestrians_seed(args.seedw)
387 | random.seed(args.seedw)
388 | msg = (
389 | "Random seed for pedestrians set to %s. This will result in the same"
390 | " pedestrian config all the time.")
391 | logging.warning(msg, str(args.seedw))
392 |
393 | # Define spawn points for walkers randomly
394 | spawn_points = []
395 | for i in range(args.number_of_walkers):
396 | spawn_point = carla.Transform()
397 | loc = world.get_random_location_from_navigation()
398 | if loc != None:
399 | spawn_point.location = loc
400 | spawn_points.append(spawn_point)
401 |
402 | # Setup batch and walker speed lists
403 | batch = []
404 | walker_speed = []
405 |
406 | # Iterate over the spawn points and spawn the walkers
407 | for spawn_point in spawn_points:
408 | walker_bp = random.choice(blueprintsWalkers)
409 | # Set pedestrians to be not invincible
410 | if walker_bp.has_attribute("is_invincible"):
411 | walker_bp.set_attribute("is_invincible", "false")
412 | # Set speed of pedestrians (walking and running)
413 | if walker_bp.has_attribute("speed"):
414 | if random.random() > percentagePedestriansRunning:
415 | # walking
416 | walker_speed.append(
417 | walker_bp.get_attribute("speed").recommended_values[1])
418 | else:
419 | # running
420 | walker_speed.append(
421 | walker_bp.get_attribute("speed").recommended_values[2])
422 | else:
423 | print("Walker has no speed")
424 | walker_speed.append(0.0)
425 | batch.append(SpawnActor(walker_bp, spawn_point))
426 |
427 | # Apply Batch
428 | results = client.apply_batch_sync(batch, True)
429 |
430 | # Remove walkers, that result in errors
431 | walker_speed2 = []
432 | for i in range(len(results)):
433 | if results[i].error:
434 | logging.error(results[i].error)
435 | else:
436 | walkers_list.append({"id": results[i].actor_id})
437 | walker_speed2.append(walker_speed[i])
438 | walker_speed = walker_speed2
439 |
440 | # Get AI walker controllers
441 | batch = []
442 | walker_controller_bp = world.get_blueprint_library().find(
443 | "controller.ai.walker")
444 | for i in range(len(walkers_list)):
445 | batch.append(
446 | SpawnActor(walker_controller_bp, carla.Transform(),
447 | walkers_list[i]["id"]))
448 | results = client.apply_batch_sync(batch, True)
449 | for i in range(len(results)):
450 | if results[i].error:
451 | logging.error(results[i].error)
452 | else:
453 | walkers_list[i]["con"] = results[i].actor_id
454 |
455 | # Match walker controllers with walkers
456 | for i in range(len(walkers_list)):
457 | all_id.append(walkers_list[i]["con"])
458 | all_id.append(walkers_list[i]["id"])
459 | all_actors = world.get_actors(all_id)
460 |
461 | # Wait for a tick to ensure client receives the last transform of the walkers we have just created
462 | if args.asynch or not synchronous_master:
463 | world.wait_for_tick()
464 | else:
465 | world.tick()
466 |
467 | # Initialize each controller and set target to walk to (list is [controler, actor, controller, actor ...])
468 | # Set how many pedestrians can cross the road
469 | world.set_pedestrians_cross_factor(percentagePedestriansCrossing)
470 | for i in range(0, len(all_id), 2):
471 | # Start walker
472 | all_actors[i].start()
473 | # Set walk to random point
474 | all_actors[i].go_to_location(
475 | world.get_random_location_from_navigation())
476 | # Max speed
477 | all_actors[i].set_max_speed(float(walker_speed[int(i / 2)]))
478 |
479 | ###########################################
480 | # Finish up traffic generation
481 | ###########################################
482 | print("Spawned %d vehicles and %d walkers, press Ctrl+C to exit." %
483 | (len(vehicles_list), len(walkers_list)))
484 |
485 | # Run until interrupted by the user
486 | while True:
487 | if not args.asynch and synchronous_master:
488 | world.tick()
489 | else:
490 | world.wait_for_tick()
491 |
492 | ###########################################
493 | # Remove all spawned actors before we quit.
494 | ###########################################
495 | finally:
496 | # Reset weather conditions
497 | if hasattr(args, "generate_weather") and args.generate_weather:
498 | print("Resetting Weather")
499 | world.set_weather(saved_weather)
500 |
501 | # Restore synchronous mode if needed.
502 | if not args.asynch and synchronous_master:
503 | settings = world.get_settings()
504 | settings.synchronous_mode = False
505 | settings.no_rendering_mode = False
506 | settings.fixed_delta_seconds = None
507 | world.apply_settings(settings)
508 |
509 | # Destroy vehicles
510 | print("\ndestroying %d vehicles" % len(vehicles_list))
511 | client.apply_batch(
512 | [carla.command.DestroyActor(x) for x in vehicles_list])
513 |
514 | # Stop walker controllers (list is [controller, actor, controller, actor ...])
515 | for i in range(0, len(all_id), 2):
516 | all_actors[i].stop()
517 |
518 | # Destroy walkers
519 | print("\ndestroying %d walkers" % len(walkers_list))
520 | client.apply_batch([carla.command.DestroyActor(x) for x in all_id])
521 |
522 | time.sleep(0.5)
523 |
524 |
525 | #########################################################
526 | #################### Helper Functions ###################
527 | #########################################################
528 | def parseArguments():
529 | """
530 | Function to parse the arguments from the user
531 |
532 | :return: parsed arguments as namespace
533 | """
534 |
535 | # Initialize argument parser
536 | argparser = argparse.ArgumentParser(description=__doc__)
537 |
538 | # Add all possible arguments
539 | argparser.add_argument(
540 | "-f",
541 | "--config_file",
542 | metavar="F",
543 | default="",
544 | help=("Path to the optional config file (json). Set arguments override the"
545 | " corresponding value in the config file."),
546 | )
547 | argparser.add_argument(
548 | "--host",
549 | metavar="H",
550 | default="127.0.0.1",
551 | help="IP of the host server (default: 127.0.0.1)",
552 | )
553 | argparser.add_argument(
554 | "-p",
555 | "--port",
556 | metavar="P",
557 | default=2000,
558 | type=int,
559 | help="TCP port to listen to (default: 2000)",
560 | )
561 | argparser.add_argument(
562 | "-n",
563 | "--number-of-vehicles",
564 | metavar="N",
565 | default=30,
566 | type=int,
567 | help="Number of vehicles (default: 30)",
568 | )
569 | argparser.add_argument(
570 | "-w",
571 | "--number-of-walkers",
572 | metavar="W",
573 | default=10,
574 | type=int,
575 | help="Number of walkers (default: 10)",
576 | )
577 | argparser.add_argument("--safe",
578 | action="store_true",
579 | help="Avoid spawning vehicles prone to accidents")
580 | argparser.add_argument(
581 | "--filterv",
582 | metavar="PATTERN",
583 | default="vehicle.*",
584 | help='Filter vehicle model (default: "vehicle.*")',
585 | )
586 | argparser.add_argument(
587 | "--generationv",
588 | metavar="G",
589 | default="All",
590 | help=('restrict to certain vehicle generation (values: "1","2","All" - default:'
591 | ' "All")'),
592 | )
593 | argparser.add_argument(
594 | "--filterw",
595 | metavar="PATTERN",
596 | default="walker.pedestrian.*",
597 | help='Filter pedestrian type (default: "walker.pedestrian.*")',
598 | )
599 | argparser.add_argument(
600 | "--generationw",
601 | metavar="G",
602 | default="2",
603 | help=(
604 | 'restrict to certain pedestrian generation (values: "1","2","All" -'
605 | ' default: "2")'),
606 | )
607 | argparser.add_argument(
608 | "--tm-port",
609 | metavar="P",
610 | default=8000,
611 | type=int,
612 | help="Port to communicate with TM (default: 8000)",
613 | )
614 | argparser.add_argument("--asynch",
615 | action="store_true",
616 | help="Activate asynchronous mode execution")
617 | argparser.add_argument("--hybrid",
618 | action="store_true",
619 | help="Activate hybrid mode for Traffic Manager")
620 | argparser.add_argument(
621 | "-s",
622 | "--seed",
623 | metavar="S",
624 | type=int,
625 | help="Set random device seed and deterministic mode for Traffic Manager",
626 | )
627 | argparser.add_argument(
628 | "--seedw",
629 | metavar="S",
630 | default=0,
631 | type=int,
632 | help="Set the seed for pedestrians module",
633 | )
634 | argparser.add_argument(
635 | "--car-lights-on",
636 | action="store_true",
637 | default=False,
638 | help="Enable automatic car light management",
639 | )
640 | argparser.add_argument(
641 | "--hero",
642 | action="store_true",
643 | default=False,
644 | help="Set one of the vehicles as hero",
645 | )
646 | argparser.add_argument(
647 | "--respawn",
648 | action="store_true",
649 | default=False,
650 | help="Automatically respawn dormant vehicles (only in large maps)",
651 | )
652 | argparser.add_argument(
653 | "--no-rendering",
654 | action="store_true",
655 | default=False,
656 | help="Activate no rendering mode",
657 | )
658 |
659 | return argparser.parse_args()
660 |
661 |
662 | def parseConfigFile(config_file_path):
663 | """
664 | Function to load the config file and parse it
665 |
666 | :param config_file_path: Path to the config file
667 | :return: failure code
668 | """
669 |
670 | # Check if filepath is global or relative
671 | if not config_file_path.startswith("/"):
672 | config_file_path = os.path.join(os.getcwd(), config_file_path)
673 |
674 | # Check if file exists
675 | if not os.path.exists(config_file_path): #
676 | logging.error("Config file not found")
677 | return None
678 |
679 | # Check if file is a yml file
680 | if not config_file_path.endswith(".yml"):
681 | logging.error("Config file is not a yml file")
682 | return None
683 |
684 | # Parse config file
685 | config = yaml.safe_load(open(config_file_path, "r"))
686 |
687 | # Get arguments with sys.argv to check which arguments were explicitly set
688 | given_args = sys.argv[1:]
689 | given_args_dict = dict()
690 | flag = None
691 |
692 | # Set arguments to True if they do not have any value
693 | for arg in given_args:
694 | if arg.startswith('-'):
695 | flag = arg.lstrip('-')
696 | given_args_dict[flag] = True
697 | else:
698 | if flag:
699 | given_args_dict[flag] = arg
700 | flag = None
701 |
702 | # catch special cases: replace p with port, n with number-of-vehicles, w with number-of-walkers and s with seed
703 | if "p" in given_args_dict.keys():
704 | given_args_dict["port"] = given_args_dict["p"]
705 | del given_args_dict["p"]
706 | if "n" in given_args_dict.keys():
707 | given_args_dict["number-of-vehicles"] = given_args_dict["n"]
708 | del given_args_dict["n"]
709 | if "w" in given_args_dict.keys():
710 | given_args_dict["number-of-walkers"] = given_args_dict["w"]
711 | del given_args_dict["w"]
712 | if "s" in given_args_dict.keys():
713 | given_args_dict["seed"] = given_args_dict["s"]
714 | del given_args_dict["s"]
715 |
716 | # Prettyprint config dict, mark explicitly set arguments in red
717 | print("\nParsed config file:")
718 | for key, value in config.items():
719 | if key in given_args_dict.keys():
720 | print("\033[91m {:<20} {:<20} {:<20} \033[0m".format(
721 | key,
722 | str(given_args_dict[key]),
723 | "[argument overwrites config_file value]",
724 | ))
725 | else:
726 | print(" {:<20} {:<20}".format(key, str(value)))
727 | print("\n")
728 |
729 | # Delete keys from config dict if they were explicitly set by user
730 | for key in given_args_dict.keys():
731 | if key in config.keys():
732 | del config[key]
733 |
734 | return config
735 |
736 |
737 | def get_actor_blueprints(world, filter, generation):
738 | """
739 | Function to get actor blueprints
740 |
741 | :param world: Carla world object
742 | :param filter: Filter for actor types
743 | :param generation: Generation of the actors (1,2 or "all")
744 | :return: List of actor blueprints
745 | """
746 | bps = world.get_blueprint_library().filter(filter)
747 |
748 | if str(generation).lower() == "all":
749 | return bps
750 |
751 | # If the filter returns only one bp, we assume that this one needed
752 | # and therefore, we ignore the generation
753 | if len(bps) == 1:
754 | return bps
755 |
756 | try:
757 | int_generation = int(generation)
758 | # Check if generation is in available generations
759 | if int_generation in [1, 2]:
760 | bps = [
761 | x for x in bps
762 | if int(x.get_attribute("generation")) == int_generation
763 | ]
764 | return bps
765 | else:
766 | logging.warning(
767 | "Actor Generation is not valid. No actor will be spawned.")
768 | return []
769 | except:
770 | logging.warning(
771 | "Actor Generation is not valid. No actor will be spawned.")
772 | return []
773 |
774 |
775 | if __name__ == "__main__":
776 | try:
777 | main()
778 | except KeyboardInterrupt:
779 | pass
780 | finally:
781 | print("\ndone.")
782 |
--------------------------------------------------------------------------------
/data-driven-development/scripts/simulation_controller.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import subprocess
3 | import random
4 | import glob
5 | import os
6 | import sys
7 | import json
8 | import argparse
9 | import time
10 |
11 | import carla
12 |
13 |
14 | def main():
15 | argparser = argparse.ArgumentParser(description=__doc__)
16 | argparser.add_argument(
17 | '--host',
18 | metavar='H',
19 | default='carla-server',
20 | help='IP of the host server (default: carla-server)')
21 | argparser.add_argument(
22 | '--spawn_point',
23 | metavar='S',
24 | default=None,
25 | help='')
26 | argparser.add_argument(
27 | '--town',
28 | metavar='T',
29 | default='Town01',
30 | help='')
31 | argparser.add_argument(
32 | '--weather',
33 | metavar='W',
34 | default=None,
35 | help='')
36 | argparser.add_argument(
37 | '--vehicle_number',
38 | metavar='N',
39 | default=None,
40 | help='')
41 | argparser.add_argument(
42 | '--vehicle_occupancy',
43 | metavar='P',
44 | default=None,
45 | help='')
46 | argparser.add_argument(
47 | '--walker_number',
48 | metavar='W',
49 | default=None,
50 | help='')
51 |
52 | args = argparser.parse_args()
53 |
54 | config_list = ["--host", args.host]
55 | tm_list = ["--host", args.host]
56 | if args.weather:
57 | config_list.extend(["--weather", args.weather])
58 | if args.vehicle_number:
59 | tm_list.extend(["--number-of-vehicles", args.vehicle_number])
60 | if args.walker_number:
61 | tm_list.extend(["--number-of-walkers", args.walker_number])
62 |
63 | actor_list = []
64 | try:
65 | client = carla.Client(args.host, 2000)
66 | client.set_timeout(10.0)
67 |
68 | # check if right map is used
69 | while True:
70 | time.sleep(0.02)
71 | world = client.get_world()
72 | print("Waiting for Town {}...".format(args.town))
73 | if world.get_map().name == args.town or world.get_map().name == "Carla/Maps/{}".format(args.town):
74 | break
75 |
76 | # --- set weather ---
77 | # setup the carla simulation config
78 | res = subprocess.call(["python", "util/config.py"] + config_list)
79 | print("Setups in config.py done")
80 |
81 | # --- enable autopilot for main vehicles in sensors.json ---
82 | # get vehicle info from sensors.json
83 | if not os.path.exists("/sensors.json"):
84 | raise RuntimeError(
85 | "Could not read object definitions from {}".format("/sensors.json"))
86 | with open("/sensors.json") as handle:
87 | json_actors = json.loads(handle.read())
88 |
89 | # save all vehicles in list
90 | vehicles = []
91 | for actor in json_actors["objects"]:
92 | actor_type = actor["type"].split('.')[0]
93 | if actor_type == "vehicle":
94 | vehicles.append(actor)
95 |
96 | # iterate over vehicles and set autopilot true
97 | for i, vehicle in enumerate(vehicles):
98 | # get spawned vehicle
99 | for actor in world.get_actors():
100 | if actor.attributes.get('role_name') == vehicle["id"]:
101 | player = actor
102 | break
103 | print("{} found - Setting autopilot: True".format(vehicle["id"]))
104 | player.set_autopilot(True)
105 |
106 | # --- spawn random traffic ---
107 | spawn_points = world.get_map().get_spawn_points()
108 | print("Map has {} spawnpoints".format(len(spawn_points)))
109 |
110 | # use vehicle_occupancy if it is set correctly and overwrite vehicle_number from list if it is also set
111 | if args.vehicle_occupancy:
112 | vehicle_occupancy = float(args.vehicle_occupancy)
113 | if 0 < vehicle_occupancy < 1:
114 | if "--number-of-vehicles" in tm_list:
115 | index = tm_list.index("--number-of-vehicles")
116 | tm_list[index +
117 | 1] = str(int(len(spawn_points)*vehicle_occupancy))
118 | else:
119 | tm_list.extend(
120 | ["--number-of-vehicles", str(int(len(spawn_points)*vehicle_occupancy))])
121 |
122 | # spawn traffic if it is set (filter out twowheeled vehicle which have no boundingbox)
123 | if "--number-of-vehicles" in tm_list or "--number-of-walkers" in tm_list:
124 | subprocess.run(["python", "set_environment.py", "--asynch", "--filterv",
125 | 'vehicle.*[!vehicle.bh.crossbike][!vehicle.diamondback.century][!vehicle.harley-davidson.low_rider][!vehicle.gazelle.omafiets][!vehicle.kawasaki.ninja][!vehicle.yamaha.yzf]'] + tm_list)
126 |
127 | while True:
128 | world.wait_for_tick()
129 |
130 | except:
131 | print('error destroying actors ...')
132 | for actor in actor_list:
133 | actor.destroy()
134 | print('done.')
135 |
136 |
137 | if __name__ == '__main__':
138 | try:
139 | exit(main())
140 |
141 | except KeyboardInterrupt:
142 | print('\nCancelled by user. Bye!')
143 | except RuntimeError as e:
144 | print(e)
145 |
--------------------------------------------------------------------------------
/data-driven-development/scripts/spawned_vehicle_check.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import glob
3 | import os
4 | import sys
5 | import argparse
6 |
7 | try:
8 | sys.path.append(
9 | glob.glob('../carla/dist/carla-*%d.%d-%s.egg' %
10 | (sys.version_info.major, sys.version_info.minor,
11 | 'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0])
12 | except IndexError:
13 | pass
14 |
15 | import carla
16 |
17 |
18 | def main():
19 | argparser = argparse.ArgumentParser(description=__doc__)
20 | argparser.add_argument(
21 | '--host',
22 | metavar='H',
23 | default='carla-server',
24 | help='IP of the host server (default: carla-server)')
25 | argparser.add_argument('--role_name',
26 | metavar='R',
27 | default='ego_vehicle',
28 | help='Name of vehicle to wait')
29 | argparser.add_argument('--role_name_list',
30 | metavar='RL',
31 | default=None,
32 | help='List of vehicle to wait')
33 |
34 | args = argparser.parse_args()
35 |
36 | if args.role_name_list:
37 | role_names = args.role_name_list.split(",")
38 | else:
39 | role_names = [args.role_name]
40 |
41 | client = carla.Client(args.host, 2000)
42 | client.set_timeout(10.0)
43 | world = client.get_world()
44 |
45 | world.wait_for_tick()
46 |
47 | is_ego_vehicle_spawned = False
48 | for role_name in role_names:
49 | actor_list = world.get_actors().filter('vehicle.*')
50 | for actor in actor_list:
51 | if actor.attributes.get('role_name') == role_name:
52 | is_ego_vehicle_spawned = True
53 |
54 | if is_ego_vehicle_spawned:
55 | print("{} is spawned.".format(role_name))
56 | else:
57 | print("Waiting for {} ...".format(role_name))
58 | return 1
59 |
60 | return 0
61 |
62 |
63 | if __name__ == '__main__':
64 | sys.exit(main())
65 |
--------------------------------------------------------------------------------
/data-driven-development/scripts/time_controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 | import glob
5 | import os
6 | import sys
7 | import argparse
8 | import time
9 |
10 | import carla
11 |
12 |
13 | def main():
14 |
15 | argparser = argparse.ArgumentParser(description=__doc__)
16 | argparser.add_argument(
17 | '--host',
18 | metavar='H',
19 | default='carla-server',
20 | help='IP of the host server (default: carla-server)')
21 | argparser.add_argument(
22 | '--max_simulation_time',
23 | metavar='T',
24 | default='300',
25 | help='Maximal simulation time before server is closed')
26 | argparser.add_argument('--max_real_time',
27 | metavar='R',
28 | default='300',
29 | help='Maximal real time before server is closed')
30 |
31 | args = argparser.parse_args()
32 |
33 | start_time = time.time()
34 |
35 | # connect to server
36 | client = carla.Client(args.host, 2000)
37 | client.set_timeout(10.0)
38 | world = client.get_world()
39 |
40 | world.wait_for_tick()
41 | delta_elapsed_seconds = world.get_snapshot().timestamp.elapsed_seconds
42 |
43 | while world.get_snapshot(
44 | ).timestamp.elapsed_seconds - delta_elapsed_seconds <= float(
45 | args.max_simulation_time) and time.time() - start_time <= float(
46 | args.max_real_time):
47 | pass
48 |
49 | if not world.get_snapshot(
50 | ).timestamp.elapsed_seconds - delta_elapsed_seconds <= float(
51 | args.max_simulation_time):
52 | print("Maximum simulation time of {} reached. Stopping the run...".
53 | format(args.max_simulation_time))
54 | if not time.time() - start_time <= float(args.max_real_time):
55 | print("Maximum real time of {} reached. Stopping the run...".format(
56 | args.max_real_time))
57 |
58 | return 1
59 |
60 |
61 | if __name__ == '__main__':
62 | sys.exit(main())
63 |
--------------------------------------------------------------------------------
/run-demo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | default_demo="software-prototyping"
3 | selected_demo=""
4 |
5 | docker_compose_command="docker compose" # change to docker-compose if old version is used
6 |
7 | if [ $# -eq 0 ]; then
8 | echo "No demo manually selected. Selecting default demo..."
9 | selected_demo=$default_demo
10 | else
11 | selected_demo=$1
12 | fi
13 |
14 | if [ "$selected_demo" != "data-driven-development" ] && [ "$selected_demo" != "automated-testing" ] && [ ! -f "$selected_demo/docker-compose.yml" ]; then
15 | echo "No demo called $selected_demo exists. Please check available demos and run again."
16 | exit 1
17 | fi
18 |
19 | # trap ctrl-c and killing the bash to call cleanup function
20 | trap cleanup EXIT
21 | trap cleanup 0
22 |
23 | function cleanup() {
24 | echo "Cleaning up..."
25 | if [ "$selected_demo" != "data-driven-development" ] && [ "$selected_demo" != "automated-testing" ]; then
26 | $docker_compose_command -f $selected_demo/docker-compose.yml down
27 | fi
28 | xhost -local:
29 | echo "Done cleaning up."
30 | }
31 |
32 | xhost +local:
33 |
34 | echo "Running demo: $selected_demo"
35 |
36 | if [ "$selected_demo" = "data-driven-development" ]; then
37 | env_name=$(grep 'name:' $selected_demo/env/environment.yml | awk '{print $2}')
38 | conda_bin_dir=$(dirname $(which conda))
39 | conda env list | grep "^${env_name} " > /dev/null 2>&1
40 | if [ $? -ne 0 ]; then
41 | echo "Conda environment '$env_name' does not exist. Creating it..."
42 | conda env create -f $selected_demo/env/environment.yml
43 | fi
44 | source $conda_bin_dir/activate $env_name
45 | cd $selected_demo
46 | python data_generation.py
47 | elif [ "$selected_demo" = "automated-testing" ]; then
48 | cd $selected_demo
49 | ./evaluate-scenarios.sh
50 | else
51 | $docker_compose_command -f $selected_demo/docker-compose.yml up
52 | fi
53 |
--------------------------------------------------------------------------------
/software-prototyping/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Use Case: *Software Prototyping*
4 |
5 | >[!NOTE]
6 | > **Background**: The *software prototyping* use case addresses the initial development phase of an automated driving function, where developers aim for simple and quick experimenting. It focuses on the flawless integrability of the component under test and assesses the general operability within the overall system. An early integration of different modules facilitates the harmonization of interfaces, which is particularly important when combining modules from different development teams. In many cases, a single example scenario is sufficient to carry out these initial tests. However, all necessary data must already be provided. For many applications, this data may include sensor data such as camera images and lidar point clouds, which is why a high fidelity simulation software such as CARLA may already be needed.
7 |
8 | The subsequent demonstration showcases *software prototyping* and specifically addresses the following requirements:
9 | - Availability of **comprehensive simulation data** in customizable data formats.
10 | - Ability to easily attach custom **Robot Operating System** (ROS)-based functions to the simulation and its provided data.
11 | - Isolation of custom ROS functions and the simulation software through **containerization**.
12 |
13 | ## Getting Started
14 |
15 | > [!IMPORTANT]
16 | > Make sure that all [system requirements](../utils/requirements.md) are fulfilled.
17 |
18 | Directly start the use case demonstration using the top-level `run-demo.sh` script:
19 |
20 | ```bash
21 | ./run-demo.sh software-prototyping
22 | ```
23 |
24 | This example demonstrates a basic CARLA simulation in tandem with the widely used Robot Operations System ([ROS](https://www.ros.org/)). We only cover ROS 2 with this demo. In addition to a CARLA simulation core, a ROS bridge enables communication between CARLA and ROS by translating simulation outputs (e.g. sensor data) to ROS topics. In addition, RViz is used as a visualization component.
25 |
26 | Specifically, there are three main components used in the `software-prototyping` demo:
27 | - [carla-server](https://github.com/ika-rwth-aachen/carla-simulator)
28 | - [carla-ros-bridge](https://github.com/ika-rwth-aachen/carla-ros-bridge)
29 | - [ros-monitoring](https://github.com/ika-rwth-aachen/carlos/blob/main/utils/carla-essentials/README.md#ros-monitoring)
30 | - A containerized image segmentation ROS node that serves as an example on how to attached a custom function to the simulation.
31 |
32 | > [!NOTE]
33 | > A detailed description of the individual components can be found in [components guide](../utils/carla-essentials/README.md).
34 |
35 | ### Quick Start
36 | After starting the `software-prototyping` demo, a CARLA GUI opens up where you can look around using WASD, holding the left or right mouse button and moving the mouse in the desired direction.
37 |
38 | After a short initialization phase, a second window shows up with RViz and a variety of raw sensor data available in ROS. Multiple RGB cameras, a depth and semantic camera, as well as a lidar sensor are attached to a vehicle, visualizing the environment in rich detail.
39 |
40 | The vehicle itself is controlled by the official [carla_ad_agent](https://github.com/carla-simulator/ros-bridge/tree/master/carla_ad_agent) package. However, you can also override the controls using the manual control PyGame window. After hitting B the manual transmission mode is enabled and allows you to drive the vehicle using WASD.
41 |
42 |
43 | 
44 |
45 | ### Integration of Custom Software Components
46 | As described above, we demonstrate how a developed software prototype can be easily integrated into the overall framework. Specifically, we use a very basic image segmentation function as an example that we attach to the simulation to compute segmented images from the images of a RGB camera. If you have a containerized ROS node available, its integration is as easy as a new entry in this demo's [Docker Compose file](docker-compose.yml):
47 | ```bash
48 | image-segmentation:
49 | image: rwthika/carlos-image-segmentation
50 | command: ros2 launch image_segmentation image_segmentation_launch.py image_topic:=/carla/ego_vehicle/rgb_front/image
51 | ```
52 |
53 | We have already included this entry in the provided file. The image segmentation node is integrated into our publicly available Docker Container: [Image segmentation ROS 2 package on DockerHub](https://hub.docker.com/r/rwthika/carlos-image-segmentation). It listens to the [sensor_msgs/Image](https://github.com/ros/common_msgs/blob/noetic-devel/sensor_msgs/msg/Image.msg) topic of a simulated front-facing RGB camera attached to the ego vehicle. As output, the node provides a topic with segmented images of type [sensor_msgs/Image](https://github.com/ros/common_msgs/blob/noetic-devel/sensor_msgs/msg/Image.msg) which is visualized in RViz. Note that the provided image segmentation function uses a small and simplified model that does not perform very well. This is intended here, because we only want to use it to demonstrate the integration of some function.
54 |
55 | 
56 |
57 |
58 | ### Interacting with the Containers
59 |
60 | Follow these steps to interact with the running containers:
61 |
62 | 1. Install [docker-run](https://github.com/ika-rwth-aachen/docker-run). This will, e.g., simplify successfully running GUI applications in the containers compared to regular `docker run` or `docker exec`.
63 | 2. List all running containers on your host with `docker ps`.
64 | 3. Attach to a running container with `docker-run --name `, e.g., `docker-run software-prototyping-carla-ros-bridge-1`.
65 | 4. Example: To list all available ROS topics, in a container where ROS 2 is installed, run `ros2 topic list`.
66 |
67 | ### Integrating Your Own Function
68 |
69 | Follow these steps to integrate your own function(s):
70 | 1. Write some ROS node prototype that you would like to attach to the simulation.
71 | 2. Make sure your ROS node listens to one of the available ROS topics.
72 | 3. Containerize the ROS node, e.g., with our tool [docker-ros](https://github.com/ika-rwth-aachen/docker-ros).
73 | 4. Integrate the container image as a service into our provided [Docker Compose file](docker-compose.yml#L35) as described above.
74 | 5. Run `./run-demo.sh software-prototyping` again.
75 | 6. Configure RViz such that the output of your custom ROS node is visualized.
76 | 7. Hit CTRL+C twice to stop the demo.
77 |
78 | You may now iterate on the development of your software prototype until you are satisfied with how it integrates with the simulation and with potential further software modules that you may also integrate. Then, you may proceed with a possible next step in the software development life cycle, [data-driven development](../data-driven-development/README.md).
--------------------------------------------------------------------------------
/software-prototyping/carla-ros-bridge.launch.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import launch
4 | import launch_ros.actions
5 | from ament_index_python.packages import get_package_share_directory
6 |
7 | def launch_target_speed_publisher(context, *args, **kwargs):
8 | topic_name = "/carla/" + launch.substitutions.LaunchConfiguration('role_name').perform(context) + "/target_speed"
9 | data_string = "{'data': " + launch.substitutions.LaunchConfiguration('target_speed').perform(context) + "}"
10 | return [
11 | launch.actions.ExecuteProcess(
12 | output="screen",
13 | cmd=["ros2", "topic", "pub", topic_name,
14 | "std_msgs/msg/Float64", data_string, "--qos-durability", "transient_local"],
15 | name='topic_pub_target_speed')]
16 |
17 | def generate_launch_description():
18 |
19 | # Args that can be set from CLI
20 |
21 | # carla-simualtor args
22 | host_launch_arg = launch.actions.DeclareLaunchArgument(
23 | name='host',
24 | default_value='carla-server'
25 | )
26 |
27 | port_launch_arg = launch.actions.DeclareLaunchArgument(
28 | name='port',
29 | default_value='2000'
30 | )
31 |
32 | timeout_launch_arg = launch.actions.DeclareLaunchArgument(
33 | name='timeout',
34 | default_value='10'
35 | )
36 |
37 | synchronous_mode_wait_launch_arg = launch.actions.DeclareLaunchArgument(
38 | name='synchronous_mode_wait_for_vehicle_control_command',
39 | default_value='False'
40 | )
41 |
42 | fixed_delta_seconds_launch_arg = launch.actions.DeclareLaunchArgument(
43 | name='fixed_delta_seconds',
44 | default_value='0.05'
45 | )
46 |
47 | town_launch_arg = launch.actions.DeclareLaunchArgument(
48 | name='town',
49 | default_value='Town10HD'
50 | )
51 |
52 | # ego_vehicle args
53 | role_name_launch_arg = launch.actions.DeclareLaunchArgument(
54 | name='role_name',
55 | default_value="ego_vehicle"
56 | )
57 |
58 | objects_definition_file_launch_arg = launch.actions.DeclareLaunchArgument(
59 | name='objects_definition_file',
60 | default_value=os.path.join(
61 | '/sensors.json'
62 | )
63 | )
64 |
65 | target_speed_launch_arg = launch.actions.DeclareLaunchArgument(
66 | name='target_speed',
67 | default_value='8.33' # in m/s
68 | )
69 |
70 | # include launch files
71 |
72 | ros_bridge_launch_include = launch.actions.IncludeLaunchDescription(
73 | launch.launch_description_sources.PythonLaunchDescriptionSource(
74 | os.path.join(
75 | get_package_share_directory('carla_ros_bridge'),
76 | 'carla_ros_bridge.launch.py'
77 | )
78 | ),
79 | launch_arguments={
80 | 'host': launch.substitutions.LaunchConfiguration('host'),
81 | 'port': launch.substitutions.LaunchConfiguration('port'),
82 | 'town': launch.substitutions.LaunchConfiguration('town'),
83 | 'timeout': launch.substitutions.LaunchConfiguration('timeout'),
84 | 'synchronous_mode_wait_for_vehicle_control_command': launch.substitutions.LaunchConfiguration('synchronous_mode_wait_for_vehicle_control_command'),
85 | 'fixed_delta_seconds': launch.substitutions.LaunchConfiguration('fixed_delta_seconds')
86 | }.items()
87 | )
88 |
89 | carla_spawn_objects_launch_include = launch.actions.IncludeLaunchDescription(
90 | launch.launch_description_sources.PythonLaunchDescriptionSource(
91 | os.path.join(
92 | get_package_share_directory('carla_spawn_objects'),
93 | 'carla_example_ego_vehicle.launch.py'
94 | )
95 | ),
96 | launch_arguments={
97 | 'role_name': launch.substitutions.LaunchConfiguration('role_name'),
98 | 'objects_definition_file': launch.substitutions.LaunchConfiguration('objects_definition_file')
99 | }.items()
100 | )
101 |
102 | carla_manual_control_launch_include = launch.actions.IncludeLaunchDescription(
103 | launch.launch_description_sources.PythonLaunchDescriptionSource(
104 | os.path.join(get_package_share_directory(
105 | 'carla_manual_control'), 'carla_manual_control.launch.py')
106 | ),
107 | launch_arguments={
108 | 'role_name': launch.substitutions.LaunchConfiguration('role_name')
109 | }.items()
110 | )
111 |
112 | carla_ad_agent_launch_include = launch.actions.IncludeLaunchDescription(
113 | launch.launch_description_sources.PythonLaunchDescriptionSource(
114 | os.path.join(get_package_share_directory(
115 | 'carla_ad_agent'), 'carla_ad_agent.launch.py')
116 | ),
117 | launch_arguments={
118 | 'role_name': launch.substitutions.LaunchConfiguration('role_name')
119 | }.items()
120 | )
121 |
122 | carla_waypoint_publisher_launch_include = launch.actions.IncludeLaunchDescription(
123 | launch.launch_description_sources.PythonLaunchDescriptionSource(
124 | os.path.join(get_package_share_directory(
125 | 'carla_waypoint_publisher'), 'carla_waypoint_publisher.launch.py')
126 | ),
127 | launch_arguments={
128 | 'host': launch.substitutions.LaunchConfiguration('host'),
129 | 'port': launch.substitutions.LaunchConfiguration('port'),
130 | 'timeout': launch.substitutions.LaunchConfiguration('timeout'),
131 | 'role_name': launch.substitutions.LaunchConfiguration('role_name')
132 | }.items()
133 | )
134 |
135 | # Return full launch description
136 |
137 | return launch.LaunchDescription([
138 | host_launch_arg,
139 | port_launch_arg,
140 | timeout_launch_arg,
141 | synchronous_mode_wait_launch_arg,
142 | fixed_delta_seconds_launch_arg,
143 | town_launch_arg,
144 | objects_definition_file_launch_arg,
145 | role_name_launch_arg,
146 | target_speed_launch_arg,
147 | ros_bridge_launch_include,
148 | carla_spawn_objects_launch_include,
149 | carla_manual_control_launch_include,
150 | carla_ad_agent_launch_include,
151 | carla_waypoint_publisher_launch_include,
152 | launch.actions.OpaqueFunction(function=launch_target_speed_publisher)
153 | ])
154 |
155 |
156 | if __name__ == '__main__':
157 | generate_launch_description()
158 |
--------------------------------------------------------------------------------
/software-prototyping/config.rviz:
--------------------------------------------------------------------------------
1 | Panels:
2 | - Class: rviz_common/Displays
3 | Help Height: 0
4 | Name: Displays
5 | Property Tree Widget:
6 | Expanded:
7 | - /Orbit1
8 | Splitter Ratio: 0.5354107618331909
9 | Tree Height: 264
10 | - Class: rviz_common/Selection
11 | Name: Selection
12 | - Class: rviz_common/Tool Properties
13 | Expanded:
14 | - /2D Pose Estimate1
15 | - /Publish Point1
16 | Name: Tool Properties
17 | Splitter Ratio: 0.5886790156364441
18 | - Class: rviz_common/Views
19 | Expanded:
20 | - /Current View1
21 | Name: Views
22 | Splitter Ratio: 0.5
23 | - Class: rviz_common/Views
24 | Expanded:
25 | - /Current View1
26 | Name: Views
27 | Splitter Ratio: 0.5
28 | - Class: rviz_carla_plugin/CarlaControl
29 | Name: CarlaControl
30 | Visualization Manager:
31 | Class: ""
32 | Displays:
33 | - Class: rviz_default_plugins/Image
34 | Enabled: true
35 | Max Value: 1
36 | Median window: 5
37 | Min Value: 0
38 | Name: Orbit
39 | Normalize Range: true
40 | Topic:
41 | Depth: 5
42 | Durability Policy: Volatile
43 | History Policy: Keep Last
44 | Reliability Policy: Reliable
45 | Value: /carla/ego_vehicle/rgb_view/image
46 | Value: true
47 | - Alpha: 1
48 | Autocompute Intensity Bounds: true
49 | Autocompute Value Bounds:
50 | Max Value: 10
51 | Min Value: -10
52 | Value: true
53 | Axis: Z
54 | Channel Name: intensity
55 | Class: rviz_default_plugins/PointCloud2
56 | Color: 255; 255; 255
57 | Color Transformer: Intensity
58 | Decay Time: 0
59 | Enabled: true
60 | Invert Rainbow: false
61 | Max Color: 255; 255; 255
62 | Max Intensity: 0.9944708347320557
63 | Min Color: 0; 0; 0
64 | Min Intensity: 0.8189496397972107
65 | Name: PointCloud2
66 | Position Transformer: XYZ
67 | Selectable: true
68 | Size (Pixels): 3
69 | Size (m): 0.10000000149011612
70 | Style: Flat Squares
71 | Topic:
72 | Depth: 5
73 | Durability Policy: Volatile
74 | Filter size: 10
75 | History Policy: Keep Last
76 | Reliability Policy: Reliable
77 | Value: /carla/ego_vehicle/lidar
78 | Use Fixed Frame: true
79 | Use rainbow: true
80 | Value: true
81 | - Class: rviz_default_plugins/MarkerArray
82 | Enabled: true
83 | Name: MarkerArray
84 | Namespaces:
85 | "": true
86 | Topic:
87 | Depth: 5
88 | Durability Policy: Volatile
89 | History Policy: Keep Last
90 | Reliability Policy: Reliable
91 | Value: /carla/markers
92 | Value: true
93 | - Class: rviz_default_plugins/Image
94 | Enabled: true
95 | Max Value: 1
96 | Median window: 5
97 | Min Value: 0
98 | Name: RGB
99 | Normalize Range: true
100 | Topic:
101 | Depth: 5
102 | Durability Policy: Volatile
103 | History Policy: Keep Last
104 | Reliability Policy: Reliable
105 | Value: /carla/ego_vehicle/rgb_front/image
106 | Value: true
107 | - Class: rviz_default_plugins/Image
108 | Enabled: true
109 | Max Value: 1
110 | Median window: 5
111 | Min Value: 0
112 | Name: Segmentation
113 | Normalize Range: true
114 | Topic:
115 | Depth: 5
116 | Durability Policy: Volatile
117 | History Policy: Keep Last
118 | Reliability Policy: Reliable
119 | Value: /carla/ego_vehicle/semantic_front/image
120 | Value: true
121 | - Class: rviz_default_plugins/Image
122 | Enabled: true
123 | Max Value: 1
124 | Median window: 5
125 | Min Value: 0
126 | Name: Depth
127 | Normalize Range: true
128 | Topic:
129 | Depth: 5
130 | Durability Policy: Volatile
131 | History Policy: Keep Last
132 | Reliability Policy: Reliable
133 | Value: /carla/ego_vehicle/depth_front/image
134 | Value: true
135 | - Class: rviz_default_plugins/Image
136 | Enabled: true
137 | Max Value: 1
138 | Median window: 5
139 | Min Value: 0
140 | Name: Image
141 | Normalize Range: true
142 | Topic:
143 | Depth: 5
144 | Durability Policy: Volatile
145 | History Policy: Keep Last
146 | Reliability Policy: Reliable
147 | Value: /image_segmentation/segmentation
148 | Value: true
149 | Enabled: true
150 | Global Options:
151 | Background Color: 48; 48; 48
152 | Fixed Frame: map
153 | Frame Rate: 30
154 | Name: root
155 | Tools:
156 | - Class: rviz_default_plugins/Interact
157 | Hide Inactive Objects: true
158 | - Class: rviz_default_plugins/MoveCamera
159 | - Class: rviz_default_plugins/Select
160 | - Class: rviz_default_plugins/FocusCamera
161 | - Class: rviz_default_plugins/Measure
162 | Line color: 128; 128; 0
163 | - Class: rviz_default_plugins/SetInitialPose
164 | Covariance x: 0.25
165 | Covariance y: 0.25
166 | Covariance yaw: 0.06853891909122467
167 | Topic:
168 | Depth: 5
169 | Durability Policy: Volatile
170 | History Policy: Keep Last
171 | Reliability Policy: Reliable
172 | Value: /initialpose
173 | - Class: rviz_default_plugins/SetGoal
174 | Topic:
175 | Depth: 5
176 | Durability Policy: Volatile
177 | History Policy: Keep Last
178 | Reliability Policy: Reliable
179 | Value: /move_base_simple/goal
180 | - Class: rviz_default_plugins/PublishPoint
181 | Single click: true
182 | Topic:
183 | Depth: 5
184 | Durability Policy: Volatile
185 | History Policy: Keep Last
186 | Reliability Policy: Reliable
187 | Value: /clicked_point
188 | Transformation:
189 | Current:
190 | Class: rviz_default_plugins/TF
191 | Value: true
192 | Views:
193 | Current:
194 | Class: rviz_default_plugins/ThirdPersonFollower
195 | Distance: 29.793502807617188
196 | Enable Stereo Rendering:
197 | Stereo Eye Separation: 0.05999999865889549
198 | Stereo Focal Distance: 1
199 | Swap Stereo Eyes: false
200 | Value: false
201 | Focal Point:
202 | X: -5.698474884033203
203 | Y: -0.13345003128051758
204 | Z: -5.542716826312244e-05
205 | Focal Shape Fixed Size: false
206 | Focal Shape Size: 0.05000000074505806
207 | Invert Z Axis: false
208 | Name: Current View
209 | Near Clip Distance: 0.009999999776482582
210 | Pitch: 0.7503990530967712
211 | Target Frame: ego_vehicle
212 | Value: ThirdPersonFollower (rviz_default_plugins)
213 | Yaw: 3.1485884189605713
214 | Saved: ~
215 | Window Geometry:
216 | CarlaControl:
217 | collapsed: false
218 | Depth:
219 | collapsed: false
220 | Displays:
221 | collapsed: false
222 | Height: 1043
223 | Hide Left Dock: false
224 | Hide Right Dock: false
225 | Image:
226 | collapsed: false
227 | Orbit:
228 | collapsed: false
229 | QMainWindow State: 000000ff00000000fd0000000300000000000001a8000003bdfc020000000cfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc0000003b00000143000000c700fffffffa000000010100000002fb0000000a005600690065007700730000000000ffffffff0000010000fffffffb000000100044006900730070006c0061007900730100000000000001fe0000015600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0056006900650077007301000001840000011c000000a000fffffffb00000014004f00720062006900740020005600690065007701000002110000013c0000000000000000fb00000018004300610072006c00610043006f006e00740072006f006c0000000249000000aa0000006e00fffffffb0000000a004f007200620069007401000002a6000001520000002800ffffff000000010000017a000003bdfc0200000014fb00000006005200470042010000003b000000c70000002800fffffffb0000000a0049006d0061006700650100000108000000c60000002800fffffffb0000000a0044006500700074006801000001d40000010e0000002800fffffffb00000018005300650067006d0065006e0074006100740069006f006e01000002e8000001100000002800fffffffb0000000a0049006d006100670065010000003b000003bd0000000000000000fb0000000a0049006d0061006700650100000256000001a20000000000000000fb0000000a0049006d006100670065010000003b000003a20000000000000000fb0000000a0049006d006100670065010000003b000003250000000000000000fb0000000a0049006d006100670065010000003b000003a20000000000000000fb0000000a0049006d0061006700650100000223000001ba0000000000000000fb0000000a0049006d00610067006501000003b30000002a0000000000000000fb0000000a0049006d006100670065010000023e0000008e0000000000000000fb0000000a0049006d00610067006501000002d20000007d0000000000000000fb0000000a0049006d0061006700650100000355000000880000000000000000fb0000002a00430061006d0065007200610020005300650063006f006e0064002000560065006800690063006c00650100000216000001c70000000000000000fb0000001800440065007000740068002000430061006d006500720061000000020f000000430000000000000000fb0000001e00530065006d0061006e007400690063002000430061006d0065007200610000000247000000430000000000000000fb00000014004400560053002000430061006d0065007200610000000285000000650000000000000000fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000001200530065006c0065006300740069006f006e010000025a000000b20000000000000000000000030000073a000000cafc0100000002fb0000000800540069006d006501000000000000077e0000000000000000fb0000000800540069006d006501000000000000045000000000000000000000040c000003bd00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
230 | RGB:
231 | collapsed: false
232 | Segmentation:
233 | collapsed: false
234 | Selection:
235 | collapsed: false
236 | Tool Properties:
237 | collapsed: false
238 | Views:
239 | collapsed: false
240 | Width: 1850
241 | X: 70
242 | Y: 0
243 |
--------------------------------------------------------------------------------
/software-prototyping/docker-compose.yml:
--------------------------------------------------------------------------------
1 | x-launch-mount: &launch-mount ./carla-ros-bridge.launch.py:/demo.launch.py
2 | x-sensors-mount: &sensors-mount ./sensors.json:/sensors.json
3 | x-rviz-config-mount: &rviz-config-mount ./config.rviz:/config.rviz
4 |
5 | # ==============================================================================
6 |
7 | services:
8 |
9 | carla-server:
10 | extends:
11 | file: ../utils/carla-essentials/carla-services.yml
12 | service: carla-server
13 |
14 | carla-ros-bridge:
15 | extends:
16 | file: ../utils/carla-essentials/carla-services.yml
17 | service: carla-ros-bridge
18 | volumes:
19 | - *launch-mount
20 | - *sensors-mount
21 | command: bash -ic 'ros2 launch /demo.launch.py'
22 |
23 | ros-monitoring:
24 | extends:
25 | file: ../utils/carla-essentials/carla-services.yml
26 | service: ros-monitoring
27 | depends_on:
28 | carla-server:
29 | condition: service_healthy
30 | volumes:
31 | - *rviz-config-mount
32 | command: bash -ic 'rviz2 -d /config.rviz --ros-args -p use_sim_time:=true &> /dev/null'
33 |
34 | image-segmentation:
35 | depends_on:
36 | carla-server:
37 | condition: service_healthy
38 | image: rwthika/carlos-image-segmentation
39 | command: ros2 launch image_segmentation image_segmentation_launch.py image_topic:=/carla/ego_vehicle/rgb_front/image
40 |
41 | #
42 | # image:
43 | # command:
44 |
45 |
--------------------------------------------------------------------------------
/software-prototyping/sensors.json:
--------------------------------------------------------------------------------
1 | {
2 | "objects":
3 | [
4 | {
5 | "type": "sensor.pseudo.objects",
6 | "id": "objects"
7 | },
8 | {
9 | "type": "sensor.pseudo.actor_list",
10 | "id": "actor_list"
11 | },
12 | {
13 | "type": "sensor.pseudo.markers",
14 | "id": "markers"
15 | },
16 | {
17 | "type": "sensor.pseudo.opendrive_map",
18 | "id": "carla_map"
19 | },
20 | {
21 | "type": "sensor.pseudo.traffic_lights",
22 | "id": "traffic_lights"
23 | },
24 | {
25 | "type": "vehicle.mercedes.coupe",
26 | "id": "ego_vehicle",
27 | "spawn_point": {"x": 106.5, "y": 5.0, "z": 1.0, "roll": 0.0, "pitch": 0.0, "yaw": 90.0},
28 | "sensors":
29 | [
30 | {
31 | "type": "sensor.camera.rgb",
32 | "id": "rgb_view",
33 | "spawn_point": {"x": -8.0, "y": 0.0, "z": 4.0, "roll": 0.0, "pitch": 20.0, "yaw": 0.0},
34 | "image_size_x": 800,
35 | "image_size_y": 600
36 | },
37 | {
38 | "type": "sensor.camera.rgb",
39 | "id": "rgb_front",
40 | "spawn_point": {"x": 2.0, "y": 0.0, "z": 2.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
41 | "image_size_x": 1024,
42 | "image_size_y": 512
43 | },
44 | {
45 | "type": "sensor.camera.semantic_segmentation",
46 | "id": "semantic_front",
47 | "spawn_point": {"x": 2.0, "y": 0.0, "z": 2.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
48 | "image_size_x": 800,
49 | "image_size_y": 600,
50 | "fov": 90.0
51 | },
52 | {
53 | "type": "sensor.camera.depth",
54 | "id": "depth_front",
55 | "spawn_point": {"x": 2.0, "y": 0.0, "z": 2.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
56 | "image_size_x": 800,
57 | "image_size_y": 600,
58 | "fov": 90.0
59 | },
60 | {
61 | "type": "sensor.lidar.ray_cast",
62 | "id": "lidar",
63 | "spawn_point": {"x": 0.0, "y": 0.0, "z": 2.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0},
64 | "range": 50,
65 | "channels": 64,
66 | "points_per_second": 640000,
67 | "upper_fov": 2.0,
68 | "lower_fov": -26.8,
69 | "rotation_frequency": 20,
70 | "noise_stddev": 0.0
71 | },
72 | {
73 | "type": "sensor.pseudo.tf",
74 | "id": "tf"
75 | },
76 | {
77 | "type": "sensor.pseudo.objects",
78 | "id": "objects"
79 | },
80 | {
81 | "type": "sensor.pseudo.odom",
82 | "id": "odometry"
83 | },
84 | {
85 | "type": "sensor.pseudo.speedometer",
86 | "id": "speedometer"
87 | },
88 | {
89 | "type": "actor.pseudo.control",
90 | "id": "control"
91 | }
92 | ]
93 | },
94 | {
95 | "type": "vehicle.tesla.model3",
96 | "id": "challenger_vehicle",
97 | "spawn_point": {"x": 99.5, "y": 25.0, "z": 1.0, "roll": 0.0, "pitch": 0.0, "yaw": -90.0},
98 | "sensors":
99 | [
100 | {
101 | "type": "sensor.camera.rgb",
102 | "id": "rgb_view",
103 | "spawn_point": {"x": -8.0, "y": 0.0, "z": 4.0, "roll": 0.0, "pitch": 20.0, "yaw": 0.0},
104 | "image_size_x": 800,
105 | "image_size_y": 600
106 | },
107 | {
108 | "type": "sensor.pseudo.tf",
109 | "id": "tf"
110 | },
111 | {
112 | "type": "sensor.pseudo.objects",
113 | "id": "objects"
114 | },
115 | {
116 | "type": "sensor.pseudo.odom",
117 | "id": "odometry"
118 | },
119 | {
120 | "type": "sensor.pseudo.speedometer",
121 | "id": "speedometer"
122 | },
123 | {
124 | "type": "actor.pseudo.control",
125 | "id": "control"
126 | }
127 | ]
128 | }
129 | ]
130 | }
131 |
--------------------------------------------------------------------------------
/utils/carla-essentials/README.md:
--------------------------------------------------------------------------------
1 | # Components
2 |
3 | This document aims to give a brief overview of the various Docker services provided by [carla-services.yml](./carla-services.yml) and utilized within the CARLOS use cases.
4 |
5 | ## Component List
6 |
7 | | Service Name | Repository | Docker Image |
8 | | --- | --- | --- |
9 | | `carla-server` | [ika-rwth-aachen/carla-simulator](https://github.com/ika-rwth-aachen/carla-simulator) | rwthika/carla-simulator:server |
10 | | `carla-client` | [ika-rwth-aachen/carla-simulator](https://github.com/ika-rwth-aachen/carla-simulator) | rwthika/carla-simulator:client |
11 | | `carla-ros-bridge` | [ika-rwth-aachen/carla-ros-bridge](https://github.com/ika-rwth-aachen/ros-bridge) | rwthika/carla-ros-bridge |
12 | | `carla-scenario-runner` | [ika-rwth-aachen/carla-scenario-runner](https://github.com/ika-rwth-aachen/carla-scenario-runner) | rwthika/carla-scenario-runner |
13 | | `ros-monitoring` | [ika-rwth-aachen/docker-ros-ml-images](https://github.com/ika-rwth-aachen/docker-ros-ml-images?tab=readme-ov-file#rwthikaros2-cuda-ros-2--cuda) | rwthika/ros2-cuda:humble-desktop-full |
14 |
15 |
16 | ## carla-server
17 |
18 | This Docker service represents a single instance of a [CARLA](http://carla.org/) simulator and constitutes the central element of the framework that aim to simulate and test automated driving features.
19 |
20 | Starting this service (e.g. by `docker compose up carla-server` in this folder) should open up a new GUI window in which you can move around the currently loaded map and follow what is happening in simulations.
21 |
22 | In addition, the Docker services provides a continuous health check monitoring if the CARLA server is running and connection can be established. Since the health of this service depends on the availability of the CARLA simulator, other services can depend on this services health to ensure a correct startup and shutdown order and thus preventing them from attempting to connect to the simulator before it is started or after it is stopped.
23 |
24 | **Note:** This only helps with startup and shutdown order. Your applications still need to have their own logic for handling connection fails during operation
25 |
26 |
27 | ### carla-server-offscreen
28 | This Docker service is a variation of the previous carla-server service, with the exception that no GUI window is opened and thus one cannot directly follow what is happening on the map.
29 |
30 | The upside to this is that this service is a bit lighter on the GPU and does not clutter up your screen as much. Especially useful when only interested in simulation without direct graphical output.
31 |
32 |
33 | ## carla-client
34 | The carla-client Docker services provides a minimal solution to interact with the CARLA server via PythonAPI. In addition, all example scripts are contained and can be used even with GUI access enabled. Thus, powerful demonstrations can be shown solely with a server and this carla-client Docker service.
35 |
36 |
37 | ## carla-ros-bridge
38 | The carla-ros-bridge is the Docker service that facilitates the powerful combination of CARLA and ROS by acting as an interface. It retrieves relevant data (e.g. [sensor data](https://carla.readthedocs.io/projects/ros-bridge/en/latest/ros_sensors/)) from the simulation to publish it on ROS topics in the [CARLA messages](https://carla.readthedocs.io/projects/ros-bridge/en/latest/ros_msgs/) format. Simultaneously the service is listening on different topics for requested actions, which are translated to commands to be executed in CARLA.
39 |
40 | Including a carla-ros-bridge into your setup is mandatory when said setup uses both CARLA and ROS and needs them to interact.
41 |
42 |
43 | ## carla-scenario-runner
44 | To enable scenario-based testing and evaluation, the carla-scenario-runner Docker service is used. It provides the scenario-runner a powerful engine that follows the [OpenSCENARIO](https://www.asam.net/standards/detail/openscenario/) standard for scenario definitions. This enables efficient scenario execution and additional metric evaluation, enabling an automatic scenario assessment.
45 |
46 | Including a carla-scenario-runner into your setup is mandatory when you want to simulate a more complex, concrete scenario.
47 |
48 |
49 | ## ros-monitoring
50 | This services provides a possibility for monitoring data within the ROS world. All [common_msgs](http://wiki.ros.org/common_msgs) definitions are preinstalled together with monitoring tools such as RViz. Make sure that all GUI forwarding settings are enabled.
51 |
52 | ### ros-monitoring-offscreen
53 | This Docker service is a variation of the previous ros-monitoring service, with the exception that no GUI window is opened and thus one cannot use visualization tools such as RViz. However, this is sufficient for any other lightweight ROS tasks.
54 |
--------------------------------------------------------------------------------
/utils/carla-essentials/carla-services.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | carla-server:
4 | extends:
5 | service: gpu-x11-service
6 | privileged: True
7 | image: rwthika/carla-simulator:server
8 | command: bash -ic './CarlaUE4.sh -nosound 2>/dev/null'
9 |
10 | carla-server-offscreen:
11 | extends:
12 | service: carla-server
13 | command: bash -ic './CarlaUE4.sh -nosound -RenderOffScreen 2>/dev/null'
14 |
15 | carla-client:
16 | extends:
17 | service: gpu-x11-service
18 | depends_on:
19 | carla-server:
20 | condition: service_healthy
21 | image: rwthika/carla-simulator:client
22 | command: sleep infinity
23 |
24 | carla-ros-bridge:
25 | extends:
26 | service: ros-x11-service
27 | depends_on:
28 | carla-server:
29 | condition: service_healthy
30 | image: rwthika/carla-ros-bridge
31 |
32 | carla-scenario-runner:
33 | extends:
34 | service: gpu-x11-service
35 | depends_on:
36 | carla-server:
37 | condition: service_healthy
38 | image: rwthika/carla-scenario-runner
39 |
40 | ros-monitoring:
41 | extends:
42 | service: gpu-x11-service
43 | image: rwthika/ros2-cuda:humble-desktop-full
44 |
45 | ros-monitoring-offscreen:
46 | extends:
47 | service: gpu-service
48 | image: rwthika/ros2-cuda:humble-desktop-full
49 |
50 | gpu-service:
51 | deploy:
52 | resources:
53 | reservations:
54 | devices:
55 | - driver: nvidia
56 | count: 1
57 | capabilities: [gpu]
58 |
59 | gpu-x11-service:
60 | extends:
61 | service: gpu-service
62 | environment:
63 | DISPLAY: $DISPLAY
64 | volumes:
65 | - /tmp/.X11-unix:/tmp/.X11-unix
66 |
67 | ros-service:
68 | environment:
69 | - DOCKER_UID
70 | - DOCKER_GID
71 |
72 | ros-x11-service:
73 | extends:
74 | service: ros-service
75 | environment:
76 | DISPLAY: $DISPLAY
77 | volumes:
78 | - /tmp/.X11-unix:/tmp/.X11-unix
79 |
--------------------------------------------------------------------------------
/utils/images/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/architecture.png
--------------------------------------------------------------------------------
/utils/images/automated-testing-cli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/automated-testing-cli.png
--------------------------------------------------------------------------------
/utils/images/automated-testing-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/automated-testing-icon.png
--------------------------------------------------------------------------------
/utils/images/automated-testing-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/automated-testing-workflow.png
--------------------------------------------------------------------------------
/utils/images/data-driven-development-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/data-driven-development-icon.png
--------------------------------------------------------------------------------
/utils/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/logo.png
--------------------------------------------------------------------------------
/utils/images/overview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/overview.gif
--------------------------------------------------------------------------------
/utils/images/software-prototyping-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/software-prototyping-icon.png
--------------------------------------------------------------------------------
/utils/images/software-prototyping-image-segmentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/software-prototyping-image-segmentation.png
--------------------------------------------------------------------------------
/utils/images/software-prototyping-rviz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/software-prototyping-rviz.png
--------------------------------------------------------------------------------
/utils/images/teaser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/teaser.png
--------------------------------------------------------------------------------
/utils/images/tutorial-dynamic-weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/tutorial-dynamic-weather.png
--------------------------------------------------------------------------------
/utils/images/tutorial-pygame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/tutorial-pygame.png
--------------------------------------------------------------------------------
/utils/images/tutorial-rviz-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ika-rwth-aachen/carlos/31d84fb3c33fb0e9cdc2655679a22e23212ee14b/utils/images/tutorial-rviz-overview.png
--------------------------------------------------------------------------------
/utils/requirements.md:
--------------------------------------------------------------------------------
1 | # Requirements
2 |
3 | > [!IMPORTANT]
4 | > The core requirements for using our simulation framework CARLOS are listed below:
5 | > - [Ubuntu 20.04 LTS Focal](https://ubuntu.com/download/desktop) (or higher) with `sudo` permission
6 | > - enough hard disk storage, which depends on the workshop and use-case (~50 GB are recommended)
7 | > - NVIDIA GPU (at least 8 GB GPU memory are recommended)
8 |
9 | > [!NOTE]
10 | > Make sure to install all prerequisites and that GUI access is available:
11 | > - [Nvidia Driver](https://ubuntu.com/server/docs/nvidia-drivers-installation) (validate installation with `nvidia-smi`)
12 | > - Docker Installation
13 | > - [Docker](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-22-04)
14 | > - [Docker Compose](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-22-04)
15 | > - [Nvidia Docker](https://github.com/NVIDIA/nvidia-docker)
16 |
17 | > [!WARNING]
18 | > Make sure that your machine has access to its X server to enable graphical output.
19 | > ```bash
20 | > xhost +local:
21 | > ```
22 |
--------------------------------------------------------------------------------
/utils/scenarios/catalogs/VehicleCatalog.xosc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/utils/scenarios/town01.xosc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/utils/scenarios/town01.xosc.opt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/utils/scenarios/town10.xosc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
--------------------------------------------------------------------------------
/utils/scenarios/town10.xosc.opt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/utils/tutorial/README.md:
--------------------------------------------------------------------------------
1 | # Tutorial: Simulative Development and Testing with CARLA and ROS
2 |
3 | > [!NOTE]
4 | > This repository provides CARLOS, an open, modular and scalable simulation framework based on the open-source [CARLA simulator](https://github.com/ika-rwth-aachen/carla-simulator). The framework can be used to develop and test C-ITS software in a closed-loop simulation environment. Have a closer look at the top-level [README](../README.md) to get a first overview of the provided demo use cases.
5 |
6 | ---
7 |
8 | ## Setup
9 |
10 | ### Requirements
11 |
12 | The core requirements for using and testing the simulation framework are provided within the [requirements guide](./requirements.md).
13 |
14 | ### Creating a Compose File
15 |
16 | The backbone of the proposed simulation framework is based on Docker Compose, enabling modular plugging of different Docker services. All described [components](../components.md) can be integrated in a custom Docker Compose file. Feel free to set up your own custom [`docker-compose.yml`](./docker-compose.yml) within the directory of this tutorial:
17 |
18 | ```yml
19 | # you can utilize yaml features to avoid repeating yourself and centralizing configurations
20 | x-rviz-config-mount: &rviz-config-mount ./config.rviz:/config.rviz
21 |
22 | # ==============================================================================
23 |
24 | services:
25 |
26 | # starts a CARLA server instance named 'carla-server' with a GUI window
27 | carla-server:
28 | extends:
29 | file: ../carla-essentials/carla-services.yml
30 | service: carla-server
31 |
32 | # starts a client instance named 'carla-client' to connect with CARLA via PythonAPI
33 | carla-client:
34 | extends:
35 | file: ../carla-essentials/carla-services.yml
36 | service: carla-client
37 | command: sleep infinity
38 |
39 | # starts the carla-ros-bridge
40 | carla-ros-bridge:
41 | extends:
42 | file: ../carla-essentials/carla-services.yml
43 | service: carla-ros-bridge
44 | # ...and then execute them. Note the -ic flag for an interactive bash!
45 | # Without an interactive bash, many important env vars wouldn't be working or even set
46 | command: bash -ic 'ros2 launch carla_ros_bridge carla_ros_bridge_with_example_ego_vehicle.launch.py host:=carla-server'
47 | # .. note that the host name is explictly set to the name of the carla-server Docker service!
48 |
49 | # starts rviz with a GUI window named 'ros-monitoring'
50 | ros-monitoring:
51 | extends:
52 | file: ../carla-essentials/carla-services.yml
53 | service: ros-monitoring
54 | depends_on:
55 | carla-server:
56 | condition: service_healthy
57 | volumes:
58 | # you can mount custom rviz configs...
59 | - *rviz-config-mount
60 | # ...and then use them when starting up rviz with the -d flag
61 | command: bash -ic 'rviz2 -d /config.rviz --ros-args -p use_sim_time:=true &> /dev/null'
62 | ```
63 |
64 | This aggregated `docker-compose.yml` file enables direct integration of CARLA into the [ROS 2](https://docs.ros.org/en/rolling/index.html) ecosystem.
65 |
66 | As a preliminary step, pull all Docker images used in this tutorial. This could take some time, so it's recommended to pull all images in advance.
67 |
68 | ```bash
69 | # optionally pull all specified service images in advance
70 | docker compose pull
71 | ```
72 |
73 | ## Running the Compose Setup
74 |
75 | ### CARLA Server + Client
76 |
77 | The [CARLA simulator](https://github.com/carla-simulator/carla) is a powerful open-source simulation tool based on Unreal Engine. It uses a server-client architecture providing APIs for Python, C++ and ROS applications.
78 |
79 | In the first example, we are starting a CARLA serveralong with a Python API client. The two processes are running in dedicated containers which can be launched via Docker Compose. Detailed information about Docker Compose can be found in the official [documentation](https://docs.docker.com/compose/).
80 |
81 | > [!IMPORTANT]
82 | > Make sure that your machine has access to its X server to enable graphical output.
83 | > ```bash
84 | > xhost +local:
85 | > ```
86 |
87 | Then, you can launch the two containers using the `docker compose up` command:
88 | ```bash
89 | # launch compose setup including carla-server and carla-client
90 | docker compose up carla-server carla-client
91 | ```
92 |
93 | This should bring up a CARLA server GUI running a map called [Town 10](https://carla.readthedocs.io/en/latest/map_town10/). You can look around by using WASD, holding the left or right mousebutton and moving the mouse in the desired direction.
94 |
95 | In a second terminal, run `docker ps` which shows all containers, one of them named `tutorial-carla-client-1`.
96 | We can use the tool [docker-run](https://github.com/ika-rwth-aachen/docker-run) CLI for direct interaction with this container:
97 |
98 | If not already installed, you can install `docker-run` directly with pip:
99 | ```bash
100 | # install docker-run-cli with docker-ros plugin
101 | pip install docker-run-cli[docker-ros]
102 | ```
103 |
104 | Check if `docker-run` can already be used:
105 | ```bash
106 | docker-run --version
107 | ```
108 |
109 | If this prints a version, you are good to go. If not (it may tell you `docker-run: command not found`), you can most likely fix it like so:
110 | ```bash
111 | echo "export PATH=$HOME/.local/bin:$PATH" >> ~/.bashrc
112 | source ~/.bashrc
113 | ```
114 |
115 | > [!NOTE]
116 | > You can also use `docker exec -it` to interact with the running container using the standard Docker CLI. Nevertheless, we highly recommend to use the useful features of [docker-run](https://github.com/ika-rwth-aachen/docker-run).
117 |
118 |
119 | Now, use `docker-run` to directly attach to the running `carla-client` container:
120 | ```bash
121 | # attach to the carla-client container
122 | docker-run --name tutorial-carla-client-1
123 | ```
124 |
125 | Inside of the container, we can interact with the `carla-server` container:
126 |
127 | ```bash
128 | # changes weather settings dynamically
129 | ./examples/dynamic_weather.py --host carla-server
130 | ```
131 | [
](../images/tutorial-dynamic-weather.png)
132 |
133 | This example script changes the weather settings of the CARLA server dynamically. It's a simple example for an interaction between the CARLA server and a Python client communicating over two separate Docker containers. The processes can be stopped using CTRL+C.
134 |
135 | The running `carla-server` and `carla-client` containers can be stopped by terminating the Docker Compose setup with CTRL+C in the first terminal. In addition, remove the stopped containers with
136 | ```bash
137 | # stops all specified services and removes their containers completely
138 | docker compose down
139 | ```
140 |
141 | ### CARLA Server + ROS 2
142 |
143 | After observing the CARLA server, we investigate some additional Docker Compose services to bridge information into the ROS 2 world.
144 |
145 | The following command launches all defined services from `docker-compose.yml` file. In addition to the previous container, it launches a `carla-ros-bridge`, and a `ros-monitoring` container. A comprehensive overview about all available Docker services can be found in the [components guide](./components.md).
146 |
147 | ```bash
148 | # launch all services defined in docker-compose.yml
149 | docker compose up
150 | ```
151 |
152 | This mainly starts a CARLA server GUI and an `rviz` window. The `carla-ros-bridge` container an ego vehicle at a random positions with various sensors, including RGB, depth and segmentation cameras, but also lidar and radar sensors. All sensor data is published as `ROS 2` topic and is visualized using RViz in the `ros-monitoring` container.
153 |
154 | Check out the `rviz` setup to get familiar with the simulation setup and all available `ROS 2` topics. You should be seeing something like this:
155 |
156 | [
](../images/tutorial-rviz-overview.png)
157 |
158 | > [!TIP]
159 | > Feel free to observe the available topics within `rviz` or change the [sensors.json](../software-prototyping/sensors.json) file within the container to customize additional sensors.
160 |
161 | Within this tutorial, the `carla-ros-bridge` container offers another GUI, enabling direct control of the ego vehicle in the simulation. A PyGame window allows to drive the vehicle around with the WASD keys or toggling the autopilot with P. While driving around, have a look in RViz to capture the generated sensor data. The setup should look similar to this:
162 |
163 | [
](../images/tutorial-pygame.png)
164 |
165 |
166 | The entire Docker Compose setup including all running containers can be stopped with CTRL+C and removed with
167 | ```bash
168 | # stops all specified services and removes their containers completely
169 | docker compose down
170 |
171 | # restricts X server access again
172 | xhost -local:
173 | ```
174 |
--------------------------------------------------------------------------------
/utils/tutorial/config.rviz:
--------------------------------------------------------------------------------
1 | Panels:
2 | - Class: rviz_common/Displays
3 | Help Height: 0
4 | Name: Displays
5 | Property Tree Widget:
6 | Expanded: ~
7 | Splitter Ratio: 0.5354107618331909
8 | Tree Height: 301
9 | - Class: rviz_common/Selection
10 | Name: Selection
11 | - Class: rviz_common/Tool Properties
12 | Expanded:
13 | - /2D Pose Estimate1
14 | - /Publish Point1
15 | Name: Tool Properties
16 | Splitter Ratio: 0.5886790156364441
17 | - Class: rviz_common/Views
18 | Expanded:
19 | - /Current View1
20 | Name: Views
21 | Splitter Ratio: 0.5
22 | - Class: rviz_common/Views
23 | Expanded:
24 | - /Current View1
25 | Name: Views
26 | Splitter Ratio: 0.5
27 | - Class: rviz_carla_plugin/CarlaControl
28 | Name: CarlaControl
29 | Visualization Manager:
30 | Class: ""
31 | Displays:
32 | - Class: rviz_default_plugins/Image
33 | Enabled: true
34 | Max Value: 1
35 | Median window: 5
36 | Min Value: 0
37 | Name: Orbit
38 | Normalize Range: true
39 | Topic:
40 | Depth: 5
41 | Durability Policy: Volatile
42 | History Policy: Keep Last
43 | Reliability Policy: Reliable
44 | Value: /carla/ego_vehicle/rgb_view/image
45 | Value: true
46 | - Class: rviz_default_plugins/MarkerArray
47 | Enabled: true
48 | Name: MarkerArray
49 | Namespaces:
50 | "": true
51 | Topic:
52 | Depth: 5
53 | Durability Policy: Volatile
54 | History Policy: Keep Last
55 | Reliability Policy: Reliable
56 | Value: /carla/markers
57 | Value: true
58 | - Class: rviz_default_plugins/Image
59 | Enabled: true
60 | Max Value: 1
61 | Median window: 5
62 | Min Value: 0
63 | Name: RGB
64 | Normalize Range: true
65 | Topic:
66 | Depth: 5
67 | Durability Policy: Volatile
68 | History Policy: Keep Last
69 | Reliability Policy: Reliable
70 | Value: /carla/ego_vehicle/rgb_front/image
71 | Value: true
72 | - Class: rviz_default_plugins/Image
73 | Enabled: true
74 | Max Value: 1
75 | Median window: 5
76 | Min Value: 0
77 | Name: Depth
78 | Normalize Range: true
79 | Topic:
80 | Depth: 5
81 | Durability Policy: Volatile
82 | History Policy: Keep Last
83 | Reliability Policy: Reliable
84 | Value: /carla/ego_vehicle/depth_front/image
85 | Value: true
86 | - Class: rviz_default_plugins/Image
87 | Enabled: true
88 | Max Value: 1
89 | Median window: 5
90 | Min Value: 0
91 | Name: Segmentation
92 | Normalize Range: true
93 | Topic:
94 | Depth: 5
95 | Durability Policy: Volatile
96 | History Policy: Keep Last
97 | Reliability Policy: Reliable
98 | Value: /carla/ego_vehicle/semantic_segmentation_front/image
99 | Value: true
100 | - Alpha: 1
101 | Autocompute Intensity Bounds: true
102 | Autocompute Value Bounds:
103 | Max Value: 10
104 | Min Value: -10
105 | Value: true
106 | Axis: Z
107 | Channel Name: intensity
108 | Class: rviz_default_plugins/PointCloud2
109 | Color: 255; 255; 255
110 | Color Transformer: Intensity
111 | Decay Time: 0
112 | Enabled: true
113 | Invert Rainbow: false
114 | Max Color: 255; 255; 255
115 | Max Intensity: 4096
116 | Min Color: 0; 0; 0
117 | Min Intensity: 0
118 | Name: Radar
119 | Position Transformer: XYZ
120 | Selectable: true
121 | Size (Pixels): 3
122 | Size (m): 0.25
123 | Style: Flat Squares
124 | Topic:
125 | Depth: 5
126 | Durability Policy: Volatile
127 | Filter size: 10
128 | History Policy: Keep Last
129 | Reliability Policy: Reliable
130 | Value: /carla/ego_vehicle/radar_front
131 | Use Fixed Frame: true
132 | Use rainbow: true
133 | Value: true
134 | - Alpha: 1
135 | Autocompute Intensity Bounds: true
136 | Autocompute Value Bounds:
137 | Max Value: 10
138 | Min Value: -10
139 | Value: true
140 | Axis: Z
141 | Channel Name: intensity
142 | Class: rviz_default_plugins/PointCloud2
143 | Color: 255; 255; 255
144 | Color Transformer: Intensity
145 | Decay Time: 0
146 | Enabled: true
147 | Invert Rainbow: false
148 | Max Color: 255; 255; 255
149 | Max Intensity: 0.988711416721344
150 | Min Color: 0; 0; 0
151 | Min Intensity: 0.8193727135658264
152 | Name: Lidar
153 | Position Transformer: XYZ
154 | Selectable: true
155 | Size (Pixels): 3
156 | Size (m): 0.10000000149011612
157 | Style: Flat Squares
158 | Topic:
159 | Depth: 5
160 | Durability Policy: Volatile
161 | Filter size: 10
162 | History Policy: Keep Last
163 | Reliability Policy: Reliable
164 | Value: /carla/ego_vehicle/lidar
165 | Use Fixed Frame: true
166 | Use rainbow: true
167 | Value: true
168 | Enabled: true
169 | Global Options:
170 | Background Color: 48; 48; 48
171 | Fixed Frame: map
172 | Frame Rate: 30
173 | Name: root
174 | Tools:
175 | - Class: rviz_default_plugins/Interact
176 | Hide Inactive Objects: true
177 | - Class: rviz_default_plugins/MoveCamera
178 | - Class: rviz_default_plugins/Select
179 | - Class: rviz_default_plugins/FocusCamera
180 | - Class: rviz_default_plugins/Measure
181 | Line color: 128; 128; 0
182 | - Class: rviz_default_plugins/SetInitialPose
183 | Covariance x: 0.25
184 | Covariance y: 0.25
185 | Covariance yaw: 0.06853891909122467
186 | Topic:
187 | Depth: 5
188 | Durability Policy: Volatile
189 | History Policy: Keep Last
190 | Reliability Policy: Reliable
191 | Value: /initialpose
192 | - Class: rviz_default_plugins/SetGoal
193 | Topic:
194 | Depth: 5
195 | Durability Policy: Volatile
196 | History Policy: Keep Last
197 | Reliability Policy: Reliable
198 | Value: /move_base_simple/goal
199 | - Class: rviz_default_plugins/PublishPoint
200 | Single click: true
201 | Topic:
202 | Depth: 5
203 | Durability Policy: Volatile
204 | History Policy: Keep Last
205 | Reliability Policy: Reliable
206 | Value: /clicked_point
207 | Transformation:
208 | Current:
209 | Class: rviz_default_plugins/TF
210 | Value: true
211 | Views:
212 | Current:
213 | Class: rviz_default_plugins/ThirdPersonFollower
214 | Distance: 29.793502807617188
215 | Enable Stereo Rendering:
216 | Stereo Eye Separation: 0.05999999865889549
217 | Stereo Focal Distance: 1
218 | Swap Stereo Eyes: false
219 | Value: false
220 | Focal Point:
221 | X: -5.698474884033203
222 | Y: -0.13345003128051758
223 | Z: -5.542716826312244e-05
224 | Focal Shape Fixed Size: false
225 | Focal Shape Size: 0.05000000074505806
226 | Invert Z Axis: false
227 | Name: Current View
228 | Near Clip Distance: 0.009999999776482582
229 | Pitch: 0.41539913415908813
230 | Target Frame: ego_vehicle
231 | Value: ThirdPersonFollower (rviz_default_plugins)
232 | Yaw: 3.128587007522583
233 | Saved: ~
234 | Window Geometry:
235 | CarlaControl:
236 | collapsed: false
237 | Depth:
238 | collapsed: false
239 | Displays:
240 | collapsed: false
241 | Height: 825
242 | Hide Left Dock: false
243 | Hide Right Dock: false
244 | Orbit:
245 | collapsed: false
246 | QMainWindow State: 000000ff00000000fd0000000300000000000001a8000002e3fc020000000cfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc0000003b00000168000000c700fffffffa000000010100000002fb0000000a005600690065007700730000000000ffffffff0000010000fffffffb000000100044006900730070006c0061007900730100000000000001fe0000015600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a00560069006500770073000000017b00000114000000a000fffffffb00000014004f00720062006900740020005600690065007701000002110000013c0000000000000000fb00000018004300610072006c00610043006f006e00740072006f006c0000000249000000aa0000006e00fffffffb0000000a004f007200620069007401000001a9000001750000002800ffffff0000000100000233000002e3fc0200000016fb00000006005200470042010000003b000001cf0000002800fffffffb0000000a0049006d0061006700650100000152000001120000000000000000fb00000018005300650067006d0065006e0074006100740069006f006e0100000210000000800000002800fffffffb0000000a004400650070007400680100000296000000880000002800fffffffb0000000600440056005300000002b10000006d0000000000000000fb00000018005300650067006d0065006e0074006100740069006f006e01000002d5000001080000000000000000fb0000000a0049006d006100670065010000003b000003bd0000000000000000fb0000000a0049006d0061006700650100000256000001a20000000000000000fb0000000a0049006d006100670065010000003b000003a20000000000000000fb0000000a0049006d006100670065010000003b000003250000000000000000fb0000000a0049006d006100670065010000003b000003a20000000000000000fb0000000a0049006d0061006700650100000223000001ba0000000000000000fb0000000a0049006d00610067006501000003b30000002a0000000000000000fb0000000a0049006d006100670065010000023e0000008e0000000000000000fb0000000a0049006d00610067006501000002d20000007d0000000000000000fb0000000a0049006d0061006700650100000355000000880000000000000000fb0000002a00430061006d0065007200610020005300650063006f006e0064002000560065006800690063006c00650100000216000001c70000000000000000fb0000001800440065007000740068002000430061006d006500720061000000020f000000430000000000000000fb0000001e00530065006d0061006e007400690063002000430061006d0065007200610000000247000000430000000000000000fb00000014004400560053002000430061006d0065007200610000000285000000650000000000000000fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000001200530065006c0065006300740069006f006e010000025a000000b20000000000000000000000030000073a000000cafc0100000002fb0000000800540069006d006501000000000000077e0000000000000000fb0000000800540069006d006501000000000000045000000000000000000000034f000002e300000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
247 | RGB:
248 | collapsed: false
249 | Segmentation:
250 | collapsed: false
251 | Selection:
252 | collapsed: false
253 | Tool Properties:
254 | collapsed: false
255 | Views:
256 | collapsed: false
257 | Width: 1846
258 | X: 73
259 | Y: 30
260 |
--------------------------------------------------------------------------------
/utils/tutorial/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # you can utilize yaml features to avoid repeating yourself and centralizing configurations
2 | x-rviz-config-mount: &rviz-config-mount ./config.rviz:/config.rviz
3 |
4 | # ==============================================================================
5 |
6 | services:
7 |
8 | # starts a CARLA simulator instance named 'carla-server' with a GUI window
9 | carla-server:
10 | extends:
11 | file: ../carla-essentials/carla-services.yml
12 | service: carla-server
13 |
14 | carla-client:
15 | extends:
16 | file: ../carla-essentials/carla-services.yml
17 | service: carla-client
18 | command: sleep infinity
19 |
20 | # starts the carla-ros-bridge
21 | carla-ros-bridge:
22 | extends:
23 | file: ../carla-essentials/carla-services.yml
24 | service: carla-ros-bridge
25 | # ...and then execute them. Note the -ic flag for an interactive bash!
26 | # Without an interactive bash, many important env vars wouldn't be working or even set
27 | command: bash -ic 'ros2 launch carla_ros_bridge carla_ros_bridge_with_example_ego_vehicle.launch.py host:=carla-server'
28 | # .. note that the host name is explictly set to the name of the carla-server Docker service!
29 |
30 | # starts rviz with a GUI window named 'ros-monitoring'
31 | ros-monitoring:
32 | extends:
33 | file: ../carla-essentials/carla-services.yml
34 | service: ros-monitoring
35 | depends_on:
36 | carla-server:
37 | condition: service_healthy
38 | volumes:
39 | # you can mount custom rviz configs...
40 | - *rviz-config-mount
41 | # ...and then use them when starting up rviz with the -d flag
42 | command: bash -ic 'rviz2 -d /config.rviz --ros-args -p use_sim_time:=true &> /dev/null'
43 |
--------------------------------------------------------------------------------