Merge branch 'master' into extend_python_interface

This commit is contained in:
Néstor Subirón 2018-12-03 14:49:01 +01:00 committed by GitHub
commit 03132fc264
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 0 additions and 1784 deletions

View File

@ -1,200 +0,0 @@
cmake_minimum_required(VERSION 2.8.3)
project(carla_ros_bridge)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
rospy
sensor_msgs
tf
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a run_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# sensor_msgs
# )
################################################
## Declare ROS dynamic reconfigure parameters ##
################################################
## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a run_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed
## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES carla_ros_bridge
# CATKIN_DEPENDS rospy sensor_msgs tf
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/carla_ros_bridge.cpp
# )
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/carla_ros_bridge_node.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables and/or libraries for installation
# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )
## Mark other files for installation (e.g. launch and bag files, etc.)
install(FILES
client.launch
client_with_rviz.launch
test/ros_bridge_client.test
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_carla_ros_bridge.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

View File

@ -1,163 +0,0 @@
# Ros bridge for Carla simulator
This ros package aims at providing a simple ros bridge for carla simulator.
![rviz setup](./assets/rviz_carla_default.png "rviz")
![depthcloud](./assets/depth_cloud_and_lidar.png "depthcloud")
![short video](https://youtu.be/S_NoN2GBtdY)
# Features
- [x] Cameras (depth, segmentation, rgb) support
- [x] Add camera matrix
- [x] Lidar sensor support
- [x] Transform publications
- [x] Manual control using ackermann msg
- [x] Autopilot mode using rosparam
- [x] Rosbag in the bridge (in order to avoid rosbag recoard -a small time errors)
- [x] Handle ros dependencies
- [x] Marker/bounding box messages for cars/pedestrian
- [ ] Add traffic light support
- [ ] Support dynamic change (restarting simulation using a topic/rosparam)
# Setup
## Create a catkin workspace and install carla_ros_bridge package
### Create the catkin workspace:
mkdir -p ~/ros/catkin_ws_for_carla/src
cd ~/ros/catkin_ws_for_carla
source /opt/ros/kinetic/setup.bash
catkin_make
source ~/ros/catkin_ws_for_carla/devel/setup.bash
For more information about configuring a ros environment see
http://wiki.ros.org/ROS/Tutorials/InstallingandConfiguringROSEnvironment
## Install carla python client in your workspace
cd carla/Deprecated/PythonClient
pip2 install -e . --user --upgrade
Check the installation is successfull by trying to import carla from python:
python -c 'import carla;print("Success")'
You should see the Success message without any errors.
### Install recent protobuf version [optional]
sudo apt-get remove python-protobuf
sudo pip2 install --upgrade protobuf
### Add the carla_ros_bridge in the catkin workspace
Run the following command after replacing [PATH_TO_CARLA] with the actual path to carla directory on your machine:
ln -s [PATH_TO_CARLA]/carla_ros_bridge/ ~/ros/catkin_ws_for_carla/src/
source ~/ros/catkin_ws_for_carla/devel/setup.bash
rosdep update
rosdep install --from-paths ~/ros/catkin_ws_for_carla
cd ~/ros/catkin_ws_for_carla
catkin_make
source ~/ros/catkin_ws_for_carla/devel/setup.bash
### Test your installation
If you use the builded binary (0.8.2):
./CarlaUE4.sh -carla-server -windowed -ResX=320 -ResY=240
Wait for the message:
Waiting for the client to connect...
Then run the tests
rostest carla_ros_bridge ros_bridge_client.test
you should see:
[carla_ros_bridge.rosunit-testTopics/test_publish][passed]
SUMMARY
* RESULT: SUCCESS
# Start the ros bridge
First run the simulator (see carla documentation: http://carla.readthedocs.io/en/latest/)
./CarlaUE4 -carla-server -windowed -ResX=320 -ResY=240
Wait for the message:
Waiting for the client to connect...
Then start the ros bridge:
source ~/ros/catkin_ws_for_carla/devel/setup.bash
roslaunch carla_ros_bridge client.launch
To start the ros bridge with rviz use:
roslaunch carla_ros_bridge client_with_rviz.launch
You can setup the wanted camera/sensors in config/settings.yaml.
# Autopilot control
To enable autopilot control set the ros param carla_autopilot to True
rosparam set carla_autopilot True
# Manual control
To enable manual control set the ros param carla_autopilot to False
rosparam set carla_autopilot False
Then you can send command to the car using the /ackermann_cmd topic.
Example of forward movements, speed in in meters/sec.
rostopic pub /ackermann_cmd ackermann_msgs/AckermannDrive "{steering_angle: 0.0, steering_angle_velocity: 0.0, speed: 10, acceleration: 0.0,
jerk: 0.0}" -r 10
Example of forward with steering
rostopic pub /ackermann_cmd ackermann_msgs/AckermannDrive "{steering_angle: 5.41, steering_angle_velocity: 0.0, speed: 10, acceleration: 0.0,
jerk: 0.0}" -r 10
Warning: the steering_angle is the driving angle (in radians) not the wheel angle, for now max wheel is set to 500 degrees.
Example for backward :
rostopic pub /ackermann_cmd ackermann_msgs/AckermannDrive "{steering_angle: 0, steering_angle_velocity: 0.0, speed: -10, acceleration: 0.0,
jerk: 0.0}" -r 10
# ROSBAG recording
The carla_ros_bridge could also be used to record all published topics into a rosbag:
roslaunch carla_ros_bridge client_with_rviz.launch rosbag_fname:=/tmp/save_session.bag
This command will create a rosbag /tmp/save_session.bag
You can of course also use rosbag record to do the same, but using the ros_bridge to do the recording you have the guarentee that all the message are saved without small desynchronization that could occurs when using *rosbag record* in an other process.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

