ROS2学习笔记29--项目从ROS1迁移到ROS2的经验参考_ros2 time now-程序员宅基地

技术标签: 自动驾驶  ROS2  

环境:ubuntu20.04 ,ros-foxy(ros2),vscode

背景:项目需要,一直折腾把ros1下面的包升级到ros2版本.以下纯属个人查找资料摸索,自我理解所得,有错误的地方,望大佬们不吝赐教.

1.消失的句柄

ros1里面有成员句柄,里面还分各种命名空间啥的,然后跟话题,参数息息相关,而在ros2里面就没有句柄成员了,个人感觉是可采用节点指针来取代其功能.

ros1句柄:

ros::NodeHandle nh;

ros2可改写:

std::shared_ptr<rclcpp::Node> nh;

参考链接:

2.接口文件(msg/srv)编写规则

1)ros2接口(自定义消息)名称首字母必须大写;并且需要在packages.xml文件里面写:

<member_of_group>rosidl_interface_packages</member_of_group>

2)编译接口(自定义数据类型)包时,注意:

Header header			#ros1,but error in ros2
std_msgs/Header header	#ros2 witten

3)包名字,能有连续下划线,能在最后下划线;第一个字符必须是字母,后面字符可以是字母数字下划线,但保证不能下划线是最后.错误例子,如:

custom__msg
custom_msg_
2custom_msg

正确案例:

custom_msg

4)ros2中,自定义消息类型(接口)时,类型和变量名称只能一个空格隔开:

sensor_msgs/PointCloud2              border_area		#ros1 define style,but error in ros2

sensor_msgs/PointCloud2 border_area		#ros2 style

5)ros2中,自定义消息类型(接口)时,名称只能由小写字母单个下划线数字组成:

float32       WB_Angle_Feedback   #ros1,error in ros2
float32 wb_angle_feedback  	#ros2
float32 wb_angle_feedback_1  #ros2

6)ros2,自定义接口文件名称(注意和包名称区别),首字母一定要大写,字母之间不能有下划线,名称组成不含数字(不知道能不能使用数字),建议使用驼峰法来命名.正确样式如:

LidarObjectArray.msg
Num.msg
AddThreeInts.srv

3.创建发布者

ros1:
声明:

ros::Publisher objects_info_pub_;

构造函数里面创建publisher:

objects_info_pub_ = node_handle_.advertise<sensor_msgs::msg::PointCloud2>( "/objects_info_pub_topic", 10);

node_handle_句柄ros::handle node_handle_

ros2:
声明:

rclcpp::Publisher<sensor_msgs::msg::PointCloud2> objects_info_pub_;

构造函数里面创建publisher:

objects_info_pub_= this->create_publisher<sensor_msgs::msg::PointCloud2>("/objects_info_pub_topic", 10);

参考链接:https://blog.csdn.net/qq_45701501/article/details/118577437

4.创建订阅者

ros1:
声明:

ros::NodeHandle n;
ros::Subscriber objects_info_sub_;

在类构造函数里面创建subscriber,并启动回调函数:

//--------------------create_subscription-----------------------------
objects_info_sub_= n.subscribe("objects_info_pub_topic", 1, Callback);
//callback function
void Callback(const sensor_msgs::msg::PointCloud2::ConstPtr msg){
    
//do stuff
}

ros2:
声明:

rclcpp::Subscription<sensor_msgs::msg::PointCloud2>::SharedPtr objects_info_sub_;

在类构造函数中创建subscriber,并启动回调函数:

//--------------------create_subscription-----------------------------
objects_info_sub_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
                    objects_info_pub_topic, 1, 
                    std::bind(&Callback, 
                              this, std::placeholders::_1));
//或者
objects_info_sub_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
                    objects_info_pub_topic, 1, 
                    [this](const sensor_msgs::msg::PointCloud2::ConstPtr msg)
    				{
    Callback(msg)};
//--------------------/create_subscription-----------------------------
//callback function
void Callback(const sensor_msgs::msg::PointCloud2::ConstPtr msg){
    
//do stuff
}

参考链接:https://blog.csdn.net/qq_45701501/article/details/118577437

5.spin()和shutdown()系列

ros1   		->   	ros2
ros::spin();              rclcpp::spin(node);//std::shared_ptr<rclcpp::Node> node
ros::spinOnce();	      rclcpp::spinOnce(node);//std::shared_ptr<rclcpp::Node> node
ros::shutdown();    	 rclcpp::shutdown();

