CARLA
 
载入中...
搜索中...
未找到
CarlaSemanticLidarPublisher.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2
3#include "CarlaSemanticLidarPublisher.h"// 引入Carla语义激光雷达发布者类的声明
4
5#include <string>// 引入字符串处理相关的标准库
6// 引入CARLA ROS2桥接库中的点云数据类型和监听器类
9// 引入Fast-DDS库中的相关类和头文件
10#include <fastdds/dds/domain/DomainParticipant.hpp>// 引入域参与者类
11#include <fastdds/dds/publisher/Publisher.hpp>// 引入发布者类
12#include <fastdds/dds/topic/Topic.hpp>// 引入话题类
13#include <fastdds/dds/publisher/DataWriter.hpp>// 引入数据写入器类
14#include <fastdds/dds/topic/TypeSupport.hpp>// 引入类型支持类
15// 引入Fast-DDS库中与QoS(服务质量)相关的类和头文件
16#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>// 引入域参与者QoS类
17#include <fastdds/dds/domain/DomainParticipantFactory.hpp> // 引入域参与者工厂类
18#include <fastdds/dds/publisher/qos/PublisherQos.hpp>// 引入发布者QoS类
19#include <fastdds/dds/topic/qos/TopicQos.hpp>// 引入话题QoS类
20// 引入Fast-RTPS库中的参与者属性和QoS策略相关的类和头文件
21#include <fastrtps/attributes/ParticipantAttributes.h>// 引入参与者属性类
22#include <fastrtps/qos/QosPolicies.h> // 引入QoS策略类
23#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>// 引入数据写入器QoS类
24#include <fastdds/dds/publisher/DataWriterListener.hpp>// 引入数据写入器监听器类
25
26/**
27 * @namespace carla::ros2
28 * @brief 命名空间,包含CARLA与ROS2桥接相关的类和函数。
29 */
30namespace carla {
31namespace ros2 {
32 /**
33 * @brief 引入Fast-DDS命名空间的别名。
34 */
35 namespace efd = eprosima::fastdds::dds;
36 /**
37 * @brief 引入Fast-RTPS返回码类型的别名。
38 */
39 using erc = eprosima::fastrtps::types::ReturnCode_t;
40 /**
41 * @struct CarlaSemanticLidarPublisherImpl
42 * @brief Carla语义激光雷达数据发布者的内部实现结构。
43 *
44 * 该结构包含了Fast-DDS所需的域参与者、发布者、话题和数据写入器等成员变量,以及一个CARLA监听器和一个用于存储点云数据的成员变量。
45 */
47 efd::DomainParticipant* _participant { nullptr };///< 域参与者指针
48 efd::Publisher* _publisher { nullptr };///< 发布者指针
49 efd::Topic* _topic { nullptr };///< 话题指针
50 efd::DataWriter* _datawriter { nullptr };///< 数据写入器指针
51 efd::TypeSupport _type { new sensor_msgs::msg::PointCloud2PubSubType() };///< 类型支持,用于点云数据
52 CarlaListener _listener {};///< CARLA监听器
53 sensor_msgs::msg::PointCloud2 _lidar {}; ///< 存储点云数据的成员变量
54 };
55 /**
56 * @brief 初始化Carla语义激光雷达数据发布者。
57 *
58 * 该函数负责创建Fast-DDS的域参与者、发布者、话题和数据写入器,并注册类型支持。
59 *
60 * @return bool 如果初始化成功,则返回true;否则返回false。
61 */
63 // 检查类型支持是否有效
64 if (_impl->_type == nullptr) {
65 std::cerr << "Invalid TypeSupport" << std::endl;
66 return false;
67 }
68 // 设置域参与者的QoS策略,并创建域参与者
69 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
70 pqos.name(_name);
71 auto factory = efd::DomainParticipantFactory::get_instance();
72 _impl->_participant = factory->create_participant(0, pqos);
73 if (_impl->_participant == nullptr) {
74 std::cerr << "Failed to create DomainParticipant" << std::endl;
75 return false;
76 }
77 // 注册类型支持
78 _impl->_type.register_type(_impl->_participant);
79 // 设置发布者的QoS策略,并创建发布者
80 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
81 _impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
82 if (_impl->_publisher == nullptr) {
83 std::cerr << "Failed to create Publisher" << std::endl;
84 return false;
85 }
86
87 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
88 const std::string base { "rt/carla/" };
89 std::string topic_name = base;
90 if (!_parent.empty())
91 topic_name += _parent + "/";
92 topic_name += _name;
93 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
94 if (_impl->_topic == nullptr) {
95 std::cerr << "Failed to create Topic" << std::endl;
96 return false;
97 }
98 // 设置数据写入器的QoS策略,并创建数据写入器
99 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
100 wqos.endpoint().history_memory_policy = eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
101 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
102 _impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
103 if (_impl->_datawriter == nullptr) {
104 std::cerr << "Failed to create DataWriter" << std::endl;
105 return false;
106 }
107 // 设置帧ID为发布者的名称
109 // 初始化成功
110 return true;
111 }
112
114 /// @var instance_handle
115 /// 用于存储Fast RTPS实例句柄的变量。
116 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
117 /// @var rcode
118 /// 用于存储写操作返回码的变量。
119 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_lidar, instance_handle);
120 /// 检查返回码,如果是RETCODE_OK,表示发布成功。
121 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
122 return true;
123 }
124 /// 返回码为RETCODE_ERROR,表示发生了错误。
125 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
126 std::cerr << "RETCODE_ERROR" << std::endl;
127 return false;
128 }
129 /// 返回码为RETCODE_UNSUPPORTED,表示操作不受支持。
130 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
131 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
132 return false;
133 }
134 /// 返回码为RETCODE_BAD_PARAMETER,表示参数错误。
135 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
136 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
137 return false;
138 }
139 /// 返回码为RETCODE_PRECONDITION_NOT_MET,表示前提条件未满足。
140 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
141 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
142 return false;
143 }
144 /// 返回码为RETCODE_OUT_OF_RESOURCES,表示资源不足。
145 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
146 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
147 return false;
148 }
149 /// 返回码为RETCODE_NOT_ENABLED,表示功能未启用。
150 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
151 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
152 return false;
153 }
154 /// 返回码为RETCODE_IMMUTABLE_POLICY,表示策略不可变。
155 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
156 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
157 return false;
158 }
159 /// 返回码为RETCODE_INCONSISTENT_POLICY,表示策略不一致。
160 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
161 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
162 return false;
163 }
164 /// 返回码为RETCODE_ALREADY_DELETED,表示对象已被删除。
165 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
166 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
167 return false;
168 }
169 /// 返回码为RETCODE_TIMEOUT,表示操作超时。
170 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
171 std::cerr << "RETCODE_TIMEOUT" << std::endl;
172 return false;
173 }
174 /// 返回码为RETCODE_NO_DATA,表示没有数据。
175 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
176 std::cerr << "RETCODE_NO_DATA" << std::endl;
177 return false;
178 }
179 /// 返回码为RETCODE_ILLEGAL_OPERATION,表示非法操作。
180 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
181 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
182 return false;
183 }
184 /// 返回码为RETCODE_NOT_ALLOWED_BY_SECURITY,表示安全策略不允许。
185 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
186 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
187 return false;
188 }
189 /// 如果返回码未知,输出UNKNOWN错误信息。
190 std::cerr << "UNKNOWN" << std::endl;
191 return false;
192 }
193 /**
194 * @brief 设置激光雷达数据,包括时间戳、数据尺寸以及浮点数据数组,并对数据进行预处理。
195 *
196 * 此函数首先遍历浮点数据数组(除了第一个元素),将其中的每个元素乘以-1(即取反)。
197 * 然后,它将浮点数数据转换为字节序列,并调用另一个重载的SetData函数来设置处理后的数据。
198 *
199 * @param seconds 时间戳的秒部分
200 * @param nanoseconds 时间戳的纳秒部分
201 * @param elements 每个点的数据元素数量(例如,一个点可能包含x, y, z坐标等)
202 * @param height 数据的高度(行数)
203 * @param width 数据的宽度(列数)
204 * @param data 指向浮点数据数组的指针,这些数据将被处理并用于设置激光雷达数据
205 */
206void CarlaSemanticLidarPublisher::SetData(int32_t seconds, uint32_t nanoseconds, size_t elements, size_t height, size_t width, float* data) {
207 // 指向数据起始位置的迭代器
208 float* it = data;
209 // 指向数据结束位置的迭代器
210 float* end = &data[height * width * elements];
211 // 遍历数据(除了第一个元素),将每个元素乘以-1
212 for (++it; it < end; it += elements) {
213 *it *= -1.0f;
214 }
215 // 用于存储转换后的字节数据的向量
216 std::vector<uint8_t> vector_data;
217 // 计算需要存储的字节数据的大小
218 const size_t size = height * width * sizeof(float) * elements;
219 // 调整向量的大小以匹配数据大小
220 vector_data.resize(size);
221 // 将浮点数据复制到字节数据向量中
222 std::memcpy(&vector_data[0], &data[0], size);
223 // 调用另一个重载的SetData函数来设置处理后的数据
224 SetData(seconds, nanoseconds, height, width, std::move(vector_data));
225}
226/**
227 * @brief 设置激光雷达数据,包括时间戳、数据尺寸以及字节数据。
228 *
229 * 此函数创建并设置ROS消息头(Header)、点字段描述符(PointField)以及激光雷达数据(Lidar)的相关属性。
230 * 它使用提供的时间戳、高度、宽度和字节数据来填充这些属性,并准备激光雷达数据以供发布。
231 *
232 * @param seconds 时间戳的秒部分
233 * @param nanoseconds 时间戳的纳秒部分
234 * @param height 数据的高度(行数)
235 * @param width 数据的宽度(点数/列数)
236 * @param data 包含激光雷达点数据的字节向量,这些数据将被直接用于设置激光雷达消息的数据部分
237 */
238void CarlaSemanticLidarPublisher::SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, std::vector<uint8_t>&& data) {
239 // 创建并设置时间戳消息
241 time.sec(seconds);
242 time.nanosec(nanoseconds);
243 // 创建并设置消息头,包括时间戳和帧ID
244 std_msgs::msg::Header header;
245 header.stamp(std::move(time));
246 header.frame_id(_frame_id);// _frame_id应为类的成员变量,表示帧的ID
247 // 创建并设置点字段描述符,这些描述符定义了点的数据结构
249 descriptor1.name("x");
250 descriptor1.offset(0);
252 descriptor1.count(1);
254 descriptor2.name("y");
255 descriptor2.offset(4);
257 descriptor2.count(1);
259 descriptor3.name("z");
260 descriptor3.offset(8);
262 descriptor3.count(1);
264 descriptor4.name("cos_inc_angle");
265 descriptor4.offset(12);
267 descriptor4.count(1);
269 descriptor5.name("object_idx");
270 descriptor5.offset(16);
272 descriptor5.count(1);
274 descriptor6.name("object_tag");
275 descriptor6.offset(20);
277 descriptor6.count(1);
278 // 计算每个点的大小(以字节为单位)
279 const size_t point_size = 6 * sizeof(float);
280 // 设置激光雷达数据的各个属性
281 _impl->_lidar.header(std::move(header));
282 _impl->_lidar.width(width);
283 _impl->_lidar.height(height);
284 _impl->_lidar.is_bigendian(false);// 设置字节序,false表示小端序
285 _impl->_lidar.fields({descriptor1, descriptor2, descriptor3, descriptor4, descriptor5, descriptor6});// 设置点字段描述符
286 _impl->_lidar.point_step(point_size);// 设置每个点的步长(即每个点的大小)
287 _impl->_lidar.row_step(width * point_size);// 设置每行的步长(即每行的总大小)
288 _impl->_lidar.is_dense(false); // 设置是否稠密,false表示可能存在无效点
289 _impl->_lidar.data(std::move(data));// 设置激光雷达数据
290 }
291/**
292 * @brief CarlaSemanticLidarPublisher类的构造函数。
293 *
294 * 初始化CarlaSemanticLidarPublisher对象,创建内部实现对象,并设置ROS节点名称和父节点名称。
295 *
296 * @param ros_name ROS节点名称。
297 * @param parent 父节点名称或空字符串(如果无父节点)。
298 */
299 CarlaSemanticLidarPublisher::CarlaSemanticLidarPublisher(const char* ros_name, const char* parent) :
300 _impl(std::make_shared<CarlaSemanticLidarPublisherImpl>()) {
301 _name = ros_name;
302 _parent = parent;
303 }
304 /**
305 * @brief CarlaSemanticLidarPublisher类的析构函数。
306 *
307 * 清理CarlaSemanticLidarPublisher对象,释放所有资源。
308 * 这包括删除数据写入器、发布者、主题和参与者(如果它们存在)。
309 */
311 // 检查_impl是否有效,如果为nullptr则直接返回。
312 if (!_impl)
313 return;
314 // 如果存在数据写入器,则删除它。
315 if (_impl->_datawriter)
316 _impl->_publisher->delete_datawriter(_impl->_datawriter);
317 // 如果存在发布者,则删除它。
318 if (_impl->_publisher)
319 _impl->_participant->delete_publisher(_impl->_publisher);
320 // 如果存在主题,则删除它。
321 if (_impl->_topic)
322 _impl->_participant->delete_topic(_impl->_topic);
323 // 如果存在参与者,则删除它。
324 if (_impl->_participant)
325 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
326 }
327 /**
328 * @brief CarlaSemanticLidarPublisher类的拷贝构造函数。
329 *
330 * 通过另一个CarlaSemanticLidarPublisher对象来初始化当前对象,实现深拷贝(如果_impl是智能指针则实现浅拷贝)。
331 *
332 * @param other 要拷贝的CarlaSemanticLidarPublisher对象。
333 */
340 /**
341 * @brief 拷贝赋值运算符重载。
342 *
343 * 将当前对象替换为另一个CarlaSemanticLidarPublisher对象的拷贝。
344 *
345 * @param other 要赋值的CarlaSemanticLidarPublisher对象。
346 * @return 引用当前对象。
347 */
349 _frame_id = other._frame_id;
350 _name = other._name;
351 _parent = other._parent;
352 _impl = other._impl;
353
354 return *this;
355 }
356 /**
357 * @brief CarlaSemanticLidarPublisher类的移动构造函数。
358 *
359 * 通过另一个CarlaSemanticLidarPublisher对象(右值引用)来初始化当前对象,实现资源的转移。
360 *
361 * @param other 要移动的CarlaSemanticLidarPublisher对象(右值)。
362 */
364 _frame_id = std::move(other._frame_id);
365 _name = std::move(other._name);
366 _parent = std::move(other._parent);
367 _impl = std::move(other._impl);
368 }
369 /**
370 * @brief 移动赋值运算符重载。
371 *
372 * 将当前对象替换为另一个CarlaSemanticLidarPublisher对象(右值)的资源转移。
373 *
374 * @param other 要赋值的CarlaSemanticLidarPublisher对象(右值)。
375 * @return 引用当前对象。
376 */
378 _frame_id = std::move(other._frame_id);
379 _name = std::move(other._name);
380 _parent = std::move(other._parent);
381 _impl = std::move(other._impl);
382
383 return *this;
384 }
385}
386}
auto end() const noexcept
此类表示用户在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
std::shared_ptr< CarlaSemanticLidarPublisherImpl > _impl
void SetData(int32_t seconds, uint32_t nanoseconds, size_t elements, size_t height, size_t width, float *data)
设置激光雷达数据,包括时间戳、数据尺寸以及浮点数据数组,并对数据进行预处理。
bool Init()
初始化Carla语义激光雷达数据发布者。
CarlaSemanticLidarPublisher(const char *ros_name="", const char *parent="")
CarlaSemanticLidarPublisher类的构造函数。
CarlaSemanticLidarPublisher & operator=(const CarlaSemanticLidarPublisher &)
拷贝赋值运算符重载。
~CarlaSemanticLidarPublisher()
CarlaSemanticLidarPublisher类的析构函数。
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
const uint8_t PointField__UINT32
Definition PointField.h:70
Carla语义激光雷达数据发布者的内部实现结构。
sensor_msgs::msg::PointCloud2 _lidar
存储点云数据的成员变量
efd::DomainParticipant * _participant
域参与者指针
efd::DataWriter * _datawriter
数据写入器指针
efd::TypeSupport _type
类型支持,用于点云数据