├── .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 | --------------------------------------------------------------------------------