CARLA中创建新传感器(Create a new sensor in CARLA)

0 系统配置

  • Ubuntu 20.04
  • CARLA 0.9.12
  • ROS Noetic

1 创建流程与逻辑

  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文件夹和其余关键代码
  • 主要参考官方文档:创建传感器
    但是官网文档给出的构建代码已经过时,部分实现函数的函数名已经修改,详见下文。
  1. 在目录:
    ~/carla/Unreal//carla/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Sensor
    创建传感器的实现函数头文件
  2. 在目录:
    ~/carla/LibCarla/source/carla/sensor/s11n/
    创建传感器的序列器(serializer)实现函数头文件
    序列器将实现函数所得的原始数据存入缓冲区中传递给事件对象,然后传递给客户端原始数据
  3. 在目录:
    ~/carla/LibCarla/source/carla/sensor/data/
    创建传感器的数据对象(事件)函数头文件
    将缓冲区中的指针解析为数组
    并对目录~/carla/PythonAPI/carla/source/libcarla/中的SensorData.cpp进行相应修改
    注意记得包含对应头文件
  4. 在目录:
    PythonAPI/carla/source/libcarla/中的SensorData.cpp将cpp方法暴露给pythonAPI
  5. 在目录:
    ~/carla/LibCarla/source/carla/sensor/中的SensorRegistry.h进行传感器注册
  6. 重新编译
    编译问题详见后续
    直接使用make cleanmake PythonAPImake launch
    不要使用make rebuild

2 存在问题

  1. 编译报错 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. 编译报错 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 PythonAPImake launch
    不要使用官方步骤的make rebuild
    尽管make rebuild相当于make cleanmake launch,但是缺少了make PythonAPI就会导致第三方库编译不完全。
  3. 编译报错 3
    make launch时报错如下:
    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
    
    其主要原因就是UE4文件夹权限被错误变更为ROOT(一般是由于sudo make xxx),make CarlaUE4Editor无法编译相关UE4库导致make失败
    解决方法:
    sudo chown -R usr_name : usr_name UE4文件夹名

3 Python实现

基于官方自带脚本manual_control.py进行实现

  1. class World(object):中加入
    self.safedistance_sensor = None
  2. def restart(self):中加入
    self.safedistance_sensor = SafeDistanceSensor(self.player)
  3. 创建一个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实现

  1. 根据底层实现,考虑最终需要返回的数据类型,编写carla.msg或者使用ros自带数据类型
    ~/catkin_ws/src/ros-bridge/carla.msgs/msg文件夹下创建CarlaSafeDistanceEvent.msg

    # A safe distance event
    
    std_msgs/Header header
    
    string ActorId # 返回其他车辆的ID
    
  2. 编写传感器的初始化,调用以及仿真结果发布的py类函数
    ~/catkin_ws/src/ros-bridge/carla_ros_bridge/src/carla_ros_bridge文件夹下创建safedistance_sensor.py

    from 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)
    
  3. 在同文件夹下的actor_factory.pydef _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
                                            )
    

    可按传感器的实际需求编写变量

  4. 在同文件下的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)
    
  5. ~/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}
    }
    
  6. 执行catkin_make

一切顺利的话,启动ros-bridge后,当两辆车的包围盒发生重叠时执行ros topic echo /carla/ego_vehicle/safe_distance终端会输出如下消息:

在这里插入图片描述

写在最后

本文仅提供参考,基于本文的方法能基本复现carla官网的流程,但仍存在部分bug,目前已知的有:

  1. 在同场景下,若重新生成车辆,上一辆车的包围盒仍停留原地,但不发生检测,将隐藏盒子参数设为true后消失
  2. ROS中会收到自身和另外对象的id,可能在多车情况下消息会失效。rosbridge中传感器消息收发代码仍需优化
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值