View File

@ -1,8 +0,0 @@
<launch>
<arg name='rosbag_fname' default=''/>
<param name="rosbag_fname" value="$(arg rosbag_fname)"/>
<rosparam file="$(find carla_ros_bridge)/config/settings.yaml" command="load" />
<param name="carla_autopilot" type="boolean" value="True" />
<param name="curr_episode" type="string" value="" />
<node pkg="carla_ros_bridge" name="carla_ros_bridge" type="client.py" output="screen"/>
</launch>

View File

@ -1,5 +0,0 @@
<launch>
<include file="$(find carla_ros_bridge)/client.launch" pass_all_args="True"/>
<param name ="/use_sim_time" value="true"/>
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find carla_ros_bridge)/config/carla_default_rviz.cfg.rviz"/>
</launch>

View File

@ -1,263 +0,0 @@
Panels:
- Class: rviz/Displays
Help Height: 102
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
- /Status1
- /DepthCloud1/Auto Size1
Splitter Ratio: 0.5
Tree Height: 332
- Class: rviz/Selection
Name: Selection
- Class: rviz/Tool Properties
Expanded:
- /2D Pose Estimate1
- /2D Nav Goal1
- /Publish Point1
Name: Tool Properties
Splitter Ratio: 0.588679016
- Class: rviz/Views
Expanded:
- /Current View1
Name: Views
Splitter Ratio: 0.5
- Class: rviz/Time
Experimental: true
Name: Time
SyncMode: 0
SyncSource: Front_cam
- Class: rviz/Displays
Help Height: 0
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
- /non_player_vehicles1
- /DepthCloud1/Auto Size1
Splitter Ratio: 0.494356662
Tree Height: 181
Visualization Manager:
Class: ""
Displays:
- Alpha: 0.100000001
Cell Size: 1
Class: rviz/Grid
Color: 170; 164; 162
Enabled: true
Line Style:
Line Width: 0.0299999993
Value: Lines
Name: Grid
Normal Cell Count: 0
Offset:
X: 0
Y: 0
Z: 0
Plane: XY
Plane Cell Count: 1000
Reference Frame: map
Value: true
- Class: rviz/Image
Enabled: true
Image Topic: /camera_front/image_raw
Max Value: 1
Median window: 5
Min Value: 0
Name: Front_cam
Normalize Range: true
Queue Size: 2
Transport Hint: raw
Unreliable: false
Value: true
- Class: rviz/Image
Enabled: true
Image Topic: /camera_depth/image_raw
Max Value: 30
Median window: 5
Min Value: 0
Name: Depth
Normalize Range: false
Queue Size: 2
Transport Hint: raw
Unreliable: false
Value: true
- Class: rviz/MarkerArray
Enabled: true
Marker Topic: /vehicles
Name: non_player_vehicles
Namespaces:
"": true
Queue Size: 100
Value: true
- Class: rviz/Marker
Enabled: true
Marker Topic: /player_vehicle
Name: Marker
Namespaces:
"": true
Queue Size: 100
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz/PointCloud2
Color: 255; 255; 255
Color Transformer: Intensity
Decay Time: 0
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: PointCloud2
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.00999999978
Style: Flat Squares
Topic: /lidar_0
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: false
- Alpha: 1
Auto Size:
Auto Size Factor: 1
Value: true
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz/DepthCloud
Color: 255; 255; 255
Color Image Topic: /camera_front/image_raw
Color Transformer: RGB8
Color Transport Hint: raw
Decay Time: 0
Depth Map Topic: /camera_depth/image_raw
Depth Map Transport Hint: raw
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: DepthCloud
Occlusion Compensation:
Occlusion Time-Out: 30
Value: false
Position Transformer: XYZ
Queue Size: 5
Selectable: true
Size (Pixels): 3
Style: Flat Squares
Topic Filter: false
Use Fixed Frame: true
Use rainbow: true
Value: true
- Alpha: 0.699999988
Class: rviz/Map
Color Scheme: map
Draw Behind: false
Enabled: true
Name: Map
Topic: /map
Unreliable: false
Use Timestamp: false
Value: true
Enabled: true
Global Options:
Background Color: 48; 48; 48
Default Light: true
Fixed Frame: map
Frame Rate: 30
Name: root
Tools:
- Class: rviz/Interact
Hide Inactive Objects: true
- Class: rviz/MoveCamera
- Class: rviz/Select
- Class: rviz/FocusCamera
- Class: rviz/Measure
- Class: rviz/SetInitialPose
Topic: /initialpose
- Class: rviz/SetGoal
Topic: /move_base_simple/goal
- Class: rviz/PublishPoint
Single click: true
Topic: /clicked_point
Value: true
Views:
Current:
Class: rviz/ThirdPersonFollower
Distance: 31.8610725
Enable Stereo Rendering:
Stereo Eye Separation: 0.0599999987
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Focal Point:
X: 6.99974823
Y: 0.798863649
Z: 2.89677428e-06
Focal Shape Fixed Size: false
Focal Shape Size: 0.0500000007
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.00999999978
Pitch: 0.185203522
Target Frame: base_link
Value: ThirdPersonFollower (rviz)
Yaw: 3.50356174
Saved:
- Class: rviz/FPS
Enable Stereo Rendering:
Stereo Eye Separation: 0.0599999987
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Invert Z Axis: false
Name: FPS
Near Clip Distance: 0.00999999978
Pitch: 0.984796941
Position:
X: 48.1403351
Y: -258.651123
Z: 284.474243
Target Frame: base_link
Value: FPS (rviz)
Yaw: 1.52198112
Window Geometry:
Depth:
collapsed: false
Displays:
collapsed: false
Front_cam:
collapsed: false
Height: 994
Hide Left Dock: false
Hide Right Dock: false
QMainWindow State: 000000ff00000000fd00000004000000000000019a00000346fc020000000afb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006300fffffffb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c00610079007300000000430000032d000000dc00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb000000100044006900730070006c0061007900730100000028000000fb000000dc00fffffffb0000001200460072006f006e0074005f00630061006d0100000129000001230000001800fffffffb0000000a0044006500700074006801000002520000011c0000001800ffffff000000010000018100000346fc0200000009fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000028000001a00000006300fffffffb0000000a004400650070007400680000000043000001e80000000000000000fb00000018005300650067006d0065006e0074006100740069006f006e000000017f0000011f0000000000000000fb0000000a0049006d0061006700650000000043000000f60000000000000000fb0000000a0049006d0061006700650000000043000001630000000000000000fb0000001a00630061006d005f00660072006f006e0074005f00720067006200000001a7000001c70000000000000000fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a0056006900650077007301000001ce000001a0000000b500fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000690000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000006900000004dfc0100000002fb0000000800540069006d0065010000000000000690000002f400fffffffb0000000800540069006d00650100000000000004500000000000000000000003690000034600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Time:
collapsed: false
Tool Properties:
collapsed: false
Views:
collapsed: false
Width: 1680
X: 49
Y: 30

