ROS1迁移ROS2经验总结(针对点云神经网络)

第一部分:项目背景

目前已经在ROS1上跑通了全卷积点云神经网络基于caffe,需要将其全部转移到ROS2上去。

这个功能包分为以下几个部分

 由图上结构可以看出,这份功能包中有common、detected_objects_visualizer、lidar_cnn_seg_detect、custom_msgs,它们的作用如下:

common基础数学库
detected_objects_visualizer可视化配置
lidar_cnn_seg_detect核心
custom_msgs自定义消息

可以看出代码的结构层次还是很明显的,下面将一步步来介绍。

第二部分:准备工作

首先需要创建一个功能包

mkdir-p lidar_cnn/src 
cd lidar_cnn
colcon build

上述指令执行完毕,将创建lidar_cnn目录,且该目录下包含build(存储中间文件的目录,该目录下会为每一个功能包创建一个单独子目录)、install(安装目录,该目录下会为每一个功能包创建一个单独子目录)、log(日志目录,用于存储日志文件)、src共四 个子级目录。 工作空间创建完毕后,我们可以在工作空间下的src目录中编写C++程序,且流程如下:

创建功能包;编辑源文件;编辑配置文件;编译;执行

创建功能包

首先要注意的是,我们需要注意原先ros1中功能包有哪些依赖(可以在package.xml中查看),我们在创建ros2过程中可以直接添加上,这样可以省去后面再重复添加的麻烦。

例如,在ros1中的依赖如下

    <build_depend>roscpp</build_depend>
    <build_depend>tf</build_depend>
    <build_depend>tf_conversions</build_depend>
    <build_depend>pcl_ros</build_depend>
    <build_depend>sensor_msgs</build_depend>
    <build_depend>geometry_msgs</build_depend>
    <build_depend>rockauto_msgs</build_depend>

 那么我们在创建功能包时就可以直接添加

ros2 pkg create lidar_cnn_seg_detect--build-type ament_cmake--dependencies rclcpp tf tf_conversions pcl sensor_msgs geometry_msgs

你可能已经发现了,我没有添加pcl_ros,这是因为ROS2并不支持pcl_ros,所以后面在改源代码的时候再解决,这里先用pcl替代。

在CMAKELists文件中也需要修改,详细可参考详解使用ament_cmake构建ROS2功能包_ament_package-CSDN博客

add_executable(lidar_cnn src/cluster2d.cpp)
                         src/cnn_segmentation.cpp
                         src/feature_generator.cpp
                         src/lidar_cnn_seg_detect_node.cpp)
ament_target_dependencies(
  lidar_cnn 
  "rclcpp"
  "std_msgs"
  "sensor_msgs"
  "message_filters"
  "pcl_conversions"
  "pcl_ros"
)

install(TARGETS 
  lidar_cnn 
  DESTINATION lib/${PROJECT_NAME})

第三部分:修改源文件

从上面文件目录可以看到,最简单的功能包当然是自定义消息,因此先构建他。

custom_msgs

同上文一样,构建一个功能包,然后再添加一个msg文件夹,在其中添加你需要的.msg文件

尤其注意

ROS2在构建自定义msg时,.msg文件的首字母必须要大写,如要写ObjectDetect.msg

 举个例子,下面在custom_msgs/mg中创建一个新的文件ObjectDetect.msg

std_msgs/Header            header                  # Ros header
float32                     speed                   # 车速(km/h)
float32                     steerAngle              # 转角

 这里也要注意在ROS2中的Header必须要加std_msgs,不然就会报如下错误

fatal error: more_interfaces/msg/detail/header__struct.h: 没有那个文件或目录
   22 | #include "more_interfaces/msg/detail/header__struct.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/more_interfaces__rosidl_generator_c.dir/build.make:124:CMakeFiles/more_interfaces__rosidl_generator_c.dir/rosidl_generator_c/more_interfaces/msg/detail/A__functions.c.o] 错误 1
make[1]: *** [CMakeFiles/Makefile2:206:CMakeFiles/more_interfaces__rosidl_generator_c.dir/all] 错误 2
make[1]: *** 正在等待未完成的任务....
#在CMAKELists中添加如下代码
find_package(rosidl_default_generators REQUIRED)
find_package(std_msgs REQUIRED)

set(msg_files
"msg/ObjectDetect.msg"
)

rosidl_generate_interfaces(${PROJECT_NAME}
 "msg/ObjectDetect.msg"
   DEPENDENCIES std_msgs
 )

#在package中添加如下代码
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
#在package.xml中添加以下行
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<exec_depend>std_msgs</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>

这些是为了将.msg文件转换成对应的C++头文件

然后编译就行了

colcon build--packages-select custom_msgs

lidar_cnn_seg_detect

然后进入核心部分,首先观察功能包结构

 我们首先将头文件逐个进行修改

比如在cnn_segmentation.h中修改

