- 自动驾驶
- 科研
- 仿真
【免费下载链接】carla
Open-source simulator for autonomous driving research.
CARLA 模拟器(CARLA Simulator)从服务端原生支持 ROS2 通信,无需外部桥接进程即可将仿真中生成的传感器数据直接发布为 ROS2 Topic。本文以 Docs/ros2_native_sensors.md 为核心,完整梳理 13 类传感器对应的 Topic 名称与 ROS 消息类型,并结合仓库源码(LibCarla/source/carla/ros2 下的发布器实现)讲解数据格式、发布机制与订阅方式。读完本文,你将能准确规划感知节点的 Topic 订阅方案,理解/clock时间同步、enable_for_ros()启用逻辑以及sensor_msgs各消息的字段来源,可直接对接目标检测、点云处理、里程计等 ROS2 下游应用。
前置概念:ROS2 原生接口与仿真时钟/clock
在进入传感器 Topic 清单之前,需要先理解两条贯穿全文的机制:
服务端原生发布:CARLA 的 ROS2 支持内建于服务端。启动时只需在命令行追加
--ros2选项(详见 Docs/ros2_native.md):./CarlaUnreal.sh --ros2此后,任何被显式启用 ROS 的传感器都会由服务端直接向 DDS 总线广播数据,不需要额外的 ros-bridge 进程。
仿真时钟
/clock:CARLA 服务端负责基于仿真时间发布/clockTopic,并且每个仿真帧都会更新一次。这是 ROS2 应用保持时间同步的关键——下游节点应将该时钟作为use_sim_time的时间源,确保时间戳与仿真帧一致。从源码看,该发布器位于 CarlaClockPublisher.cpp,它通过BasePublisher("rt/clock")创建名为rt/clock的写者,并将仿真秒数与纳秒写入rosgraph_msgs/Clock消息:CarlaClockPublisher::CarlaClockPublisher() : BasePublisher("rt/clock"), _impl(std::make_shared<PublisherImpl<CarlaClockMsgTraits>>()) { if (!_impl->Init(GetBaseTopicName())) { log_error("CarlaClockPublisher: failed to initialise writer for rt/clock"); } } bool CarlaClockPublisher::Write(std::int32_t seconds, std::uint32_t nanoseconds) { auto *message = _impl->GetMessage(); message->clock().sec(seconds); message->clock().nanosec(nanoseconds); return true; }可以看到底层通过 eProsima Fast-DDS 类型的
ClockPubSubType序列化发布,Topic 名以rt/前缀声明(对应 ROS 的 reliable-transient-local 语义)。
传感器数据广播机制:如何让传感器"进入 ROS"
默认情况下,仿真中 spawn 的传感器不会自动向 ROS 发布数据。必须显式调用传感器对象的enable_for_ros()方法,例如在 Python 客户端中:
sensor = world.spawn_actor(sensor_blueprint, transform) sensor.enable_for_ros()这条调用在客户端侧形成一条完整的链路:ServerSideSensor.cpp 中的ServerSideSensor::EnableForROS()请求所在 Episode,进而由 Simulator.cpp 的Simulator::EnableForROS()调用 Client.cpp 的Client::EnableForROS(),通过该传感器的 streaming token 通知服务端开启对应流的 ROS 转发。也就是说,"是否发布"由服务端按传感器逐一控制,而非全局开关。
Topic 命名规则
Topic 名称由传感器 blueprint 中的ros_name属性决定,需在 spawn 之前设置(默认会生成随机字符串名称):
bp = bp_lib.find('sensor.camera.rgb') bp.set_attribute('ros_name', 'front_camera')无父级时的 Topic 形如:
/carla/front_camera/image若传感器挂载在某个 actor(例如自车)之下,Topic 会再拼接父级 actor 的 role name,形如:
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image例如自车 role name 为ego、相机ros_name为front_camera时,图像 Topic 为/carla/ego/front_camera/image(对应 Docs/ros2_native.md 的示例)。下表所有 Topic 中的<PARENT ROLE NAME>即为父级 actor 的 role name,<SENSOR ROLE NAME>即ros_name;无父级时两者之间的路径段省略。
相机类传感器:图像与内参消息
相机类传感器通常同时发布两个 Topic:图像数据(sensor_msgs/Image)与相机内参(sensor_msgs/CameraInfo)。从源码看,这一对写者统一实现在 CarlaCameraPublisher.cpp 中:构造函数同时为base_topic + "/image"与base_topic + "/camera_info"各初始化一个PublisherImpl,Publish()时两者无条件共同发布(一处失败不会压制另一处)。
CameraInfo消息的填充值得注意(同一源文件中WriteCameraInfo()):
distortion_model固定为"plumb_bob",畸变向量D为 5 个零值;- 内参矩阵
K由ComputeIntrinsics(width, height, fov)依据分辨率与视场角实时计算(fx/fy、主点 cx/cy); - 矫正矩阵
R为单位阵,投影矩阵P为标准针孔形式,binning_x/binning_y为 0; roi区域直接回填图像的 offset、height、width 与do_rectify标志。
而Image消息的step与encoding则由各传感器子类决定:例如 RGB 相机发布器 CarlaRGBCameraPublisher.h 重写GetChannels()返回 4、GetEncoding()返回"bgra8"(BGRA 四通道像素)。可以推断,Depth、Semantic Segmentation、Instance Segmentation、Normals、Optical Flow 等发布器(CarlaDepthCameraPublisher.h、CarlaSSCameraPublisher.h、CarlaISCameraPublisher.h、CarlaNormalsCameraPublisher.h、CarlaOpticalFlowCameraPublisher.h)均以同样的子类化方式定义各自的像素格式,下游消费者应依据消息中的encoding字段做对应解码。
RGB camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
Depth camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
Semantic segmentation camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
Instance segmentation camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
Normals camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
Optical flow camera
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
光流数据以图像形式承载在/imageTopic 中。仓库中 OpticalFlowEncoding.h 专门负责光流结果的编码转换,说明仿真内部的光流计算结果在进入 ROS 消息前会经过一次编码层处理,消费端需按该编码规则解码出二维光流矢量。
DVS camera
DVS 事件相机是唯一同时发布"事件流 + 图像 + 内参"三类 Topic 的传感器:
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/events | sensor_msgs/PointCloud2 |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/image | sensor_msgs/Image |
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME>/camera_info | sensor_msgs/CameraInfo |
其实现 CarlaDVSCameraPublisher.cpp 由两个子发布器组合而成:CarlaDVSImagePublisher通过 DvsEventEncoding.h 中的EncodeDvsEventsToBgr将原始事件累加编码为 BGR 图像;CarlaDVSPointCloudPublisher则通过EncodeDvsEventsToPointCloud把每个事件(基于carla/sensor/data/DVSEvent结构,见GetPointSize()返回的sizeof(sensor::data::DVSEvent))转换为带时间戳t字段的点云消息。源码注释特别指出:事件时间戳为 int64,必须在编码为 FLOAT64t槽位时转换为 double,不能直接做字节拷贝,否则订阅方按 double 解码会得到错误比特。这解释了为什么eventsTopic 采用PointCloud2而非自定义消息——每个点即一个 (x, y, t, polarity) 事件。
点云类传感器:Lidar / Semantic lidar / Radar
三类三维感知传感器统一发布为sensor_msgs/PointCloud2,Topic 名不带后缀,直接落在基础名称上。
Lidar
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | sensor_msgs/PointCloud2 |
发布器实现在 CarlaLidarPublisher.cpp,点云字段布局由 PointCloudFieldsLayout.h 统一定义,保证下游(如 rviz、点云滤波、目标检测)可按标准PointField结构解析 x/y/z/intensity 等字段。
Semantic lidar
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | sensor_msgs/PointCloud2 |
语义激光雷达在几何信息基础上附带对象标签信息,发布器 CarlaSemanticLidarPublisher.cpp 负责将语义点数据写入PointCloud2字段。
Radar
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | sensor_msgs/PointCloud2 |
雷达发布器 CarlaRadarPublisher.cpp 需要把雷达返回的极坐标量测转换为笛卡尔坐标系下的点云,仓库中的 RadarPolarToCartesian.h 即承担这一坐标转换职责。消费雷达点云时,注意其字段除位置外通常还包含径向速度、方位角与俯仰角信息,字段名以PointCloud2消息内实际声明为准。
位姿与导航类传感器:IMU / GNSS
IMU
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | sensor_msgs/Imu |
IMU 发布器 CarlaIMUPublisher.cpp 输出标准sensor_msgs/Imu(含线加速度、角速度与四元数姿态)。实现中引用了 ImuMath.h,可以推断原始惯性数据在写入消息前经过数学变换(例如坐标系对齐或单位换算),订阅方以消息内容为准即可。
GNSS
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | sensor_msgs/NavSatFix |
GNSS 发布器 CarlaGNSSPublisher.cpp 输出sensor_msgs/NavSatFix,携带纬度、经度、海拔与定位状态协方差,可直接对接机器人导航栈(如 robot_localization、mapviz)。
事件类传感器:Lane Invasion Sensor
Lane Invasion Sensor
| Topic | 类型 |
|---|---|
/carla/[<PARENT ROLE NAME>]/<SENSOR ROLE NAME> | carla_msgs/CarlaLaneInvasionEvent |
车道入侵传感器发布自定义消息CarlaLaneInvasionEvent,其字段在 Docs/ros2_native_msgs.md 中有完整定义:
| 字段 | 类型 | 描述 |
|---|---|---|
header | std_msgs/Header | 消息发布时的时间戳与 frame ID |
crossed_lane_markings | int32[] | 上一仿真步内被跨越的车道线集合,使用常量标识:LANE_MARKING_OTHER=0、LANE_MARKING_BROKEN=1、LANE_MARKING_SOLID=2 |
该消息属于carla_msgs自定义消息族。与sensor_msgs标准消息不同,使用前需要安装对应的消息定义包(CARLA 生态中的ros-carla-msgs),订阅方在编译期即可获得强类型定义。
实践指南:如何订阅这些 Topic
1. 验证数据是否在发布
启动带--ros2的 CARLA 服务端、spawn 并enable_for_ros()传感器后,使用 ROS2 命令行工具即可列出并检查 Topic:
ros2 topic list ros2 topic echo /carla/ego/front_camera/camera_info --once ros2 topic hz /carla/lidar其中ros2 topic hz可用于确认点云/图像的发布频率与仿真帧率一致;相机图像可借助rqt_image_view直接可视化/carla/.../image。
2. 订阅相机图像(Python 示例)
以下示例订阅 RGB 相机图像并打印其尺寸、编码与step:
import rclpy from rclpy.node import Node from sensor_msgs.msg import Image class CarlaImageSubscriber(Node): def __init__(self): super().__init__('carla_image_subscriber') self.sub = self.create_subscription( Image, '/carla/ego/front_camera/image', self.on_image, 10) def on_image(self, msg: Image): self.get_logger().info( f'image {msg.width}x{msg.height}, encoding={msg.encoding}, ' f'step={msg.step}, stamp={msg.header.stamp.sec}.{msg.header.stamp.nanosec}') def main(): rclpy.init() rclpy.spin(CarlaImageSubscriber()) rclpy.shutdown()注意三点:一是相机消息encoding字段(如 RGB 相机为"bgra8")决定了像素解码方式;二是header.stamp与/clock来自同一仿真时钟,建议为节点启用use_sim_time;三是Image.data的长度为height * step,其中step = width * channels,不可用裸width * height计算(源码 CarlaCameraPublisher.cpp 中step(width * GetChannels())明确了这一关系)。
3. 订阅点云与 IMU
点云与 IMU 都是标准sensor_msgs消息,可直接复用通用处理管线:
PointCloud2:使用sensor_msgs_py.point_cloud2.read_points()逐点解析,或直接送入rviz2的 PointCloud2 显示插件;Imu/NavSatFix:可分别接入惯性导航融合与全局定位模块,NavSatFix的经纬高直接对应仿真世界坐标在 WGS84 下的投影。
延伸阅读
- 传感器之外的控制链路与启用细节,见 ROS2 原生接口总览(含
--ros2启动、ros_name设置、/carla/ego/vehicle_control_cmd控制 Topic 与CarlaEgoVehicleControl字段说明); - 全部 CARLA 自定义消息(含
CarlaLaneInvasionEvent、CarlaEgoVehicleControl、CarlaStatus、CarlaWorldInfo等)的逐字段参考,见 CARLA 消息参考; - 感兴趣的读者可深入 LibCarla/source/carla/ros2/publishers 目录逐一阅读各发布器实现,理解每个消息的序列化类型(
...PubSubTypes,见 LibCarla/source/carla/ros2/types)与字段填充逻辑。
- 自动驾驶
- 科研
- 仿真
【免费下载链接】carla
Open-source simulator for autonomous driving research.
相关推荐
Skia图形库深度解析:从平面到球面的实时着色器映射技术
Skia图形库深度解析:从平面到球面的实时着色器映射技术 在当今的图形处理领域,Skia作为Google开源的2D图形库,不仅提供了基础的文本、几何和图像绘制能
自动驾驶科研仿真wagmi core `signMessage` Action 完全指南:消息签名、参数详解与源码原理
wagmi core signMessage Action 完全指南:消息签名、参数详解与源码原理 本文是 wagmi(Reactive primitives
区块链Web3前端Apache DolphinScheduler 启动参数(Startup Parameter)完全指南:工作流级参数配置、传递规则与源码原理
Apache DolphinScheduler 启动参数(Startup Parameter)完全指南:工作流级参数配置、传递规则与源码原理 导读 启动参数(S
任务调度数据编排工作流自动化后端大数据
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考