Merge branch 'master' into windows_build

This commit is contained in:
Marc Garcia Puig 2018-03-09 19:03:29 +01:00
commit b0e06c2ffa
174 changed files with 4751 additions and 1449 deletions

1
.gitignore vendored
View File

@ -26,4 +26,5 @@ Util/Build
__pycache__
_benchmarks_results
_images*
_out
core

View File

@ -76,7 +76,7 @@
{
"name": "CARLA - make CarlaUE4",
"working_dir": "${project_path}/Unreal/CarlaUE4",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"file_regex": "Unreal\\/CarlaUE4\\/([^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"syntax": "Packages/Makefile/Make Output.sublime-syntax",
"linux":
{
@ -86,7 +86,7 @@
{
"name": "CARLA - make CarlaUE4 ARGS=-clean",
"working_dir": "${project_path}/Unreal/CarlaUE4",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"file_regex": "Unreal\\/CarlaUE4\\/([^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"syntax": "Packages/Makefile/Make Output.sublime-syntax",
"linux":
{
@ -96,7 +96,7 @@
{
"name": "CARLA - make CarlaUE4Editor",
"working_dir": "${project_path}/Unreal/CarlaUE4",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"file_regex": "Unreal\\/CarlaUE4\\/([^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"syntax": "Packages/Makefile/Make Output.sublime-syntax",
"linux":
{
@ -106,7 +106,7 @@
{
"name": "CARLA - make CarlaUE4Editor ARGS=-clean",
"working_dir": "${project_path}/Unreal/CarlaUE4",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"file_regex": "Unreal\\/CarlaUE4\\/([^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"syntax": "Packages/Makefile/Make Output.sublime-syntax",
"linux":
{

View File

@ -63,6 +63,17 @@ please contact one of us (or send an email to carla.simulator@gmail.com).
[projectslink]: https://github.com/carla-simulator/carla/projects/1
#### Where can I learn more about Unreal Engine?
A basic introduction to C++ programming with UE4 can be found at Unreal's
[C++ Programming Tutorials][ue4tutorials]. Then, if you want to dive into UE4
C++ development there are few paying options online. The
[Unreal C++ Course at Udemy][ue4course] it's pretty complete and there are
usually offers that make it very affordable.
[ue4tutorials]: https://docs.unrealengine.com/latest/INT/Programming/Tutorials/
[ue4course]: https://www.udemy.com/unrealcourse/
#### What should I know before I get started?
Check out the ["CARLA Design"](carla_design.md) document to get an idea on the
@ -71,6 +82,27 @@ the new feature. We are aware the developers documentation is still scarce,
please ask us in case of doubt, and of course don't hesitate to improve the
current documentation if you feel confident enough.
#### Are there any examples in CARLA to see how Unreal programming works?
You can find an example of how C++ classes work in UE4 in
[`ASceneCaptureToDiskCamera`][capturelink] (and its parent class
`ASceneCaptureCamera`). This class creates an actor that can be dropped into the
scene. In the editor, type _"Scene Capture To Disk"_ in the Modes tab, and drag
and drop the actor into the scene. Now searching for its detail tab you can find
all the `UPROPERTY` members reflected. This shows the basic mechanism to use C++
classes in Unreal Editor.
For a more advanced example on how to extend C++ classes with blueprints, you
can take a look at the _"VehicleSpawner"_ blueprint. It derives from the C++
class `AVehicleSpawnerBase`. The C++ class decides where and when it spawns a
vehicle, then calls the function `SpawnVehicle()`, which is implemented in the
blueprint. The blueprint then decides model and color of the vehicle being
spawned. Note that the blueprint can call back C++ functions, for instance for
getting the random engine. This way there is a back-and-forth communication
between C++ code and blueprints.
[capturelink]: https://github.com/carla-simulator/carla/blob/master/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/SceneCaptureToDiskCamera.h
#### Coding standard
Please follow the current [coding standard](coding_standard.md) when submitting

View File

@ -1,16 +1,20 @@
; Example of settings file for CARLA.
;
; Use it with `./CarlaUE4.sh -carla-settings=Path/To/This/File`.
; This file can be loaded with the Python client to be sent to the server. It
; defines the parameters to be used when requesting a new episode.
;
; Note that server specific variables are loaded in server only. Use it with
; `./CarlaUE4.sh -carla-settings=Path/To/This/File`.
[CARLA/Server]
; If set to false, a mock controller will be used instead of waiting for a real
; client to connect.
; client to connect. (Server only)
UseNetworking=true
; Ports to use for the server-client communication. This can be overridden by
; the command-line switch `-world-port=N`, write and read ports will be set to
; N+1 and N+2 respectively.
; N+1 and N+2 respectively. (Server only)
WorldPort=2000
; Time-out in milliseconds for the networking operations.
; Time-out in milliseconds for the networking operations. (Server only)
ServerTimeOut=10000
; In synchronous mode, CARLA waits every frame until the control from the client
; is received.
@ -36,16 +40,26 @@ WeatherId=1
SeedVehicles=123456789
SeedPedestrians=123456789
[CARLA/SceneCapture]
; Names of the cameras to be attached to the player, comma-separated, each of
; them should be defined in its own subsection. E.g., Uncomment next line to add
; a camera called MyCamera to the vehicle
[CARLA/Sensor]
; Names of the sensors to be attached to the player, comma-separated, each of
; them should be defined in its own subsection.
; Cameras=MyCamera
; Uncomment next line to add a camera called MyCamera to the vehicle
; Sensors=MyCamera
; or uncomment next line to add a camera and a LiDAR
; Sensors=MyCamera,MyLidar
; or uncomment next line to add a regular camera and a depth camera
; Sensors=MyCamera,MyCamera/Depth
; Now, every camera we added needs to be defined it in its own subsection.
[CARLA/SceneCapture/MyCamera]
; Post-processing effect to be applied. Valid values:
[CARLA/Sensor/MyCamera]
; Type of the sensor. The available types are:
; * CAMERA A scene capture camera.
; * LIDAR_RAY_TRACE A LiDAR implementation based on ray-tracing.
SensorType=CAMERA
; Post-processing effect to be applied to this camera. Valid values:
; * None No effects applied.
; * SceneFinal Post-processing present at scene (bloom, fog, etc).
; * Depth Depth map ground-truth only.
@ -55,42 +69,39 @@ PostProcessing=SceneFinal
ImageSizeX=800
ImageSizeY=600
; Camera (horizontal) field of view in degrees.
CameraFOV=90
FOV=90
; Position of the camera relative to the car in centimeters.
CameraPositionX=15
CameraPositionY=0
CameraPositionZ=123
PositionX=15
PositionY=0
PositionZ=123
; Rotation of the camera relative to the car in degrees.
CameraRotationPitch=8
CameraRotationRoll=0
CameraRotationYaw=0
RotationPitch=8
RotationRoll=0
RotationYaw=0
; Stereo setup example:
;
; [CARLA/SceneCapture]
; Cameras=CameraStereoLeft/RGB,CameraStereoLeft/Depth,CameraStereoRight/RGB,CameraStereoRight/Depth
; ImageSizeX=720
; ImageSizeY=512
; CameraFOV=90
; [CARLA/SceneCapture/CameraStereoLeft]
; CameraPositionX=170
; CameraPositionY=-30
; CameraPositionZ=150
; CameraRotationPitch=0
; CameraRotationRoll=0
; CameraRotationYaw=0
; [CARLA/SceneCapture/CameraStereoLeft/RGB]
; PostProcessing=SceneFinal
; [CARLA/SceneCapture/CameraStereoLeft/Depth]
; PostProcessing=Depth
; [CARLA/SceneCapture/CameraStereoRight]
; CameraPositionX=170
; CameraPositionY=30
; CameraPositionZ=150
; CameraRotationPitch=0
; CameraRotationRoll=0
; CameraRotationYaw=0
; [CARLA/SceneCapture/CameraStereoRight/RGB]
; PostProcessing=SceneFinal
; [CARLA/SceneCapture/CameraStereoRight/Depth]
; PostProcessing=Depth
[CARLA/Sensor/MyCamera/Depth]
; The sensor can be defined in a subsection of MyCamera so it inherits the
; values in MyCamera. This adds a camera similar to MyCamera but generating
; depth map images instead.
PostProcessing=Depth
[CARLA/Sensor/MyLidar]
SensorType=LIDAR_RAY_TRACE
; Number of lasers.
Channels=32
; Measure distance in centimeters.
Range=5000
; Points generated by all lasers per second.
PointsPerSecond=100000
; Lidar rotation frequency.
RotationFrequency=10
; Upper and lower laser angles, positive values means above horizontal line.
UpperFOVLimit=10
LowerFOVLimit=-30
; Position and rotation relative to the vehicle.
PositionX=0
PositionY=0
PositionZ=140
RotationPitch=0
RotationYaw=0
RotationRoll=0

View File

@ -2,20 +2,20 @@ Cameras and sensors
===================
Cameras and sensors can be added to the player vehicle by defining them in the
settings file sent by the client on every new episode. Check out the examples at
[CARLA Settings example][settingslink].
settings sent by the client on every new episode. This can be done either by
filling a `CarlaSettings` Python class ([client_example.py][clientexamplelink])
or by loading an INI settings file ([CARLA Settings example][settingslink]).
This document describes the details of the different cameras/sensors currently
available as well as the resulting images produced by them.
Although we plan to extend the sensor suite of CARLA in the near future, at the
moment there are three different sensors available. These three sensors are
implemented as different post-processing effects applied to scene capture
cameras.
moment there are four different sensors available.
* [Scene final](#scene-final)
* [Depth map](#depth-map)
* [Semantic segmentation](#semantic-segmentation)
* [Camera: Scene final](#camera-scene-final)
* [Camera: Depth map](#camera-depth-map)
* [Camera: Semantic segmentation](#camera-semantic-segmentation)
* [Ray-trace based lidar](#ray-trace-based-lidar)
!!! note
The images are sent by the server as a BGRA array of bytes. The provided
@ -23,24 +23,27 @@ cameras.
parse the images and convert them to the desired format. There are some
examples in the PythonClient folder showing how to parse the images.
There is a fourth post-processing effect available, _None_, which provides a
view with of the scene with no effect, not even lens effects like flares or
depth of field; we will skip this one in the following descriptions.
There is a fourth post-processing effect available for cameras, _None_, which
provides a view with of the scene with no effect, not even scene lighting; we
will skip this one in the following descriptions.
We provide a tool to convert raw depth and semantic segmentation images to a
more human readable palette of colors. It can be found at
["Util/ImageConverter"][imgconvlink].
We provide a tool to convert raw depth and semantic segmentation images in bulk
to a more human readable palette of colors. It can be found at
["Util/ImageConverter"][imgconvlink]. Alternatively, they can also be converted
using the functions at `carla.image_converter` Python module.
[clientexamplelink]: https://github.com/carla-simulator/carla/blob/master/PythonClient/client_example.py
[settingslink]: https://github.com/carla-simulator/carla/blob/master/Docs/Example.CarlaSettings.ini
[imgconvlink]: https://github.com/carla-simulator/carla/tree/master/Util/ImageConverter
Scene final
-----------
Camera: Scene final
-------------------
![SceneFinal](img/capture_scenefinal.png)<br>
The "scene final" camera provides a view of the scene after applying some
post-processing effects to create a more realistic feel. These are actually
stored on the Level, in an actor called [PostProcessVolume][postprolink] and not
stored in the Level, in an actor called [PostProcessVolume][postprolink] and not
in the Camera. We use the following post process effects:
* **Vignette** Darkens the border of the screen.
@ -52,8 +55,39 @@ in the Camera. We use the following post process effects:
[postprolink]: https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/
Depth map
---------
###### Python
```py
camera = carla.sensor.Camera('MyCamera', PostProcessing='SceneFinal')
camera.set(FOV=90.0)
camera.set_image_size(800, 600)
camera.set_position(x=30, y=0, z=130)
camera.set_rotation(pitch=0, yaw=0, roll=0)
carla_settings.add_sensor(camera)
```
###### CarlaSettings.ini
```ini
[CARLA/Sensor/MyCamera]
SensorType=CAMERA
PostProcessing=SceneFinal
ImageSizeX=800
ImageSizeY=600
FOV=90
PositionX=30
PositionY=0
PositionZ=130
RotationPitch=0
RotationRoll=0
RotationYaw=0
```
Camera: Depth map
-----------------
![Depth](img/capture_depth.png)
The "depth map" camera provides an image with 24 bit floating precision point
codified in the 3 channels of the RGB color space. The order from less to more
@ -78,15 +112,50 @@ Our max render distance (far) is 1km.
Ans * far
Semantic segmentation
---------------------
The generated "depth map" images are usually converted to a logarithmic
grayscale for display. A point cloud can also be extracted from depth images as
seen in "PythonClient/point_cloud_example.py".
###### Python
```py
camera = carla.sensor.Camera('MyCamera', PostProcessing='Depth')
camera.set(FOV=90.0)
camera.set_image_size(800, 600)
camera.set_position(x=30, y=0, z=130)
camera.set_rotation(pitch=0, yaw=0, roll=0)
carla_settings.add_sensor(camera)
```
###### CarlaSettings.ini
```ini
[CARLA/Sensor/MyCamera]
SensorType=CAMERA
PostProcessing=Depth
ImageSizeX=800
ImageSizeY=600
FOV=90
PositionX=30
PositionY=0
PositionZ=130
RotationPitch=0
RotationRoll=0
RotationYaw=0
```
Camera: Semantic segmentation
-----------------------------
![SemanticSegmentation](img/capture_semseg.png)
The "semantic segmentation" camera classifies every object in the view by
displaying it in a different color according to the object class. E.g.,
pedestrians appear in a different color than vehicles.
The server provides an image with the tag information encoded in the red
channel. A pixel with a red value of x displays an object with tag x. The
The server provides an image with the tag information **encoded in the red
channel**. A pixel with a red value of x displays an object with tag x. The
following tags are currently available
Value | Tag
@ -106,6 +175,102 @@ Value | Tag
12 | TrafficSigns
This is implemented by tagging every object in the scene before hand (either at
begin play or on spawn). The objects are classified by their relative file
system path in the project. E.g., every mesh stored in the "pedestrians" folder
it's tagged as pedestrian.
begin play or on spawn). The objects are classified by their relative file path
in the project. E.g., every mesh stored in the
_"Unreal/CarlaUE4/Content/Static/Pedestrians"_ folder it's tagged as pedestrian.
!!! note
**Adding new tags**:
At the moment adding new tags is not very flexible and requires to modify
the C++ code. Add a new label to the `ECityObjectLabel` enum in "Tagger.h",
and its corresponding filepath check inside `GetLabelByFolderName()`
function in "Tagger.cpp".
###### Python
```py
camera = carla.sensor.Camera('MyCamera', PostProcessing='SemanticSegmentation')
camera.set(FOV=90.0)
camera.set_image_size(800, 600)
camera.set_position(x=30, y=0, z=130)
camera.set_rotation(pitch=0, yaw=0, roll=0)
carla_settings.add_sensor(camera)
```
###### CarlaSettings.ini
```ini
[CARLA/Sensor/MyCamera]
SensorType=CAMERA
PostProcessing=SemanticSegmentation
ImageSizeX=800
ImageSizeY=600
FOV=90
PositionX=30
PositionY=0
PositionZ=130
RotationPitch=0
RotationRoll=0
RotationYaw=0
```
Ray-trace based Lidar
---------------------
![LidarPointCloud](img/lidar_point_cloud.gif)
A rotating Lidar implemented with ray-tracing. The points are computed by adding
a laser for each channel distributed in the vertical FOV, then the rotation is
simulated computing the horizontal angle that the Lidar rotated this frame, and
doing a ray-cast for each point that each laser was supposed to generate this
frame; `PointsPerSecond / (FPS * Channels)`.
Each frame the server sends a packet with all the points generated during a
`1/FPS` interval. During the interval the physics wasnt updated so all the
points in a packet reflect the same "static picture" of the scene.
The received `LidarMeasurement` object contains the following information
Key | Type | Description
-------------------------- | ---------- | ------------
horizontal_angle | float | Angle in XY plane of the lidar this frame
channels | uint32 | Number of channels (lasers) of the lidar
point_count_by_channel | uint32 | Number of points per channel captured this frame
point_cloud | PointCloud | Captured points this frame
###### Python
```py
lidar = carla.sensor.Lidar('MyLidar')
lidar.set(
Channels=32,
Range=5000,
PointsPerSecond=100000,
RotationFrequency=10,
UpperFovLimit=10,
LowerFovLimit=-30)
lidar.set_position(x=0, y=0, z=140)
lidar.set_rotation(pitch=0, yaw=0, roll=0)
carla_settings.add_sensor(lidar)
```
###### CarlaSettings.ini
```ini
[CARLA/Sensor/MyLidar]
SensorType=LIDAR_RAY_TRACE
Channels=32
Range=5000
PointsPerSecond=100000
RotationFrequency=10
UpperFOVLimit=10
LowerFOVLimit=-30
PositionX=0
PositionY=0
PositionZ=140
RotationPitch=0
RotationYaw=0
RotationRoll=0
```

View File

@ -12,6 +12,10 @@ CARLA is composed by the following modules
- Carla plugin for Unreal Engine: "Unreal/CarlaUE4/Plugins/Carla"
- CarlaServer: "Util/CarlaServer"
!!! tip
Documentation for the C++ code can be generated by running
[Doxygen](http://www.doxygen.org) in the main folder of CARLA project.
Python client API
-----------------

89
Docs/carla_headless.md Normal file
View File

@ -0,0 +1,89 @@
Running CARLA without Display and Selecting GPUs
------
This tutorial is designed for:
- Remote server users that have several nvidia graphical cards and want to effectively use CARLA on all GPUs.
- Desktop users who want to use the GPU that is not plugged on the screen for rendering CARLA.
On this tutorial you will learn.
- How to configure your server to have nvidia working on rendering without a display attached.
- How to use VNC + VGL to simulate a display connected to any GPU you have in your machine.
- And Finally, how to run CARLA in this environment
This tutorial was tested in Ubuntu 16.04 and using NVIDIA 384.11 drivers.
## Preliminaries
A few things need to be working in your server before.
Latest NVIDIA Drivers, OpenGL, VirtualGL(VGL), TurboVNC 2.11, ,
#### NVIDIA Drivers
Download and install NVIDIA-drivers with typical tutorials
http://www.nvidia.es/Download/index.aspx
#### OpenGL
Openg GL is necessary for Virtual GL. Normally OpenGL
can be installed through apt.
sudo apt-get install freeglut3-dev mesa-utils
#### VGL
Follow this tutorial and install vgl: <br>
[Installing VGL](https://virtualgl.org/vgldoc/2_2_1/#hd004001)
#### TurboVNC
Follow the tutorial below to install TurboVNC 2.11:<br>
[Installing TurboVNC](https://cdn.rawgit.com/TurboVNC/turbovnc/2.1.1/doc/index.html#hd005001)
WARNING: Take care on which VNC you install as it may not be compatible with Unreal. The one above was the only one that worked for me.
#### Extra Packages
These extra packages were necessary to make unreal to work.
sudo apt install x11-xserver-utils libxrandr-dev
#### Configure your X
You must generate a X compatible with your nvdia and compatible to run without display. For that, the following command worked:
sudo nvidia-xconfig -a --use-display-device=None --virtual=1280x1024
## Emulating The Virtual Display
Run your own Xorg. Here I use number 7, but it could be labeled with any free number.
sudo nohup Xorg :7 &
Run an auxiliary remote VNC-Xserver. This will create a
virtual display "8".
/opt/TurboVNC/bin/vncserver :8
If everything is working fine the following command
should run smoothly.
DISPLAY=:8 vglrun -d :7.0 glxinfo
Note. This will run glxinfo on Xserver 7, device 0. This means you are selecting the GPU 0 on your machine. To run on other GPU, such as GPU 1 run:
DISPLAY=:8 vglrun -d :7.1 glxinfo
#### Extra
If you want disable the need of sudo when creating the 'nohup Xorg'
go to the '/etc/X11/Xwrapper.config' file and change 'allowed_users=console' to 'allowed_users=anybody'
It may be needed to stop all Xorg servers before running nohup Xorg.
The command for that could change depending on your system. Generally for Ubuntu 16.04
you should use:
sudo service lightdm stop
## Running CARLA
Now, finally, to run CARLA on a certain gpu_number placed in a certain $CARLA_PATH, run.
DISPLAY=:8 vglrun -d :7.<gpu_number> $CARLA_PATH/CarlaUE4/Binaries/Linux/CarlaUE4

View File

@ -48,10 +48,11 @@ Server only writes, first measurements message then the bulk of raw images.
Every image is an array of uint32's
[width, height, type, color[0], color[1],...]
[width, height, type, FOV, color[0], color[1],...]
where each color is an [FColor][fcolorlink] (BGRA) as stored in Unreal Engine,
and the possible types of images are
where FOV is the horizontal field of view of the camera as float, each color is
an [FColor][fcolorlink] (BGRA) as stored in Unreal Engine, and the possible
types of images are
type = 0 None (RGB without any post-processing)
type = 1 SceneFinal (RGB with post-processing present at the scene)

View File

@ -152,3 +152,52 @@ rebuild of all the project files with
It takes a long time but fixes the issue. Sometimes a reboot is also needed.
</details>
<!-- ======================================================================= -->
<details>
<summary><h5 style="display:inline">
Fatal error: 'carla/carla_server.h' file not found.
</h4></summary>
This indicates that the CarlaServer dependency failed to compile.
Please follow the instructions at
[How to build on Linux](http://carla.readthedocs.io/en/latest/how_to_build_on_linux/).
Make sure that the Setup script does print _"Success!"_ at the end
$ ./Setup.sh
...
...
****************
*** Success! ***
****************
Then check if CarlaServer compiles without errors running make
$ make
It should end printing something like
```
[1/1] Install the project...
-- Install configuration: "Release"
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++abi.so.1
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++abi.so.1.0
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++.so.1
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++.so.1.0
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++.so
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/shared/libc++abi.so
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/lib/libc++abi.a
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/lib/libboost_system.a
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/lib/libprotobuf.a
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/include/carla
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/include/carla/carla_server.h
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/lib/libcarlaserver.a
-- Installing: Unreal/CarlaUE4/Plugins/Carla/CarlaServer/bin/test_carlaserver
-- Set runtime path of "Unreal/CarlaUE4/Plugins/Carla/CarlaServer/bin/test_carlaserver" to ""
```
If so you can safely run Rebuild.sh.
</details>

View File

@ -20,15 +20,17 @@ change your default clang version to compile Unreal
Build Unreal Engine
-------------------
Download and compile Unreal Engine 4.17. Here we will assume you install it at
"~/UnrealEngine_4.17", but you can install it anywhere, just replace the path
!!! note
Unreal Engine repositories are set to private. In order to gain access you
need to add your GitHub username when you sign up at
[www.unrealengine.com](https://www.unrealengine.com).
Download and compile Unreal Engine 4.18. Here we will assume you install it at
"~/UnrealEngine_4.18", but you can install it anywhere, just replace the path
where necessary.
Unreal Engine repositories are set to private. In order to gain access you need
to add your GitHub username when you sign up at https://unrealengine.com.
$ git clone --depth=1 -b 4.17 https://github.com/EpicGames/UnrealEngine.git ~/UnrealEngine_4.17
$ cd ~/UnrealEngine_4.17
$ git clone --depth=1 -b 4.18 https://github.com/EpicGames/UnrealEngine.git ~/UnrealEngine_4.18
$ cd ~/UnrealEngine_4.18
$ ./Setup.sh && ./GenerateProjectFiles.sh && make
Check Unreal's documentation
@ -59,7 +61,7 @@ To build CARLA, use the rebuild script. This script deletes all intermediate
files, rebuilds whole CARLA, and launches the editor. Use it too for making a
clean rebuild of CARLA
$ UE4_ROOT=~/UnrealEngine_4.17 ./Rebuild.sh
$ UE4_ROOT=~/UnrealEngine_4.18 ./Rebuild.sh
It looks at the environment variable `UE4_ROOT` to find the right version of
Unreal Engine. You can also add this variable to your "~/.bashrc" or similar.
@ -89,7 +91,7 @@ Launching the editor
To open the editor once the project is already built
$ cd Unreal/CarlaUE4
$ ~/UnrealEngine_4.17/Engine/Binaries/Linux/UE4Editor "$PWD/CarlaUE4.uproject"
$ ~/UnrealEngine_4.18/Engine/Binaries/Linux/UE4Editor "$PWD/CarlaUE4.uproject"
Test (Optional)
---------------

BIN
Docs/img/capture_depth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
Docs/img/capture_semseg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,268 @@
// =============================================================================
// -- Unreal classes -----------------------------------------------------------
// =============================================================================
/**
* @hidden
* @opt nodefillcolor gray
*/
class UObject {}
/** @opt nodefillcolor gray */ class AAIController extends AController {}
/** @opt nodefillcolor gray */ class AActor extends UObject {}
/** @opt nodefillcolor gray */ class ACharacter extends APawn {}
/** @opt nodefillcolor gray */ class AController extends AActor {}
/** @opt nodefillcolor gray */ class AGameModeBase extends AActor {}
/** @opt nodefillcolor gray */ class AHUD extends AActor {}
/** @opt nodefillcolor gray */ class AInfo extends AActor {}
/** @opt nodefillcolor gray */ class APawn extends AActor {}
/** @opt nodefillcolor gray */ class APlayerController extends AController {}
/** @opt nodefillcolor gray */ class APlayerState extends AInfo {}
/** @opt nodefillcolor gray */ class AWheeledVehicle extends APawn {}
/** @opt nodefillcolor gray */ class UActorComponent extends UObject {}
/** @opt nodefillcolor gray */ class UCameraComponent extends USceneComponent {}
/** @opt nodefillcolor gray */ class UGameInstance extends UObject {}
/** @opt nodefillcolor gray */ class USceneComponent extends UActorComponent {}
// =============================================================================
// -- Agent --------------------------------------------------------------------
// =============================================================================
class UAgentComponent extends USceneComponent {}
class UTrafficSignAgentComponent extends UAgentComponent {}
class UVehicleAgentComponent extends UAgentComponent {}
class UWalkerAgentComponent extends UAgentComponent {}
// =============================================================================
// -- Game ---------------------------------------------------------------------
// =============================================================================
/**
* @has - - - FDataRouter
*/
class ICarlaGameControllerBase {}
/**
* @composed - - - ICarlaGameControllerBase
* @composed - - - FDataRouter
* @composed - - - UCarlaSettings
*/
class UCarlaGameInstance extends UGameInstance {}
// * @has - Player - ACarlaVehicleController
/**
* @depend - - - UCarlaGameInstance
* @composed - - - UTaggerDelegate
* @composed - - - ADynamicWeather
* @composed - - - AVehicleSpawnerBase
* @composed - - - AWalkerSpawnerBase
*/
class ACarlaGameModeBase extends AGameModeBase {}
class ACarlaHUD extends AHUD {}
class ACarlaPlayerState extends APlayerState {}
/**
* @depend - - - UAgentComponent
* @depend - - - ACarlaVehicleController
* @composed - - - ISensorDataSink
*/
class FDataRouter {}
/**
* @composed - - - FMockSensorDataSink
*/
class MockGameController extends ICarlaGameControllerBase {}
class FMockSensorDataSink extends ISensorDataSink {}
/**
* @depend - - - ATagger
*/
class UTaggerDelegate extends UObject {}
class ATagger /*extends AActor*/ {}
// =============================================================================
// -- MapGen -------------------------------------------------------------------
// =============================================================================
// MapGen is ignored here.
// =============================================================================
// -- Sensor -------------------------------------------------------------------
// =============================================================================
class ALidar extends ASensor {}
class ASceneCaptureCamera extends ASensor {}
/**
* @depend - - - ISensorDataSink
*/
class ASensor extends AActor {}
class ISensorDataSink {}
// =============================================================================
// -- Server -------------------------------------------------------------------
// =============================================================================
/**
* @depend - - - CarlaServerAPI
*/
class FCarlaServer {}
/**
* @composed - - - FCarlaServer
* @has - - - FServerSensorDataSink
*/
class FServerGameController extends ICarlaGameControllerBase {}
/**
* @depend - - - FCarlaServer
*/
class FServerSensorDataSink extends ISensorDataSink {}
/**
* CarlaServer
* Library API
* @opt commentname
* @opt nodefillcolor #fdf6e3
*/
class CarlaServerAPI {}
// =============================================================================
// -- Settings -----------------------------------------------------------------
// =============================================================================
class UCameraDescription extends USensorDescription {}
/**
* @composed - - - USensorDescription
*/
class UCarlaSettings extends UObject {}
class ULidarDescription extends USensorDescription {}
class USensorDescription extends UObject {}
// =============================================================================
// -- Traffic ------------------------------------------------------------------
// =============================================================================
class ATrafficLightBase extends ATrafficSignBase {}
/**
* @composed - - - UTrafficSignAgentComponent
*/
class ATrafficSignBase extends AActor {}
// =============================================================================
// -- Util ---------------------------------------------------------------------
// =============================================================================
class AActorWithRandomEngine extends AActor {}
// =============================================================================
// -- Vehicle ------------------------------------------------------------------
// =============================================================================
/**
* @has - - - ACarlaPlayerState
* @has - - - ACarlaHUD
*/
class ACarlaVehicleController extends AWheeledVehicleController {}
/**
* @composed - - - UVehicleAgentComponent
*/
class ACarlaWheeledVehicle extends AWheeledVehicle {}
/**
* @has - - - ACarlaWheeledVehicle
*/
class AVehicleSpawnerBase extends AActorWithRandomEngine {}
/**
* @has - - - ACarlaWheeledVehicle
*/
class AWheeledVehicleAIController extends APlayerController {}
/**
* @composed - - - UCameraComponent
*/
class AWheeledVehicleController extends AWheeledVehicleAIController {}
// =============================================================================
// -- Walker -------------------------------------------------------------------
// =============================================================================
/**
* @has - - - ACharacter
*/
class AWalkerAIController extends AAIController {}
/**
* @has - - - ACharacter
*/
class AWalkerSpawnerBase extends AActorWithRandomEngine {}
// =============================================================================
// -- Blueprints ---------------------------------------------------------------
// =============================================================================
/**
* Carla Game Mode
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class CarlaGameMode extends ACarlaGameModeBase {}
/**
* Speed Limit Sign
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class SpeedLimitSignBlueprint extends ATrafficSignBase {}
/**
* Traffic Light
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class TrafficLightBlueprint extends ATrafficLightBase {}
/**
* Vehicle Blueprints
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class VehicleBlueprints extends ACarlaWheeledVehicle {}
/**
* Vehicle Spawner
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class VehicleSpawnerBlueprint extends AVehicleSpawnerBase {}
/**
* Walker Blueprints
* @opt commentname
* @opt nodefillcolor #bfe4ff
* @composed - - - UWalkerAgentComponent
*/
class WalkerBlueprints extends ACharacter {}
/**
* Walker Spawner
* @opt commentname
* @opt nodefillcolor #bfe4ff
*/
class WalkerSpawnerBlueprint extends AWalkerSpawnerBase {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View File

@ -7,6 +7,7 @@ CARLA Documentation
* [CARLA settings](carla_settings.md)
* [Measurements](measurements.md)
* [Cameras and sensors](cameras_and_sensors.md)
* [CARLA without Display and Selecting GPUs](carla_headless.md)
* [Benchmark](benchmark.md)
* [F.A.Q.](faq.md)

View File

@ -6,4 +6,7 @@ If you are asking a question please make sure your question was not asked before
by searching among the existing issues. Also make sure you have read our
documentation and FAQ at carla.readthedocs.io.
If you are reporting an issue, please provide the CARLA version number you are
using and your Platform/OS.
-->

View File

@ -88,9 +88,9 @@ run_test_release:
launch_test_clients:
@echo "Launch echo client"
@python3 $(PYTHON_CLIENT_FOLDER)/test_client.py --echo -p 4000 --log echo_client.log & echo $$! > echo_client.pid
@python3 $(PYTHON_CLIENT_FOLDER)/test_client.py --echo -v -p 4000 --log echo_client.log & echo $$! > echo_client.pid
@echo "Launch carla client"
@python3 $(PYTHON_CLIENT_FOLDER)/test_client.py -p 2000 --log carla_client.log & echo $$! > carla_client.pid
@python3 $(PYTHON_CLIENT_FOLDER)/test_client.py -v -p 2000 --log carla_client.log & echo $$! > carla_client.pid
kill_test_clients:
@echo "Kill echo client"

View File

@ -120,9 +120,15 @@ if $DO_COPY_FILES ; then
cp -v ./Docs/Example.CarlaSettings.ini ${DESTINATION}/Example.CarlaSettings.ini
rsync -vhr --delete --delete-excluded \
--exclude "__pycache__" \
--exclude "*.egg-info" \
--exclude "*.log" \
--exclude "*.pyc" \
--exclude ".*" \
--exclude ".tags*" \
--exclude "__pycache__" \
--exclude "_benchmarks_results*" \
--exclude "_images*" \
--exclude "_out*" \
PythonClient/ ${DESTINATION}/PythonClient
echo

View File

@ -1,4 +1,4 @@
[TYPECHECK]
ignore=carla_server_pb2.py
ignored-modules=ConfigParser,numpy,numpy.random,pygame,shutil
ignored-classes=_socketobject,EpisodeReady
ignored-classes=_socketobject,EpisodeReady,SceneDescription,Sensor

View File

@ -138,7 +138,7 @@ class CoRL2017(Benchmark):
# This single RGB camera is used on every experiment
camera = Camera('CameraRGB')
camera.set(CameraFOV=100)
camera.set(FOV=100)
camera.set_image_size(800, 600)

View File

@ -19,11 +19,37 @@ DESCRIPTOR = _descriptor.FileDescriptor(
name='carla_server.proto',
package='carla_server',
syntax='proto3',
serialized_pb=_b('\n\x12\x63\x61rla_server.proto\x12\x0c\x63\x61rla_server\"+\n\x08Vector3D\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"6\n\nRotation3D\x12\r\n\x05pitch\x18\x01 \x01(\x02\x12\x0b\n\x03yaw\x18\x02 \x01(\x02\x12\x0c\n\x04roll\x18\x03 \x01(\x02\"\x92\x01\n\tTransform\x12(\n\x08location\x18\x01 \x01(\x0b\x32\x16.carla_server.Vector3D\x12/\n\x0borientation\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3DB\x02\x18\x01\x12*\n\x08rotation\x18\x03 \x01(\x0b\x32\x18.carla_server.Rotation3D\"x\n\x07Vehicle\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12*\n\nbox_extent\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x03 \x01(\x02\"{\n\nPedestrian\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12*\n\nbox_extent\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x03 \x01(\x02\"\x94\x01\n\x0cTrafficLight\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12/\n\x05state\x18\x02 \x01(\x0e\x32 .carla_server.TrafficLight.State\"\'\n\x05State\x12\t\n\x05GREEN\x10\x00\x12\n\n\x06YELLOW\x10\x01\x12\x07\n\x03RED\x10\x02\"Q\n\x0eSpeedLimitSign\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12\x13\n\x0bspeed_limit\x18\x02 \x01(\x02\"\xe5\x01\n\x05\x41gent\x12\n\n\x02id\x18\x01 \x01(\x07\x12(\n\x07vehicle\x18\x02 \x01(\x0b\x32\x15.carla_server.VehicleH\x00\x12.\n\npedestrian\x18\x03 \x01(\x0b\x32\x18.carla_server.PedestrianH\x00\x12\x33\n\rtraffic_light\x18\x04 \x01(\x0b\x32\x1a.carla_server.TrafficLightH\x00\x12\x38\n\x10speed_limit_sign\x18\x05 \x01(\x0b\x32\x1c.carla_server.SpeedLimitSignH\x00\x42\x07\n\x05\x61gent\"%\n\x11RequestNewEpisode\x12\x10\n\x08ini_file\x18\x01 \x01(\t\"G\n\x10SceneDescription\x12\x33\n\x12player_start_spots\x18\x01 \x03(\x0b\x32\x17.carla_server.Transform\"/\n\x0c\x45pisodeStart\x12\x1f\n\x17player_start_spot_index\x18\x01 \x01(\r\"\x1d\n\x0c\x45pisodeReady\x12\r\n\x05ready\x18\x01 \x01(\x08\"^\n\x07\x43ontrol\x12\r\n\x05steer\x18\x01 \x01(\x02\x12\x10\n\x08throttle\x18\x02 \x01(\x02\x12\r\n\x05\x62rake\x18\x03 \x01(\x02\x12\x12\n\nhand_brake\x18\x04 \x01(\x08\x12\x0f\n\x07reverse\x18\x05 \x01(\x08\"\x8a\x04\n\x0cMeasurements\x12\x1a\n\x12platform_timestamp\x18\x01 \x01(\r\x12\x16\n\x0egame_timestamp\x18\x02 \x01(\r\x12J\n\x13player_measurements\x18\x03 \x01(\x0b\x32-.carla_server.Measurements.PlayerMeasurements\x12.\n\x11non_player_agents\x18\x04 \x03(\x0b\x32\x13.carla_server.Agent\x1a\xc9\x02\n\x12PlayerMeasurements\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12,\n\x0c\x61\x63\x63\x65leration\x18\x03 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x04 \x01(\x02\x12\x1a\n\x12\x63ollision_vehicles\x18\x05 \x01(\x02\x12\x1d\n\x15\x63ollision_pedestrians\x18\x06 \x01(\x02\x12\x17\n\x0f\x63ollision_other\x18\x07 \x01(\x02\x12\x1e\n\x16intersection_otherlane\x18\x08 \x01(\x02\x12\x1c\n\x14intersection_offroad\x18\t \x01(\x02\x12\x30\n\x11\x61utopilot_control\x18\n \x01(\x0b\x32\x15.carla_server.ControlB\x03\xf8\x01\x01\x62\x06proto3')
serialized_pb=_b('\n\x12\x63\x61rla_server.proto\x12\x0c\x63\x61rla_server\"+\n\x08Vector3D\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"6\n\nRotation3D\x12\r\n\x05pitch\x18\x01 \x01(\x02\x12\x0b\n\x03yaw\x18\x02 \x01(\x02\x12\x0c\n\x04roll\x18\x03 \x01(\x02\"\x92\x01\n\tTransform\x12(\n\x08location\x18\x01 \x01(\x0b\x32\x16.carla_server.Vector3D\x12/\n\x0borientation\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3DB\x02\x18\x01\x12*\n\x08rotation\x18\x03 \x01(\x0b\x32\x18.carla_server.Rotation3D\"\x81\x01\n\x06Sensor\x12\n\n\x02id\x18\x01 \x01(\x07\x12\'\n\x04type\x18\x02 \x01(\x0e\x32\x19.carla_server.Sensor.Type\x12\x0c\n\x04name\x18\x03 \x01(\t\"4\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x43\x41MERA\x10\x01\x12\x13\n\x0fLIDAR_RAY_TRACE\x10\x02\"x\n\x07Vehicle\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12*\n\nbox_extent\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x03 \x01(\x02\"{\n\nPedestrian\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12*\n\nbox_extent\x18\x02 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x03 \x01(\x02\"\x94\x01\n\x0cTrafficLight\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12/\n\x05state\x18\x02 \x01(\x0e\x32 .carla_server.TrafficLight.State\"\'\n\x05State\x12\t\n\x05GREEN\x10\x00\x12\n\n\x06YELLOW\x10\x01\x12\x07\n\x03RED\x10\x02\"Q\n\x0eSpeedLimitSign\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12\x13\n\x0bspeed_limit\x18\x02 \x01(\x02\"\xe5\x01\n\x05\x41gent\x12\n\n\x02id\x18\x01 \x01(\x07\x12(\n\x07vehicle\x18\x02 \x01(\x0b\x32\x15.carla_server.VehicleH\x00\x12.\n\npedestrian\x18\x03 \x01(\x0b\x32\x18.carla_server.PedestrianH\x00\x12\x33\n\rtraffic_light\x18\x04 \x01(\x0b\x32\x1a.carla_server.TrafficLightH\x00\x12\x38\n\x10speed_limit_sign\x18\x05 \x01(\x0b\x32\x1c.carla_server.SpeedLimitSignH\x00\x42\x07\n\x05\x61gent\"%\n\x11RequestNewEpisode\x12\x10\n\x08ini_file\x18\x01 \x01(\t\"n\n\x10SceneDescription\x12\x33\n\x12player_start_spots\x18\x01 \x03(\x0b\x32\x17.carla_server.Transform\x12%\n\x07sensors\x18\x02 \x03(\x0b\x32\x14.carla_server.Sensor\"/\n\x0c\x45pisodeStart\x12\x1f\n\x17player_start_spot_index\x18\x01 \x01(\r\"\x1d\n\x0c\x45pisodeReady\x12\r\n\x05ready\x18\x01 \x01(\x08\"^\n\x07\x43ontrol\x12\r\n\x05steer\x18\x01 \x01(\x02\x12\x10\n\x08throttle\x18\x02 \x01(\x02\x12\r\n\x05\x62rake\x18\x03 \x01(\x02\x12\x12\n\nhand_brake\x18\x04 \x01(\x08\x12\x0f\n\x07reverse\x18\x05 \x01(\x08\"\x8a\x04\n\x0cMeasurements\x12\x1a\n\x12platform_timestamp\x18\x01 \x01(\r\x12\x16\n\x0egame_timestamp\x18\x02 \x01(\r\x12J\n\x13player_measurements\x18\x03 \x01(\x0b\x32-.carla_server.Measurements.PlayerMeasurements\x12.\n\x11non_player_agents\x18\x04 \x03(\x0b\x32\x13.carla_server.Agent\x1a\xc9\x02\n\x12PlayerMeasurements\x12*\n\ttransform\x18\x01 \x01(\x0b\x32\x17.carla_server.Transform\x12,\n\x0c\x61\x63\x63\x65leration\x18\x03 \x01(\x0b\x32\x16.carla_server.Vector3D\x12\x15\n\rforward_speed\x18\x04 \x01(\x02\x12\x1a\n\x12\x63ollision_vehicles\x18\x05 \x01(\x02\x12\x1d\n\x15\x63ollision_pedestrians\x18\x06 \x01(\x02\x12\x17\n\x0f\x63ollision_other\x18\x07 \x01(\x02\x12\x1e\n\x16intersection_otherlane\x18\x08 \x01(\x02\x12\x1c\n\x14intersection_offroad\x18\t \x01(\x02\x12\x30\n\x11\x61utopilot_control\x18\n \x01(\x0b\x32\x15.carla_server.ControlB\x03\xf8\x01\x01\x62\x06proto3')
)
_SENSOR_TYPE = _descriptor.EnumDescriptor(
name='Type',
full_name='carla_server.Sensor.Type',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='UNKNOWN', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CAMERA', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LIDAR_RAY_TRACE', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=364,
serialized_end=416,
)
_sym_db.RegisterEnumDescriptor(_SENSOR_TYPE)
_TRAFFICLIGHT_STATE = _descriptor.EnumDescriptor(
name='State',
full_name='carla_server.TrafficLight.State',
@ -45,8 +71,8 @@ _TRAFFICLIGHT_STATE = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=643,
serialized_end=682,
serialized_start=775,
serialized_end=814,
)
_sym_db.RegisterEnumDescriptor(_TRAFFICLIGHT_STATE)
@ -186,6 +212,52 @@ _TRANSFORM = _descriptor.Descriptor(
)
_SENSOR = _descriptor.Descriptor(
name='Sensor',
full_name='carla_server.Sensor',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='carla_server.Sensor.id', index=0,
number=1, type=7, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='type', full_name='carla_server.Sensor.type', index=1,
number=2, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='name', full_name='carla_server.Sensor.name', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
_SENSOR_TYPE,
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=287,
serialized_end=416,
)
_VEHICLE = _descriptor.Descriptor(
name='Vehicle',
full_name='carla_server.Vehicle',
@ -226,8 +298,8 @@ _VEHICLE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=286,
serialized_end=406,
serialized_start=418,
serialized_end=538,
)
@ -271,8 +343,8 @@ _PEDESTRIAN = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=408,
serialized_end=531,
serialized_start=540,
serialized_end=663,
)
@ -310,8 +382,8 @@ _TRAFFICLIGHT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=534,
serialized_end=682,
serialized_start=666,
serialized_end=814,
)
@ -348,8 +420,8 @@ _SPEEDLIMITSIGN = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=684,
serialized_end=765,
serialized_start=816,
serialized_end=897,
)
@ -410,8 +482,8 @@ _AGENT = _descriptor.Descriptor(
name='agent', full_name='carla_server.Agent.agent',
index=0, containing_type=None, fields=[]),
],
serialized_start=768,
serialized_end=997,
serialized_start=900,
serialized_end=1129,
)
@ -441,8 +513,8 @@ _REQUESTNEWEPISODE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=999,
serialized_end=1036,
serialized_start=1131,
serialized_end=1168,
)
@ -460,6 +532,13 @@ _SCENEDESCRIPTION = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='sensors', full_name='carla_server.SceneDescription.sensors', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
@ -472,8 +551,8 @@ _SCENEDESCRIPTION = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1038,
serialized_end=1109,
serialized_start=1170,
serialized_end=1280,
)
@ -503,8 +582,8 @@ _EPISODESTART = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1111,
serialized_end=1158,
serialized_start=1282,
serialized_end=1329,
)
@ -534,8 +613,8 @@ _EPISODEREADY = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1160,
serialized_end=1189,
serialized_start=1331,
serialized_end=1360,
)
@ -593,8 +672,8 @@ _CONTROL = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1191,
serialized_end=1285,
serialized_start=1362,
serialized_end=1456,
)
@ -680,8 +759,8 @@ _MEASUREMENTS_PLAYERMEASUREMENTS = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1481,
serialized_end=1810,
serialized_start=1652,
serialized_end=1981,
)
_MEASUREMENTS = _descriptor.Descriptor(
@ -731,13 +810,15 @@ _MEASUREMENTS = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=1288,
serialized_end=1810,
serialized_start=1459,
serialized_end=1981,
)
_TRANSFORM.fields_by_name['location'].message_type = _VECTOR3D
_TRANSFORM.fields_by_name['orientation'].message_type = _VECTOR3D
_TRANSFORM.fields_by_name['rotation'].message_type = _ROTATION3D
_SENSOR.fields_by_name['type'].enum_type = _SENSOR_TYPE
_SENSOR_TYPE.containing_type = _SENSOR
_VEHICLE.fields_by_name['transform'].message_type = _TRANSFORM
_VEHICLE.fields_by_name['box_extent'].message_type = _VECTOR3D
_PEDESTRIAN.fields_by_name['transform'].message_type = _TRANSFORM
@ -763,6 +844,7 @@ _AGENT.oneofs_by_name['agent'].fields.append(
_AGENT.fields_by_name['speed_limit_sign'])
_AGENT.fields_by_name['speed_limit_sign'].containing_oneof = _AGENT.oneofs_by_name['agent']
_SCENEDESCRIPTION.fields_by_name['player_start_spots'].message_type = _TRANSFORM
_SCENEDESCRIPTION.fields_by_name['sensors'].message_type = _SENSOR
_MEASUREMENTS_PLAYERMEASUREMENTS.fields_by_name['transform'].message_type = _TRANSFORM
_MEASUREMENTS_PLAYERMEASUREMENTS.fields_by_name['acceleration'].message_type = _VECTOR3D
_MEASUREMENTS_PLAYERMEASUREMENTS.fields_by_name['autopilot_control'].message_type = _CONTROL
@ -772,6 +854,7 @@ _MEASUREMENTS.fields_by_name['non_player_agents'].message_type = _AGENT
DESCRIPTOR.message_types_by_name['Vector3D'] = _VECTOR3D
DESCRIPTOR.message_types_by_name['Rotation3D'] = _ROTATION3D
DESCRIPTOR.message_types_by_name['Transform'] = _TRANSFORM
DESCRIPTOR.message_types_by_name['Sensor'] = _SENSOR
DESCRIPTOR.message_types_by_name['Vehicle'] = _VEHICLE
DESCRIPTOR.message_types_by_name['Pedestrian'] = _PEDESTRIAN
DESCRIPTOR.message_types_by_name['TrafficLight'] = _TRAFFICLIGHT
@ -806,6 +889,13 @@ Transform = _reflection.GeneratedProtocolMessageType('Transform', (_message.Mess
))
_sym_db.RegisterMessage(Transform)
Sensor = _reflection.GeneratedProtocolMessageType('Sensor', (_message.Message,), dict(
DESCRIPTOR = _SENSOR,
__module__ = 'carla_server_pb2'
# @@protoc_insertion_point(class_scope:carla_server.Sensor)
))
_sym_db.RegisterMessage(Sensor)
Vehicle = _reflection.GeneratedProtocolMessageType('Vehicle', (_message.Message,), dict(
DESCRIPTOR = _VEHICLE,
__module__ = 'carla_server_pb2'

View File

@ -6,12 +6,12 @@
"""CARLA Client."""
import logging
import struct
from contextlib import contextmanager
from . import sensor
from . import settings
from . import tcp
from . import util
@ -20,6 +20,11 @@ try:
except ImportError:
raise RuntimeError('cannot import "carla_server_pb2.py", run the protobuf compiler to generate this file')
try:
import numpy
except ImportError:
raise RuntimeError('cannot import numpy, make sure numpy package is installed.')
VehicleControl = carla_protocol.Control
@ -40,7 +45,7 @@ class CarlaClient(object):
self._control_client = tcp.TCPClient(host, world_port + 2, timeout)
self._current_settings = None
self._is_episode_requested = False
self._sensor_names = []
self._sensors = {}
def connect(self, connection_attempts=10):
"""
@ -69,7 +74,6 @@ class CarlaClient(object):
self._current_settings = carla_settings
return self._request_new_episode(carla_settings)
def start_episode(self, player_start_index):
"""
Start the new episode at the player start given by the
@ -120,8 +124,7 @@ class CarlaClient(object):
pb_message = carla_protocol.Measurements()
pb_message.ParseFromString(data)
# Read sensor data.
raw_sensor_data = self._stream_client.read()
return pb_message, self._parse_raw_sensor_data(raw_sensor_data)
return pb_message, dict(x for x in self._read_sensor_data())
def send_control(self, *args, **kwargs):
"""
@ -159,30 +162,66 @@ class CarlaClient(object):
raise RuntimeError('failed to read data from server')
pb_message = carla_protocol.SceneDescription()
pb_message.ParseFromString(data)
self._sensor_names = settings.get_sensor_names(carla_settings)
self._sensors = dict((sensor.id, sensor) \
for sensor in _make_sensor_parsers(pb_message.sensors))
self._is_episode_requested = True
return pb_message
def _parse_raw_sensor_data(self, raw_data):
"""Return a dict of {'sensor_name': sensor_data, ...}."""
return dict((name, data) for name, data in zip(
self._sensor_names,
self._iterate_sensor_data(raw_data)))
def _read_sensor_data(self):
while True:
data = self._stream_client.read()
if not data:
raise StopIteration
yield self._parse_sensor_data(data)
@staticmethod
def _iterate_sensor_data(raw_data):
# At this point the only sensors available are images, the raw_data
# consists of images only.
image_types = ['None', 'SceneFinal', 'Depth', 'SemanticSegmentation']
gettype = lambda id: image_types[id] if len(image_types) > id else 'Unknown'
getval = lambda index: struct.unpack('<L', raw_data[index*4:index*4+4])[0]
total_size = len(raw_data) / 4
index = 0
while index < total_size:
width = getval(index)
height = getval(index + 1)
image_type = gettype(getval(index + 2))
begin = index + 3
end = begin + width * height
index = end
yield sensor.Image(width, height, image_type, raw_data[begin*4:end*4])
def _parse_sensor_data(self, data):
sensor_id = struct.unpack('<L', data[0:4])[0]
parser = self._sensors[sensor_id]
return parser.name, parser.parse_raw_data(data[4:])
def _make_sensor_parsers(sensors):
image_types = ['None', 'SceneFinal', 'Depth', 'SemanticSegmentation']
getimgtype = lambda id: image_types[id] if len(image_types) > id else 'Unknown'
getint = lambda data, index: struct.unpack('<L', data[index*4:index*4+4])[0]
getfloat = lambda data, index: struct.unpack('<f', data[index*4:index*4+4])[0]
def parse_image(data):
width = getint(data, 0)
height = getint(data, 1)
image_type = getimgtype(getint(data, 2))
fov = getfloat(data, 3)
return sensor.Image(width, height, image_type, fov, data[16:])
def parse_lidar(data):
horizontal_angle = getfloat(data, 0)
channels = getint(data, 1)
point_count_by_channel = numpy.frombuffer(
data[8:8+channels*4],
dtype=numpy.dtype('uint32'))
points = numpy.frombuffer(
data[8+channels*4:],
dtype=numpy.dtype('f4'))
points = numpy.reshape(points, (int(points.shape[0]/3), 3))
return sensor.LidarMeasurement(
horizontal_angle,
channels,
point_count_by_channel,
sensor.PointCloud(points))
class SensorDefinition(object):
def __init__(self, s):
self.id = s.id
self.name = s.name
self.type = s.type
self.parse_raw_data = lambda x: x
for s in sensors:
sensor_def = SensorDefinition(s)
if sensor_def.type == carla_protocol.Sensor.CAMERA:
sensor_def.parse_raw_data = parse_image
elif sensor_def.type == carla_protocol.Sensor.LIDAR_RAY_TRACE:
sensor_def.parse_raw_data = parse_lidar
else:
logging.error('unknown sensor type %s', sensor_def.type)
yield sensor_def

View File

@ -13,9 +13,11 @@ them afterwards with the C++ implementation at "Util/ImageConverter" as it
provides considerably better performance.
"""
import math
try:
import numpy
from numpy.matlib import repmat
except ImportError:
raise RuntimeError('cannot import numpy, make sure numpy package is installed')
@ -55,19 +57,19 @@ def labels_to_cityscapes_palette(image):
Cityscapes palette.
"""
classes = {
0: [0, 0, 0], # None
1: [70, 70, 70], # Buildings
2: [190, 153, 153], # Fences
3: [72, 0, 90], # Other
4: [220, 20, 60], # Pedestrians
5: [153, 153, 153], # Poles
6: [157, 234, 50], # RoadLines
7: [128, 64, 128], # Roads
8: [244, 35, 232], # Sidewalks
9: [107, 142, 35], # Vegetation
10: [0, 0, 255], # Vehicles
11: [102, 102, 156], # Walls
12: [220, 220, 0] # TrafficSigns
0: [0, 0, 0], # None
1: [70, 70, 70], # Buildings
2: [190, 153, 153], # Fences
3: [72, 0, 90], # Other
4: [220, 20, 60], # Pedestrians
5: [153, 153, 153], # Poles
6: [157, 234, 50], # RoadLines
7: [128, 64, 128], # Roads
8: [244, 35, 232], # Sidewalks
9: [107, 142, 35], # Vegetation
10: [0, 0, 255], # Vehicles
11: [102, 102, 156], # Walls
12: [220, 220, 0] # TrafficSigns
}
array = labels_to_array(image)
result = numpy.zeros((array.shape[0], array.shape[1], 3))
@ -84,20 +86,74 @@ def depth_to_array(image):
array = to_bgra_array(image)
array = array.astype(numpy.float32)
# Apply (R + G * 256 + B * 256 * 256) / (256 * 256 * 256 - 1).
grayscale = numpy.dot(array[:, :, :3], [256.0 * 256.0, 256.0, 1.0])
grayscale /= (256.0 * 256.0 * 256.0 - 1.0)
return grayscale
normalized_depth = numpy.dot(array[:, :, :3], [65536.0, 256.0, 1.0])
normalized_depth /= 16777215.0 # (256.0 * 256.0 * 256.0 - 1.0)
return normalized_depth
def depth_to_logarithmic_grayscale(image):
"""
Convert an image containing CARLA encoded depth-map to a logarithmic
grayscale image array.
"max_depth" is used to omit the points that are far enough.
"""
grayscale = depth_to_array(image)
normalized_depth = depth_to_array(image)
# Convert to logarithmic depth.
logdepth = numpy.ones(grayscale.shape) + (numpy.log(grayscale) / 5.70378)
logdepth = numpy.ones(normalized_depth.shape) + \
(numpy.log(normalized_depth) / 5.70378)
logdepth = numpy.clip(logdepth, 0.0, 1.0)
logdepth *= 255.0
# Expand to three colors.
return numpy.repeat(logdepth[:, :, numpy.newaxis], 3, axis=2)
def depth_to_local_point_cloud(image, color=None, max_depth=0.9):
"""
Convert an image containing CARLA encoded depth-map to a 2D array containing
the 3D position (relative to the camera) of each pixel and its corresponding
RGB color of an array.
"max_depth" is used to omit the points that are far enough.
"""
far = 100000.0 # max depth in centimeters
normalized_depth = depth_to_array(image)
# (Intrinsic) K Matrix
k = numpy.identity(3)
k[0, 2] = image.width / 2.0
k[1, 2] = image.height / 2.0
k[0, 0] = k[1, 1] = image.width / \
(2.0 * math.tan(image.fov * math.pi / 360.0))
# 2d pixel coordinates
pixel_length = image.width * image.height
u_coord = repmat(numpy.r_[image.width-1:-1:-1],
image.height, 1).reshape(pixel_length)
v_coord = repmat(numpy.c_[image.height-1:-1:-1],
1, image.width).reshape(pixel_length)
if color is not None:
color = color.reshape(pixel_length, 3)
normalized_depth = numpy.reshape(normalized_depth, pixel_length)
# Search for pixels where the depth is greater than max_depth to
# delete them
max_depth_indexes = numpy.where(normalized_depth > max_depth)
normalized_depth = numpy.delete(normalized_depth, max_depth_indexes)
u_coord = numpy.delete(u_coord, max_depth_indexes)
v_coord = numpy.delete(v_coord, max_depth_indexes)
if color is not None:
color = numpy.delete(color, max_depth_indexes, axis=0)
# pd2 = [u,v,1]
p2d = numpy.array([u_coord, v_coord, numpy.ones_like(u_coord)])
# P = [X,Y,Z]
p3d = numpy.dot(numpy.linalg.inv(k), p2d)
p3d *= normalized_depth * far
# Formating the output to:
# [[X1,Y1,Z1,R1,G1,B1],[X2,Y2,Z2,R2,G2,B2], ... [Xn,Yn,Zn,Rn,Gn,Bn]]
if color is not None:
# numpy.concatenate((numpy.transpose(p3d), color), axis=1)
return sensor.PointCloud(numpy.transpose(p3d), color_array=color)
# [[X1,Y1,Z1],[X2,Y2,Z2], ... [Xn,Yn,Zn]]
return sensor.PointCloud(numpy.transpose(p3d))

View File

@ -9,6 +9,32 @@
import os
from collections import namedtuple
try:
import numpy
except ImportError:
raise RuntimeError('cannot import numpy, make sure numpy package is installed.')
from .transform import Transform, Translation, Rotation, Scale
# ==============================================================================
# -- Helpers -------------------------------------------------------------------
# ==============================================================================
Color = namedtuple('Color', 'r g b')
Color.__new__.__defaults__ = (0, 0, 0)
Point = namedtuple('Point', 'x y z color')
Point.__new__.__defaults__ = (0.0, 0.0, 0.0, None)
def _append_extension(filename, ext):
return filename if filename.lower().endswith(ext.lower()) else filename + ext
# ==============================================================================
# -- Sensor --------------------------------------------------------------------
@ -19,7 +45,51 @@ class Sensor(object):
"""
Base class for sensor descriptions. Used to add sensors to CarlaSettings.
"""
pass
def __init__(self, name, sensor_type):
self.SensorName = name
self.SensorType = sensor_type
self.PositionX = 140.0
self.PositionY = 0.0
self.PositionZ = 140.0
self.RotationPitch = 0.0
self.RotationRoll = 0.0
self.RotationYaw = 0.0
def set(self, **kwargs):
for key, value in kwargs.items():
if not hasattr(self, key):
raise ValueError('sensor.Sensor: no key named %r' % key)
setattr(self, key, value)
def set_position(self, x, y, z):
self.PositionX = x
self.PositionY = y
self.PositionZ = z
def set_rotation(self, pitch, yaw, roll):
self.RotationPitch = pitch
self.RotationYaw = yaw
self.RotationRoll = roll
def get_transform(self):
'''
Returns the camera to [whatever the camera is attached to]
transformation.
'''
return Transform(
Translation(self.PositionX, self.PositionY, self.PositionZ),
Rotation(self.RotationPitch, self.RotationYaw, self.RotationRoll))
def get_unreal_transform(self):
'''
Returns the camera to [whatever the camera is attached to]
transformation with the Unreal necessary corrections applied.
@todo Do we need to expose this?
'''
to_unreal_transform = Transform(Rotation(roll=-90, yaw=90), Scale(x=-1))
return self.get_transform() * to_unreal_transform
class Camera(Sensor):
@ -29,45 +99,41 @@ class Camera(Sensor):
"""
def __init__(self, name, **kwargs):
self.CameraName = name
super(Camera, self).__init__(name, sensor_type="CAMERA")
self.PostProcessing = 'SceneFinal'
self.ImageSizeX = 800
self.ImageSizeY = 600
self.CameraFOV = 90
self.CameraPositionX = 140
self.CameraPositionY = 0
self.CameraPositionZ = 140
self.CameraRotationPitch = 0
self.CameraRotationRoll = 0
self.CameraRotationYaw = 0
self.ImageSizeX = 720
self.ImageSizeY = 512
self.FOV = 90.0
self.set(**kwargs)
def set(self, **kwargs):
for key, value in kwargs.items():
if not hasattr(self, key):
raise ValueError('CarlaSettings.Camera: no key named %r' % key)
setattr(self, key, value)
def set_image_size(self, pixels_x, pixels_y):
'''Sets the image size in pixels'''
self.ImageSizeX = pixels_x
self.ImageSizeY = pixels_y
def set_position(self, x, y, z):
self.CameraPositionX = x
self.CameraPositionY = y
self.CameraPositionZ = z
def set_rotation(self, pitch, roll, yaw):
self.CameraRotationPitch = pitch
self.CameraRotationRoll = roll
self.CameraRotationYaw = yaw
class Lidar(Sensor):
"""
Lidar description. This class can be added to a CarlaSettings object to add
a Lidar to the player vehicle.
"""
def __init__(self, name, **kwargs):
super(Lidar, self).__init__(name, sensor_type="LIDAR_RAY_TRACE")
self.Channels = 32
self.Range = 5000.0
self.PointsPerSecond = 56000
self.RotationFrequency = 10.0
self.UpperFovLimit = 10.0
self.LowerFovLimit = -30.0
self.ShowDebugPoints = False
self.set(**kwargs)
# ==============================================================================
# -- SensorData ----------------------------------------------------------------
# ==============================================================================
class SensorData(object):
"""Base class for sensor data returned from the server."""
pass
@ -76,11 +142,12 @@ class SensorData(object):
class Image(SensorData):
"""Data generated by a Camera."""
def __init__(self, width, height, image_type, raw_data):
def __init__(self, width, height, image_type, fov, raw_data):
assert len(raw_data) == 4 * width * height
self.width = width
self.height = height
self.type = image_type
self.fov = fov
self.raw_data = raw_data
self._converted_data = None
@ -103,20 +170,160 @@ class Image(SensorData):
def save_to_disk(self, filename):
"""Save this image to disk (requires PIL installed)."""
filename = _append_extension(filename, '.png')
try:
from PIL import Image as PImage
except ImportError:
raise RuntimeError('cannot import PIL, make sure pillow package is installed')
raise RuntimeError(
'cannot import PIL, make sure pillow package is installed')
image = PImage.frombytes(
mode='RGBA',
size=(self.width, self.height),
data=self.raw_data,
decoder_name='raw')
b, g, r, _ = image.split()
image = PImage.merge("RGB", (r, g, b))
color = image.split()
image = PImage.merge("RGB", color[2::-1])
folder = os.path.dirname(filename)
if not os.path.isdir(folder):
os.makedirs(folder)
image.save(filename)
class PointCloud(SensorData):
"""A list of points."""
def __init__(self, array, color_array=None):
self._array = array
self._color_array = color_array
self._has_colors = color_array is not None
@property
def array(self):
"""The numpy array holding the point-cloud.
3D points format for n elements:
[ [X0,Y0,Z0],
...,
[Xn,Yn,Zn] ]
"""
return self._array
@property
def color_array(self):
"""The numpy array holding the colors corresponding to each point.
It is None if there are no colors.
Colors format for n elements:
[ [R0,G0,B0],
...,
[Rn,Gn,Bn] ]
"""
return self._color_array
def has_colors(self):
"""Return whether the points have color."""
return self._has_colors
def apply_transform(self, transformation):
"""Modify the PointCloud instance transforming its points"""
self._array = transformation.transform_points(self._array)
def save_to_disk(self, filename):
"""Save this point-cloud to disk as PLY format."""
filename = _append_extension(filename, '.ply')
def construct_ply_header():
"""Generates a PLY header given a total number of 3D points and
coloring property if specified
"""
points = len(self) # Total point number
header = ['ply',
'format ascii 1.0',
'element vertex {}',
'property float32 x',
'property float32 y',
'property float32 z',
'property uchar diffuse_red',
'property uchar diffuse_green',
'property uchar diffuse_blue',
'end_header']
if not self._has_colors:
return '\n'.join(header[0:6] + [header[-1]]).format(points)
return '\n'.join(header).format(points)
if not self._has_colors:
ply = '\n'.join(['{:.2f} {:.2f} {:.2f}'.format(
*p) for p in self._array.tolist()])
else:
points_3d = numpy.concatenate(
(self._array, self._color_array), axis=1)
ply = '\n'.join(['{:.2f} {:.2f} {:.2f} {:.0f} {:.0f} {:.0f}'
.format(*p) for p in points_3d.tolist()])
# Create folder to save if does not exist.
folder = os.path.dirname(filename)
if not os.path.isdir(folder):
os.makedirs(folder)
# Open the file and save with the specific PLY format.
with open(filename, 'w+') as ply_file:
ply_file.write('\n'.join([construct_ply_header(), ply]))
def __len__(self):
return len(self.array)
def __getitem__(self, key):
color = None if self._color_array is None else Color(
*self._color_array[key])
return Point(*self._array[key], color=color)
def __iter__(self):
class PointIterator(object):
"""Iterator class for PointCloud"""
def __init__(self, point_cloud):
self.point_cloud = point_cloud
self.index = -1
def __next__(self):
self.index += 1
if self.index >= len(self.point_cloud):
raise StopIteration
return self.point_cloud[self.index]
def next(self):
return self.__next__()
return PointIterator(self)
def __str__(self):
return str(self.array)
class LidarMeasurement(SensorData):
"""Data generated by a Lidar."""
def __init__(self, horizontal_angle, channels, point_count_by_channel, point_cloud):
assert numpy.sum(point_count_by_channel) == len(point_cloud.array)
self.horizontal_angle = horizontal_angle
self.channels = channels
self.point_count_by_channel = point_count_by_channel
self.point_cloud = point_cloud
@property
def data(self):
"""The numpy array holding the point-cloud.
3D points format for n elements:
[ [X0,Y0,Z0],
...,
[Xn,Yn,Zn] ]
"""
return self.point_cloud.array
def save_to_disk(self, filename):
"""Save point-cloud to disk as PLY format."""
self.point_cloud.save_to_disk(filename)

View File

@ -40,12 +40,11 @@ class CarlaSettings(object):
self.PlayerVehicle = None
self.NumberOfVehicles = 20
self.NumberOfPedestrians = 30
self.WeatherId = -1
self.WeatherId = 1
self.SeedVehicles = None
self.SeedPedestrians = None
self.randomize_weather()
self.set(**kwargs)
self._cameras = []
self._sensors = []
def set(self, **kwargs):
for key, value in kwargs.items():
@ -67,18 +66,20 @@ class CarlaSettings(object):
def add_sensor(self, sensor):
"""Add a sensor to the player vehicle (see sensor.py)."""
if isinstance(sensor, carla_sensor.Camera):
self._cameras.append(sensor)
else:
if not isinstance(sensor, carla_sensor.Sensor):
raise ValueError('Sensor not supported')
self._sensors.append(sensor)
def __str__(self):
"""Converts this object to an INI formatted string."""
ini = ConfigParser()
ini.optionxform=str
ini.optionxform = str
S_SERVER = 'CARLA/Server'
S_LEVEL = 'CARLA/LevelSettings'
S_CAPTURE = 'CARLA/SceneCapture'
S_SENSOR = 'CARLA/Sensor'
def get_attribs(obj):
return [a for a in dir(obj) if not a.startswith('_') and not callable(getattr(obj, a))]
def add_section(section, obj, keys):
for key in keys:
@ -97,21 +98,12 @@ class CarlaSettings(object):
'SeedVehicles',
'SeedPedestrians'])
ini.add_section(S_CAPTURE)
ini.set(S_CAPTURE, 'Cameras', ','.join(c.CameraName for c in self._cameras))
ini.add_section(S_SENSOR)
ini.set(S_SENSOR, 'Sensors', ','.join(s.SensorName for s in self._sensors))
for camera in self._cameras:
add_section(S_CAPTURE + '/' + camera.CameraName, camera, [
'PostProcessing',
'ImageSizeX',
'ImageSizeY',
'CameraFOV',
'CameraPositionX',
'CameraPositionY',
'CameraPositionZ',
'CameraRotationPitch',
'CameraRotationRoll',
'CameraRotationYaw'])
for sensor_def in self._sensors:
section = S_SENSOR + '/' + sensor_def.SensorName
add_section(section, sensor_def, get_attribs(sensor_def))
if sys.version_info >= (3, 0):
text = io.StringIO()
@ -120,28 +112,3 @@ class CarlaSettings(object):
ini.write(text)
return text.getvalue().replace(' = ', '=')
def get_sensor_names(settings):
"""
Return a list with the names of the sensors defined in the settings object.
The settings object can be a CarlaSettings or an INI formatted string.
"""
if isinstance(settings, CarlaSettings):
# pylint: disable=protected-access
return [camera.CameraName for camera in settings._cameras]
ini = ConfigParser()
if sys.version_info >= (3, 2):
ini.read_string(settings)
elif sys.version_info >= (3, 0):
ini.readfp(io.StringIO(settings)) # pylint: disable=deprecated-method
else:
ini.readfp(io.BytesIO(settings)) # pylint: disable=deprecated-method
section_name = 'CARLA/SceneCapture'
option_name = 'Cameras'
if ini.has_section(section_name) and ini.has_option(section_name, option_name):
cameras = ini.get(section_name, option_name)
return cameras.split(',')
return []

View File

@ -0,0 +1,137 @@
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB), and the INTEL Visual Computing Lab.
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
import math
from collections import namedtuple
try:
import numpy
except ImportError:
raise RuntimeError(
'cannot import numpy, make sure numpy package is installed.')
try:
from . import carla_server_pb2 as carla_protocol
except ImportError:
raise RuntimeError('cannot import "carla_server_pb2.py", run '
'the protobuf compiler to generate this file')
Translation = namedtuple('Translation', 'x y z')
Translation.__new__.__defaults__ = (0.0, 0.0, 0.0)
Rotation = namedtuple('Rotation', 'pitch yaw roll')
Rotation.__new__.__defaults__ = (0.0, 0.0, 0.0)
Scale = namedtuple('Scale', 'x y z')
Scale.__new__.__defaults__ = (1.0, 1.0, 1.0)
class Transform(object):
"""A 3D transformation.
The transformation is applied in the order: scale, rotation, translation.
"""
def __init__(self, *args, **kwargs):
if 'matrix' in kwargs:
self.matrix = kwargs['matrix']
return
if isinstance(args[0], carla_protocol.Transform):
args = [
Translation(
args[0].location.x,
args[0].location.y,
args[0].location.z),
Rotation(
args[0].rotation.pitch,
args[0].rotation.yaw,
args[0].rotation.roll)
]
self.matrix = numpy.matrix(numpy.identity(4))
self.set(*args, **kwargs)
def set(self, *args):
"""Builds the transform matrix given a Translate, Rotation
and Scale.
"""
translation = Translation()
rotation = Rotation()
scale = Scale()
if len(args) > 3:
raise ValueError("'Transform' accepts 3 values as maximum.")
def get_single_obj_type(obj_type):
"""Returns the unique object contained in the
arguments lists that is instance of 'obj_type'.
"""
obj = [x for x in args if isinstance(x, obj_type)]
if len(obj) > 1:
raise ValueError("Transform only accepts one instances of " +
str(obj_type) + " as a parameter")
elif not obj:
# Create an instance of the type that is 'obj_type'
return obj_type()
return obj[0]
translation = get_single_obj_type(Translation)
rotation = get_single_obj_type(Rotation)
scale = get_single_obj_type(Scale)
for param in args:
if not isinstance(param, Translation) and \
not isinstance(param, Rotation) and \
not isinstance(param, Scale):
raise TypeError(
"'" + str(type(param)) + "' type not match with \
'Translation', 'Rotation' or 'Scale'")
# Transformation matrix
cy = math.cos(numpy.radians(rotation.yaw))
sy = math.sin(numpy.radians(rotation.yaw))
cr = math.cos(numpy.radians(rotation.roll))
sr = math.sin(numpy.radians(rotation.roll))
cp = math.cos(numpy.radians(rotation.pitch))
sp = math.sin(numpy.radians(rotation.pitch))
self.matrix[0, 3] = translation.x
self.matrix[1, 3] = translation.y
self.matrix[2, 3] = translation.z
self.matrix[0, 0] = scale.x * (cp * cy)
self.matrix[0, 1] = scale.y * (cy * sp * sr - sy * cr)
self.matrix[0, 2] = -scale.z * (cy * sp * cr + sy * sr)
self.matrix[1, 0] = scale.x * (sy * cp)
self.matrix[1, 1] = scale.y * (sy * sp * sr + cy * cr)
self.matrix[1, 2] = scale.z * (cy * sr - sy * sp * cr)
self.matrix[2, 0] = scale.x * (sp)
self.matrix[2, 1] = -scale.y * (cp * sr)
self.matrix[2, 2] = scale.z * (cp * cr)
def inverse(self):
"""Return the inverse transform."""
return Transform(matrix=numpy.linalg.inv(self.matrix))
def transform_points(self, points):
"""
Given a 4x4 transformation matrix, transform an array of 3D points.
Expected point foramt: [[X0,Y0,Z0],..[Xn,Yn,Zn]]
"""
# Needed foramt: [[X0,..Xn],[Z0,..Zn],[Z0,..Zn]]. So let's transpose
# the point matrix.
points = points.transpose()
# Add 0s row: [[X0..,Xn],[Y0..,Yn],[Z0..,Zn],[0,..0]]
points = numpy.append(points, numpy.ones((1, points.shape[1])), axis=0)
# Point transformation
points = self.matrix * points
# Return all but last row
return points[0:3].transpose()
def __mul__(self, other):
return Transform(matrix=numpy.dot(self.matrix, other.matrix))
def __str__(self):
return str(self.matrix)

View File

@ -31,8 +31,11 @@ class StopWatch(object):
def stop(self):
self.end = datetime.datetime.now()
def seconds(self):
return (self.end - self.start).total_seconds()
def milliseconds(self):
return 1000.0 * (self.end - self.start).total_seconds()
return 1000.0 * self.seconds()
def to_hex_str(header):

View File

@ -16,13 +16,13 @@ import random
import time
from carla.client import make_carla_client
from carla.sensor import Camera
from carla.sensor import Camera, Lidar
from carla.settings import CarlaSettings
from carla.tcp import TCPConnectionError
from carla.util import print_over_same_line
def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filename_format, settings_filepath):
def run_carla_client(args):
# Here we will run 3 episodes with 300 frames each.
number_of_episodes = 3
frames_per_episode = 300
@ -32,13 +32,13 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena
# context manager, it creates a CARLA client object and starts the
# connection. It will throw an exception if something goes wrong. The
# context manager makes sure the connection is always cleaned up on exit.
with make_carla_client(host, port) as client:
with make_carla_client(args.host, args.port) as client:
print('CarlaClient connected')
for episode in range(0, number_of_episodes):
# Start a new episode.
if settings_filepath is None:
if args.settings_filepath is None:
# Create a CarlaSettings object. This object is a wrapper around
# the CarlaSettings.ini file. Here we set the configuration we
@ -70,10 +70,23 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena
camera1.set_position(30, 0, 130)
settings.add_sensor(camera1)
if args.lidar:
lidar = Lidar('Lidar32')
lidar.set_position(0, 0, 250)
lidar.set_rotation(0, 0, 0)
lidar.set(
Channels=32,
Range=5000,
PointsPerSecond=100000,
RotationFrequency=10,
UpperFovLimit=10,
LowerFovLimit=-30)
settings.add_sensor(lidar)
else:
# Alternatively, we can load these settings from a file.
with open(settings_filepath, 'r') as fp:
with open(args.settings_filepath, 'r') as fp:
settings = fp.read()
# Now we load these settings into the server. The server replies
@ -102,9 +115,10 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena
print_measurements(measurements)
# Save the images to disk if requested.
if save_images_to_disk:
for name, image in sensor_data.items():
image.save_to_disk(image_filename_format.format(episode, name, frame))
if args.save_images_to_disk:
for name, measurement in sensor_data.items():
filename = args.out_filename_format.format(episode, name, frame)
measurement.save_to_disk(filename)
# We can access the encoded data of a given image as numpy
# array using its "data" property. For instance, to get the
@ -118,7 +132,7 @@ def run_carla_client(host, port, autopilot_on, save_images_to_disk, image_filena
# If we are in synchronous mode the server will pause the
# simulation until we send this control.
if not autopilot_on:
if not args.autopilot:
client.send_control(
steer=random.uniform(-1.0, 1.0),
@ -183,13 +197,19 @@ def main():
'-a', '--autopilot',
action='store_true',
help='enable autopilot')
argparser.add_argument(
'-l', '--lidar',
action='store_true',
help='enable Lidar')
argparser.add_argument(
'-i', '--images-to-disk',
action='store_true',
help='save images to disk')
dest='save_images_to_disk',
help='save images (and Lidar data if active) to disk')
argparser.add_argument(
'-c', '--carla-settings',
metavar='PATH',
dest='settings_filepath',
default=None,
help='Path to a "CarlaSettings.ini" file')
@ -200,16 +220,12 @@ def main():
logging.info('listening to server %s:%s', args.host, args.port)
args.out_filename_format = '_out/episode_{:0>4d}/{:s}/{:0>6d}'
while True:
try:
run_carla_client(
host=args.host,
port=args.port,
autopilot_on=args.autopilot,
save_images_to_disk=args.images_to_disk,
image_filename_format='_images/episode_{:0>3d}/{:s}/image_{:0>5d}.png',
settings_filepath=args.carla_settings)
run_carla_client(args)
print('Done.')
return

View File

@ -6,7 +6,7 @@
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
# Keyboard controlling for carla. Please refer to client_example for a simpler
# Keyboard controlling for CARLA. Please refer to client_example.py for a simpler
# and more documented example.
"""
@ -68,7 +68,7 @@ MINI_WINDOW_WIDTH = 320
MINI_WINDOW_HEIGHT = 180
def make_carla_settings():
def make_carla_settings(enable_lidar):
"""Make a CarlaSettings object with the settings we need."""
settings = CarlaSettings()
settings.set(
@ -93,6 +93,18 @@ def make_carla_settings():
camera2.set_position(200, 0, 140)
camera2.set_rotation(0.0, 0.0, 0.0)
settings.add_sensor(camera2)
if enable_lidar:
lidar = sensor.Lidar('Lidar32')
lidar.set_position(0, 0, 250)
lidar.set_rotation(0, 0, 0)
lidar.set(
Channels=32,
Range=5000,
PointsPerSecond=100000,
RotationFrequency=10,
UpperFovLimit=10,
LowerFovLimit=-30)
settings.add_sensor(lidar)
return settings
@ -117,13 +129,15 @@ class Timer(object):
class CarlaGame(object):
def __init__(self, carla_client, city_name=None):
def __init__(self, carla_client, enable_lidar=False, city_name=None):
self.client = carla_client
self._timer = None
self._display = None
self._main_image = None
self._mini_view_image1 = None
self._mini_view_image2 = None
self._enable_lidar = enable_lidar
self._lidar_measurement = None
self._map_view = None
self._is_on_reverse = False
self._city_name = city_name
@ -161,7 +175,7 @@ class CarlaGame(object):
self._on_new_episode()
def _on_new_episode(self):
scene = self.client.load_settings(make_carla_settings())
scene = self.client.load_settings(make_carla_settings(self._enable_lidar))
number_of_player_starts = len(scene.player_start_spots)
player_start = np.random.randint(number_of_player_starts)
print('Starting new episode...')
@ -177,6 +191,8 @@ class CarlaGame(object):
self._main_image = sensor_data['CameraRGB']
self._mini_view_image1 = sensor_data['CameraDepth']
self._mini_view_image2 = sensor_data['CameraSemSeg']
if self._enable_lidar:
self._lidar_measurement = sensor_data['Lidar32']
# Print measurements every second.
if self._timer.elapsed_seconds_since_lap() > 1.0:
@ -207,9 +223,9 @@ class CarlaGame(object):
# Set the player position
if self._city_name is not None:
self._position = self._map.convert_to_pixel([
measurements.player_measurements.transform.location.x,
measurements.player_measurements.transform.location.y,
measurements.player_measurements.transform.location.z])
measurements.player_measurements.transform.location.x,
measurements.player_measurements.transform.location.y,
measurements.player_measurements.transform.location.z])
self._agent_positions = measurements.non_player_agents
if control is None:
@ -246,7 +262,8 @@ class CarlaGame(object):
map_position,
lane_orientation):
message = 'Step {step} ({fps:.1f} FPS): '
message += 'Map Position ({map_x:.1f},{map_y:.1f}) Lane Orientation ({ori_x:.1f},{ori_y:.1f}) '
message += 'Map Position ({map_x:.1f},{map_y:.1f}) '
message += 'Lane Orientation ({ori_x:.1f},{ori_y:.1f}) '
message += '{speed:.2f} km/h, '
message += '{other_lane:.0f}% other lane, {offroad:.0f}% off-road'
message = message.format(
@ -295,17 +312,33 @@ class CarlaGame(object):
self._display.blit(
surface, (2 * gap_x + MINI_WINDOW_WIDTH, mini_image_y))
if self._lidar_measurement is not None:
lidar_data = np.array(self._lidar_measurement.data[:, :2])
lidar_data /= 50.0
lidar_data += 100.0
lidar_data = np.fabs(lidar_data)
lidar_data = lidar_data.astype(np.int32)
lidar_data = np.reshape(lidar_data, (-1, 2))
#draw lidar
lidar_img_size = (200, 200, 3)
lidar_img = np.zeros(lidar_img_size)
lidar_img[tuple(lidar_data.T)] = (255, 255, 255)
surface = pygame.surfarray.make_surface(lidar_img)
self._display.blit(surface, (10, 10))
if self._map_view is not None:
array = self._map_view
array = array[:, :, :3]
new_window_width =(float(WINDOW_HEIGHT)/float(self._map_shape[0]))*float(self._map_shape[1])
new_window_width = \
(float(WINDOW_HEIGHT) / float(self._map_shape[0])) * \
float(self._map_shape[1])
surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
w_pos = int(self._position[0]*(float(WINDOW_HEIGHT)/float(self._map_shape[0])))
h_pos = int(self._position[1] *(new_window_width/float(self._map_shape[1])))
pygame.draw.circle(surface, [255, 0, 0, 255], (w_pos,h_pos), 6, 0)
pygame.draw.circle(surface, [255, 0, 0, 255], (w_pos, h_pos), 6, 0)
for agent in self._agent_positions:
if agent.HasField('vehicle'):
agent_position = self._map.convert_to_pixel([
@ -316,7 +349,7 @@ class CarlaGame(object):
w_pos = int(agent_position[0]*(float(WINDOW_HEIGHT)/float(self._map_shape[0])))
h_pos = int(agent_position[1] *(new_window_width/float(self._map_shape[1])))
pygame.draw.circle(surface, [255, 0, 255, 255], (w_pos ,h_pos), 4, 0)
pygame.draw.circle(surface, [255, 0, 255, 255], (w_pos, h_pos), 4, 0)
self._display.blit(surface, (WINDOW_WIDTH, 0))
@ -342,11 +375,16 @@ def main():
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-l', '--lidar',
action='store_true',
help='enable Lidar')
argparser.add_argument(
'-m', '--map-name',
metavar='M',
default=None,
help='plot the map of the current city (needs to match active map in server, options: Town01 or Town02)')
help='plot the map of the current city (needs to match active map in '
'server, options: Town01 or Town02)')
args = argparser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
@ -360,7 +398,7 @@ def main():
try:
with make_carla_client(args.host, args.port) as client:
game = CarlaGame(client, args.map_name)
game = CarlaGame(client, args.lidar, args.map_name)
game.execute()
break

View File

@ -0,0 +1,191 @@
#!/usr/bin/env python3
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB), and the INTEL Visual Computing Lab.
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
"""Basic CARLA client to generate point cloud in PLY format that you
can visualize with MeshLab (meshlab.net) for instance. Please
refer to client_example.py for a simpler and more documented example."""
from __future__ import print_function
import argparse
import logging
import os
import random
import time
from carla.client import make_carla_client
from carla.sensor import Camera
from carla.settings import CarlaSettings
from carla.tcp import TCPConnectionError
from carla.util import print_over_same_line, StopWatch
from carla.image_converter import depth_to_local_point_cloud, to_rgb_array
from carla.transform import Transform
def run_carla_client(host, port, far):
# Here we will run a single episode with 300 frames.
number_of_frames = 3000
frame_step = 100 # Save one image every 100 frames
output_folder = '_out'
image_size = [800, 600]
camera_local_pos = [30, 0, 130] # [X, Y, Z]
camera_local_rotation = [0, 0, 0] # [pitch(Y), yaw(Z), roll(X)]
fov = 70
# Connect with the server
with make_carla_client(host, port) as client:
print('CarlaClient connected')
# Here we load the settings.
settings = CarlaSettings()
settings.set(
SynchronousMode=True,
SendNonPlayerAgentsInfo=False,
NumberOfVehicles=20,
NumberOfPedestrians=40,
WeatherId=random.choice([1, 3, 7, 8, 14]))
settings.randomize_seeds()
camera1 = Camera('CameraDepth', PostProcessing='Depth', FOV=fov)
camera1.set_image_size(*image_size)
camera1.set_position(*camera_local_pos)
camera1.set_rotation(*camera_local_rotation)
settings.add_sensor(camera1)
camera2 = Camera('CameraRGB', PostProcessing='SceneFinal', FOV=fov)
camera2.set_image_size(*image_size)
camera2.set_position(*camera_local_pos)
camera2.set_rotation(*camera_local_rotation)
settings.add_sensor(camera2)
client.load_settings(settings)
# Start at location index id '0'
client.start_episode(0)
# Compute the camera transform matrix
camera_to_car_transform = camera2.get_unreal_transform()
# Iterate every frame in the episode except for the first one.
for frame in range(1, number_of_frames):
# Read the data produced by the server this frame.
measurements, sensor_data = client.read_data()
# Save one image every 'frame_step' frames
if not frame % frame_step:
# Start transformations time mesure.
timer = StopWatch()
# RGB image [[[r,g,b],..[r,g,b]],..[[r,g,b],..[r,g,b]]]
image_RGB = to_rgb_array(sensor_data['CameraRGB'])
# 2d to (camera) local 3d
# We use the image_RGB to colorize each 3D point, this is optional.
# "max_depth" is used to keep only the points that are near to the
# camera, meaning 1.0 the farest points (sky)
point_cloud = depth_to_local_point_cloud(
sensor_data['CameraDepth'],
image_RGB,
max_depth=far
)
# (Camera) local 3d to world 3d.
# Get the transform from the player protobuf transformation.
world_transform = Transform(
measurements.player_measurements.transform
)
# Compute the final transformation matrix.
car_to_world_transform = world_transform * camera_to_car_transform
# Car to World transformation given the 3D points and the
# transformation matrix.
point_cloud.apply_transform(car_to_world_transform)
# End transformations time mesure.
timer.stop()
# Save PLY to disk
# This generates the PLY string with the 3D points and the RGB colors
# for each row of the file.
point_cloud.save_to_disk(os.path.join(
output_folder, '{:0>5}.ply'.format(frame))
)
print_message(timer.milliseconds(), len(point_cloud), frame)
client.send_control(
measurements.player_measurements.autopilot_control
)
def print_message(elapsed_time, point_n, frame):
message = ' '.join([
'Transformations took {:>3.0f} ms.',
'Saved {:>6} points to "{:0>5}.ply".'
]).format(elapsed_time, point_n, frame)
print_over_same_line(message)
def check_far(value):
fvalue = float(value)
if fvalue < 0.0 or fvalue > 1.0:
raise argparse.ArgumentTypeError(
"{} must be a float between 0.0 and 1.0")
return fvalue
def main():
argparser = argparse.ArgumentParser(description=__doc__)
argparser.add_argument(
'-v', '--verbose',
action='store_true',
dest='debug',
help='print debug information')
argparser.add_argument(
'--host',
metavar='H',
default='localhost',
help='IP of the host server (default: localhost)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-f', '--far',
default=0.2,
type=check_far,
help='The maximum save distance of camera-point '
'[0.0 (near), 1.0 (far)] (default: 0.2)')
args = argparser.parse_args()
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(format='%(levelname)s: %(message)s', level=log_level)
logging.info('listening to server %s:%s', args.host, args.port)
while True:
try:
run_carla_client(host=args.host, port=args.port, far=args.far)
print('\nDone!')
return
except TCPConnectionError as error:
logging.error(error)
time.sleep(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('\nClient stoped by user.')

View File

@ -19,8 +19,8 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import carla
from carla import sensor
from carla.client import CarlaClient
from carla.sensor import Camera, Image
from carla.settings import CarlaSettings
from carla.tcp import TCPClient
from carla.util import make_connection
@ -31,17 +31,19 @@ import console
def run_carla_client(args):
with make_connection(CarlaClient, args.host, args.port, timeout=15) as client:
logging.info('CarlaClient connected')
filename = '_images/episode_{:0>3d}/image_{:0>5d}.png'
filename = '_out/test_episode_{:0>4d}/{:s}/{:0>6d}'
frames_per_episode = 300
episode = 0
while True:
episode += 1
settings = CarlaSettings()
settings.set(SendNonPlayerAgentsInfo=True,SynchronousMode=args.synchronous)
settings.set(SendNonPlayerAgentsInfo=True, SynchronousMode=args.synchronous)
settings.randomize_seeds()
camera = Camera('DefaultCamera')
camera = sensor.Camera('DefaultCamera')
camera.set_image_size(300, 200) # Do not change this, hard-coded in test.
settings.add_sensor(camera)
lidar = sensor.Lidar('DefaultLidar')
settings.add_sensor(lidar)
logging.debug('sending CarlaSettings:\n%s', settings)
logging.info('new episode requested')
@ -64,14 +66,15 @@ def run_carla_client(args):
for frame in range(0, frames_per_episode):
logging.debug('reading measurements...')
measurements, sensor_data = client.read_data()
images = [x for x in sensor_data.values() if isinstance(x, Image)]
images = [x for x in sensor_data.values() if isinstance(x, sensor.Image)]
logging.debug('received data of %d agents', len(measurements.non_player_agents))
assert len(images) == 1
assert (images[0].width, images[0].height) == (camera.ImageSizeX, camera.ImageSizeY)
if len(images) > 0:
assert (images[0].width, images[0].height) == (camera.ImageSizeX, camera.ImageSizeY)
if args.images_to_disk:
images[0].save_to_disk(filename.format(episode, frame))
for name, data in sensor_data.items():
data.save_to_disk(filename.format(episode, name, frame))
logging.debug('sending control...')
control = measurements.player_measurements.autopilot_control

View File

@ -13,6 +13,7 @@ import carla
from carla.client import CarlaClient
from carla.sensor import Camera, Image
from carla.sensor import Lidar, LidarMeasurement
from carla.settings import CarlaSettings
from carla.util import make_connection
@ -45,8 +46,8 @@ class _BasicTestBase(unit_tests.CarlaServerTest):
number_of_agents = len(measurements.non_player_agents)
logging.debug('received data of %d agents', number_of_agents)
logging.debug('received %d images', len(images))
if len(images) != len(carla_settings._cameras):
raise RuntimeError('received %d images, expected %d' % (len(images), len(carla_settings._cameras)))
if len(sensor_data) != len(carla_settings._sensors):
raise RuntimeError('received %d, expected %d' % (len(sensor_data), len(carla_settings._sensors)))
logging.debug('sending control...')
control = measurements.player_measurements.autopilot_control
if not use_autopilot_control:
@ -80,7 +81,7 @@ class TwoCameras(_BasicTestBase):
settings = CarlaSettings()
settings.add_sensor(Camera('DefaultCamera'))
camera2 = Camera('Camera2')
camera2.set(PostProcessing='Depth', CameraFOV=120)
camera2.set(PostProcessing='Depth', FOV=120)
camera2.set_image_size(1924, 1028)
settings.add_sensor(camera2)
self.run_carla_client(settings, 3, 100)
@ -110,3 +111,10 @@ class LongEpisode(_BasicTestBase):
settings = CarlaSettings()
settings.add_sensor(Camera('DefaultCamera'))
self.run_carla_client(settings, 1, 2000, use_autopilot_control=True)
class LidarTest(_BasicTestBase):
def run(self):
settings = CarlaSettings()
settings.add_sensor(Lidar('DefaultLidar'))
self.run_carla_client(settings, 3, 100)

View File

@ -2,6 +2,8 @@ CARLA Simulator
===============
[![Build Status](https://travis-ci.org/carla-simulator/carla.svg?branch=master)](https://travis-ci.org/carla-simulator/carla)
[![Documentation](https://readthedocs.org/projects/carla/badge/?version=latest)](http://carla.readthedocs.io)
[![Waffle.io](https://badge.waffle.io/carla-simulator/carla.svg?columns=Next,In%20Progress,Review)](https://waffle.io/carla-simulator/carla)
CARLA is an open-source simulator for autonomous driving research. CARLA has
been developed from the ground up to support development, training, and
@ -25,8 +27,8 @@ paper, check out
News
----
- 05.02.2018 CARLA 0.7.1 available for Windows too, [release](https://github.com/carla-simulator/carla/releases/tag/0.7.1).
- 25.01.2018 CARLA 0.7.1 released: [change log](https://github.com/carla-simulator/carla/blob/master/CHANGELOG.md#carla-071), [release](https://github.com/carla-simulator/carla/releases/tag/0.7.1).
- 22.01.2018 Job opening: [C++ (UE4) Programmer](https://drive.google.com/open?id=1Hx0eUgpXl95d4IL9meEGhJECgSRos1T1).
- 28.11.2017 CARLA 0.7.0 released: [change log](https://github.com/carla-simulator/carla/blob/master/CHANGELOG.md#carla-070), [release](https://github.com/carla-simulator/carla/releases/tag/0.7.0).
- 15.11.2017 CARLA 0.6.0 released: [change log](https://github.com/carla-simulator/carla/blob/master/CHANGELOG.md#carla-060), [release](https://github.com/carla-simulator/carla/releases/tag/0.6.0).
@ -92,13 +94,6 @@ F.A.Q.
If you run into problems, check our
[FAQ](http://carla.readthedocs.io/en/latest/faq/).
Jobs
----
We are currently looking for a new programmer to join our team
* [C++ (UE4) Programmer](https://drive.google.com/open?id=1Hx0eUgpXl95d4IL9meEGhJECgSRos1T1)
License
-------

View File

@ -58,6 +58,8 @@ function log {
if [ ! -d "${UE4_ROOT}" ]; then
fatal_error "UE4_ROOT is not defined, or points to a non-existant directory, please set this environment variable."
else
echo "Using Unreal Engine at '$UE4_ROOT'"
fi
# ==============================================================================
@ -94,7 +96,7 @@ pushd "$UNREAL_PROJECT_FOLDER" >/dev/null
# This command usually fails but normally we can continue anyway.
set +e
log "Generate Unreal project files..."
${UE4_ROOT}/GenerateProjectFiles.sh -project="${PWD}/CarlaUE4.uproject" -game -engine
${UE4_ROOT}/GenerateProjectFiles.sh -project="${PWD}/CarlaUE4.uproject" -game -engine -makefiles
set -e
log "Build CarlaUE4 project..."

View File

@ -17,3 +17,4 @@ Config/CarlaSettings.ini
CMakeLists.txt
Makefile
.vscode

View File

@ -1,6 +1,6 @@
{
"FileVersion": 3,
"EngineAssociation": "4.17",
"EngineAssociation": "4.18",
"Category": "",
"Description": "",
"Modules": [

View File

@ -1,22 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "TrafficSignBase.h"
#include "Game/CarlaGameState.h"
ATrafficSignBase::ATrafficSignBase() : Super() {}
void ATrafficSignBase::BeginPlay()
{
auto *GameState = GetWorld()->GetGameState<ACarlaGameState>();
if (GameState != nullptr) {
GameState->RegisterTrafficSign(this);
} else {
UE_LOG(LogCarla, Error, TEXT("Missing CARLA game state!"));
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla.h"
#include "AgentComponent.h"
#include "Game/CarlaGameModeBase.h"
#include "Game/DataRouter.h"
static FDataRouter &GetDataRouter(UWorld *World)
{
check(World != nullptr);
auto *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
check(GameMode != nullptr);
return GameMode->GetDataRouter();
}
UAgentComponent::UAgentComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bVisible = false;
bHiddenInGame = true;
bShouldUpdatePhysicsVolume = false;
PrimaryComponentTick.bCanEverTick = false;
}
void UAgentComponent::AcceptVisitor(IAgentComponentVisitor &Visitor) const
{
unimplemented();
}
void UAgentComponent::BeginPlay()
{
Super::BeginPlay();
GetDataRouter(GetWorld()).RegisterAgent(this);
}
void UAgentComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetDataRouter(GetWorld()).DeregisterAgent(this);
Super::EndPlay(EndPlayReason);
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Agent/AgentComponentVisitor.h"
#include "Components/SceneComponent.h"
#include "Templates/SharedPointer.h"
#include "AgentComponent.generated.h"
/// Actors with an UAgentComponent are registered as agents in the scene and
/// their status is sent to the client each frame (if requested by the client).
UCLASS(Abstract)
class CARLA_API UAgentComponent : public USceneComponent
{
GENERATED_BODY()
public:
UAgentComponent(const FObjectInitializer& ObjectInitializer);
uint32 GetId() const
{
return GetTypeHash(this);
}
virtual void AcceptVisitor(IAgentComponentVisitor &Visitor) const;
protected:
virtual void BeginPlay() override;
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override;
};

View File

@ -0,0 +1,23 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
class UAgentComponent;
class UTrafficSignAgentComponent;
class UVehicleAgentComponent;
class UWalkerAgentComponent;
class IAgentComponentVisitor
{
public:
virtual void Visit(const UTrafficSignAgentComponent &) = 0;
virtual void Visit(const UVehicleAgentComponent &) = 0;
virtual void Visit(const UWalkerAgentComponent &) = 0;
};

View File

@ -0,0 +1,23 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla.h"
#include "TrafficSignAgentComponent.h"
#include "Traffic/TrafficSignBase.h"
UTrafficSignAgentComponent::UTrafficSignAgentComponent(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer) {}
void UTrafficSignAgentComponent::BeginPlay()
{
TrafficSign = Cast<ATrafficSignBase>(GetOwner());
checkf(TrafficSign != nullptr, TEXT("UTrafficSignAgentComponent can only be attached to ATrafficSignBase"));
Super::BeginPlay();
}

View File

@ -0,0 +1,43 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Agent/AgentComponent.h"
#include "TrafficSignAgentComponent.generated.h"
class ATrafficSignBase;
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class CARLA_API UTrafficSignAgentComponent : public UAgentComponent
{
GENERATED_BODY()
public:
UTrafficSignAgentComponent(const FObjectInitializer &ObjectInitializer);
const ATrafficSignBase &GetTrafficSign() const
{
check(TrafficSign != nullptr);
return *TrafficSign;
}
protected:
virtual void BeginPlay() override;
virtual void AcceptVisitor(IAgentComponentVisitor &Visitor) const final
{
Visitor.Visit(*this);
}
private:
UPROPERTY()
ATrafficSignBase *TrafficSign = nullptr;
};

View File

@ -0,0 +1,23 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla.h"
#include "VehicleAgentComponent.h"
#include "Vehicle/CarlaWheeledVehicle.h"
UVehicleAgentComponent::UVehicleAgentComponent(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer) {}
void UVehicleAgentComponent::BeginPlay()
{
WheeledVehicle = Cast<ACarlaWheeledVehicle>(GetOwner());
checkf(WheeledVehicle != nullptr, TEXT("UVehicleAgentComponent can only be attached to ACarlaWheeledVehicle"));
Super::BeginPlay();
}

View File

@ -0,0 +1,42 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Agent/AgentComponent.h"
#include "VehicleAgentComponent.generated.h"
class ACarlaWheeledVehicle;
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class CARLA_API UVehicleAgentComponent : public UAgentComponent
{
GENERATED_BODY()
public:
UVehicleAgentComponent(const FObjectInitializer &ObjectInitializer);
ACarlaWheeledVehicle &GetVehicle() const
{
check(WheeledVehicle != nullptr);
return *WheeledVehicle;
}
protected:
virtual void BeginPlay() override;
virtual void AcceptVisitor(IAgentComponentVisitor &Visitor) const final
{
Visitor.Visit(*this);
}
private:
ACarlaWheeledVehicle *WheeledVehicle = nullptr;
};

View File

@ -0,0 +1,29 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla.h"
#include "WalkerAgentComponent.h"
#include "GameFramework/Character.h"
UWalkerAgentComponent::UWalkerAgentComponent(const FObjectInitializer &ObjectInitializer)
: Super(ObjectInitializer) {}
float UWalkerAgentComponent::GetForwardSpeed() const
{
/// @todo Is it necessary to compute this speed every tick?
return FVector::DotProduct(Walker->GetVelocity(), Walker->GetActorRotation().Vector()) * 0.036f;
}
void UWalkerAgentComponent::BeginPlay()
{
Walker = Cast<ACharacter>(GetOwner());
checkf(Walker != nullptr, TEXT("UWalkerAgentComponent can only be attached to ACharacter"));
Super::BeginPlay();
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Agent/AgentComponent.h"
#include "WalkerAgentComponent.generated.h"
class ACharacter;
/// This component can be added to any ACharacter to be added as agent.
/// See UAgentComponent.
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class CARLA_API UWalkerAgentComponent : public UAgentComponent
{
GENERATED_BODY()
public:
UWalkerAgentComponent(const FObjectInitializer &ObjectInitializer);
/// Return forward speed in km/h.
float GetForwardSpeed() const;
FVector GetBoundingBoxExtent() const
{
/// @todo Perhaps the box it is not the same for every walker...
return {45.0f, 35.0f, 100.0f};
}
protected:
virtual void BeginPlay() override;
virtual void AcceptVisitor(IAgentComponentVisitor &Visitor) const final
{
Visitor.Visit(*this);
}
private:
UPROPERTY()
ACharacter *Walker = nullptr;
};

View File

@ -9,18 +9,39 @@
#include "MapGen/GraphGenerator.h"
#include "MapGen/RoadMap.h"
#include "Tagger.h"
#include "Game/Tagger.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Engine/World.h"
#include "Paths.h"
#include <algorithm>
#include <unordered_set>
#ifdef CARLA_ROAD_GENERATOR_EXTRA_LOG
#include <sstream>
#endif // CARLA_ROAD_GENERATOR_EXTRA_LOG
// =============================================================================
// -- Private types ------------------------------------------------------------
// =============================================================================
class FHalfEdgeCounter {
public:
using HalfEdge = MapGen::DoublyConnectedEdgeList::HalfEdge;
bool Insert(const HalfEdge &InHalfEdge)
{
return Set.insert(&InHalfEdge).second &&
Set.insert(&MapGen::DoublyConnectedEdgeList::GetPair(InHalfEdge)).second;
}
private:
std::unordered_set<const HalfEdge *> Set;
};
// =============================================================================
// -- Constructor and destructor -----------------------------------------------
// =============================================================================
@ -135,35 +156,39 @@ void ACityMapGenerator::GenerateRoads()
const uint32 margin = CityMapMeshTag::GetRoadIntersectionSize() / 2u;
FHalfEdgeCounter HalfEdgeCounter;
// For each edge add road segment.
for (auto &edge : graph.GetHalfEdges()) {
auto source = Graph::GetSource(edge).GetPosition();
auto target = Graph::GetTarget(edge).GetPosition();
if (HalfEdgeCounter.Insert(edge)) {
auto source = Graph::GetSource(edge).GetPosition();
auto target = Graph::GetTarget(edge).GetPosition();
if (source.x == target.x) {
// vertical
auto y = 1u + margin + std::min(source.y, target.y);
auto end = std::max(source.y, target.y) - margin;
for (; y < end; ++y) {
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneLeft, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneRight, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkLeft, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkRight, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneMarkingBroken, source.x, y, HALF_PI);
if (source.x == target.x) {
// vertical
auto y = 1u + margin + std::min(source.y, target.y);
auto end = std::max(source.y, target.y) - margin;
for (; y < end; ++y) {
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneLeft, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneRight, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkLeft, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkRight, source.x, y, HALF_PI);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneMarkingBroken, source.x, y, HALF_PI);
}
} else if (source.y == target.y) {
// horizontal
auto x = 1u + margin + std::min(source.x, target.x);
auto end = std::max(source.x, target.x) - margin;
for (; x < end; ++x) {
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneLeft, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneRight, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkLeft, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkRight, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneMarkingBroken, x, source.y);
}
} else {
UE_LOG(LogCarla, Warning, TEXT("Diagonal edge ignored"));
}
} else if (source.y == target.y) {
// horizontal
auto x = 1u + margin + std::min(source.x, target.x);
auto end = std::max(source.x, target.x) - margin;
for (; x < end; ++x) {
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneLeft, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneRight, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkLeft, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_SidewalkRight, x, source.y);
AddInstance(ECityMapMeshTag::RoadTwoLanes_LaneMarkingBroken, x, source.y);
}
} else {
UE_LOG(LogCarla, Warning, TEXT("Diagonal edge ignored"));
}
}
@ -291,7 +316,7 @@ void ACityMapGenerator::GenerateRoadMap()
#endif // WITH_EDITOR
if (bSaveRoadMapToDisk) {
RoadMap->SaveAsPNG(FPaths::GameSavedDir(), World->GetMapName());
RoadMap->SaveAsPNG(FPaths::ProjectSavedDir(), World->GetMapName());
}
#if WITH_EDITOR

View File

@ -7,8 +7,10 @@
#pragma once
#include "MapGen/CityMapMeshHolder.h"
#include "MapGen/DoublyConnectedEdgeList.h"
#include "MapGen/GraphParser.h"
#include "CityMapGenerator.generated.h"
class URoadMap;

View File

@ -21,7 +21,7 @@ static FString GetIniFileName(const FString &MapName = TEXT(""))
static bool GetWeatherIniFilePath(const FString &FileName, FString &FilePath)
{
FilePath = FPaths::Combine(FPaths::GameConfigDir(), FileName);
FilePath = FPaths::Combine(FPaths::ProjectConfigDir(), FileName);
const bool bFileExists = FPaths::FileExists(FilePath);
if (!bFileExists) {
UE_LOG(LogCarla, Warning, TEXT("\"%s\" not found"), *FilePath);
@ -46,7 +46,7 @@ void ADynamicWeather::LoadWeatherDescriptionsFromFile(
FString DefaultFilePath;
if (GetWeatherIniFilePath(GetIniFileName(), DefaultFilePath)) {
UE_LOG(LogCarla, Log, TEXT("Loading weather description from %s"), *DefaultFilePath);
IniFile ConfigFile(DefaultFilePath);
FIniFile ConfigFile(DefaultFilePath);
{ // Override map specific presets.
FString MapOverridesFilePath;
@ -190,7 +190,7 @@ bool ADynamicWeather::LoadFromConfigFile()
{
FString FilePath;
if (GetWeatherIniFilePath(FileName, FilePath) && CheckWeatherValidity(Weather)) {
IniFile ConfigFile(FilePath);
FIniFile ConfigFile(FilePath);
if (!ConfigFile.HasSection(Weather.Name)) {
UE_LOG(LogCarla, Error, TEXT("Weather \"%s\" is not present in config file"), *Weather.Name);
return false;
@ -206,7 +206,7 @@ bool ADynamicWeather::SaveToConfigFile() const
{
FString FilePath;
if (GetWeatherIniFilePath(FileName, FilePath) && CheckWeatherValidity(Weather)) {
IniFile ConfigFile(FilePath);
FIniFile ConfigFile(FilePath);
Weather.WriteToConfigFile(ConfigFile);
return ConfigFile.Write(FilePath);
} else {

View File

@ -7,7 +7,9 @@
#pragma once
#include "GameFramework/Actor.h"
#include "Settings/WeatherDescription.h"
#include "DynamicWeather.generated.h"
class UArrowComponent;

View File

@ -1,31 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Settings/PostProcessEffect.h"
#include "CapturedImage.generated.h"
/// Bitmap and meta info of a scene capture.
///
/// The bitmap may be empty if the capture failed.
USTRUCT()
struct FCapturedImage
{
GENERATED_USTRUCT_BODY()
UPROPERTY(VisibleAnywhere)
uint32 SizeX = 0u;
UPROPERTY(VisibleAnywhere)
uint32 SizeY = 0u;
UPROPERTY(VisibleAnywhere)
EPostProcessEffect PostProcessEffect = EPostProcessEffect::INVALID;
UPROPERTY(VisibleAnywhere)
TArray<FColor> BitMap;
};

View File

@ -1,45 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CarlaGameControllerBase.h"
class ACarlaGameState;
class ACarlaVehicleController;
class CarlaServer;
/// Implements remote control of game and player.
class CARLA_API CarlaGameController : public CarlaGameControllerBase
{
public:
explicit CarlaGameController();
~CarlaGameController();
virtual void Initialize(UCarlaSettings &CarlaSettings) override;
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) override;
virtual void RegisterPlayer(AController &NewPlayer) override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
private:
void RestartLevel();
TUniquePtr<CarlaServer> Server;
ACarlaVehicleController *Player = nullptr;
const ACarlaGameState *GameState = nullptr;
UCarlaSettings *CarlaSettings = nullptr;
};

View File

@ -6,18 +6,21 @@
#pragma once
#include "Array.h"
#include "Containers/Array.h"
class AController;
class APlayerStart;
class FDataRouter;
class UCarlaSettings;
/// Base class for a CARLA game controller.
class CARLA_API CarlaGameControllerBase
class ICarlaGameControllerBase
{
public:
virtual ~CarlaGameControllerBase() {}
ICarlaGameControllerBase(FDataRouter &DataRouter) : DataRouter(DataRouter) {}
virtual ~ICarlaGameControllerBase() {}
virtual void Initialize(UCarlaSettings &CarlaSettings) = 0;
@ -28,4 +31,8 @@ public:
virtual void BeginPlay() = 0;
virtual void Tick(float DeltaSeconds) = 0;
protected:
FDataRouter &DataRouter;
};

View File

@ -7,8 +7,8 @@
#include "Carla.h"
#include "CarlaGameInstance.h"
#include "CarlaGameController.h"
#include "MockGameController.h"
#include "Game/MockGameController.h"
#include "Server/ServerGameController.h"
#include "Settings/CarlaSettings.h"
UCarlaGameInstance::UCarlaGameInstance() {
@ -25,9 +25,9 @@ void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
{
if (GameController == nullptr) {
if (CarlaSettings->bUseNetworking) {
GameController = MakeUnique<CarlaGameController>();
GameController = MakeUnique<FServerGameController>(DataRouter);
} else {
GameController = MakeUnique<MockGameController>(MockControllerSettings);
GameController = MakeUnique<MockGameController>(DataRouter, MockControllerSettings);
UE_LOG(LogCarla, Log, TEXT("Using mock CARLA controller"));
}
}

View File

@ -7,7 +7,10 @@
#pragma once
#include "Engine/GameInstance.h"
#include "CarlaGameControllerBase.h"
#include "Game/CarlaGameControllerBase.h"
#include "Game/DataRouter.h"
#include "CarlaGameInstance.generated.h"
class UCarlaSettings;
@ -29,7 +32,7 @@ public:
void InitializeGameControllerIfNotPresent(
const FMockGameControllerSettings &MockControllerSettings);
CarlaGameControllerBase &GetGameController()
ICarlaGameControllerBase &GetGameController()
{
check(GameController != nullptr);
return *GameController;
@ -54,10 +57,17 @@ public:
return CarlaSettings;
}
FDataRouter &GetDataRouter()
{
return DataRouter;
}
private:
UPROPERTY(Category = "CARLA Settings", EditAnywhere)
UCarlaSettings *CarlaSettings;
TUniquePtr<CarlaGameControllerBase> GameController;
FDataRouter DataRouter;
TUniquePtr<ICarlaGameControllerBase> GameController;
};

View File

@ -7,21 +7,23 @@
#include "Carla.h"
#include "CarlaGameModeBase.h"
#include "Game/CarlaGameInstance.h"
#include "Game/CarlaHUD.h"
#include "Game/CarlaPlayerState.h"
#include "Game/Tagger.h"
#include "Game/TaggerDelegate.h"
#include "Sensor/Sensor.h"
#include "Sensor/SensorFactory.h"
#include "Settings/CarlaSettings.h"
#include "Util/RandomEngine.h"
#include "Vehicle/CarlaVehicleController.h"
#include "ConstructorHelpers.h"
#include "Engine/PlayerStartPIE.h"
#include "EngineUtils.h"
#include "GameFramework/PlayerStart.h"
#include "SceneViewport.h"
#include "CarlaGameInstance.h"
#include "CarlaGameState.h"
#include "CarlaHUD.h"
#include "CarlaPlayerState.h"
#include "CarlaVehicleController.h"
#include "Settings/CarlaSettings.h"
#include "Tagger.h"
#include "TaggerDelegate.h"
ACarlaGameModeBase::ACarlaGameModeBase(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer),
GameController(nullptr),
@ -32,7 +34,6 @@ ACarlaGameModeBase::ACarlaGameModeBase(const FObjectInitializer& ObjectInitializ
bAllowTickBeforeBeginPlay = false;
PlayerControllerClass = ACarlaVehicleController::StaticClass();
GameStateClass = ACarlaGameState::StaticClass();
PlayerStateClass = ACarlaPlayerState::StaticClass();
HUDClass = ACarlaHUD::StaticClass();
@ -129,17 +130,6 @@ void ACarlaGameModeBase::BeginPlay()
{
Super::BeginPlay();
auto CarlaGameState = Cast<ACarlaGameState>(GameState);
checkf(
CarlaGameState != nullptr,
TEXT("GameState is not a ACarlaGameState, did you forget to set it in the project settings?"));
if (WalkerSpawner != nullptr) {
CarlaGameState->WalkerSpawner = WalkerSpawner;
}
if (VehicleSpawner != nullptr) {
CarlaGameState->VehicleSpawner = VehicleSpawner;
}
const auto &CarlaSettings = GameInstance->GetCarlaSettings();
// Setup semantic segmentation if necessary.
@ -204,26 +194,34 @@ void ACarlaGameModeBase::RegisterPlayer(AController &NewPlayer)
{
check(GameController != nullptr);
AddTickPrerequisiteActor(&NewPlayer);
GameController->RegisterPlayer(NewPlayer);
PlayerController = Cast<ACarlaVehicleController>(&NewPlayer);
AttachCaptureCamerasToPlayer();
if (PlayerController != nullptr) {
GetDataRouter().RegisterPlayer(*PlayerController);
GameController->RegisterPlayer(*PlayerController);
AttachSensorsToPlayer();
} else {
UE_LOG(LogCarla, Error, TEXT("ACarlaGameModeBase: Player is not a ACarlaVehicleController"));
}
}
void ACarlaGameModeBase::AttachCaptureCamerasToPlayer()
void ACarlaGameModeBase::AttachSensorsToPlayer()
{
if (PlayerController == nullptr) {
UE_LOG(LogCarla, Warning, TEXT("Trying to add capture cameras but player is not a ACarlaVehicleController"));
return;
}
check(PlayerController != nullptr);
const auto &Settings = GameInstance->GetCarlaSettings();
const auto *Weather = Settings.GetActiveWeatherDescription();
const FCameraPostProcessParameters *OverridePostProcessParameters = nullptr;
if ((Weather != nullptr) && (Weather->bOverrideCameraPostProcessParameters)) {
OverridePostProcessParameters = &Weather->CameraPostProcessParameters;
}
for (const auto &Item : Settings.CameraDescriptions) {
PlayerController->AddSceneCaptureCamera(Item.Value, OverridePostProcessParameters);
for (auto &Item : Settings.SensorDescriptions)
{
check(Item.Value != nullptr);
auto &SensorDescription = *Item.Value;
if (Weather != nullptr)
{
SensorDescription.AdjustToWeather(*Weather);
}
auto *Sensor = FSensorFactory::Make(SensorDescription, *GetWorld());
check(Sensor != nullptr);
Sensor->AttachToActor(PlayerController->GetPawn());
GetDataRouter().RegisterSensor(*Sensor);
}
}

View File

@ -7,21 +7,22 @@
#pragma once
#include "GameFramework/GameModeBase.h"
#include "AI/VehicleSpawnerBase.h"
#include "AI/WalkerSpawnerBase.h"
#include "CarlaGameControllerBase.h"
#include "DynamicWeather.h"
#include "MockGameControllerSettings.h"
#include "Game/CarlaGameControllerBase.h"
#include "Game/CarlaGameInstance.h"
#include "Game/MockGameControllerSettings.h"
#include "Vehicle/VehicleSpawnerBase.h"
#include "Walker/WalkerSpawnerBase.h"
#include "CarlaGameModeBase.generated.h"
class ACarlaVehicleController;
class APlayerStart;
class ASceneCaptureCamera;
class UCarlaGameInstance;
class UTaggerDelegate;
/**
*
*/
UCLASS(HideCategories=(ActorTick))
class CARLA_API ACarlaGameModeBase : public AGameModeBase
{
@ -39,6 +40,12 @@ public:
virtual void Tick(float DeltaSeconds) override;
FDataRouter &GetDataRouter()
{
check(GameInstance != nullptr);
return GameInstance->GetDataRouter();
}
protected:
/** Used only when networking is disabled. */
@ -61,7 +68,7 @@ private:
void RegisterPlayer(AController &NewPlayer);
void AttachCaptureCamerasToPlayer();
void AttachSensorsToPlayer();
void TagActorsForSemanticSegmentation();
@ -73,7 +80,7 @@ private:
AController *Player,
TArray<APlayerStart *> &UnOccupiedStartPoints);
CarlaGameControllerBase *GameController;
ICarlaGameControllerBase *GameController;
UPROPERTY()
UCarlaGameInstance *GameInstance;

View File

@ -1,54 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "GameFramework/GameStateBase.h"
#include "AI/TrafficSignBase.h"
#include "AI/VehicleSpawnerBase.h"
#include "AI/WalkerSpawnerBase.h"
#include "CarlaGameState.generated.h"
UCLASS()
class CARLA_API ACarlaGameState : public AGameStateBase
{
GENERATED_BODY()
public:
const AVehicleSpawnerBase *GetVehicleSpawner() const
{
return VehicleSpawner;
}
const AWalkerSpawnerBase *GetWalkerSpawner() const
{
return WalkerSpawner;
}
const TArray<ATrafficSignBase *> &GetTrafficSigns() const
{
return TrafficSigns;
}
void RegisterTrafficSign(ATrafficSignBase *TrafficSign)
{
TrafficSigns.Add(TrafficSign);
}
private:
friend class ACarlaGameModeBase;
UPROPERTY()
AVehicleSpawnerBase *VehicleSpawner = nullptr;
UPROPERTY()
AWalkerSpawnerBase *WalkerSpawner = nullptr;
UPROPERTY()
TArray<ATrafficSignBase *> TrafficSigns;
};

View File

@ -7,7 +7,8 @@
#include "Carla.h"
#include "CarlaHUD.h"
#include "CarlaVehicleController.h"
#include "Vehicle/CarlaVehicleController.h"
#include "CommandLine.h"
#include "ConstructorHelpers.h"
#include "Engine/Canvas.h"

View File

@ -12,7 +12,7 @@
class FTexture;
UCLASS()
class ACarlaHUD : public AHUD
class CARLA_API ACarlaHUD : public AHUD
{
GENERATED_BODY()

View File

@ -15,7 +15,6 @@ void ACarlaPlayerState::Reset()
CollisionIntensityCars = 0.0f;
CollisionIntensityPedestrians = 0.0f;
CollisionIntensityOther = 0.0f;
Images.Empty();
}
void ACarlaPlayerState::CopyProperties(APlayerState *PlayerState)
@ -44,7 +43,6 @@ void ACarlaPlayerState::CopyProperties(APlayerState *PlayerState)
CollisionIntensityOther = Other->CollisionIntensityOther;
OtherLaneIntersectionFactor = Other->OtherLaneIntersectionFactor;
OffRoadIntersectionFactor = Other->OffRoadIntersectionFactor;
Images = Other->Images;
UE_LOG(LogCarla, Log, TEXT("Copied properties of ACarlaPlayerState"));
}
}

View File

@ -7,8 +7,9 @@
#pragma once
#include "GameFramework/PlayerState.h"
#include "AI/TrafficLightState.h"
#include "CapturedImage.h"
#include "Traffic/TrafficLightState.h"
#include "CarlaPlayerState.generated.h"
/// Current state of the player, updated every frame by ACarlaVehicleController.
@ -183,29 +184,6 @@ public:
return OffRoadIntersectionFactor;
}
/// @}
// ===========================================================================
/// @name Images
// ===========================================================================
/// @{
UFUNCTION(BlueprintCallable)
int32 GetNumberOfImages() const
{
return Images.Num();
}
UFUNCTION(BlueprintCallable)
bool HasImages() const
{
return GetNumberOfImages() > 0;
}
const TArray<FCapturedImage> &GetImages() const
{
return Images;
}
/// @}
// ===========================================================================
// -- Modifiers --------------------------------------------------------------
@ -283,7 +261,4 @@ private:
UPROPERTY(VisibleAnywhere)
float OffRoadIntersectionFactor = 0.0f;
UPROPERTY(VisibleAnywhere)
TArray<FCapturedImage> Images;
};

View File

@ -1,350 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "CarlaServer.h"
#include "GameFramework/PlayerStart.h"
#include "CarlaPlayerState.h"
#include "CarlaVehicleController.h"
#include "CarlaWheeledVehicle.h"
#include "SceneCaptureCamera.h"
#include "Settings/CarlaSettings.h"
#include <carla/carla_server.h>
// =============================================================================
// -- Static local methods -----------------------------------------------------
// =============================================================================
static CarlaServer::ErrorCode ParseErrorCode(const uint32 ErrorCode)
{
if (ErrorCode == CARLA_SERVER_SUCCESS) {
return CarlaServer::Success;
} else if (ErrorCode == CARLA_SERVER_TRY_AGAIN) {
return CarlaServer::TryAgain;
} else {
return CarlaServer::Error;
}
}
static int32 GetTimeOut(uint32 TimeOut, const bool bBlocking)
{
return (bBlocking ? TimeOut : 0u);
}
// =============================================================================
// -- Set functions ------------------------------------------------------------
// =============================================================================
static inline void Set(bool &lhs, bool rhs)
{
lhs = rhs;
}
static inline void Set(float &lhs, float rhs)
{
lhs = rhs;
}
static inline void Set(carla_vector3d &lhs, const FVector &rhs)
{
lhs = {rhs.X, rhs.Y, rhs.Z};
}
static inline void Set(carla_rotation3d &lhs, const FRotator &rhs)
{
lhs.pitch = rhs.Pitch;
lhs.roll = rhs.Roll;
lhs.yaw = rhs.Yaw;
}
static inline void Set(carla_transform &lhs, const FTransform &rhs)
{
Set(lhs.location, rhs.GetLocation());
Set(lhs.orientation, rhs.GetRotation().GetForwardVector());
Set(lhs.rotation, rhs.Rotator());
}
static void Set(carla_image &cImage, const FCapturedImage &uImage)
{
if (uImage.BitMap.Num() > 0) {
cImage.width = uImage.SizeX;
cImage.height = uImage.SizeY;
cImage.type = PostProcessEffect::ToUInt(uImage.PostProcessEffect);
cImage.data = &uImage.BitMap.GetData()->DWColor();
#ifdef CARLA_SERVER_EXTRA_LOG
{
const auto Size = uImage.BitMap.Num();
UE_LOG(LogCarlaServer, Log, TEXT("Sending image %dx%d (%d) type %d"), cImage.width, cImage.height, Size, cImage.type);
}
} else {
UE_LOG(LogCarlaServer, Warning, TEXT("Sending empty image"));
#endif // CARLA_SERVER_EXTRA_LOG
}
}
static void SetBoxSpeedAndType(carla_agent &values, const ACharacter *Walker)
{
values.type = CARLA_SERVER_AGENT_PEDESTRIAN;
values.forward_speed = FVector::DotProduct(Walker->GetVelocity(), Walker->GetActorRotation().Vector()) * 0.036f;
/// @todo Perhaps the box it is not the same for every walker...
values.box_extent = {45.0f, 35.0f, 100.0f};
}
static void SetBoxSpeedAndType(carla_agent &values, const ACarlaWheeledVehicle *Vehicle)
{
values.type = CARLA_SERVER_AGENT_VEHICLE;
values.forward_speed = Vehicle->GetVehicleForwardSpeed();
Set(values.box_extent, Vehicle->GetVehicleBoundsExtent());
}
static void SetBoxSpeedAndType(carla_agent &values, const ATrafficSignBase *TrafficSign)
{
switch (TrafficSign->GetTrafficSignState()) {
case ETrafficSignState::TrafficLightRed:
values.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_RED;
break;
case ETrafficSignState::TrafficLightYellow:
values.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_YELLOW;
break;
case ETrafficSignState::TrafficLightGreen:
values.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_GREEN;
break;
case ETrafficSignState::SpeedLimit_30:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 30.0f;
break;
case ETrafficSignState::SpeedLimit_40:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 40.0f;
break;
case ETrafficSignState::SpeedLimit_50:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 50.0f;
break;
case ETrafficSignState::SpeedLimit_60:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 60.0f;
break;
case ETrafficSignState::SpeedLimit_90:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 90.0f;
break;
case ETrafficSignState::SpeedLimit_100:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 100.0f;
break;
case ETrafficSignState::SpeedLimit_120:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 120.0f;
break;
case ETrafficSignState::SpeedLimit_130:
values.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
values.forward_speed = 130.0f;
break;
default:
UE_LOG(LogCarla, Error, TEXT("Unknown traffic sign!"));
}
}
// =============================================================================
// -- CarlaServer --------------------------------------------------------------
// =============================================================================
CarlaServer::CarlaServer(const uint32 InWorldPort, const uint32 InTimeOut) :
WorldPort(InWorldPort),
TimeOut(InTimeOut),
Server(carla_make_server()) {
check(Server != nullptr);
}
CarlaServer::~CarlaServer()
{
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Warning, TEXT("Destroying CarlaServer"));
#endif // CARLA_SERVER_EXTRA_LOG
carla_free_server(Server);
}
CarlaServer::ErrorCode CarlaServer::Connect()
{
UE_LOG(LogCarlaServer, Log, TEXT("Waiting for the client to connect..."));
return ParseErrorCode(carla_server_connect(Server, WorldPort, TimeOut));
}
CarlaServer::ErrorCode CarlaServer::ReadNewEpisode(UCarlaSettings &Settings, const bool bBlocking)
{
carla_request_new_episode values;
auto ec = ParseErrorCode(carla_read_request_new_episode(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
auto IniFile = FString(values.ini_file_length, ANSI_TO_TCHAR(values.ini_file));
UE_LOG(LogCarlaServer, Log, TEXT("Received new episode"));
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Log, TEXT("Received CarlaSettings.ini:\n%s"), *IniFile);
#endif // CARLA_SERVER_EXTRA_LOG
Settings.LoadSettingsFromString(IniFile);
}
return ec;
}
CarlaServer::ErrorCode CarlaServer::SendSceneDescription(
const TArray<APlayerStart *> &AvailableStartSpots,
const bool bBlocking)
{
const int32 NumberOfStartSpots = AvailableStartSpots.Num();
auto StartSpots = MakeUnique<carla_transform[]>(NumberOfStartSpots);
for (auto i = 0; i < NumberOfStartSpots; ++i) {
Set(StartSpots[i], AvailableStartSpots[i]->GetActorTransform());
}
UE_LOG(LogCarlaServer, Log, TEXT("Sending %d available start positions"), NumberOfStartSpots);
carla_scene_description scene;
scene.player_start_spots = StartSpots.Get();
scene.number_of_player_start_spots = NumberOfStartSpots;
return ParseErrorCode(carla_write_scene_description(Server, scene, GetTimeOut(TimeOut, bBlocking)));
}
CarlaServer::ErrorCode CarlaServer::ReadEpisodeStart(uint32 &StartPositionIndex, const bool bBlocking)
{
carla_episode_start values;
auto ec = ParseErrorCode(carla_read_episode_start(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
StartPositionIndex = values.player_start_spot_index;
UE_LOG(LogCarlaServer, Log, TEXT("Episode start received: { StartIndex = %d }"), StartPositionIndex);
}
return ec;
}
CarlaServer::ErrorCode CarlaServer::SendEpisodeReady(const bool bBlocking)
{
UE_LOG(LogCarlaServer, Log, TEXT("Ready to play, notifying client"));
const carla_episode_ready values = {true};
return ParseErrorCode(carla_write_episode_ready(Server, values, GetTimeOut(TimeOut, bBlocking)));
}
CarlaServer::ErrorCode CarlaServer::ReadControl(ACarlaVehicleController &Player, const bool bBlocking)
{
carla_control values;
auto ec = ParseErrorCode(carla_read_control(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
check(Player.IsPossessingAVehicle());
auto Vehicle = Player.GetPossessedVehicle();
Vehicle->SetSteeringInput(values.steer);
Vehicle->SetThrottleInput(values.throttle);
Vehicle->SetBrakeInput(values.brake);
Vehicle->SetHandbrakeInput(values.hand_brake);
Vehicle->SetReverse(values.reverse);
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(
LogCarlaServer,
Log,
TEXT("Read control (%s): { Steer = %f, Throttle = %f, Brake = %f, Handbrake = %s, Reverse = %s }"),
(bBlocking ? TEXT("Sync") : TEXT("Async")),
values.steer,
values.throttle,
values.brake,
(values.hand_brake ? TEXT("True") : TEXT("False")),
(values.reverse ? TEXT("True") : TEXT("False")));
#endif // CARLA_SERVER_EXTRA_LOG
} else if ((!bBlocking) && (TryAgain == ec)) {
UE_LOG(LogCarlaServer, Warning, TEXT("No control received from the client this frame!"));
}
return ec;
}
template <typename T>
static void AddAgents(TArray<carla_agent> &Agents, const TArray<T> &Actors)
{
for (auto &&Actor : Actors) {
if (Actor != nullptr) {
Agents.Emplace();
auto &values = Agents.Last();
values.id = GetTypeHash(Actor);
Set(values.transform, Actor->GetActorTransform());
SetBoxSpeedAndType(values, Actor);
}
}
}
static void GetAgentInfo(
const ACarlaGameState &GameState,
TArray<carla_agent> &Agents)
{
const auto *WalkerSpawner = GameState.GetWalkerSpawner();
const auto *VehicleSpawner = GameState.GetVehicleSpawner();
const auto &TrafficSigns = GameState.GetTrafficSigns();
auto NumberOfAgents = TrafficSigns.Num();
if (WalkerSpawner != nullptr) {
NumberOfAgents += WalkerSpawner->GetCurrentNumberOfWalkers();
}
if (VehicleSpawner != nullptr) {
NumberOfAgents += VehicleSpawner->GetNumberOfSpawnedVehicles();
}
Agents.Reserve(NumberOfAgents);
AddAgents(Agents, TrafficSigns);
if (WalkerSpawner != nullptr) {
AddAgents(Agents, WalkerSpawner->GetWalkersWhiteList());
AddAgents(Agents, WalkerSpawner->GetWalkersBlackList());
}
if (VehicleSpawner != nullptr) {
AddAgents(Agents, VehicleSpawner->GetVehicles());
}
}
CarlaServer::ErrorCode CarlaServer::SendMeasurements(
const ACarlaGameState &GameState,
const ACarlaPlayerState &PlayerState,
const bool bSendNonPlayerAgentsInfo)
{
// Measurements.
carla_measurements values;
values.platform_timestamp = PlayerState.GetPlatformTimeStamp();
values.game_timestamp = PlayerState.GetGameTimeStamp();
auto &player = values.player_measurements;
Set(player.transform, PlayerState.GetTransform());
Set(player.acceleration, PlayerState.GetAcceleration());
Set(player.forward_speed, PlayerState.GetForwardSpeed());
Set(player.collision_vehicles, PlayerState.GetCollisionIntensityCars());
Set(player.collision_pedestrians, PlayerState.GetCollisionIntensityPedestrians());
Set(player.collision_other, PlayerState.GetCollisionIntensityOther());
Set(player.intersection_otherlane, PlayerState.GetOtherLaneIntersectionFactor());
Set(player.intersection_offroad, PlayerState.GetOffRoadIntersectionFactor());
Set(player.autopilot_control.steer, PlayerState.GetSteer());
Set(player.autopilot_control.throttle, PlayerState.GetThrottle());
Set(player.autopilot_control.brake, PlayerState.GetBrake());
Set(player.autopilot_control.hand_brake, PlayerState.GetHandBrake());
Set(player.autopilot_control.reverse, PlayerState.GetCurrentGear() < 0);
TArray<carla_agent> Agents;
if (bSendNonPlayerAgentsInfo) {
GetAgentInfo(GameState, Agents);
}
values.non_player_agents = (Agents.Num() > 0 ? Agents.GetData() : nullptr);
values.number_of_non_player_agents = Agents.Num();
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Log, TEXT("Sending data of %d agents"), values.number_of_non_player_agents);
#endif // CARLA_SERVER_EXTRA_LOG
// Images.
const auto NumberOfImages = PlayerState.GetNumberOfImages();
TUniquePtr<carla_image[]> images;
if (NumberOfImages > 0) {
images = MakeUnique<carla_image[]>(NumberOfImages);
for (auto i = 0; i < NumberOfImages; ++i) {
Set(images[i], PlayerState.GetImages()[i]);
}
}
return ParseErrorCode(carla_write_measurements(Server, values, images.Get(), NumberOfImages));
}

View File

@ -0,0 +1,47 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "DataRouter.h"
#include "Sensor/Sensor.h"
void FDataRouter::RegisterPlayer(ACarlaVehicleController &InPlayer)
{
if (Player == nullptr) {
Player = &InPlayer;
} else {
UE_LOG(
LogCarla,
Error,
TEXT("FDataRouter: Trying to register a second player but only one is supported"));
}
}
void FDataRouter::RegisterSensor(ASensor &InSensor)
{
if (SensorDataSink.IsValid()) {
InSensor.SetSensorDataSink(SensorDataSink);
} else {
UE_LOG(
LogCarla,
Error,
TEXT("FDataRouter: Trying to register a sensor but I don't have a SensorDataSink"));
}
}
void FDataRouter::RestartLevel()
{
if (Player != nullptr) {
Player->RestartLevel();
Player = nullptr;
} else {
UE_LOG(
LogCarla,
Error,
TEXT("FDataRouter: Trying to restart level but I don't have any player registered"));
}
}

View File

@ -0,0 +1,73 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Util/NonCopyable.h"
#include "Sensor/SensorDataSink.h"
#include "Vehicle/CarlaVehicleController.h"
#include "Vehicle/CarlaWheeledVehicle.h"
class ACarlaPlayerState;
class ASensor;
class UAgentComponent;
struct FVehicleControl;
class FDataRouter : private NonCopyable
{
public:
void SetSensorDataSink(TSharedPtr<ISensorDataSink> InSensorDataSink)
{
check(!SensorDataSink.IsValid());
SensorDataSink = InSensorDataSink;
}
void RegisterPlayer(ACarlaVehicleController &InPlayer);
void RegisterSensor(ASensor &InSensor);
void RegisterAgent(const UAgentComponent *Agent)
{
check(Agent != nullptr);
Agents.Emplace(Agent);
}
void DeregisterAgent(const UAgentComponent *Agent)
{
check(Agent != nullptr);
Agents.RemoveSwap(Agent);
}
const ACarlaPlayerState &GetPlayerState() const
{
check(Player != nullptr);
return Player->GetPlayerState();
}
const TArray<const UAgentComponent *> &GetAgents() const
{
return Agents;
}
void ApplyVehicleControl(const FVehicleControl &VehicleControl)
{
check((Player != nullptr) && (Player->IsPossessingAVehicle()));
Player->GetPossessedVehicle()->ApplyVehicleControl(VehicleControl);
}
void RestartLevel();
private:
TArray<const UAgentComponent *> Agents;
ACarlaVehicleController *Player = nullptr;
TSharedPtr<ISensorDataSink> SensorDataSink = nullptr;
};

View File

@ -7,8 +7,22 @@
#include "Carla.h"
#include "MockGameController.h"
MockGameController::MockGameController(const FMockGameControllerSettings &InSettings) :
Settings(InSettings) {}
#include "Game/DataRouter.h"
#include "Sensor/SensorDataSink.h"
class FMockSensorDataSink : public ISensorDataSink {
public:
virtual void Write(const FSensorDataView &) final {}
};
MockGameController::MockGameController(
FDataRouter &InDataRouter,
const FMockGameControllerSettings &InSettings)
: ICarlaGameControllerBase(InDataRouter),
Settings(InSettings) {
DataRouter.SetSensorDataSink(MakeShared<FMockSensorDataSink>());
}
void MockGameController::Initialize(UCarlaSettings &CarlaSettings)
{

View File

@ -6,25 +6,26 @@
#pragma once
#include "CarlaGameControllerBase.h"
#include "MockGameControllerSettings.h"
#include "Game/CarlaGameControllerBase.h"
#include "Game/MockGameControllerSettings.h"
/// Mocks the CARLA game controller class for testing purposes.
class CARLA_API MockGameController : public CarlaGameControllerBase
class MockGameController : public ICarlaGameControllerBase
{
public:
explicit MockGameController(const FMockGameControllerSettings &Settings);
explicit MockGameController(FDataRouter &DataRouter, const FMockGameControllerSettings &Settings);
virtual void Initialize(UCarlaSettings &CarlaSettings) override;
virtual void Initialize(UCarlaSettings &CarlaSettings) final;
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) override;
virtual APlayerStart *ChoosePlayerStart(const TArray<APlayerStart *> &AvailableStartSpots) final;
virtual void RegisterPlayer(AController &NewPlayer) override;
virtual void RegisterPlayer(AController &NewPlayer) final;
virtual void BeginPlay() override;
virtual void BeginPlay() final;
virtual void Tick(float DeltaSeconds) override;
virtual void Tick(float DeltaSeconds) final;
private:

View File

@ -9,7 +9,7 @@
#include "MockGameControllerSettings.generated.h"
USTRUCT(BlueprintType)
struct FMockGameControllerSettings
struct CARLA_API FMockGameControllerSettings
{
GENERATED_USTRUCT_BODY()

View File

@ -6,11 +6,12 @@
#include "Carla.h"
#include "Tagger.h"
#include "EngineUtils.h"
#include "Engine/StaticMesh.h"
#include "Engine/SkeletalMesh.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/SkeletalMesh.h"
#include "Engine/StaticMesh.h"
#include "EngineUtils.h"
#include "PhysicsEngine/PhysicsAsset.h"
#ifdef CARLA_TAGGER_EXTRA_LOG

View File

@ -7,8 +7,9 @@
#include "Carla.h"
#include "TaggerDelegate.h"
#include "Game/Tagger.h"
#include "Engine/World.h"
#include "Tagger.h"
UTaggerDelegate::UTaggerDelegate() :
ActorSpawnedDelegate(FOnActorSpawned::FDelegate::CreateUObject(this, &UTaggerDelegate::OnActorSpawned)) {}

View File

@ -73,7 +73,7 @@ enum class ECityMapMeshTag : uint8
};
/// Helper class for working with ECityMapMeshTag.
class CARLA_API CityMapMeshTag
class CityMapMeshTag
{
public:

View File

@ -11,7 +11,7 @@
namespace MapGen {
/// Random DoublyConnectedEdgeList generator.
class CARLA_API GraphGenerator : private NonCopyable
class GraphGenerator : private NonCopyable
{
public:

View File

@ -16,7 +16,7 @@ namespace MapGen {
class DoublyConnectedEdgeList;
class CARLA_API GraphParser : private NonCopyable
class GraphParser : private NonCopyable
{
public:

View File

@ -11,7 +11,7 @@
namespace MapGen {
template<typename T>
class CARLA_API Position {
class Position {
public:
using number_type = T;

View File

@ -12,7 +12,7 @@
/// Road map intersection result. See URoadMap.
USTRUCT(BlueprintType)
struct FRoadMapIntersectionResult
struct CARLA_API FRoadMapIntersectionResult
{
GENERATED_BODY()

View File

@ -13,7 +13,7 @@
namespace MapGen {
class CARLA_API RoadSegmentDescription : private NonCopyable
class RoadSegmentDescription : private NonCopyable
{
public:

View File

@ -19,7 +19,7 @@ enum class ELaneMarkingType : uint8
/// Description of a road segment piece.
USTRUCT(BlueprintType)
struct FRoadSegmentPiece
struct CARLA_API FRoadSegmentPiece
{
GENERATED_BODY()

View File

@ -0,0 +1,144 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Carla.h"
#include "Lidar.h"
#include "DrawDebugHelpers.h"
#include "Engine/CollisionProfile.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
#include "StaticMeshResources.h"
ALidar::ALidar(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
auto MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh0"));
MeshComp->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
MeshComp->bHiddenInGame = true;
MeshComp->CastShadow = false;
MeshComp->PostPhysicsComponentTick.bCanEverTick = false;
RootComponent = MeshComp;
}
void ALidar::Set(const ULidarDescription &LidarDescription)
{
Super::Set(LidarDescription);
Description = &LidarDescription;
LidarMeasurement = FLidarMeasurement(GetId(), Description->Channels);
CreateLasers();
}
void ALidar::CreateLasers()
{
check(Description != nullptr);
const auto NumberOfLasers = Description->Channels;
check(NumberOfLasers > 0u);
const float DeltaAngle =
(Description->UpperFovLimit - Description->LowerFovLimit) /
static_cast<float>(NumberOfLasers - 1);
LaserAngles.Empty(NumberOfLasers);
for(auto i = 0u; i < NumberOfLasers; ++i)
{
const float VerticalAngle =
Description->UpperFovLimit - static_cast<float>(i) * DeltaAngle;
LaserAngles.Emplace(VerticalAngle);
}
}
void ALidar::Tick(const float DeltaTime)
{
Super::Tick(DeltaTime);
ReadPoints(DeltaTime);
WriteSensorData(LidarMeasurement.GetView());
}
void ALidar::ReadPoints(const float DeltaTime)
{
const uint32 ChannelCount = Description->Channels;
const uint32 PointsToScanWithOneLaser =
FMath::RoundHalfFromZero(
Description->PointsPerSecond * DeltaTime / float(ChannelCount));
check(PointsToScanWithOneLaser > 0);
check(ChannelCount == LaserAngles.Num());
check(Description != nullptr);
const float CurrentHorizontalAngle = LidarMeasurement.GetHorizontalAngle();
const float AngleDistanceOfTick = Description->RotationFrequency * 360.0f * DeltaTime;
const float AngleDistanceOfLaserMeasure = AngleDistanceOfTick / PointsToScanWithOneLaser;
LidarMeasurement.Reset(ChannelCount * PointsToScanWithOneLaser);
for (auto Channel = 0u; Channel < ChannelCount; ++Channel)
{
for (auto i = 0u; i < PointsToScanWithOneLaser; ++i)
{
FVector Point;
const float Angle = CurrentHorizontalAngle + AngleDistanceOfLaserMeasure * i;
if (ShootLaser(Channel, Angle, Point))
{
LidarMeasurement.WritePoint(Channel, Point);
}
}
}
const float HorizontalAngle = std::fmod(CurrentHorizontalAngle + AngleDistanceOfTick, 360.0f);
LidarMeasurement.SetHorizontalAngle(HorizontalAngle);
}
bool ALidar::ShootLaser(const uint32 Channel, const float HorizontalAngle, FVector &XYZ) const
{
const float VerticalAngle = LaserAngles[Channel];
FCollisionQueryParams TraceParams = FCollisionQueryParams(FName(TEXT("Laser_Trace")), true, this);
TraceParams.bTraceComplex = true;
TraceParams.bReturnPhysicalMaterial = false;
FHitResult HitInfo(ForceInit);
FVector LidarBodyLoc = GetActorLocation();
FRotator LidarBodyRot = GetActorRotation();
FRotator LaserRot (VerticalAngle, HorizontalAngle, 0); // float InPitch, float InYaw, float InRoll
FRotator ResultRot = UKismetMathLibrary::ComposeRotators(
LaserRot,
LidarBodyRot
);
const auto Range = Description->Range;
FVector EndTrace = Range * UKismetMathLibrary::GetForwardVector(ResultRot) + LidarBodyLoc;
GetWorld()->LineTraceSingleByChannel(
HitInfo,
LidarBodyLoc,
EndTrace,
ECC_MAX,
TraceParams,
FCollisionResponseParams::DefaultResponseParam
);
if (HitInfo.bBlockingHit)
{
if (Description->ShowDebugPoints)
{
DrawDebugPoint(
GetWorld(),
HitInfo.ImpactPoint,
10, //size
FColor(255,0,255),
false, //persistent (never goes away)
0.1 //point leaves a trail on moving object
);
}
XYZ = LidarBodyLoc - HitInfo.ImpactPoint;
XYZ = UKismetMathLibrary::RotateAngleAxis(
XYZ,
- LidarBodyRot.Yaw + 90,
FVector(0, 0, 1)
);
return true;
} else {
return false;
}
}

View File

@ -0,0 +1,45 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Sensor/Sensor.h"
#include "Sensor/LidarMeasurement.h"
#include "Settings/LidarDescription.h"
#include "Lidar.generated.h"
/// A ray-trace based Lidar sensor.
UCLASS()
class CARLA_API ALidar : public ASensor
{
GENERATED_BODY()
public:
ALidar(const FObjectInitializer &ObjectInitializer);
void Set(const ULidarDescription &LidarDescription);
protected:
virtual void Tick(float DeltaTime) override;
private:
/// Creates a Laser for each channel.
void CreateLasers();
/// Updates LidarMeasurement with the points read in DeltaTime.
void ReadPoints(float DeltaTime);
/// Shoot a laser ray-trace, return whether the laser hit something.
bool ShootLaser(uint32 Channel, float HorizontalAngle, FVector &Point) const;
UPROPERTY(Category = "LiDAR", VisibleAnywhere)
const ULidarDescription *Description;
TArray<float> LaserAngles;
FLidarMeasurement LidarMeasurement;
};

View File

@ -0,0 +1,95 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Sensor/SensorDataView.h"
#include "Containers/Array.h"
/// Stores the data generated by ALidar. To be used by ALidar solely.
///
/// The header consists of an array of uint32's in the following layout
///
/// {
/// Horizontal angle (float),
/// Channel count,
/// Point count of channel 0,
/// ...
/// Point count of channel n,
/// }
///
/// The points are stored in an array of floats
///
/// {
/// X0, Y0, Z0,
/// ...
/// Xn, Yn, Zn,
/// }
///
class FLidarMeasurement {
static_assert(sizeof(float) == sizeof(uint32), "Invalid float size");
public:
explicit FLidarMeasurement(uint32 SensorId = 0u, uint32 ChannelCount = 0u)
: SensorId(SensorId)
{
Header.AddDefaulted(2u + ChannelCount);
Header[1] = ChannelCount;
}
FLidarMeasurement &operator=(FLidarMeasurement &&Other)
{
SensorId = Other.SensorId;
Header = std::move(Other.Header);
Points = std::move(Other.Points);
Other.SensorId = 0u;
return *this;
}
float GetHorizontalAngle() const
{
return reinterpret_cast<const float &>(Header[0]);
}
void SetHorizontalAngle(float HorizontalAngle)
{
Header[0] = reinterpret_cast<const uint32 &>(HorizontalAngle);
}
uint32 GetChannelCount() const
{
return Header[1];
}
void Reset(uint32 TotalPointCount)
{
std::memset(Header.GetData() + 2u, 0, sizeof(uint32) * GetChannelCount());
Points.Reset(3u * TotalPointCount);
}
void WritePoint(uint32 Channel, const FVector &Point)
{
check(Header[1] > Channel);
Header[2u + Channel] += 1u;
Points.Emplace(Point.X);
Points.Emplace(Point.Y);
Points.Emplace(Point.Z);
}
FSensorDataView GetView() const
{
return FSensorDataView(SensorId, Header, Points);
}
private:
uint32 SensorId;
TArray<uint32> Header;
TArray<float> Points;
};

View File

@ -0,0 +1,45 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Containers/Array.h"
/// A view over a read-only buffer. Does not own the data.
class FReadOnlyBufferView {
public:
FReadOnlyBufferView() = default;
explicit FReadOnlyBufferView(const void *InData, uint32 InSize)
: Data(InData),
Size(InSize) {}
template <typename T>
FReadOnlyBufferView(const TArray<T> &Array)
: FReadOnlyBufferView(Array.GetData(), sizeof(T) * Array.Num()) {}
bool HasData() const
{
return (Data != nullptr) && (Size > 0u);
}
const void *GetData() const
{
return Data;
}
uint32 GetSize() const
{
return Size;
}
private:
const void *Data = nullptr;
uint32 Size = 0u;
};

View File

@ -7,6 +7,8 @@
#include "Carla.h"
#include "SceneCaptureCamera.h"
#include "Sensor/SensorDataView.h"
#include "Components/DrawFrustumComponent.h"
#include "Components/SceneCaptureComponent2D.h"
#include "Components/StaticMeshComponent.h"
@ -38,7 +40,7 @@ ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitial
SizeY(512u),
PostProcessEffect(EPostProcessEffect::SceneFinal)
{
PrimaryActorTick.bCanEverTick = true; /// @todo Does it need to tick?
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh0"));
@ -119,6 +121,43 @@ void ASceneCaptureCamera::BeginPlay()
Super::BeginPlay();
}
void ASceneCaptureCamera::Tick(const float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
/// @todo This should be done on render thread.
struct {
uint32 Width;
uint32 Height;
uint32 Type;
float FOV;
} ImageHeader = {
SizeX,
SizeY,
PostProcessEffect::ToUInt(PostProcessEffect),
CaptureComponent2D->FOVAngle
};
static_assert(sizeof(ImageHeader) == 4u * sizeof(uint32), "Invalid header size");
TArray<FColor> BitMap;
if (ReadPixels(BitMap)) {
FSensorDataView DataView(
GetId(),
FReadOnlyBufferView{reinterpret_cast<const void *>(&ImageHeader), sizeof(ImageHeader)},
FReadOnlyBufferView{BitMap});
WriteSensorData(DataView);
}
}
float ASceneCaptureCamera::GetFOVAngle() const
{
check(CaptureComponent2D != nullptr);
return CaptureComponent2D->FOVAngle;
}
void ASceneCaptureCamera::SetImageSize(uint32 otherSizeX, uint32 otherSizeY)
{
SizeX = otherSizeX;
@ -149,29 +188,27 @@ void ASceneCaptureCamera::SetTargetGamma(const float TargetGamma)
CaptureRenderTarget->TargetGamma = TargetGamma;
}
void ASceneCaptureCamera::Set(const FCameraDescription &CameraDescription)
void ASceneCaptureCamera::Set(const UCameraDescription &CameraDescription)
{
Super::Set(CameraDescription);
if (CameraDescription.bOverrideCameraPostProcessParameters) {
auto &Override = CameraDescription.CameraPostProcessParameters;
auto &PostProcessSettings = CaptureComponent2D->PostProcessSettings;
PostProcessSettings.bOverride_AutoExposureMethod = true;
PostProcessSettings.AutoExposureMethod = Override.AutoExposureMethod;
PostProcessSettings.bOverride_AutoExposureMinBrightness = true;
PostProcessSettings.AutoExposureMinBrightness = Override.AutoExposureMinBrightness;
PostProcessSettings.bOverride_AutoExposureMaxBrightness = true;
PostProcessSettings.AutoExposureMaxBrightness = Override.AutoExposureMaxBrightness;
PostProcessSettings.bOverride_AutoExposureBias = true;
PostProcessSettings.AutoExposureBias = Override.AutoExposureBias;
}
SetImageSize(CameraDescription.ImageSizeX, CameraDescription.ImageSizeY);
SetPostProcessEffect(CameraDescription.PostProcessEffect);
SetFOVAngle(CameraDescription.FOVAngle);
}
void ASceneCaptureCamera::Set(
const FCameraDescription &CameraDescription,
const FCameraPostProcessParameters &OverridePostProcessParameters)
{
auto &PostProcessSettings = CaptureComponent2D->PostProcessSettings;
PostProcessSettings.bOverride_AutoExposureMethod = true;
PostProcessSettings.AutoExposureMethod = OverridePostProcessParameters.AutoExposureMethod;
PostProcessSettings.bOverride_AutoExposureMinBrightness = true;
PostProcessSettings.AutoExposureMinBrightness = OverridePostProcessParameters.AutoExposureMinBrightness;
PostProcessSettings.bOverride_AutoExposureMaxBrightness = true;
PostProcessSettings.AutoExposureMaxBrightness = OverridePostProcessParameters.AutoExposureMaxBrightness;
PostProcessSettings.bOverride_AutoExposureBias = true;
PostProcessSettings.AutoExposureBias = OverridePostProcessParameters.AutoExposureBias;
Set(CameraDescription);
}
bool ASceneCaptureCamera::ReadPixels(TArray<FColor> &BitMap) const
{
FTextureRenderTargetResource* RTResource = CaptureRenderTarget->GameThread_GetRenderTargetResource();

View File

@ -6,9 +6,12 @@
#pragma once
#include "GameFramework/Actor.h"
#include "StaticMeshResources.h"
#include "Sensor/Sensor.h"
#include "Settings/CameraDescription.h"
#include "StaticMeshResources.h"
#include "SceneCaptureCamera.generated.h"
class UDrawFrustumComponent;
@ -19,7 +22,7 @@ class UTextureRenderTarget2D;
/// Own SceneCapture, re-implementing some of the methods since ASceneCapture
/// cannot be subclassed.
UCLASS(hidecategories=(Collision, Attachment, Actor))
class CARLA_API ASceneCaptureCamera : public AActor
class CARLA_API ASceneCaptureCamera : public ASensor
{
GENERATED_BODY()
@ -35,6 +38,8 @@ public:
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
uint32 GetImageSizeX() const
{
return SizeX;
@ -50,6 +55,8 @@ public:
return PostProcessEffect;
}
float GetFOVAngle() const;
void SetImageSize(uint32 SizeX, uint32 SizeY);
void SetPostProcessEffect(EPostProcessEffect PostProcessEffect);
@ -58,11 +65,7 @@ public:
void SetTargetGamma(float TargetGamma);
void Set(const FCameraDescription &CameraDescription);
void Set(
const FCameraDescription &CameraDescription,
const FCameraPostProcessParameters &OverridePostProcessParameters);
void Set(const UCameraDescription &CameraDescription);
bool ReadPixels(TArray<FColor> &BitMap) const;

View File

@ -12,7 +12,7 @@
ASceneCaptureToDiskCamera::ASceneCaptureToDiskCamera(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer),
SaveToFolder(FPaths::Combine(FPaths::GameSavedDir(), "SceneCaptures")),
SaveToFolder(FPaths::Combine(FPaths::ProjectSavedDir(), "SceneCaptures")),
FileName("capture_%05d.png") {}
void ASceneCaptureToDiskCamera::BeginPlay()

View File

@ -6,7 +6,8 @@
#pragma once
#include "SceneCaptureCamera.h"
#include "Sensor/SceneCaptureCamera.h"
#include "SceneCaptureToDiskCamera.generated.h"
UCLASS(Blueprintable,BlueprintType)

View File

@ -0,0 +1,20 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "Sensor.h"
ASensor::ASensor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer),
Id(0u) {}
void ASensor::AttachToActor(AActor *Actor)
{
check(Actor != nullptr);
Super::AttachToActor(Actor, FAttachmentTransformRules::KeepRelativeTransform);
SetOwner(Actor);
Actor->AddTickPrerequisiteActor(this);
}

View File

@ -0,0 +1,60 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "GameFramework/Actor.h"
#include "Sensor/SensorDataSink.h"
#include "Settings/SensorDescription.h"
#include "Sensor.generated.h"
/// Base class for sensors.
UCLASS(Abstract, hidecategories=(Collision, Attachment, Actor))
class CARLA_API ASensor : public AActor
{
GENERATED_BODY()
public:
ASensor(const FObjectInitializer& ObjectInitializer);
uint32 GetId() const
{
return Id;
}
void AttachToActor(AActor *Actor);
void SetSensorDataSink(TSharedPtr<ISensorDataSink> InSensorDataSink)
{
SensorDataSink = InSensorDataSink;
}
protected:
void Set(const USensorDescription &SensorDescription)
{
Id = SensorDescription.GetId();
}
void WriteSensorData(const FSensorDataView &SensorData)
{
if (SensorDataSink.IsValid()) {
SensorDataSink->Write(SensorData);
} else {
UE_LOG(LogCarla, Warning, TEXT("Sensor %d has no data sink."), Id);
}
}
private:
UPROPERTY(VisibleAnywhere)
uint32 Id;
TSharedPtr<ISensorDataSink> SensorDataSink = nullptr;
};

View File

@ -4,9 +4,15 @@
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "CarlaGameState.h"
#pragma once
class FSensorDataView;
/// Interface for sensor data sinks.
class ISensorDataSink {
public:
virtual ~ISensorDataSink() {}
virtual void Write(const FSensorDataView &SensorData) = 0;
};

View File

@ -0,0 +1,45 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Sensor/ReadOnlyBufferView.h"
/// A view over a sensor's output data. Does not own the data.
class FSensorDataView {
public:
FSensorDataView(
uint32 InSensorId,
FReadOnlyBufferView InHeader,
FReadOnlyBufferView InData)
: SensorId(InSensorId),
Header(InHeader),
Data(InData) {}
uint32 GetSensorId() const
{
return SensorId;
}
FReadOnlyBufferView GetHeader() const
{
return Header;
}
FReadOnlyBufferView GetData() const
{
return Data;
}
private:
uint32 SensorId;
FReadOnlyBufferView Header;
FReadOnlyBufferView Data;
};

View File

@ -0,0 +1,60 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Carla.h"
#include "SensorFactory.h"
#include "Sensor/Lidar.h"
#include "Sensor/SceneCaptureCamera.h"
#include "Settings/CameraDescription.h"
#include "Settings/LidarDescription.h"
template <typename T, typename D>
static T *SpawnSensor(const D &Description, UWorld &World)
{
FActorSpawnParameters Params;
Params.Name = FName(*Description.Name);
return World.SpawnActor<T>(Description.Position, Description.Rotation, Params);
}
ASensor *FSensorFactory::Make(
const USensorDescription &Description,
UWorld &World)
{
FSensorFactory Visitor(World);
Description.AcceptVisitor(Visitor);
check(Visitor.Sensor != nullptr);
return Visitor.Sensor;
}
FSensorFactory::FSensorFactory(UWorld &World) : World(World) {}
void FSensorFactory::Visit(const UCameraDescription &Description)
{
auto Camera = SpawnSensor<ASceneCaptureCamera>(Description, World);
Camera->Set(Description);
UE_LOG(
LogCarla,
Log,
TEXT("Created Capture Camera %d with postprocess \"%s\""),
Camera->GetId(),
*PostProcessEffect::ToString(Camera->GetPostProcessEffect()));
Sensor = Camera;
}
void FSensorFactory::Visit(const ULidarDescription &Description)
{
auto Lidar = SpawnSensor<ALidar>(Description, World);
Lidar->Set(Description);
UE_LOG(
LogCarla,
Log,
TEXT("Created LiDAR %d"),
Lidar->GetId());
Sensor = Lidar;
}

View File

@ -0,0 +1,33 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Settings/SensorDescriptionVisitor.h"
class ASensor;
class UWorld;
class FSensorFactory : private ISensorDescriptionVisitor
{
public:
static ASensor *Make(
const USensorDescription &Description,
UWorld &World);
private:
FSensorFactory(UWorld &World);
virtual void Visit(const UCameraDescription &) final;
virtual void Visit(const ULidarDescription &) final;
UWorld &World;
ASensor *Sensor = nullptr;
};

View File

@ -0,0 +1,209 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "CarlaEncoder.h"
#include "Agent/TrafficSignAgentComponent.h"
#include "Agent/VehicleAgentComponent.h"
#include "Agent/WalkerAgentComponent.h"
#include "Game/CarlaPlayerState.h"
#include "Settings/SensorDescription.h"
#include "GameFramework/PlayerStart.h"
#include <cstring>
// =============================================================================
// -- Static local methods -----------------------------------------------------
// =============================================================================
static auto MakeCharBuffer(const FString &String)
{
const char *Ptr = TCHAR_TO_ANSI(*String);
auto Buffer = MakeUnique<char[]>(std::strlen(Ptr) + 1u); // + null terminator.
std::strcpy(Buffer.Get(), Ptr);
return TUniquePtr<const char[]>(Buffer.Release());
}
static void Encode(const FVector &Vector, carla_vector3d &Data)
{
Data = {Vector.X, Vector.Y, Vector.Z};
}
static void Encode(const FRotator &Rotator, carla_rotation3d &Data)
{
Data.pitch = Rotator.Pitch;
Data.roll = Rotator.Roll;
Data.yaw = Rotator.Yaw;
}
static void Encode(const FTransform &Transform, carla_transform &Data)
{
Encode(Transform.GetLocation(), Data.location);
Encode(Transform.GetRotation().GetForwardVector(), Data.orientation);
Encode(Transform.Rotator(), Data.rotation);
}
static TUniquePtr<const char[]> Encode(
const USensorDescription &SensorDescription,
carla_sensor_definition &Data)
{
Data.id = SensorDescription.GetId();
Data.type = [](const FString &Type) {
#define CARLA_CHECK_TYPE(Str) if (Type == TEXT(#Str)) return CARLA_SERVER_ ## Str;
CARLA_CHECK_TYPE(CAMERA)
CARLA_CHECK_TYPE(LIDAR_RAY_TRACE)
else return CARLA_SERVER_SENSOR_UNKNOWN;
#undef CARLA_CHECK_TYPE
}(SensorDescription.Type);
auto Memory = MakeCharBuffer(SensorDescription.Name);
Data.name = Memory.Get();
return Memory;
}
// =============================================================================
// -- FCarlaEncoder static methods ---------------------------------------------
// =============================================================================
void FCarlaEncoder::Encode(
const TArray<APlayerStart *> &AvailableStartSpots,
TArray<carla_transform> &Data)
{
const int32 NumberOfStartSpots = AvailableStartSpots.Num();
Data.AddUninitialized(NumberOfStartSpots);
for (auto i = 0; i < NumberOfStartSpots; ++i) {
check(AvailableStartSpots[i] != nullptr);
::Encode(AvailableStartSpots[i]->GetActorTransform(), Data[i]);
}
}
void FCarlaEncoder::Encode(
const TArray<USensorDescription *> &SensorDescriptions,
TArray<carla_sensor_definition> &Data,
TArray<TUniquePtr<const char[]>> &SensorNames)
{
const int32 NumberOfSensors = SensorDescriptions.Num();
Data.AddUninitialized(NumberOfSensors);
SensorNames.Reserve(NumberOfSensors);
for (auto i = 0; i < NumberOfSensors; ++i) {
check(SensorDescriptions[i] != nullptr);
SensorNames.Emplace(::Encode(*SensorDescriptions[i], Data[i]));
}
}
void FCarlaEncoder::Encode(
const ACarlaPlayerState &PlayerState,
carla_measurements &Data)
{
Data.platform_timestamp = PlayerState.GetPlatformTimeStamp();
Data.game_timestamp = PlayerState.GetGameTimeStamp();
auto &Player = Data.player_measurements;
::Encode(PlayerState.GetTransform(), Player.transform);
::Encode(PlayerState.GetAcceleration(), Player.acceleration);
Player.forward_speed = PlayerState.GetForwardSpeed();
Player.collision_vehicles = PlayerState.GetCollisionIntensityCars();
Player.collision_pedestrians = PlayerState.GetCollisionIntensityPedestrians();
Player.collision_other = PlayerState.GetCollisionIntensityOther();
Player.intersection_otherlane = PlayerState.GetOtherLaneIntersectionFactor();
Player.intersection_offroad = PlayerState.GetOffRoadIntersectionFactor();
Player.autopilot_control.steer = PlayerState.GetSteer();
Player.autopilot_control.throttle = PlayerState.GetThrottle();
Player.autopilot_control.brake = PlayerState.GetBrake();
Player.autopilot_control.hand_brake = PlayerState.GetHandBrake();
Player.autopilot_control.reverse = PlayerState.GetCurrentGear() < 0;
}
void FCarlaEncoder::Encode(
const TArray<const UAgentComponent *> &Agents,
TArray<carla_agent> &Data)
{
const int32 NumberOfAgents = Agents.Num();
Data.AddUninitialized(NumberOfAgents);
for (auto i = 0; i < NumberOfAgents; ++i) {
check(Agents[i] != nullptr);
Encode(*Agents[i], Data[i]);
}
}
void FCarlaEncoder::Encode(const UAgentComponent &AgentComponent, carla_agent &AgentData)
{
AgentData.id = AgentComponent.GetId();
::Encode(AgentComponent.GetComponentTransform(), AgentData.transform);
FCarlaEncoder Encoder(AgentData);
AgentComponent.AcceptVisitor(Encoder);
}
// =============================================================================
// -- FCarlaEncoder ------------------------------------------------------------
// =============================================================================
FCarlaEncoder::FCarlaEncoder(carla_agent &InData) : Data(InData) {}
void FCarlaEncoder::Visit(const UTrafficSignAgentComponent &Agent)
{
auto &TrafficSign = Agent.GetTrafficSign();
switch (TrafficSign.GetTrafficSignState()) {
case ETrafficSignState::TrafficLightRed:
Data.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_RED;
break;
case ETrafficSignState::TrafficLightYellow:
Data.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_YELLOW;
break;
case ETrafficSignState::TrafficLightGreen:
Data.type = CARLA_SERVER_AGENT_TRAFFICLIGHT_GREEN;
break;
case ETrafficSignState::SpeedLimit_30:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 30.0f;
break;
case ETrafficSignState::SpeedLimit_40:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 40.0f;
break;
case ETrafficSignState::SpeedLimit_50:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 50.0f;
break;
case ETrafficSignState::SpeedLimit_60:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 60.0f;
break;
case ETrafficSignState::SpeedLimit_90:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 90.0f;
break;
case ETrafficSignState::SpeedLimit_100:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 100.0f;
break;
case ETrafficSignState::SpeedLimit_120:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 120.0f;
break;
case ETrafficSignState::SpeedLimit_130:
Data.type = CARLA_SERVER_AGENT_SPEEDLIMITSIGN;
Data.forward_speed = 130.0f;
break;
default:
UE_LOG(LogCarla, Error, TEXT("Unknown traffic sign!"));
}
}
void FCarlaEncoder::Visit(const UVehicleAgentComponent &Agent)
{
auto &Vehicle = Agent.GetVehicle();
Data.type = CARLA_SERVER_AGENT_VEHICLE;
Data.forward_speed = Vehicle.GetVehicleForwardSpeed();
::Encode(Vehicle.GetVehicleBoundsExtent(), Data.box_extent);
}
void FCarlaEncoder::Visit(const UWalkerAgentComponent &Agent)
{
Data.type = CARLA_SERVER_AGENT_PEDESTRIAN;
Data.forward_speed = Agent.GetForwardSpeed();
::Encode(Agent.GetBoundingBoxExtent(), Data.box_extent);
}

View File

@ -0,0 +1,74 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Agent/AgentComponentVisitor.h"
#include "Sensor/SensorDataView.h"
#include "Vehicle/VehicleControl.h"
#include <carla/carla_server.h>
/// Encodes Unreal classes to CarlaServer API. To be used by FCarlaServer only.
class FCarlaEncoder : private IAgentComponentVisitor
{
public:
static void Encode(
const TArray<APlayerStart *> &AvailableStartSpots,
TArray<carla_transform> &Data);
static void Encode(
const TArray<USensorDescription *> &SensorDescriptions,
TArray<carla_sensor_definition> &Data,
TArray<TUniquePtr<const char[]>> &SensorNamesMemory);
static void Encode(
const ACarlaPlayerState &PlayerState,
carla_measurements &Data);
static void Encode(
const TArray<const UAgentComponent *> &Agents,
TArray<carla_agent> &Data);
static void Encode(const FSensorDataView &SensorData, carla_sensor_data &Data)
{
Data.id = SensorData.GetSensorId();
Data.header = SensorData.GetHeader().GetData();
Data.header_size = SensorData.GetHeader().GetSize();
Data.data = SensorData.GetData().GetData();
Data.data_size = SensorData.GetData().GetSize();
}
static void Decode(const carla_request_new_episode &Data, FString &IniFile)
{
IniFile = FString(Data.ini_file_length, ANSI_TO_TCHAR(Data.ini_file));
}
static void Decode(const carla_control &Data, FVehicleControl &Control)
{
Control.Steer = Data.steer;
Control.Throttle = Data.throttle;
Control.Brake = Data.brake;
Control.bHandBrake = Data.hand_brake;
Control.bReverse = Data.reverse;
}
private:
static void Encode(const UAgentComponent &AgentComponent, carla_agent &Data);
FCarlaEncoder(carla_agent &Data);
virtual void Visit(const UTrafficSignAgentComponent &) override;
virtual void Visit(const UVehicleAgentComponent &) override;
virtual void Visit(const UWalkerAgentComponent &) override;
carla_agent &Data;
};

View File

@ -0,0 +1,165 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "Carla.h"
#include "CarlaServer.h"
#include "Server/CarlaEncoder.h"
#include <carla/carla_server.h>
// =============================================================================
// -- Static local methods -----------------------------------------------------
// =============================================================================
static FCarlaServer::ErrorCode ParseErrorCode(const uint32 ErrorCode)
{
if (ErrorCode == CARLA_SERVER_SUCCESS) {
return FCarlaServer::Success;
} else if (ErrorCode == CARLA_SERVER_TRY_AGAIN) {
return FCarlaServer::TryAgain;
} else {
return FCarlaServer::Error;
}
}
static int32 GetTimeOut(uint32 TimeOut, const bool bBlocking)
{
return (bBlocking ? TimeOut : 0u);
}
// =============================================================================
// -- CarlaServer --------------------------------------------------------------
// =============================================================================
FCarlaServer::FCarlaServer(const uint32 InWorldPort, const uint32 InTimeOut) :
WorldPort(InWorldPort),
TimeOut(InTimeOut),
Server(carla_make_server()) {
check(Server != nullptr);
}
FCarlaServer::~FCarlaServer()
{
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Warning, TEXT("Destroying CarlaServer"));
#endif // CARLA_SERVER_EXTRA_LOG
carla_free_server(Server);
}
FCarlaServer::ErrorCode FCarlaServer::Connect()
{
UE_LOG(LogCarlaServer, Log, TEXT("Waiting for the client to connect..."));
return ParseErrorCode(carla_server_connect(Server, WorldPort, TimeOut));
}
FCarlaServer::ErrorCode FCarlaServer::ReadNewEpisode(FString &IniFile, const bool bBlocking)
{
carla_request_new_episode values;
auto ec = ParseErrorCode(carla_read_request_new_episode(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
FCarlaEncoder::Decode(values, IniFile);
UE_LOG(LogCarlaServer, Log, TEXT("Received new episode"));
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Log, TEXT("Received CarlaSettings.ini:\n%s"), *IniFile);
#endif // CARLA_SERVER_EXTRA_LOG
}
return ec;
}
FCarlaServer::ErrorCode FCarlaServer::SendSceneDescription(
const TArray<APlayerStart *> &AvailableStartSpots,
const TArray<USensorDescription *> &SensorDescriptions,
const bool bBlocking)
{
carla_scene_description scene;
// Encode start spots.
TArray<carla_transform> Transforms;
FCarlaEncoder::Encode(AvailableStartSpots, Transforms);
scene.player_start_spots = (Transforms.Num() > 0 ? Transforms.GetData() : nullptr);;
scene.number_of_player_start_spots = Transforms.Num();
// Encode sensors.
TArray<TUniquePtr<const char[]>> SensorNames; // This holds the memory while we send it.
TArray<carla_sensor_definition> Sensors;
FCarlaEncoder::Encode(SensorDescriptions, Sensors, SensorNames);
scene.sensors = (Sensors.Num() > 0 ? Sensors.GetData() : nullptr);;
scene.number_of_sensors = Sensors.Num();
// Send scene description.
UE_LOG(LogCarlaServer, Log, TEXT("Sending %d available start positions"), scene.number_of_player_start_spots);
UE_LOG(LogCarlaServer, Log, TEXT("Sending %d sensor descriptions"), scene.number_of_sensors);
return ParseErrorCode(carla_write_scene_description(Server, scene, GetTimeOut(TimeOut, bBlocking)));
}
FCarlaServer::ErrorCode FCarlaServer::ReadEpisodeStart(uint32 &StartPositionIndex, const bool bBlocking)
{
carla_episode_start values;
auto ec = ParseErrorCode(carla_read_episode_start(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
StartPositionIndex = values.player_start_spot_index;
UE_LOG(LogCarlaServer, Log, TEXT("Episode start received: { StartIndex = %d }"), StartPositionIndex);
}
return ec;
}
FCarlaServer::ErrorCode FCarlaServer::SendEpisodeReady(const bool bBlocking)
{
UE_LOG(LogCarlaServer, Log, TEXT("Ready to play, notifying client"));
const carla_episode_ready values = {true};
return ParseErrorCode(carla_write_episode_ready(Server, values, GetTimeOut(TimeOut, bBlocking)));
}
FCarlaServer::ErrorCode FCarlaServer::ReadControl(FVehicleControl &Control, const bool bBlocking)
{
carla_control values;
auto ec = ParseErrorCode(carla_read_control(Server, values, GetTimeOut(TimeOut, bBlocking)));
if (Success == ec) {
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(
LogCarlaServer,
Log,
TEXT("Read control (%s): { Steer = %f, Throttle = %f, Brake = %f, Handbrake = %s, Reverse = %s }"),
(bBlocking ? TEXT("Sync") : TEXT("Async")),
values.steer,
values.throttle,
values.brake,
(values.hand_brake ? TEXT("True") : TEXT("False")),
(values.reverse ? TEXT("True") : TEXT("False")));
#endif // CARLA_SERVER_EXTRA_LOG
FCarlaEncoder::Decode(values, Control);
} else if ((!bBlocking) && (TryAgain == ec)) {
UE_LOG(LogCarlaServer, Warning, TEXT("No control received from the client this frame!"));
}
return ec;
}
FCarlaServer::ErrorCode FCarlaServer::SendSensorData(const FSensorDataView &Data)
{
carla_sensor_data values;
FCarlaEncoder::Encode(Data, values);
return ParseErrorCode(carla_write_sensor_data(Server, values));
}
FCarlaServer::ErrorCode FCarlaServer::SendMeasurements(
const ACarlaPlayerState &PlayerState,
const TArray<const UAgentComponent *> &Agents,
const bool bSendNonPlayerAgentsInfo)
{
// Encode measurements.
carla_measurements values;
FCarlaEncoder::Encode(PlayerState, values);
// Encode agents.
TArray<carla_agent> AgentsData;
if (bSendNonPlayerAgentsInfo) {
FCarlaEncoder::Encode(Agents, AgentsData);
}
values.non_player_agents = (AgentsData.Num() > 0 ? AgentsData.GetData() : nullptr);;
values.number_of_non_player_agents = AgentsData.Num();
// Send measurements.
#ifdef CARLA_SERVER_EXTRA_LOG
UE_LOG(LogCarlaServer, Log, TEXT("Sending data of %d agents"), values.number_of_non_player_agents);
#endif // CARLA_SERVER_EXTRA_LOG
return ParseErrorCode(carla_write_measurements(Server, values));
}

Some files were not shown because too many files have changed in this diff Show More