View File

@ -1,97 +0,0 @@
# carla original variable name is used unchanged here (i.e CamelCase, etc)
carla:
host: localhost
port: 2000
QualityLevel: Low # Low or Epic
SynchronousMode: True
sensors:
CameraRGB:
SensorType: CAMERA
carla_settings:
PostProcessing: SceneFinal
ImageSizeX: 800
ImageSizeY: 600
FOV: 90
PositionX: -5.00
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 0
camera_depth:
SensorType: CAMERA
carla_settings:
PostProcessing: Depth
ImageSizeX: 800
ImageSizeY: 600
FOV: 90
PositionX: -5.00
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 0
camera_depth_front:
SensorType: CAMERA
carla_settings:
PostProcessing: Depth
ImageSizeX: 800
ImageSizeY: 600
FOV: 90
PositionX: 7.00
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 180
CameraRGB_front:
SensorType: CAMERA
carla_settings:
PostProcessing: SceneFinal
ImageSizeX: 800
ImageSizeY: 600
FOV: 90
PositionX: 7.00
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 180
#camera_semantic_segmentation:
# SensorType: CAMERA
# carla_settings:
# PostProcessing: SemanticSegmentation
# ImageSizeX: 800
# ImageSizeY: 600
# FOV: 90
# PositionX: 0.00
# PositionY: 0
# PositionZ: 1.30
# RotationPitch: 0
# RotationRoll: 0
# RotationYaw: 0
lidar_0:
SensorType: LIDAR_RAY_CAST
carla_settings:
Channels: 4
Range: 120
PointsPerSecond: 200000
RotationFrequency: 25
UpperFovLimit: 1.6
LowerFovLimit: -1.6
PositionX: 0.0
PositionY: 0
PositionZ: 1.50
RotationPitch: 0
RotationYaw: 0
RotationRoll: 0

View File

@ -1,57 +0,0 @@
carla:
host: localhost
port: 2000
QualityLevel: Low # Low or Epic
SynchronousMode: True
SendNonPlayerAgentsInfo: True
NumberOfVehicles: 30
NumberOfPedestrians: 10
WeatherId: 1
Framesperepisode: -1 # -1: run episode indefinitely until interrupted
Episodes: 2
sensors:
camera_front:
SensorType: CAMERA
carla_settings:
PostProcessing: SceneFinal
ImageSizeX: 320
ImageSizeY: 240
FOV: 90
PositionX: 1.80
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 0
camera_depth:
SensorType: CAMERA
carla_settings:
PostProcessing: Depth
ImageSizeX: 320
ImageSizeY: 240
FOV: 90
PositionX: 1.80
PositionY: 0
PositionZ: 1.30
RotationPitch: 0
RotationRoll: 0
RotationYaw: 0
# Uncomment the following lines if you want to enable lidar publication
# lidar_0:
# SensorType: LIDAR_RAY_CAST
# carla_settings:
# Channels: 4
# Range: 120
# PointsPerSecond: 200000
# RotationFrequency: 25
# UpperFovLimit: 1.6
# LowerFovLimit: -1.6
# PositionX: 0.0
# PositionY: 0
# PositionZ: 1.50
# RotationPitch: 0
# RotationYaw: 0
# RotationRoll: 0

View File

@ -1,75 +0,0 @@
<?xml version="1.0"?>
<package format="2">
<name>carla_ros_bridge</name>
<version>0.0.1</version>
<description>The carla_ros_bridge package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
<maintainer email="laurent.george@valeo.com">lgeorge</maintainer>
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>MIT</license>
<!-- Url tags are optional, but multiple are allowed, one per tag -->
<!-- Optional attribute type can be: website, bugtracker, or repository -->
<!-- Example: -->
<!-- <url type="website">http://wiki.ros.org/carla_ros_client</url> -->
<!-- Author tags are optional, multiple are allowed, one per tag -->
<!-- Authors do not have to be maintainers, but could be -->
<!-- Example: -->
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
<!-- The *depend tags are used to specify dependencies -->
<!-- Dependencies can be catkin packages or system dependencies -->
<!-- Examples: -->
<!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
<!-- <depend>roscpp</depend> -->
<!-- Note that this is equivalent to the following: -->
<!-- <build_depend>roscpp</build_depend> -->
<!-- <exec_depend>roscpp</exec_depend> -->
<!-- Use build_depend for packages you need at compile time: -->
<!-- <build_depend>message_generation</build_depend> -->
<!-- Use build_export_depend for packages you need in order to build against this package: -->
<!-- <build_export_depend>message_generation</build_export_depend> -->
<!-- Use buildtool_depend for build tool packages: -->
<!-- <buildtool_depend>catkin</buildtool_depend> -->
<!-- Use exec_depend for packages you need at runtime: -->
<!-- <exec_depend>message_runtime</exec_depend> -->
<!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> -->
<!-- Use doc_depend for packages you need only for building documentation: -->
<!-- <doc_depend>doxygen</doc_depend> -->
<buildtool_depend>catkin</buildtool_depend>
<build_depend>rospy</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>tf</build_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>sensor_msgs</build_export_depend>
<build_export_depend>tf</build_export_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<exec_depend>tf</exec_depend>
<exec_depend>tf2</exec_depend>
<exec_depend>rviz</exec_depend>
<exec_depend>ackermann_msgs</exec_depend>
<exec_depend>cv_bridge</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>rosbag_storage</exec_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>