spin()表示循环并监听回调函数;spinOnce()表示仅监听回调函数,并不循环

参考链接:

https://roboticsbackend.com/ros2-rclcpp-parameter-callback/
https://www.huaweicloud.com/articles/13536904.html

6.类

对于ros包类,下面是个人的基本思考采用的方式,仅供参考:
ros1:

class{
    
	....
};

ros2:

class: public rclcpp:Node 
{
    
	....
};

为啥我这么考虑呢?个人理解,在ros1时,我们想打印点消息到终端,只要头文件包含了"ros/ros.h",直接使用 ROS_INFO("...")即可输出,但是ros2里面输出,并不单单是"rclcpp/rclcpp.h",而且需要有节点指针指向get_logger()函数才行输出的,如RCLCPP_INFO(this->get_logger(),"...");,为了方便使用this,所以直接继承rclcpp::Node类,来得方便.否则,目前我能想到的方法是全局构造一个节点指针来搞.

参考链接:

7.时间系列

ros1:
时间点声明:

ros::Time timestamp ;

使用例子:

ros::Time timestamp = ros::Time::now();

时间段声明:

定时器声明:

定时器回调:

ros2:
时间点声明:

rclcpp::Time timestamp ;

使用例子:

rclcpp::Time timestamp = np->now();//std::shared_ptr<rclcpp::Node> np

时间段声明:

定时器声明:

rclcpp::TimerBase::SharedPtr timer1;

定时器回调:

std::shared_ptr<rclcpp::Node> nh;
//创建定时器
rclcpp::TimerBase::SharedPtr timer1;
//定时器timer1初始化,250ms中断,回调函数timer1_callback
timer1 = nh->create_wall_timer(250ms,timer1_callback);

参考链接:

https://blog.csdn.net/yang434584531/article/details/115749810#commentBox

8.创建包以及编译指令

ros1:
创建包:

catkin_create_pkg <package_name>

编译包:

catkin_make

ros2:

创建包:

ros2 pkg create --build-type ament_cmake <package_name>

编译包:

colcon build

参考链接:https://blog.csdn.net/qq_45701501/article/details/118574569#t6

9.cmakelists.txt部分细节参考

ros2:
launch文件夹查找标签:

参考链接:

10.parameter参数系列

ros1:

ros::handle node_handle;
node_handle_.param("/listen_freq_param", listen_freq_, 1000);

ros2:

rclcpp::Node::SharedPtr nh;
nh->get_parameter_or("/listen_freq_param", listen_freq_, 1000);

这里有个小疑惑,参考材料说,"/listen_freq_param"这个参数,需要声明才能使用使用,形式如:

this->declare_parameter<bool>("b_use_", true);
this->get_parameter_or<bool>("b_use_", b_use_, true);//无法获取时用默认值

参考链接:

https://blog.csdn.net/yang434584531/article/details/115749810#commentBox

11.创建服务器端

ros1:
ros2:
参考链接:

12.创建客户端

ros1:
ros2:
参考链接:

13.创建action

ros1:
ros2:
参考链接:

14.初始化init()

ros1:

ros::init(argc, argv, "listener");

ros2:

rclcpp::init(argc, argv);

ros1的话,初始化时候,随便给了节点名了,但在ros2里面,只是初始化,节点名在其他地方搞的,如:

 auto node = rclcpp::Node::make_shared("listener");

参考链接:

16.vscode的cpp开发时路径配置经验参考

1)编译器空间,尽量保证只放一个包,目地是防止路径污染导致疏忽错误;

2)路径添加,第一种是安装在系统上面的,如"/opt/ros/foxy/include/",第二种是自定义的,如自定义包位置,"/home/ylh/xxx_ws/install/custom_pkg_xxx/include",还有自己当前包的头文件引用,如"${workspaceFolder}/include"

3)路径添加方式,第一次加载包时,头文件会有很多下划波浪线报错,光标停留报错行,会出现 小灯泡 ,单击小灯泡,打开界面;此时会在编译器工作空间的目录,生成 .vscode文件夹,选择文件c_cpp_properties.json,添加上述路径,效果如:

