0 系统配置
- Ubuntu 20.04
- CARLA 0.9.12
- ROS Noetic
1 创建流程与逻辑
- 写在最前
- carla中AActor类含有大量实现函数
头文件位于👇
~/carla/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Actor/CarlaActor.h
- CarlaEpisode表示模拟器中运行的当前情节,即自上次加载地图以来的模拟状态。它包含 Carla 的所有相关信息。
头文件位于👇
~/carla/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Game/CarlaEpisode.h
- 操作前注意备份Content文件夹和其余关键代码
- 主要参考官方文档:创建传感器
但是官网文档给出的构建代码已经过时,部分实现函数的函数名已经修改,详见下文。
- 在目录:
~/carla/Unreal//carla/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor
中
创建传感器的实现函数和头文件 - 在目录:
~/carla/LibCarla/source/carla/sensor/s11n/
中
创建传感器的序列器(serializer)实现函数和头文件
序列器将实现函数所得的原始数据存入缓冲区中传递给事件对象,然后传递给客户端原始数据 - 在目录:
~/carla/LibCarla/source/carla/sensor/data/
中
创建传感器的数据对象(事件)函数头文件
将缓冲区中的指针解析为数组
并对目录~/carla/PythonAPI/carla/source/libcarla/
中的SensorData.cpp进行相应修改
注意记得包含对应头文件 - 在目录:
PythonAPI/carla/source/libcarla/
中的SensorData.cpp将cpp方法暴露给pythonAPI - 在目录:
~/carla/LibCarla/source/carla/sensor/
中的SensorRegistry.h进行传感器注册 - 重新编译
编译问题详见后续
直接使用make clean
后make PythonAPI
后make launch
不要使用make rebuild
2 存在问题
- 编译报错 1
解决方法:In file included from ../../LibCarla/source/carla/sensor/s11n/SafeDistanceSerializer.cpp:3: ../../LibCarla/cmake/../source/carla/sensor/data/SafeDistanceEvent.h:14:9: error: no matching constructor for initialization of 'Array<rpc::ActorId>' (aka 'Array<unsigned int>') : Array<rpc::ActorId>(std::move(data)) {}
在 SafeDistanceEvent.h 中改写
Array<rpc::ActorId>(std::move(data)) {}
为Array<rpc::ActorId>(0u, std::move(data)) {}
.
在 SafeDistanceSerializer.h 中改写
ActorId id = episode.FindActor(actor).GetActorId();
为ActorId id = episode.FindCarlaActor(actor)->GetActorId();
.
该处为更新的代码,原代码已不适用 - 编译报错 2
解决方法:x86_64-linux-gnu-gcc: error: /home/ikaros/carla/PythonAPI/carla/dependencies/lib/libxerces-c.a: 没有那个文件或目录 x86_64-linux-gnu-gcc: error: /home/ikaros/carla/PythonAPI/carla/dependencies/lib/libproj.a: 没有那个文件或目录 x86_64-linux-gnu-gcc: error: /home/ikaros/carla/PythonAPI/carla/dependencies/lib/libsqlite3.a: 没有那个文件或目录
make clean
后重新make PythonAPI
和make launch
不要使用官方步骤的make rebuild
尽管make rebuild
相当于make clean
后make launch
,但是缺少了make PythonAPI
就会导致第三方库编译不完全。 - 编译报错 3
make launch
时报错如下:
其主要原因就是UE4文件夹权限被错误变更为ROOT(一般是由于make[1]: 进入目录“/home/ikaros/carla/Unreal/CarlaUE4” make[1]: *** 没有规则可制作目标“CarlaUE4Editor”。停止。 make[1]: 离开目录“/home/ikaros/carla/Unreal/CarlaUE4” make: *** [Util/BuildTools/Linux.mk:7:launch] 错误 2
sudo make xxx
),make CarlaUE4Editor
无法编译相关UE4库导致make失败
解决方法:
sudo chown -R usr_name : usr_name UE4文件夹名
3 Python实现
基于官方自带脚本manual_control.py
进行实现
- 在
class World(object):
中加入
self.safedistance_sensor = None
- 在
def restart(self):
中加入
self.safedistance_sensor = SafeDistanceSensor(self.player)
- 创建一个
SafeDistanceSensor
类class SafeDistanceSensor(object): def __init__(self, parent_actor): self._parent = parent_actor world = self._parent.get_world() bp = world.get_blueprint_library().find('sensor.other.safe_distance') self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent) def callback(event): for actor_id in event: vehicle = world.get_actor(actor_id) print('Vehicle too close: %s' % vehicle.type_id) self.sensor.listen(callback)
一切顺利的话,当两辆车包围盒重叠时,终端会输出如下画面:
4 ROS-bridge实现
-
根据底层实现,考虑最终需要返回的数据类型,编写carla.msg或者使用ros自带数据类型
在~/catkin_ws/src/ros-bridge/carla.msgs/msg
文件夹下创建CarlaSafeDistanceEvent.msg# A safe distance event std_msgs/Header header string ActorId # 返回其他车辆的ID
-
编写传感器的初始化,调用以及仿真结果发布的py类函数
在~/catkin_ws/src/ros-bridge/carla_ros_bridge/src/carla_ros_bridge
文件夹下创建safedistance_sensor.pyfrom carla_ros_bridge.sensor import Sensor from carla_msgs.msg import CarlaSafeDistanceEvent # 自定义的消息类型,发布其它车辆的ID class SafeDistanceSensor(Sensor): def __init__(self, uid, name, parent, relative_spawn_pose, node, carla_actor, synchronous_mode, world): super(SafeDistanceSensor, self).__init__(uid=uid, name=name, parent=parent, relative_spawn_pose=relative_spawn_pose, node=node, carla_actor=carla_actor, synchronous_mode=synchronous_mode, is_event_sensor=True ) self.world = world # 初始化传入的世界参数 self.safedistance_publisher = node.new_publisher(CarlaSafeDistanceEvent, self.get_topic_prefix(), qos_profile=10) self.self_actor_id = self.carla_actor_id # 获取当前角色id self.listen() def destroy(self): super(SafeDistanceSensor, self).destroy() self.node.destroy_publisher(self.safedistance_publisher) def sensor_data_updated(self, safedistance_event): safedistance_msg = CarlaSafeDistanceEvent() safedistance_msg.header = self.get_msg_header(timestamp=safedistance_event.timestamp) vehicle_list = list(safedistance_event) # 获取激活的缓存数据(包围盒重叠) vehicle_id = self.world.get_actor(vehicle_list[0]) if self.self_actor_id != vehicle_id:# 如果不属于本身的角色id,将其id输出 safedistance_msg.ActorId = str(vehicle_id.type_id) self.safedistance_publisher.publish(safedistance_msg)
-
在同文件夹下的actor_factory.py的
def _create_object(self, uid, type_id, name, attach_to, spawn_pose, carla_actor=None):
中引用该传感器类elif carla_actor.type_id.startswith("sensor.other.safe_distance"): actor = SafeDistanceSensor(uid, name, parent, spawn_pose, self.node, carla_actor, self.sync_mode, self.world )
可按传感器的实际需求编写变量
-
在同文件下的bridge.py中调用ActorFactory
from carla_ros_bridge.actor_factory import ActorFactory def initialize_bridge(self, carla_world, params): ... self.actor_factory = ActorFactory(self, carla_world, self.sync_mode)
-
在
~/catkin_ws/src/ros-bridge/carla_spawn_objects/config
文件夹的objects.json中添加新传感器位置配置{ "type":"sensor.other.safe_distance", "id":"safe_distance", "spawn_point":{"x": 0.0, "y": 0.0, "z": 0.0} }
-
执行
catkin_make
一切顺利的话,启动ros-bridge后,当两辆车的包围盒发生重叠时执行ros topic echo /carla/ego_vehicle/safe_distance
终端会输出如下消息:
写在最后
本文仅提供参考,基于本文的方法能基本复现carla官网的流程,但仍存在部分bug,目前已知的有:
- 在同场景下,若重新生成车辆,上一辆车的包围盒仍停留原地,但不发生检测,将隐藏盒子参数设为true后消失
- ROS中会收到自身和另外对象的id,可能在多车情况下消息会失效。rosbridge中传感器消息收发代码仍需优化