View File

@ -1,10 +0,0 @@
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
d = generate_distutils_setup(
packages=['carla_ros_bridge'],
package_dir={'': 'src'}
)
setup(**d)

View File

@ -1,184 +0,0 @@
"""
Rosbridge class:
Class that handle communication between CARLA and ROS
"""
import random
from itertools import count
from rosgraph_msgs.msg import Clock
from tf2_msgs.msg import TFMessage
import rospy
from carla.settings import CarlaSettings
from carla_ros_bridge.control import InputController
from carla_ros_bridge.markers import PlayerAgentHandler, NonPlayerAgentsHandler
from carla_ros_bridge.sensors import CameraHandler, LidarHandler
from carla_ros_bridge.map import MapHandler
class CarlaRosBridge(object):
"""
Carla Ros bridge
"""
def __init__(self, client, params):
"""
:param params: dict of parameters, see settings.yaml
:param rate: rate to query data from carla in Hz
"""
self.setup_carla_client(client=client, params=params)
self.frames_per_episode = params['Framesperepisode']
self.tf_to_publish = []
self.msgs_to_publish = []
self.publishers = {}
# definitions useful for time
self.cur_time = rospy.Time.from_sec(
0) # at the beginning of simulation
self.carla_game_stamp = 0
self.carla_platform_stamp = 0
# creating handler to handle vehicles messages
self.player_handler = PlayerAgentHandler(
"player_vehicle", process_msg_fun=self.process_msg)
self.non_players_handler = NonPlayerAgentsHandler(
"vehicles", process_msg_fun=self.process_msg)
# creating handler for sensors
self.sensors = {}
for name, _ in self.param_sensors.items():
self.add_sensor(name)
# creating input controller listener
self.input_controller = InputController()
def setup_carla_client(self, client, params):
self.client = client
self.param_sensors = params.get('sensors', {})
self.carla_settings = CarlaSettings()
self.carla_settings.set(
SendNonPlayerAgentsInfo=params.get('SendNonPlayerAgentsInfo', True),
NumberOfVehicles=params.get('NumberOfVehicles', 20),
NumberOfPedestrians=params.get('NumberOfPedestrians', 40),
WeatherId=params.get('WeatherId', random.choice([1, 3, 7, 8, 14])),
SynchronousMode=params.get('SynchronousMode', True),
QualityLevel=params.get('QualityLevel', 'Low')
)
self.carla_settings.randomize_seeds()
def add_sensor(self, name):
rospy.loginfo("Adding sensor {}".format(name))
sensor_type = self.param_sensors[name]['SensorType']
params = self.param_sensors[name]['carla_settings']
sensor_handler = None
if sensor_type == 'LIDAR_RAY_CAST':
sensor_handler = LidarHandler
if sensor_type == 'CAMERA':
sensor_handler = CameraHandler
if sensor_handler:
self.sensors[name] = sensor_handler(
name,
params,
carla_settings=self.carla_settings,
process_msg_fun=self.process_msg)
else:
rospy.logerr(
"Unable to handle sensor {name} of type {sensor_type}".format(
sensor_type=sensor_type, name=name))
def on_shutdown(self):
rospy.loginfo("Shutdown requested")
def process_msg(self, topic=None, msg=None):
"""
Function used to process message
Here we create publisher if not yet created
Store the message in a list (waiting for their publication) with their associated publisher
Messages for /tf topics are handle differently in order to publish all transform in the same message
:param topic: topic to publish the message on
:param msg: ros message
"""
if topic not in self.publishers:
if topic == 'tf':
self.publishers[topic] = rospy.Publisher(
topic, TFMessage, queue_size=100)
else:
self.publishers[topic] = rospy.Publisher(
topic, type(msg), queue_size=10)
if topic == 'tf':
# transform are merged in same message
self.tf_to_publish.append(msg)
else:
self.msgs_to_publish.append((self.publishers[topic], msg))
def send_msgs(self):
for publisher, msg in self.msgs_to_publish:
publisher.publish(msg)
self.msgs_to_publish = []
tf_msg = TFMessage(self.tf_to_publish)
self.publishers['tf'].publish(tf_msg)
self.tf_to_publish = []
def compute_cur_time_msg(self):
self.process_msg('clock', Clock(self.cur_time))
def run(self):
self.publishers['clock'] = rospy.Publisher(
"clock", Clock, queue_size=10)
# load settings into the server
scene = self.client.load_settings(self.carla_settings)
# Choose one player start at random.
number_of_player_starts = len(scene.player_start_spots)
player_start = random.randint(0, max(0, number_of_player_starts - 1))
# Send occupancy grid to rivz
map_handler = MapHandler(scene.map_name)
map_handler.send_map()
self.client.start_episode(player_start)
for frame in count():
if (frame == self.frames_per_episode) or rospy.is_shutdown():
break
measurements, sensor_data = self.client.read_data()
# handle time
self.carla_game_stamp = measurements.game_timestamp
self.cur_time = rospy.Time.from_sec(self.carla_game_stamp * 1e-3)
self.compute_cur_time_msg()
# handle agents
self.player_handler.process_msg(
measurements.player_measurements, cur_time=self.cur_time)
self.non_players_handler.process_msg(
measurements.non_player_agents, cur_time=self.cur_time)
# handle sensors
for name, data in sensor_data.items():
self.sensors[name].process_sensor_data(data, self.cur_time)
# publish all messages
self.send_msgs()
# handle control
if rospy.get_param('carla_autopilot', True):
control = measurements.player_measurements.autopilot_control
self.client.send_control(control)
else:
control = self.input_controller.cur_control
self.client.send_control(**control)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
rospy.loginfo("Exiting Bridge")
return None