{
    
    "configurations": [
        {
    
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/home/ylh/xxx_ws/install/custom_pkg_xxx/include",
                "/opt/ros/foxy/include/",
                "${workspaceFolder}/include"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu17",
            "cppStandard": "gnu++14",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}

注意,自定义包的头文件路径,一般都是在所在工作空间编译生成的include文件夹下面的 包名/include

如果担心手写路径写错的话,可终端cd进去目标文件夹,pwd输出全路径,在复制过来即可.

17.打印终端输出

ros1版本:

 ROS_INFO_ONCE("Waiting for yqy...");

ros2版本:

RCLCPP_INFO_ONCE(nh->get_logger(),"Waiting for yqy...");

解析:nh为(rclcpp::Node)节点指针,如果是在rclcpp::Node子类里面,可使用this->get_logger()

其他输出类似,把ROS修改成RCLCPP,然后括号里面添加xx->get_logger(),,如:

 ROS_INFO  ->	RCLCPP_INFO
 ROS_DEBUG  ->		RCLCPP_DEBUG 
 ......

18.头文件引用自定义接口

ros1版本:

 #include <std_msgs/Int16MultiArray.h> //ros1写法

ros2版本:

#include <std_msgs/msg/int16_multi_array.h>//ros2写法,增加了详细路径msg以及将大写改为小写,
											//并添加以大写字母为界添加下划线

19.回调函数的形参

//ros1:
void callback(const std_msgs::String::ConstPtr & msg);

//ros2:
void callback(std_msgs::msg::String::ConstSharedPtr msg);

注意形式参数写法的变化(ros1写法可能还在支持,但是推荐使用ros2方式编写)

其他

奈何笔记过于凌乱,后续继续更新上面内容....

#####################
不积硅步,无以至千里
好记性不如烂笔头
感觉有点收获的话,麻烦大大们点赞收藏哈

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_45701501/article/details/120143845

智能推荐

动态版通讯录_动态通讯录-程序员宅基地

文章浏览阅读278次,点赞15次,收藏7次。目录一.通讯录的准备工作二.通讯录的实现步骤创建主菜单存放个人信息(静态)存放个人信息(动态)增加联系人(静态)增加联系人(动态)显示联系人删除指定的联系人查找指定联系人修改指定的联系人销毁通讯录(动态)三.源代码(动态)一.通讯录的准备工作首先我们要想一想开辟一个通讯录我们需要做哪些工作。要存放一些人的基本信息(名字+性别+年龄+电话+住址),增加联系人,删除联系人,修改联系人,查找联系人,最后要存入文档以便找不到。这里我们..._动态通讯录

win10和ubuntu的pyCharm配置python解释器_ubuntu conda环境文件夹中没有python.exe-程序员宅基地

文章浏览阅读2.5k次。ubuntu配置python3.6文件---新建项目---选择需要的python版本(基本解释器python3.6)创建---新建Python文件test01.py打开设置添加系统Python解释器,点齿轮--添加--系统解释器 选择python3 点击确定点击添加配置点击 “+” -> Python选定脚本路径点击确定,配置完成..._ubuntu conda环境文件夹中没有python.exe

StringUtils工具类常用方法汇总(判空、转换、移除、替换、反转)_stringutils.remove-程序员宅基地

文章浏览阅读4.9k次,点赞8次,收藏26次。Apache commons lang3包下的StringUtils工具类中封装了一些字符串操作的方法,非常实用,使用起来也非常方便。最近自己也经常在项目中使用到了里面的一些方法,在这里将常用的方法总结了一下,方便以后查阅,大家有兴趣也可以看一下。  首先需要说明的一点是,StringUtils类在操作字符串时,即使操作的为null值也是安全的,不会报NullPointerException,这一..._stringutils.remove

html如何做点击按钮左侧展开收起,如何使用CSS3 实现侧边栏展开收起动画-程序员宅基地

文章浏览阅读1.2k次。@keyframes规则用于创建动画。@keyframes 中规定某项 CSS 样式,就能创建由当前样式逐渐改为新样式的动画效果@keyframes 中创建动画时,请把它捆绑到某个选择器,否则不会产生动画效果。通过规定至少以下两项 CSS3 动画属性,即可将动画绑定到选择器:规定动画的名称规定动画的时长animationanimation 属性是一个简写属性,用于设置动画属性:animation-..._keyframes向左展开动画

python游戏程序代码大全_童年游戏,Python一行代码就能实现!-程序员宅基地

文章浏览阅读2.5k次。大家好,儿童节到了,虽然秃头程序员没有头发,但是童心还是一直都在的,今天就分享一个私藏的GitHub项目——free-python-games,一行代码就能进入使用Python开发的小游戏快乐玩耍!安装与使用安装当然也很简单一行代码就可以pip install freegames由于该项目中的所有游戏均是基于Python内置模块Turtle制作,所以没有太多依赖,安装不会有困难。安装完之后我们可以..._童年游戏代码大全

Eclipse中项目Src看不到.Java文件_eclipse导入的项目src下没java-程序员宅基地

文章浏览阅读5.2k次。Eclipse中项目Src看不到.Java文件需要从Java切换到java EE 工作空间_eclipse导入的项目src下没java

随便推点

YOLOV3实战4:Darknet中cfg文件说明和理解_yolo cfg-程序员宅基地

文章浏览阅读4.7w次,点赞89次,收藏435次。大家好,我是小p,从今天起,将逐渐从源码角度解析Darknet,欢迎加入对象检测群813221712讨论和交流,进群请看群公告!今天将要说明的是Darknet中的cfg文件,废话少说,直接干!(以cfg/yolov3.cfg为例,其它类似)[net] ★ [xxx]开始的行表示网络的一层,其后的内容为该层的参数配置,[net]为特殊的层,配置整个网..._yolo cfg

python生成唯一Id的几种方法_python并发生成唯一数据-程序员宅基地

文章浏览阅读2w次,点赞2次,收藏4次。# coding:utf-8import randomdef createRandomString(len): print ('wet'.center(10,'*')) raw = "" range1 = range(58, 65) # between 0~9 and A~Z range2 = range(91, 97) # between A~Z and a~..._python并发生成唯一数据

Maven1-配置及创建JavaSE项目_maven 创建javase工程-程序员宅基地

文章浏览阅读431次。一、Maven简介项目构建工具(不只是管理jar包),项目设计和编码由程序员来做,它做不了;而编译,运行,测试,打包,部署,jar管理它都能做Apache提供,Java开发的,运行Maven要有基本的java开发工具包Maven仓库:存储jar包本地仓库:当前本地电脑远程仓库:局域网中的服务器中央仓库:远程服务器有远程仓库:本地连接远程,远程仓库中有就下载到本地,没有就去连中央仓库,中央仓库下载到远程,远程再下载到本地,适合团队开发,远程仓库可以连接多个本地仓库,所以很多公_maven 创建javase工程

【转载】FPGA配置方式_quartus烧录-程序员宅基地

文章浏览阅读6.3k次,点赞2次,收藏31次。【概要】FPGA配置方式首先介绍下AS、PS、JTAG三种模式的区别。AS模式: 主动串行配置模式。将.pof文件烧写到flash(掉电不丢失)芯片,FPGA器件每次上电时,作为主控制器从配置器件flash(EPCS)主动读取程序文件并存放至FPGA内部的配置存储器(configure RAM),实现逻辑运作,该方法适用于不需要经常升级的场合,一次性读取程序文件;PS..._quartus烧录

GitHub集成Circle CI(附 Circle CI 配置示例文件)_circleci building status github-程序员宅基地

文章浏览阅读1.6k次。文章目录GitHub 集成Circle CICI(持续集成) 简单解释CI 工具Circle的使用将GitHub项目授权给 Circle CI书写 config.yml文件测试 Circle CI 配置文件是否生效备注写在最后GitHub 集成Circle CICI(持续集成) 简单解释CI 即 Continuous Integration. 当代码提交上来有变动的时候,在merge之前自动进行一些流程,如:代码风格检查、单元测试是否通过等。当被merge之后,又会自动进行一些流程,如:自动打包、_circleci building status github

matlab题目如何在一个圆形区域进行三维作图_meshgrid ,边界是圆-程序员宅基地

文章浏览阅读3.2k次,点赞3次,收藏7次。不废话上图[r,t]=meshgrid(0:0.1:2,0:0.02:2*pi);x=r.*cos(t);y=r.*sin(t);z=x.^2+y.^2;mesh(x,y,z)其实在数学上使用了一个圆的参数方程来实现绘制区域为圆形的效果在这个区域上面是一个碗状图形_meshgrid ,边界是圆