Add C++ client example
This commit is contained in:
parent
bbb526be54
commit
5ef3dde552
|
@ -4,7 +4,8 @@
|
|||
- Added optional parameter to show more details about a recorder file (related to `show_recorder_file_info.py`)
|
||||
- Added playback speed (slow/fast motion) for the replayer
|
||||
- We can use an absolute path for the recorded files (to choose where to 'write to' or 'read from')
|
||||
* Fixed Lidar effectiveness bug in manual_control.py
|
||||
* Fixed Lidar effectiveness bug in manual_control.py
|
||||
* Added C++ client example using LibCarla
|
||||
|
||||
## CARLA 0.9.5
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/ToolChain.cmake
|
||||
/bin
|
||||
/build
|
||||
/libcarla-install
|
||||
_*
|
|
@ -0,0 +1,60 @@
|
|||
CARLADIR=$(CURDIR)/../..
|
||||
BUILDDIR=$(CURDIR)/build
|
||||
BINDIR=$(CURDIR)/bin
|
||||
INSTALLDIR=$(CURDIR)/libcarla-install
|
||||
TOOLCHAIN=$(CURDIR)/ToolChain.cmake
|
||||
|
||||
CC=/usr/bin/clang-6.0
|
||||
CXX=/usr/bin/clang++-6.0
|
||||
CXXFLAGS=-std=c++14 -pthread -fPIC -O3 -DNDEBUG -Werror -Wall -Wextra
|
||||
|
||||
define log
|
||||
@echo "\033[1;35m$(1)\033[0m"
|
||||
endef
|
||||
|
||||
default: build
|
||||
|
||||
clean:
|
||||
@rm -rf $(BUILDDIR) $(INSTALLDIR)
|
||||
@rm -f ToolChain.cmake
|
||||
|
||||
run: build
|
||||
$(call log,Running C++ Client...)
|
||||
@$(BINDIR)/cpp_client
|
||||
|
||||
build: $(BINDIR)/cpp_client
|
||||
|
||||
$(BINDIR)/cpp_client: build_libcarla
|
||||
$(call log,Compiling C++ Client...)
|
||||
@mkdir -p $(BINDIR)
|
||||
@$(CXX) $(CXXFLAGS) -I$(INSTALLDIR)/include -L$(INSTALLDIR)/lib \
|
||||
-o $(BINDIR)/cpp_client main.cpp \
|
||||
-Wl,-Bstatic -lcarla_client -lrpc -lboost_filesystem -Wl,-Bdynamic \
|
||||
-lpng -ltiff -ljpeg
|
||||
|
||||
build_libcarla: $(TOOLCHAIN)
|
||||
@cd $(CARLADIR); make setup
|
||||
@mkdir -p $(BUILDDIR)
|
||||
$(call log,Compiling LibCarla.client...)
|
||||
@{ \
|
||||
cd $(BUILDDIR); \
|
||||
if [ ! -f "build.ninja" ]; then \
|
||||
cmake \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Client \
|
||||
-DLIBCARLA_BUILD_RELEASE=ON \
|
||||
-DLIBCARLA_BUILD_DEBUG=OFF \
|
||||
-DLIBCARLA_BUILD_TEST=OFF \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN) \
|
||||
-DCMAKE_INSTALL_PREFIX=$(INSTALLDIR) \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
|
||||
$(CARLADIR); \
|
||||
fi; \
|
||||
ninja; \
|
||||
ninja install | grep -v "Up-to-date:"; \
|
||||
}
|
||||
|
||||
$(TOOLCHAIN):
|
||||
@echo "set(CMAKE_C_COMPILER $(CC))" > $(TOOLCHAIN)
|
||||
@echo "set(CMAKE_CXX_COMPILER $(CXX))" >> $(TOOLCHAIN)
|
||||
@echo "set(CMAKE_CXX_FLAGS \"\$${CMAKE_CXX_FLAGS} $(CXXFLAGS)\" CACHE STRING \"\" FORCE)" >> $(TOOLCHAIN)
|
|
@ -0,0 +1,75 @@
|
|||
C++ Client Example
|
||||
==================
|
||||
|
||||
This example creates an application using CARLA's C++ API to connect and control
|
||||
the simulator from C++.
|
||||
|
||||
Compile and run
|
||||
---------------
|
||||
|
||||
Use the Makefile provided (Linux only), to compile and run the example. Note
|
||||
that it expects to have a simulator running at port 2000.
|
||||
|
||||
```
|
||||
make run
|
||||
```
|
||||
|
||||
How it works
|
||||
------------
|
||||
|
||||
In order to link our application against LibCarla, we need to compile LibCarla
|
||||
with the same compiler and configuration we are using with our application. To
|
||||
do so, we generate a CMake tool-chain file specifying the compiler and flags we
|
||||
want
|
||||
|
||||
```cmake
|
||||
# Example ToolChain.cmake
|
||||
set(CMAKE_C_COMPILER /usr/bin/clang-6.0)
|
||||
set(CMAKE_CXX_COMPILER /usr/bin/clang++-6.0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -DNDEBUG" CACHE STRING "" FORCE)
|
||||
```
|
||||
|
||||
We pass this file to CMake when compiling LibCarla.client
|
||||
|
||||
```sh
|
||||
cd /path/to/carla-root-folder
|
||||
|
||||
make setup
|
||||
|
||||
cd /path/to/build-folder
|
||||
|
||||
cmake \
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Client \
|
||||
-DLIBCARLA_BUILD_RELEASE=ON \
|
||||
-DLIBCARLA_BUILD_DEBUG=OFF \
|
||||
-DLIBCARLA_BUILD_TEST=OFF \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/path/to/ToolChain.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/path/to/install-folder \
|
||||
/path/to/carla-root-folder
|
||||
|
||||
ninja
|
||||
ninja install
|
||||
```
|
||||
|
||||
This will generate the following structure at the provided install path
|
||||
|
||||
```
|
||||
libcarla-install/
|
||||
├── include/
|
||||
│ ├── carla/
|
||||
│ ├── boost/
|
||||
│ ├── rpc/
|
||||
│ └── ...
|
||||
└── lib/
|
||||
├── libcarla_client.a
|
||||
├── librpc.a
|
||||
├── libboost_filesystem.a
|
||||
└── ...
|
||||
```
|
||||
|
||||
Our application needs to be linked at minimum against `libcarla_client.a` and
|
||||
`librpc.a`. If we make use of IO functionality and/or image processing we would
|
||||
need to link against `boost_filesystem`, `png`, `tiff`, and/or `jpeg`.
|
||||
|
||||
For more details take a look at the Makefile provided.
|
|
@ -0,0 +1,133 @@
|
|||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
|
||||
#include <carla/client/ActorBlueprint.h>
|
||||
#include <carla/client/BlueprintLibrary.h>
|
||||
#include <carla/client/Client.h>
|
||||
#include <carla/client/Map.h>
|
||||
#include <carla/client/Sensor.h>
|
||||
#include <carla/client/TimeoutException.h>
|
||||
#include <carla/client/World.h>
|
||||
#include <carla/geom/Transform.h>
|
||||
#include <carla/image/ImageIO.h>
|
||||
#include <carla/image/ImageView.h>
|
||||
#include <carla/sensor/data/Image.h>
|
||||
|
||||
namespace cc = carla::client;
|
||||
namespace cg = carla::geom;
|
||||
namespace csd = carla::sensor::data;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::string_literals;
|
||||
|
||||
#define EXPECT_TRUE(pred) if (!(pred)) { throw std::runtime_error(#pred); }
|
||||
|
||||
/// Pick a random element from @a range.
|
||||
template <typename RangeT, typename RNG>
|
||||
static auto &RandomChoice(const RangeT &range, RNG &&generator) {
|
||||
EXPECT_TRUE(range.size() > 0u);
|
||||
std::uniform_int_distribution<size_t> dist{0u, range.size() - 1u};
|
||||
return range[dist(std::forward<RNG>(generator))];
|
||||
}
|
||||
|
||||
/// Save a semantic segmentation image to disk converting to CityScapes palette.
|
||||
static void SaveSemSegImageToDisk(const csd::Image &image) {
|
||||
using namespace carla::image;
|
||||
|
||||
char buffer[9u];
|
||||
std::snprintf(buffer, sizeof(buffer), "%08zu", image.GetFrameNumber());
|
||||
auto filename = "_images/"s + buffer + ".png";
|
||||
|
||||
auto view = ImageView::MakeColorConvertedView(
|
||||
ImageView::MakeView(image),
|
||||
ColorConverter::CityScapesPalette());
|
||||
ImageIO::WriteView(filename, view);
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
|
||||
std::mt19937_64 rng((std::random_device())());
|
||||
|
||||
auto client = cc::Client("localhost", 2000);
|
||||
client.SetTimeout(10s);
|
||||
|
||||
std::cout << "Client API version : " << client.GetClientVersion() << '\n';
|
||||
std::cout << "Server API version : " << client.GetServerVersion() << '\n';
|
||||
|
||||
// Load a random town.
|
||||
auto town_name = RandomChoice(client.GetAvailableMaps(), rng);
|
||||
std::cout << "Loading world: " << town_name << std::endl;
|
||||
auto world = client.LoadWorld(town_name);
|
||||
|
||||
// Get a random vehicle blueprint.
|
||||
auto blueprint_library = world.GetBlueprintLibrary();
|
||||
auto vehicles = blueprint_library->Filter("vehicle");
|
||||
auto blueprint = RandomChoice(*vehicles, rng);
|
||||
|
||||
// Randomize the blueprint.
|
||||
if (blueprint.ContainsAttribute("color")) {
|
||||
auto &attribute = blueprint.GetAttribute("color");
|
||||
blueprint.SetAttribute(
|
||||
"color",
|
||||
RandomChoice(attribute.GetRecommendedValues(), rng));
|
||||
}
|
||||
|
||||
// Find a valid spawn point.
|
||||
auto map = world.GetMap();
|
||||
auto transform = RandomChoice(map->GetRecommendedSpawnPoints(), rng);
|
||||
|
||||
// Spawn the vehicle.
|
||||
auto actor = world.SpawnActor(blueprint, transform);
|
||||
std::cout << "Spawned " << actor->GetDisplayId() << '\n';
|
||||
auto vehicle = boost::static_pointer_cast<cc::Vehicle>(actor);
|
||||
|
||||
// Apply control to vehicle.
|
||||
cc::Vehicle::Control control;
|
||||
control.throttle = 1.0f;
|
||||
vehicle->ApplyControl(control);
|
||||
|
||||
// Move spectator so we can see the vehicle from the simulator window.
|
||||
auto spectator = world.GetSpectator();
|
||||
transform.location += 32.0f * transform.GetForwardVector();
|
||||
transform.location.z += 2.0f;
|
||||
transform.rotation.yaw += 180.0f;
|
||||
transform.rotation.pitch = -15.0f;
|
||||
spectator->SetTransform(transform);
|
||||
|
||||
// Find a camera blueprint.
|
||||
auto camera_bp = blueprint_library->Find("sensor.camera.semantic_segmentation");
|
||||
EXPECT_TRUE(camera_bp != nullptr);
|
||||
|
||||
// Spawn a camera attached to the vehicle.
|
||||
auto camera_transform = cg::Transform{
|
||||
cg::Location{-5.5f, 0.0f, 2.8f}, // x, y, z.
|
||||
cg::Rotation{-15.0f, 0.0f, 0.0f}}; // pitch, yaw, roll.
|
||||
auto cam_actor = world.SpawnActor(*camera_bp, camera_transform, actor.get());
|
||||
auto camera = boost::static_pointer_cast<cc::Sensor>(cam_actor);
|
||||
|
||||
// Register a callback to save images to disk.
|
||||
camera->Listen([](auto data) {
|
||||
auto image = boost::static_pointer_cast<csd::Image>(data);
|
||||
EXPECT_TRUE(image != nullptr);
|
||||
SaveSemSegImageToDisk(*image);
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
// Remove actors from the simulation.
|
||||
camera->Destroy();
|
||||
vehicle->Destroy();
|
||||
std::cout << "Actors destroyed." << std::endl;
|
||||
|
||||
} catch (const cc::TimeoutException &e) {
|
||||
std::cout << '\n' << e.what() << std::endl;
|
||||
return 1;
|
||||
} catch (const std::exception &e) {
|
||||
std::cout << "\nException: " << e.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -194,6 +194,9 @@ if (LIBCARLA_BUILD_RELEASE)
|
|||
if (WIN32) # @todo Fix PythonAPI build on Windows.
|
||||
set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
else ()
|
||||
if (NOT DEFINED CMAKE_CXX_FLAGS_RELEASE_CLIENT)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE_CLIENT ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
endif()
|
||||
set_target_properties(carla_client PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE_CLIENT})
|
||||
endif (WIN32)
|
||||
|
||||
|
|
Loading…
Reference in New Issue