View File

@ -1,40 +0,0 @@
"""
RosBridge class with rosbag support
"""
import time
from datetime import datetime
from tf2_msgs.msg import TFMessage
import rosbag
import rospy
import os
from carla_ros_bridge.bridge import CarlaRosBridge
class CarlaRosBridgeWithBag(CarlaRosBridge):
def __init__(self, *args, **kwargs):
super(CarlaRosBridgeWithBag, self).__init__(*args, **kwargs)
prefix, ext = os.path.splitext(rospy.get_param('rosbag_fname'))
rosbag_fname = os.path.abspath(prefix + rospy.get_param('curr_episode'))
self.bag = rosbag.Bag(rosbag_fname, mode='w')
def send_msgs(self):
for publisher, msg in self.msgs_to_publish:
self.bag.write(publisher.name, msg, self.cur_time)
tf_msg = TFMessage(self.tf_to_publish)
self.bag.write('tf', tf_msg, self.cur_time)
super(CarlaRosBridgeWithBag, self).send_msgs()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
rospy.loginfo("Closing the bag file")
self.bag.close()
super(CarlaRosBridgeWithBag, self).__exit__(exc_type, exc_value,
traceback)

View File

@ -1,42 +0,0 @@
#!/usr/bin/env python
"""
Ros Bridge node for carla simulator
"""
import rospy
from carla.client import make_carla_client
from carla_ros_bridge.bridge import CarlaRosBridge
from carla_ros_bridge.bridge_with_rosbag import CarlaRosBridgeWithBag
def main():
rospy.init_node("carla_client", anonymous=True)
params = rospy.get_param('carla')
host = params['host']
port = params['port']
num_episodes = params['Episodes']
rospy.loginfo("Trying to connect to {host}:{port}".format(
host=host, port=port))
with make_carla_client(host, port) as client:
rospy.loginfo("Connected")
for episode in range(0, num_episodes):
if rospy.is_shutdown():
break
rospy.loginfo("Starting Episode --> {}".format(episode))
current_eps = '_episode' + '_' + str(episode)
rospy.set_param(param_name='curr_episode',
param_value=current_eps)
bridge_cls = CarlaRosBridgeWithBag if rospy.get_param(
'rosbag_fname', '') else CarlaRosBridge
with bridge_cls(client=client, params=params) as carla_ros_bridge:
rospy.on_shutdown(carla_ros_bridge.on_shutdown)
carla_ros_bridge.run()
if __name__ == "__main__":
main()

View File

@ -1,68 +0,0 @@
"""
Class to handle control input
"""
import math
import numpy as np
import rospy
from ackermann_msgs.msg import AckermannDrive
class InputController(object):
"""
Class to handle ros input command
Each time a ros control msg (an ackermann_cmd msg) is received on control topic, a carla control message is
computed.
"""
def __init__(self, topic_name='/ackermann_cmd'):
# current control command
self.cur_control = {
'steer': 0.0,
'throttle': 0.0,
'brake': 0.0,
'hand_brake': False,
'reverse': False
}
self.cmd_vel_subscriber = rospy.Subscriber(
'/ackermann_cmd', AckermannDrive, self.set_control_cmd_callback)
def set_control_cmd_callback(self, data):
"""
Convert a Ackerman drive msg into carla control msg
Right now the control is really simple and don't enforce acceleration and jerk command, nor the steering acceleration too
:param data: AckermannDrive msg
:return:
"""
steering_angle_ctrl = data.steering_angle
speed_ctrl = data.speed
max_steering_angle = math.radians(
500
) # 500 degrees is the max steering angle that I have on my car,
# would be nice if we could use the value provided by carla
max_speed = 27 # just a value for me, 27 m/sec seems to be a reasonable max speed for now
control = {}
if abs(steering_angle_ctrl) > max_steering_angle:
rospy.logerr("Max steering angle reached, clipping value")
steering_angle_ctrl = np.clip(
steering_angle_ctrl, -max_steering_angle, max_steering_angle)
if abs(speed_ctrl) > max_speed:
rospy.logerr("Max speed reached, clipping value")
speed_ctrl = np.clip(speed_ctrl, -max_speed, max_speed)
if speed_ctrl == 0:
control['brake'] = True
control['steer'] = steering_angle_ctrl / max_steering_angle
control['throttle'] = abs(speed_ctrl / max_speed)
control['reverse'] = True if speed_ctrl < 0 else False
self.cur_control = control

View File

