CARLA
 
载入中...
搜索中...
未找到
CarlaRadarPublisher.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2
4
5#include <string>
6
7#include "carla/sensor/data/RadarData.h"/// @brief 包含CARLA雷达数据结构的头文件。
8#include "carla/ros2/types/PointCloud2PubSubTypes.h"/// @brief 包含ROS 2点云发布/订阅类型的头文件。
9#include "carla/ros2/listeners/CarlaListener.h"/// @brief 包含CARLA监听器类的头文件。
10
11#include <fastdds/dds/domain/DomainParticipant.hpp>/// @brief 包含Fast-DDS域参与者的头文件。
12#include <fastdds/dds/publisher/Publisher.hpp> /// @brief 包含Fast-DDS发布者的头文件。
13#include <fastdds/dds/topic/Topic.hpp> /// @brief 包含Fast-DDS主题的头文件。
14#include <fastdds/dds/publisher/DataWriter.hpp>/// @brief 包含Fast-DDS数据写入器的头文件。
15#include <fastdds/dds/topic/TypeSupport.hpp>/// @brief 包含Fast-DDS类型支持的头文件。
16
17#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>/// @brief 包含Fast-DDS域参与者服务质量(QoS)的头文件。
18#include <fastdds/dds/domain/DomainParticipantFactory.hpp>/// @brief 包含Fast-DDS域参与者工厂的头文件。
19#include <fastdds/dds/publisher/qos/PublisherQos.hpp>/// @brief 包含Fast-DDS发布者服务质量(QoS)的头文件。
20#include <fastdds/dds/topic/qos/TopicQos.hpp>/// @brief 包含Fast-DDS主题服务质量(QoS)的头文件。
21
22#include <fastrtps/attributes/ParticipantAttributes.h>/// @brief 包含Fast-RTPS参与者属性的头文件。
23#include <fastrtps/qos/QosPolicies.h>/// @brief 包含Fast-RTPS服务质量(QoS)策略的头文件。
24#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>/// @brief 包含Fast-DDS数据写入器服务质量(QoS)的头文件。
25#include <fastdds/dds/publisher/DataWriterListener.hpp>/// @brief 包含Fast-DDS数据写入器监听器的头文件。
26
27/**
28 * @namespace carla::ros2
29 * @brief 包含CARLA与ROS 2集成相关功能的命名空间。
30 */
31namespace carla {
32namespace ros2 {
33 /**
34 * @brief 简化eprosima::fastdds::dds命名空间的别名,以便代码更简洁。
35 */
36 namespace efd = eprosima::fastdds::dds;
37 /**
38 * @brief 简化eprosima::fastrtps::types::ReturnCode_t类型的别名,用于错误码返回。
39 */
40 using erc = eprosima::fastrtps::types::ReturnCode_t;
41 /**
42 * @struct CarlaRadarPublisherImpl
43 * @brief CarlaRadarPublisher的内部实现结构体,封装了Fast-DDS发布雷达数据所需的对象。
44 */
46 /**
47 * @brief Fast-DDS域参与者对象指针。
48 */
49 efd::DomainParticipant* _participant { nullptr };
50 /**
51 * @brief Fast-DDS发布者对象指针。
52 */
53 efd::Publisher* _publisher { nullptr };
54 /**
55 * @brief Fast-DDS主题对象指针。
56 */
57 efd::Topic* _topic { nullptr };
58 /**
59 * @brief Fast-DDS数据写入器对象指针。
60 */
61 efd::DataWriter* _datawriter { nullptr };
62 /**
63 * @brief Fast-DDS类型支持对象,用于注册ROS 2点云消息类型。
64 */
66 /**
67 * @brief CARLA监听器对象,用于接收来自CARLA的雷达数据。
68 */
69 CarlaListener _listener {};
70 /**
71 * @brief 存储雷达数据的ROS 2点云消息对象。
72 */
74 };
75 /**
76 * @struct RadarDetectionWithPosition
77 * @brief 包含雷达检测及其位置信息的结构体。
78 */
80 /**
81 * @brief 检测到的目标在X轴上的位置。
82 */
83 float x;
84 /**
85 * @brief 检测到的目标在Y轴上的位置。
86 */
87 float y;
88 /**
89 * @brief 检测到的目标在Z轴上的位置。
90 */
91 float z;
92 /**
93 * @brief CARLA雷达检测数据。
94 */
96 };
97 /**
98 * @brief 初始化CarlaRadarPublisher对象。
99 *
100 * 此函数负责创建Fast-DDS域参与者、发布者、主题和数据写入器,并注册ROS 2点云消息类型。
101 *
102 * @return 如果初始化成功,则返回true;否则返回false。
103 */
105 /**
106 * 检查类型支持是否有效。如果_impl->_type为nullptr,表示类型支持无效,打印错误信息并返回false。
107 */
108 if (_impl->_type == nullptr) {
109 std::cerr << "Invalid TypeSupport" << std::endl;
110 return false;
111 }
112 /**
113 * 设置域参与者(DomainParticipant)的质量服务(Qos)参数,使用默认值,并设置名称。
114 */
115 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
116 pqos.name(_name); // 设置域参与者的名称
117 auto factory = efd::DomainParticipantFactory::get_instance();
118 _impl->_participant = factory->create_participant(0, pqos);
119 /**
120 * 检查域参与者是否创建成功。如果为nullptr,表示创建失败,打印错误信息并返回false。
121 */
122 if (_impl->_participant == nullptr) {
123 std::cerr << "Failed to create DomainParticipant" << std::endl;
124 return false;
125 }
126 /**
127 * 注册类型支持到域参与者。
128 */
129 _impl->_type.register_type(_impl->_participant);// 注册类型支持
130 /**
131 * 设置发布者(Publisher)的质量服务(Qos)参数,使用默认值。
132 */
133 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
134 /**
135 * 创建发布者。
136 */
137 _impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
138 /**
139 * 检查发布者是否创建成功。如果为nullptr,表示创建失败,打印错误信息并返回false。
140 */
141 if (_impl->_publisher == nullptr) {
142 std::cerr << "Failed to create Publisher" << std::endl;
143 return false;
144 }
145 /**
146 * 设置主题(Topic)的质量服务(Qos)参数,使用默认值。
147 */
148 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
149 /**
150 * 构造主题名称,根据基础名称"rt/carla/"和可能的父级名称以及本对象的名称。
151 */
152 const std::string base { "rt/carla/" };
153 std::string topic_name = base;
154 if (!_parent.empty())
155 topic_name += _parent + "/";
156 topic_name += _name;
157 /**
158 * 创建主题。
159 */
160 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
161 /**
162 * 检查主题是否创建成功。如果为nullptr,表示创建失败,打印错误信息并返回false。
163 */
164 if (_impl->_topic == nullptr) {
165 std::cerr << "Failed to create Topic" << std::endl;
166 return false;
167 }
168 /**
169 * 设置数据写入器(DataWriter)的质量服务(Qos)参数,使用默认值,并设置历史内存策略为预分配并重新分配模式。
170 */
171 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
172 wqos.endpoint().history_memory_policy = eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
173 /**
174 * 获取数据写入器监听器实例。
175 */
176 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
177 /**
178 * 创建数据写入器。
179 */
180 _impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
181 /**
182 * 检查数据写入器是否创建成功。如果为nullptr,表示创建失败,打印错误信息并返回false。
183 */
184 if (_impl->_datawriter == nullptr) {
185 std::cerr << "Failed to create DataWriter" << std::endl;
186 return false;
187 }
188 // 设置帧ID
190 /**
191 * 初始化成功,返回true。
192 */
193 return true;
194 }
195 /**
196 * @brief 发布雷达数据
197 *
198 * 此函数尝试通过Fast-RTPS发布雷达数据。根据返回代码,函数会返回不同的结果,并在控制台上打印相应的错误信息。
199 *
200 * @return true 如果数据成功发布
201 * @return false 如果数据发布失败,并根据返回代码打印错误信息
202 */
204 /// Fast-RTPS实例句柄
205 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
206 /// 尝试写入雷达数据到数据写入器,并获取返回代码
207 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_radar, instance_handle);
208 /// 根据返回代码处理不同的结果
209 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
210 /// 数据成功发布
211 return true;
212 }
213 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
214 /// 通用错误
215 std::cerr << "RETCODE_ERROR" << std::endl;
216 return false;
217 }
218 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
219 /// 操作不支持
220 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
221 return false;
222 }
223 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
224 /// 参数错误
225 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
226 return false;
227 }
228 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
229 /// 先决条件未满足
230 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
231 return false;
232 }
233 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
234 /// 资源不足
235 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
236 return false;
237 }
238 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
239 /// 功能未启用
240 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
241 return false;
242 }
243 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
244 /// 不可变策略
245 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
246 return false;
247 }
248 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
249 /// 策略不一致
250 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
251 return false;
252 }
253 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
254 /// 已被删除
255 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
256 return false;
257 }
258 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
259 /// 超时
260 std::cerr << "RETCODE_TIMEOUT" << std::endl;
261 return false;
262 }
263 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
264 /// 无数据
265 std::cerr << "RETCODE_NO_DATA" << std::endl;
266 return false;
267 }
268 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
269 /// 非法操作
270 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
271 return false;
272 }
273 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
274 /// 安全策略不允许
275 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
276 return false;
277 }
278 /// 未知错误
279 std::cerr << "UNKNOWN" << std::endl;
280 return false;
281 }
282 /**
283 * @brief 设置雷达数据
284 *
285 * 该函数接收雷达检测数据,并将其转换为内部使用的格式,然后调用另一个重载的SetData函数来发布数据。
286 *
287 * @param seconds 时间戳的秒部分
288 * @param nanoseconds 时间戳的纳秒部分
289 * @param height 数据的高度(通常用于图像数据,这里可能表示雷达扫描的垂直分辨率)
290 * @param width 数据的宽度(通常用于图像数据,这里可能表示雷达扫描的水平分辨率)
291 * @param elements 数据点的数量
292 * @param data 指向雷达检测数据的指针,数据格式为carla::sensor::data::RadarDetection
293 */
294void CarlaRadarPublisher::SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, size_t elements, const uint8_t* data) {
295 // 创建一个用于存储转换后数据的向量
296 std::vector<uint8_t> vector_data;
297 // 计算需要存储的数据大小
298 const size_t size = elements * sizeof(RadarDetectionWithPosition);
299 // 调整向量大小以适应数据
300 vector_data.resize(size);
301 // 将向量的起始地址转换为RadarDetectionWithPosition类型的指针
302 RadarDetectionWithPosition* radar_data = (RadarDetectionWithPosition*)&vector_data[0];
303 // 将输入数据的起始地址转换为carla::sensor::data::RadarDetection类型的指针
305 // 遍历每个检测数据点,进行转换
306 for (size_t i = 0; i < elements; ++i, ++radar_data, ++detection_data) {
307 // 根据深度、方位角和仰角计算x坐标
308 radar_data->x = detection_data->depth * cosf(detection_data->azimuth) * cosf(-detection_data->altitude);
309 // 根据深度、方位角和仰角计算y坐标
310 radar_data->y = detection_data->depth * sinf(-detection_data->azimuth) * cosf(detection_data->altitude);
311 // 根据深度和仰角计算z坐标
312 radar_data->z = detection_data->depth * sinf(detection_data->altitude);
313 // 复制完整的检测数据
314 radar_data->detection = *detection_data;
315 }
316 // 调用重载的SetData函数,发布转换后的数据
317 SetData(seconds, nanoseconds, height, width, elements, std::move(vector_data));
318 }
319/**
320 * @brief 设置雷达数据并发布
321 *
322 * 该函数接收时间戳、数据尺寸、数据点数量以及数据本身,然后将这些数据封装成ROS消息格式并发布。
323 *
324 * @param seconds 时间戳的秒部分
325 * @param nanoseconds 时间戳的纳秒部分
326 * @param height 数据的高度
327 * @param width 数据的宽度
328 * @param elements 数据点的数量
329 * @param data 包含雷达检测数据的向量,数据格式为RadarDetectionWithPosition
330 */
331 void CarlaRadarPublisher::SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, size_t elements, std::vector<uint8_t>&& data) {
332 // 创建一个时间戳消息
334 time.sec(seconds);
335 time.nanosec(nanoseconds);
336 // 创建一个消息头
337 std_msgs::msg::Header header;
338 header.stamp(std::move(time));
339 header.frame_id(_frame_id);
340 // 创建点字段描述符,用于描述点云数据的结构
342 descriptor1.name("x");
343 descriptor1.offset(0);
345 descriptor1.count(1);
347 descriptor2.name("y");
348 descriptor2.offset(4);
350 descriptor2.count(1);
352 descriptor3.name("z");
353 descriptor3.offset(8);
355 descriptor3.count(1);
357 descriptor4.name("velocity");
358 descriptor4.offset(12);
360 descriptor4.count(1);
362 descriptor5.name("azimuth");
363 descriptor5.offset(16);
365 descriptor5.count(1);
367 descriptor6.name("altitude");
368 descriptor6.offset(20);
370 descriptor6.count(1);
372 descriptor7.name("depth");
373 descriptor7.offset(24);
375 descriptor7.count(1);
376 // 获取点数据的大小
377 const size_t point_size = sizeof(RadarDetectionWithPosition);
378 // 设置雷达消息的头信息、宽度、高度、字节序、字段描述符、点步长、行步长和是否稠密
379 _impl->_radar.header(std::move(header));
380 _impl->_radar.width(elements);
381 _impl->_radar.height(height);
382 _impl->_radar.is_bigendian(false);
383 _impl->_radar.fields({descriptor1, descriptor2, descriptor3, descriptor4, descriptor5, descriptor6, descriptor7});
384 _impl->_radar.point_step(point_size);
385 _impl->_radar.row_step(elements * point_size);
386 _impl->_radar.is_dense(false);
387 // 设置雷达消息的数据
388 _impl->_radar.data(std::move(data));
389 }
390 /**
391 * @brief CarlaRadarPublisher 类的构造函数
392 *
393 * 初始化 CarlaRadarPublisher 对象,并创建一个 CarlaRadarPublisherImpl 对象的智能指针。
394 *
395 * @param ros_name ROS 节点的名称
396 * @param parent 父节点的名称
397 */
398 CarlaRadarPublisher::CarlaRadarPublisher(const char* ros_name, const char* parent) :
399 _impl(std::make_shared<CarlaRadarPublisherImpl>()) {
400 _name = ros_name;///< ROS 节点的名称
401 _parent = parent;///< 父节点的名称
402 }
403 /**
404 * @brief CarlaRadarPublisher 类的析构函数
405 *
406 * 清理资源,包括删除 DataWriter、Publisher、Topic 和 Participant。
407 */
409 if (!_impl)
410 return;
411
412 if (_impl->_datawriter)
413 _impl->_publisher->delete_datawriter(_impl->_datawriter);///< 删除 DataWriter
414
415 if (_impl->_publisher)
416 _impl->_participant->delete_publisher(_impl->_publisher);///< 删除 Publisher
417
418 if (_impl->_topic)
419 _impl->_participant->delete_topic(_impl->_topic); ///< 删除 Topic
420
421 if (_impl->_participant)
422 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);///< 删除 Participant
423 }
424 /**
425 * @brief CarlaRadarPublisher 类的拷贝构造函数
426 *
427 * 使用另一个 CarlaRadarPublisher 对象来初始化当前对象。
428 *
429 * @param other 另一个 CarlaRadarPublisher 对象
430 */
432 _frame_id = other._frame_id;///< 拷贝帧 ID
433 _name = other._name;///< 拷贝 ROS 节点的名称
434 _parent = other._parent;///< 拷贝父节点的名称
435 _impl = other._impl; ///< 共享相同的 CarlaRadarPublisherImpl 对象
436 }
437 /**
438 * @brief 拷贝赋值运算符
439 *
440 * 使用另一个 CarlaRadarPublisher 对象来更新当前对象。
441 *
442 * @param other 另一个 CarlaRadarPublisher 对象
443 * @return CarlaRadarPublisher& 当前对象的引用
444 */
446 _frame_id = other._frame_id;///< 拷贝帧 ID
447 _name = other._name;///< 拷贝 ROS 节点的名称
448 _parent = other._parent;///< 拷贝父节点的名称
449 _impl = other._impl;///< 共享相同的 CarlaRadarPublisherImpl 对象
450
451 return *this;
452 }
453 /**
454 * @brief CarlaRadarPublisher 类的移动构造函数
455 *
456 * 使用另一个 CarlaRadarPublisher 对象(右值)来初始化当前对象。
457 *
458 * @param other 另一个 CarlaRadarPublisher 对象(右值)
459 */
461 _frame_id = std::move(other._frame_id);///< 移动帧 ID
462 _name = std::move(other._name);///< 移动 ROS 节点的名称
463 _parent = std::move(other._parent);///< 移动父节点的名称
464 _impl = std::move(other._impl);///< 移动 CarlaRadarPublisherImpl 对象
465 }
466 /**
467 * @brief 移动赋值运算符
468 *
469 * 使用另一个 CarlaRadarPublisher 对象(右值)来更新当前对象。
470 *
471 * @param other 另一个 CarlaRadarPublisher 对象(右值)
472 * @return CarlaRadarPublisher& 当前对象的引用
473 */
475 _frame_id = std::move(other._frame_id);///< 移动帧 ID
476 _name = std::move(other._name);///< 移动 ROS 节点的名称
477 _parent = std::move(other._parent);///< 移动父节点的名称
478 _impl = std::move(other._impl);///< 移动 CarlaRadarPublisherImpl 对象
479
480 return *this;
481 }
482}
483}
此类表示用户在IDL文件中定义的Time结构。
eProsima_user_DllExport void nanosec(uint32_t _nanosec)
此函数设置成员nanosec的值。
Definition Time.cpp:183
eProsima_user_DllExport void sec(int32_t _sec)
此函数设置成员sec的值。
Definition Time.cpp:152
const std::string & parent() const
CarlaRadarPublisher(const char *ros_name="", const char *parent="")
CarlaRadarPublisher 类的构造函数
std::shared_ptr< CarlaRadarPublisherImpl > _impl
void SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, size_t elements, const uint8_t *data)
设置雷达数据
bool Init()
初始化CarlaRadarPublisher对象。
CarlaRadarPublisher & operator=(const CarlaRadarPublisher &)
拷贝赋值运算符
~CarlaRadarPublisher()
CarlaRadarPublisher 类的析构函数
This class represents the TopicDataType of the type PointCloud2 defined by the user in the IDL file.
This class represents the structure PointCloud2 defined by the user in the IDL file.
Definition PointCloud2.h:74
此类表示用户在 IDL 文件中定义的结构 PointField。 <>
Definition PointField.h:79
eProsima_user_DllExport void count(uint32_t _count)
此函数设置成员 count 的值
eProsima_user_DllExport void offset(uint32_t _offset)
此函数设置成员 offset 的值
eProsima_user_DllExport void name(const std::string &_name)
此函数复制成员 name 的值
eProsima_user_DllExport void datatype(uint8_t _datatype)
此函数设置成员 datatype 的值
eprosima::fastrtps::types::ReturnCode_t erc
@using erc
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
const uint8_t PointField__FLOAT32
Definition PointField.h:71
CarlaRadarPublisher的内部实现结构体,封装了Fast-DDS发布雷达数据所需的对象。
sensor_msgs::msg::PointCloud2 _radar
存储雷达数据的ROS 2点云消息对象。
efd::TypeSupport _type
Fast-DDS类型支持对象,用于注册ROS 2点云消息类型。
efd::Publisher * _publisher
Fast-DDS发布者对象指针。
CarlaListener _listener
CARLA监听器对象,用于接收来自CARLA的雷达数据。
efd::Topic * _topic
Fast-DDS主题对象指针。
efd::DomainParticipant * _participant
Fast-DDS域参与者对象指针。
efd::DataWriter * _datawriter
Fast-DDS数据写入器对象指针。
包含雷达检测及其位置信息的结构体。
carla::sensor::data::RadarDetection detection
CARLA雷达检测数据。
float y
检测到的目标在Y轴上的位置。
float x
检测到的目标在X轴上的位置。
float z
检测到的目标在Z轴上的位置。