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