@ -1,58 +0,0 @@
"""
Class to handle occupancy grid
"""
import numpy as np
import rospy
import tf
from nav_msgs.msg import OccupancyGrid
from carla.planner.map import CarlaMap
class MapHandler(object):
"""
Convert CarlaMap lane image to ROS OccupancyGrid message
"""
def __init__(self, map_name, topic='/map'):
self.map_name = map_name
self.carla_map = CarlaMap(map_name)
self.map_pub = rospy.Publisher(
topic, OccupancyGrid, queue_size=10, latch=True)
self.build_map_message()
def build_map_message(self):
self.map_msg = map_msg = OccupancyGrid()
# form array for map
map_img = self.carla_map.get_map_lanes()
# extract green channel, invert, scale to range 0..100, convert to int8
map_img = (100 - map_img[..., 1] * 100.0 / 255).astype(np.int8)
map_msg.data = map_img.ravel().tolist()
# set up general info
map_msg.info.resolution = self.carla_map._pixel_density
map_msg.info.width = map_img.shape[1]
map_msg.info.height = map_img.shape[0]
# set up origin orientation
quat = tf.transformations.quaternion_from_euler(0, 0, np.pi)
map_msg.info.origin.orientation.x = quat[0]
map_msg.info.origin.orientation.y = quat[1]
map_msg.info.origin.orientation.z = quat[2]
map_msg.info.origin.orientation.w = quat[3]
# set up origin position
top_right_corner = float(map_img.shape[1]), 0.0
to_world = self.carla_map.convert_to_world(top_right_corner)
map_msg.info.origin.position.x = to_world[0]
map_msg.info.origin.position.y = -to_world[1]
map_msg.info.origin.position.z = to_world[2]
# FIXME: height for Town01 is still in centimeters (issue #541)
if self.map_name == 'Town01':
map_msg.info.origin.position.z *= 100
def send_map(self):
self.map_pub.publish(self.map_msg)

View File

@ -1,170 +0,0 @@
"""
Classes to handle Agent object (player and non-player)
"""
from geometry_msgs.msg import TransformStamped
from nav_msgs.msg import Odometry
from std_msgs.msg import Header
from visualization_msgs.msg import MarkerArray, Marker
from carla.sensor import Transform as carla_Transform
from carla_ros_bridge.transforms import carla_transform_to_ros_transform, ros_transform_to_pose
class AgentObjectHandler(object):
"""
Generic class to convert carla agent information to ros messages
In ros messages are represented as Marker message (thus they are viewable in Rviz).
"""
def __init__(self, name, process_msg_fun=None, world_link='map'):
self.name = name
self.world_link = world_link
self.process_msg_fun = process_msg_fun
self.lookup_table_marker_id = {}
def process_msg(self, data, cur_time):
"""
:param data: carla agent data
:param cur_time: current ros simulation time
:return:
"""
raise NotImplemented
def get_marker_id(self, agent_id):
"""
Return a unique marker id for each agent
ros marker id should be int32, carla/unrealengine seems to use int64
A lookup table is used to remap agent_id to small number between 0 and max_int32
:param agent_id:
:return:
"""
if agent_id not in self.lookup_table_marker_id:
self.lookup_table_marker_id[agent_id] = len(
self.lookup_table_marker_id)
return self.lookup_table_marker_id[agent_id]
class PlayerAgentHandler(AgentObjectHandler):
"""
Convert player agent into ros message (as marker and odometry)
"""
def __init__(self, name, **kwargs):
super(PlayerAgentHandler, self).__init__(name, **kwargs)
def process_msg(self, data, cur_time):
t = TransformStamped()
t.header.stamp = cur_time
t.header.frame_id = self.world_link
t.child_frame_id = "base_link"
t.transform = carla_transform_to_ros_transform(
carla_Transform(data.transform))
header = Header()
header.stamp = cur_time
header.frame_id = self.world_link
marker = get_vehicle_marker(
data, header=header, marker_id=0, is_player=True)
self.process_msg_fun(self.name, marker)
self.process_msg_fun('tf', t)
# forming an odometry message
odometry = get_vehicle_odometry(
data, header=header)
self.process_msg_fun('player_odometry', odometry)
class NonPlayerAgentsHandler(AgentObjectHandler):
"""
Convert non-player agents into ros messages
"""
def __init__(self, name, **kwargs):
super(NonPlayerAgentsHandler, self).__init__(name, **kwargs)
def process_msg(self, data, cur_time):
"""
:param data: list of carla_server_pb2.Agent return by carla API,
with field 'id', 'vehicle', 'pedestrian', 'traffic_light', 'speed_limit_sign'
:return:
"""
vehicles = [(self.get_marker_id(agent.id), agent.vehicle)
for agent in data if agent.HasField('vehicle')]
header = Header(stamp=cur_time, frame_id=self.world_link)
if not (vehicles):
return
markers = [
get_vehicle_marker(vehicle, header, agent_id)
for agent_id, vehicle in vehicles
]
marker_array = MarkerArray(markers)
self.process_msg_fun('vehicles', marker_array)
def get_vehicle_marker(object, header, marker_id=0, is_player=False):
"""
Return a marker msg
:param object: carla agent object (pb2 object (vehicle, pedestrian or traffic light))
:param header: ros header (stamp/frame_id)
:param marker_id: a marker id (int32)
:param is_player: True if player else False (usefull to change marker color)
:return: a ros marker msg
"""
marker = Marker(header=header)
marker.color.a = 0.3
if is_player:
marker.color.g = 1
marker.color.r = 0
marker.color.b = 0
else:
marker.color.r = 1
marker.color.g = 0
marker.color.b = 0
marker.id = marker_id
marker.text = "id = {}".format(marker_id)
update_marker_pose(object, marker)
return marker
def update_marker_pose(object, base_marker):
"""
Update pose of a marker based on carla information
:param object: pb2 carla object
:param base_marker: marker to update pose
"""
ros_transform = carla_transform_to_ros_transform(
carla_Transform(object.bounding_box.transform) *
carla_Transform(object.transform))
base_marker.pose = ros_transform_to_pose(ros_transform)
base_marker.scale.x = object.bounding_box.extent.x * 2.0
base_marker.scale.y = object.bounding_box.extent.y * 2.0
base_marker.scale.z = object.bounding_box.extent.z * 2.0
base_marker.type = Marker.CUBE
def get_vehicle_odometry(object, header):
"""
Return an odometry msg
:param object: carla agent object (pb2 object (vehicle, pedestrian or traffic light))
:param header: ros header (stamp/frame_id)
:return: a ros odometry msg
"""
ros_transform = carla_transform_to_ros_transform(
carla_Transform(object.transform))
odometry = Odometry(header=header)
odometry.child_frame_id = "base_link"
odometry.pose.pose = ros_transform_to_pose(ros_transform)
return odometry