#原版本
#include <chrono>
#include <ros/ros.h>
#include "caffe/caffe.hpp"
#include <pcl/point_types.h>
#include <pcl_ros/point_cloud.h>
#include <pcl/filters/extract_indices.h>
#include <custom_msgs/DetectedObjectArray.h>
#include <visualization_msgs/MarkerArray.h>
#include <jsk_recognition_msgs/BoundingBoxArray.h>
#include <std_msgs/Header.h>
#include "cluster2d.h"
#include "feature_generator.h"

#ROS2版本
#include <chrono>
#include <rclcpp/rclcpp.h>
#include "caffe/caffe.hpp"
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/filters/extract_indices.h>
#include <custom_msgs/msg/DetectedObjectArray.h>
#include <visualization_msgs/msg/marker_array.h>
#include <jsk_recognition_msgs/msg/bounding_box_array.h>
#include <std_msgs/msg/header.h>
#include "cluster2d.h"
#include "feature_generator.h"

然后根据ROS2的特点,通常推荐以继承Node的方式来创建节点对象,因此需要将CNNSegmantation类修改成如下

#要修改的地方
class CNNSegmentation : public rclcpp::Node
{
public:
    CNNSegmentation:Node(cnn_seg_node){}
    void run();
    void test_run();
private:
#将发布方和订阅方修改,在代码中也需要修改
rclcpp::Subscription<sensor_msgs::msg::PointCloud2>::SharedPtr points_sub_;
rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr points_pub_;
}

详细可参考:ROS1到ROS2迁移教程(以rslidar_to_velodyne功能包为例)+ ROS2版本LIO-SAM试跑_ros1转ros2-CSDN博客

然后就可以编译这个包了,但是出现了如下问题

很明显这是找不到自定义msg生成的hpp

于是去install/custom_msgs/include/custom_msgs/msg找发现确实没有这个hpp

 于是先验证自定义msg是否正常生成

ros2 interface show custom_msgs/msg/DetectedObject

这样的格式说明没有问题,于是反思是不是在ros2生成自定义msg头文件与ros1不同,于是尝试

#include <custom_msgs/msg/detected_object.hpp>

#include <custom_msgs/msg/detected_object_array.hpp>

竟然成了,这些文件名和install/custom_msgs/include/custom_msgs/msg相同

这么奇怪吗??这里确实没搞懂,但是编译这部分没报错了。

然后就开始各种问题,下面一一列举

问题1

于是在PCL库中去找看真的是不是没有,因为我只包含了

#include <pcl/point_types.h>

#include <pcl/point_cloud.h>

发现这两个头文件中的确没有,突然发现PCL库中还有一个包就叫PointIndices.h,于是直接加上,问题解决

问题2

这里是忘记改了,要把所有格式都改成ROS2版本的

问题3

很明显这个函数需要两个参数,把它补齐即可

RCLCPP_INFO_STREAM(this->get_logger(),"process takes "<<elapsed<<" ms.");

问题4

 

这个地方需要尤为注意,在ROS2中最好不要这么写

subscription_ = this->create_subscription<Student>("topic_stu", 10,
std::bind(&MinimalSubscriber::topic_callback, this, _1));

因为尝试将某个类型的回调函数赋值给 callback_variant_,但是类型不匹配。可能的原因之一是 std::function 无法正确地将某个类型的回调函数或函数对象进行包装。确保回调函数的类型与 std::function 的模板参数匹配: 确保你的回调函数的参数和返回类型与 std::function 所期望的类型相匹配。包括确保回调函数接受 constsensor_msgs::msg::PointCloud2_<std::allocator<void>> & 作为参数。

最好使用 Lambda 表达式而不是 std::bind。Lambda 表达式的类型通常更容易与 std::function 匹配。

subscription_ = this->create_subscription<std_msgs::msg::String>(
    "topic", 10,
    [this](const std_msgs::msg::String::SharedPtr msg) {
        this->topic_callback(msg);
    });

问题5

 

这个错误表明你正在尝试使用 const 修饰的 Header 对象进行某些操作,但是这个操作要求对象是可修改的。该错误通常发生在你尝试在一个 const 成员函数内修改对象的成员时。

在C++中,const 成员函数是指被声明为 const 的类成员函数。这样的函数表明它不会修改调用它的对象的状态。在 const 成员函数内,不能修改类的非静态成员变量,也不能调用非 const 成员函数,这有助于确保在使用 const 对象时不会意外地修改其状态。

因此把const类回调函数改为普通回调函数,去掉const即可

void CNNSegmentation::pointsCallback(const sensor_msgs::msg::PointCloud2::SharedPtr msg)

问题6

 

参考【PCL build issue】WARNING ** io features related to pcap png will be disabled_io features related to pcap will be disabled-CSDN博客

请一定按照教程走完,因为PCL库对ROS2支持不全,很多地方没有更改,所以会报很多warning,需要耐心查找问题。

  • 39
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值