View File

@ -1,211 +0,0 @@
"""
Classes to handle Carla sensors
"""
import math
import numpy as np
import tf
from cv_bridge import CvBridge
from geometry_msgs.msg import TransformStamped
from sensor_msgs.msg import CameraInfo
from sensor_msgs.point_cloud2 import create_cloud_xyz32
from std_msgs.msg import Header
from carla.sensor import Camera, Lidar, Sensor
from carla_ros_bridge.transforms import carla_transform_to_ros_transform
cv_bridge = CvBridge(
) # global cv bridge to convert image between opencv and ros
class SensorHandler(object):
"""
Generic Sensor Handler
A sensor handler compute the associated ros message to a carla sensor data, and the transform asssociated to the
sensor.
These messages are passed to a *process_msg_fun* which will take care of publishing them.
"""
def __init__(self,
name,
params=None,
carla_sensor_class=Sensor,
carla_settings=None,
process_msg_fun=None):
"""
:param name: sensor name
:param params: params used to set the sensor in carla
:param carla_sensor_class: type of sensor
:param carla_settings: carla_settings object
:param process_msg_fun: function to call on each new computed message
"""
self.process_msg_fun = process_msg_fun
self.carla_object = carla_sensor_class(name, **params)
carla_settings.add_sensor(self.carla_object)
self.name = name
def process_sensor_data(self, data, cur_time):
"""
process a carla sensor data object
Generate sensor message and transform message
:param data: carla sensor data
:param cur_time: current ros simulation time
:return:
"""
self._compute_sensor_msg(data, cur_time)
self._compute_transform(data, cur_time)
def _compute_sensor_msg(self, data, cur_time):
"""
Compute the ros msg associated to carla data
:param data: SensorData object
:param cur_time: current ros simulation time
"""
raise NotImplemented
def _compute_transform(self, data, cur_time):
"""
Compute the tf msg associated to carla data
:param data: SensorData object
:param cur_time: current ros simulation time
"""
raise NotImplemented
class LidarHandler(SensorHandler):
"""
Class to handle Lidar sensors
"""
def __init__(self, name, params, **kwargs):
super(LidarHandler, self).__init__(
name, carla_sensor_class=Lidar, params=params, **kwargs)
def _compute_sensor_msg(self, sensor_data, cur_time):
header = Header()
header.frame_id = self.name
header.stamp = cur_time
# we take the oposite of y axis (as lidar point are express in left handed coordinate system, and ros need right handed)
# we need a copy here, because the data are read only in carla numpy array
new_sensor_data = sensor_data.data.copy()
new_sensor_data = -new_sensor_data
# we also need to permute x and y
new_sensor_data = new_sensor_data[..., [1, 0, 2]]
point_cloud_msg = create_cloud_xyz32(header, new_sensor_data)
topic = self.name
self.process_msg_fun(topic, point_cloud_msg)
def _compute_transform(self, sensor_data, cur_time):
parent_frame_id = "base_link"
child_frame_id = self.name
t = TransformStamped()
t.header.stamp = cur_time
t.header.frame_id = parent_frame_id
t.child_frame_id = child_frame_id
t.transform = carla_transform_to_ros_transform(
self.carla_object.get_transform())
# for some reasons lidar sends already rotated cloud,
# so it is need to ignore pitch and roll
r = t.transform.rotation
quat = [r.x, r.y, r.z, r.w]
roll, pitch, yaw = tf.transformations.euler_from_quaternion(quat)
quat = tf.transformations.quaternion_from_euler(0, 0, yaw)
t.transform.rotation.x = quat[0]
t.transform.rotation.y = quat[1]
t.transform.rotation.z = quat[2]
t.transform.rotation.w = quat[3]
self.process_msg_fun('tf', t)
class CameraHandler(SensorHandler):
"""
Class to handle Camera sensors
"""
def __init__(self, name, params, **kwargs):
super(CameraHandler, self).__init__(
name, carla_sensor_class=Camera, params=params, **kwargs)
self.topic_image = '/'.join([name, 'image_raw'])
self.topic_cam_info = '/'.join([name, 'camera_info'])
self.build_camera_info()
def build_camera_info(self):
"""
computing camera info
camera info doesn't change over time
"""
camera_info = CameraInfo()
camera_info.header.frame_id = self.name
camera_info.width = self.carla_object.ImageSizeX
camera_info.height = self.carla_object.ImageSizeY
camera_info.distortion_model = 'plumb_bob'
cx = self.carla_object.ImageSizeX / 2.0
cy = self.carla_object.ImageSizeY / 2.0
fx = self.carla_object.ImageSizeX / (
2.0 * math.tan(self.carla_object.FOV * math.pi / 360.0))
fy = fx
camera_info.K = [fx, 0, cx, 0, fy, cy, 0, 0, 1]
camera_info.D = [0, 0, 0, 0, 0]
camera_info.R = [1.0, 0, 0, 0, 1.0, 0, 0, 0, 1.0]
camera_info.P = [fx, 0, cx, 0, 0, fy, cy, 0, 0, 0, 1.0, 0]
self._camera_info = camera_info
def _compute_sensor_msg(self, sensor_data, cur_time):
if sensor_data.type == 'Depth':
# ROS PEP 0118 : Depth images are published as sensor_msgs/Image encoded as 32-bit float.
# Each pixel is a depth (along the camera Z axis) in meters.
data = np.float32(sensor_data.data * 1000.0) # in carla 1.0 = 1km
encoding = 'passthrough'
elif sensor_data.type == 'SemanticSegmentation':
encoding = 'mono16' # for semantic segmentation we use mono16 in order to be able to limit range in rviz
data = np.uint16(sensor_data.data)
else:
encoding = 'rgb8'
data = sensor_data.data
img_msg = cv_bridge.cv2_to_imgmsg(data, encoding=encoding)
img_msg.header.frame_id = self.name
img_msg.header.stamp = cur_time
cam_info = self._camera_info
cam_info.header = img_msg.header
self.process_msg_fun(self.topic_cam_info, cam_info)
self.process_msg_fun(self.topic_image, img_msg)
def _compute_transform(self, sensor_data, cur_time):
parent_frame_id = "base_link"
child_frame_id = self.name
t = TransformStamped()
t.header.stamp = cur_time
t.header.frame_id = parent_frame_id
t.child_frame_id = child_frame_id
# for camera we reorient it to look at the same axis as the opencv projection
# in order to get easy depth cloud for RGBD camera
t.transform = carla_transform_to_ros_transform(
self.carla_object.get_transform())
rotation = t.transform.rotation
quat = [rotation.x, rotation.y, rotation.z, rotation.w]
quat_swap = tf.transformations.quaternion_from_matrix(
[[0, 0, 1, 0],
[-1, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, 0, 1]])
quat = tf.transformations.quaternion_multiply(quat, quat_swap)
t.transform.rotation.x = quat[0]
t.transform.rotation.y = quat[1]
t.transform.rotation.z = quat[2]
t.transform.rotation.w = quat[3]
self.process_msg_fun('tf', t)

View File

@ -1,79 +0,0 @@
"""
Tool functions to convert transforms from carla to ros coordinate system
"""
from geometry_msgs.msg import Transform, Pose
import tf
def carla_transform_to_ros_transform(carla_transform):
"""
Convert a carla transform to a ros transform
:param carla_transform:
:return: a ros transform
"""
transform_matrix = carla_transform.matrix
x, y, z = tf.transformations.translation_from_matrix(transform_matrix)
quat = tf.transformations.quaternion_from_matrix(transform_matrix)
ros_transform = Transform()
# remember that we go from left-handed system (unreal) to right-handed system (ros)
ros_transform.translation.x = x
ros_transform.translation.y = -y
ros_transform.translation.z = z
roll, pitch, yaw = tf.transformations.euler_from_quaternion(quat)
roll = -roll
pitch = pitch
yaw = -yaw
quat = tf.transformations.quaternion_from_euler(roll, pitch, yaw)
ros_transform.rotation.x = quat[0]
ros_transform.rotation.y = quat[1]
ros_transform.rotation.z = quat[2]
ros_transform.rotation.w = quat[3]
return ros_transform
def carla_transform_to_ros_pose(carla_transform):
"""
convert a carla transform to ros pose msg
:param carla_transform:
:return: a ros pose msg
"""
transform_matrix = Transform(carla_transform).matrix
x, y, z = tf.transformations.translation_from_matrix(transform_matrix)
quat = tf.transformations.quaternion_from_matrix(transform_matrix)
ros_transform = Transform()
ros_transform.translation.x = x
ros_transform.translation.y = y
ros_transform.translation.z = z
ros_transform.rotation.x = quat[0]
ros_transform.rotation.y = quat[1]
ros_transform.rotation.z = quat[2]
ros_transform.rotation.w = quat[3]
return ros_transform
def ros_transform_to_pose(ros_transform):
"""
Util function to convert a ros transform into a ros pose
:param ros_transform:
:return: a ros pose msg
"""
pose = Pose()
pose.position.x, pose.position.y, pose.position.z = ros_transform.translation.x, \
ros_transform.translation.y, \
ros_transform.translation.z
pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w = ros_transform.rotation.x, \
ros_transform.rotation.y, \
ros_transform.rotation.z, \
ros_transform.rotation.w
return pose

View File

@ -1,16 +0,0 @@
#!/usr/bin/env python
import rostest
import sys
import unittest
from carla_ros_bridge.client import main
## A sample python unit test
class TestPublishedTopics(unittest.TestCase):
def test_camera_topics(self):
self.assertEquals(1, 1, "1!=1")
if __name__ == '__main__':
rostest.rosrun(__name__, 'test_published_topics', TestPublishedTopics)

View File

@ -1,38 +0,0 @@
<launch>
<arg name='enable_rosbag' default='False'/>
<rosparam file="$(find carla_ros_bridge)/config/settings.yaml" command="load" />
<param name="carla_autopilot" type="boolean" value="True" />
<param name='enable_rosbag' type="boolean" value="False"/>
<node pkg="carla_ros_bridge" name="carla_ros_bridge" type="client.py" output="screen"/>
<test test-name="testTopics" pkg="rostest" type="publishtest" time-limit="20.0">
<rosparam>
topics:
- name: /player_vehicle
timeout: 20
negative: False
- name: /tf
timeout: 20
negative: False
- name: /camera_front/image_raw
timeout: 20
negative: False
- name: /camera_front/camera_info
timeout: 20
negative: False
- name: /camera_depth/image_raw
timeout: 20
negative: False
- name: /camera_depth/camera_info
timeout: 20
negative: False
- name: /vehicles
timeout: 20
negative: False
</rosparam>
</test>
</launch>