Bootstrap

ROS2入门到精通—— 1-3 ROS1移植到ROS2系统梳理

ROS2同一功能包只能同时包含Python或者C++一种

1 ROS1 && ROS2 CMakeList.txt

ROS1中CMakeLists.txt架构如下

cmake_minimum_required()	#CMake的最低版本号

project()					#项目名称

find_package()				#找到编译需要的其他CMake/Catkin	package 

catkin_python_setup()		#catkin新加宏,打开catkin的Python Module的支持

add_message_files()			#catkin新加宏,添加自定义Message文件 

add_service_files()         #catkin新加宏,添加自定义Service文件 

add_action_files()          #catkin新加宏,添加自定义Action文件 

generate_message()			#catkin新加宏,生成不同语言版本的msg/srv/action接口 

catkin_package()			#catkin新加宏,生成当前package的cmake配置,供依赖本包的其他软件包调用 

add_library()				#生成库 

add_executable()			#生成可执行二进制文件

add_dependencies()			#定义目标文件依赖于其他目标文件,确保其他目标已被构建 

target_link_libraries()		#链接

catkin_add_gtest()			#catkin新加宏,生成测试

install()					#生成可安装目标
cmake_minimum_required(VERSION	2.8.3)
 # CMake至少为2.8.3版
project(turtlesim)
  # 项目(package)名称为turtlesim,在后续文件中可使用变量${PROJECT_NAME}来引用项目名称turltesim

# 这两个是 通过ros 指令 创建包  中就自动生成好的
find_package(catkin	REQUIRED	COMPONENTS	
   geometry_msgs	
   message_generation	
   rosconsole	
   roscpp	
   roscpp_serialization	
   roslib	
   rostime	
   std_msgs	
   std_srvs) 
#cmake宏,指定依赖的其他pacakge,实际是生成了一些环境变量,如<NAME>_FOUND,	<NAME>_INCLUDE_DIRS ,	<NAME>_LIBRARYIS #此处catkin是必备依赖	其余的geometry_msgs...为组件
include_directories(include	${catkin_INCLUDE_DIRS}	${Boost_INCLUDE_DIRS}) 
#指定C++的头文件路径
link_directories(${catkin_LIBRARY_DIRS}) 
#指定链接库的路径
add_message_files(DIRECTORY	msg	FILES Color.msg	Pose.msg) #自定义msg文件
add_service_files(DIRECTORY	srv	FILES Kill.srv SetPen.srv Spawn.srv TeleportAbsolute.srv TeleportRelative.srv) #自定义srv文件
generate_messages(DEPENDENCIES	geometry_msgs	std_msgs	std_srvs)
#在add_message_files、add_service_files宏之后必须加上这句话,用于生成srv msg头文件,生 成的文件位于devel/include中
catkin_package(CATKIN_DEPENDS	geometry_msgs	message_runtime	std_msgs	std_srvs) 
#	catkin宏命令,用于配置ROS的package配置文件和CMake文件 
#	这个命令必须在add_library()或者add_executable()之前调用,该函数有5个可选参数: 
#	(1)	INCLUDE_DIRS	-	导出包的include路径 
#	(2)	LIBRARIES	-	导出项目中的库 
#	(3)	CATKIN_DEPENDS	-	该项目依赖的其他catkin项目 
#	(4)	DEPENDS	-	该项目所依赖的非catkin	CMake项目。 
#	(5)	CFG_EXTRAS	-	其他配置选
set(turtlesim_node_SRCS src/turtlesim.cpp src/turtle.cpp src/turtle_frame.cpp) 
set(turtlesim_node_HDRS include/turtlesim/turtle_frame.h ) 
#指定turtlesim_node_SRCS、turtlesim_node_HDRS变量
qt5_wrap_cpp(turtlesim_node_MOCS	${turtlesim_node_HDRS})
add_executable(turtlesim_node	${turtlesim_node_SRCS}	${turtlesim_node_MOCS}) #	指定可执行文件目标turtlesim_node 
target_link_libraries(turtlesim_node	Qt5::Widgets	${catkin_LIBRARIES}	${Boost_LIBRARIE S}) #	指定链接可执行文件

add_dependencies(turtlesim_node	turtlesim_gencpp)
add_executable(turtle_teleop_key	tutorials/teleop_turtle_key.cpp) target_link_libraries(turtle_teleop_key	${catkin_LIBRARIES}) add_dependencies(turtle_teleop_key	turtlesim_gencpp)
add_executable(draw_square	tutorials/draw_square.cpp) target_link_libraries(draw_square	${catkin_LIBRARIES}	${Boost_LIBRARIES}) add_dependencies(draw_square	turtlesim_gencpp)
add_executable(mimic	tutorials/mimic.cpp) target_link_libraries(mimic	${catkin_LIBRARIES}) add_dependencies(mimic	turtlesim_gencpp) 
#	同样指定可执行目标、链接、依赖

install(TARGETS	turtlesim_node	turtle_teleop_key	draw_square	mimic RUNTIME	DESTINATION	${CATKIN_PACKAGE_BIN_DESTINATION}) #	安装目标文件到本地系统
install(DIRECTORY	images DESTINATION	${CATKIN_PACKAGE_SHARE_DESTINATION} FILES_MATCHING	PATTERN	"*.png"	PATTERN	"*.svg")

ROS2中CMakeLists.txt架构如下

cmake_minimum_required()			#CMake的最低版本号

project()				  		   #项目名称

find_package()   				    #查找系统中的依赖项

ament_target_dependencies()          #依赖于其他目标文件,确保其他目标已被构建 

add_executable()				    #生成可执行二进制文件

install()						   #生成可安装目标

ament_package()						#生成功能包

rosidl_generate_interfaces()		# 自定义消息类型接口
cmake_minimum_required(VERSION 3.5)
project(test_c)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

add_executable(talker src/publisher_member_function.cpp)	# 修改2
ament_target_dependencies(talker rclcpp std_msgs)			# 修改3

install(TARGETS
  talker												# 修改4
  DESTINATION lib/${PROJECT_NAME})

install(DIRECTORY include/
  DESTINATION include/
)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 添加自定义消息类型需要添加项
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Num.msg"				# 自定义1
  "msg/Sphere.msg"			# 自定义2
  "srv/AddThreeInts.srv"     # 自定义3
  DEPENDENCIES geometry_msgs
)

ament_package()

2 ROS1 && ROS2 package.xml

ROS1

<?xml version="1.0"?>    <!--本示例为老版本的pacakge.xml-->
<package>                <!--pacakge为根标签,写在最外面-->
  <name>turtlesim</name>
  <version>0.8.1</version>
  <description>
 	turtlesim is a tool made for teaching ROS and ROS packages.
  </description>
  <maintainer email="[email protected]">Dirk Thomas</maintainer>
  <license>BSD</license>
  
  <url type="website">http://www.ros.org/wiki/turtlesim</url>
  <url type="bugtracker">https://github.com/ros/ros_tutorials/issues</url>
  <url type="repository">https://github.com/ros/ros_tutorials</url>
  <author>Josh Faust</author>

  <!--编译工具为catkin-->
  <buildtool_depend>catkin</buildtool_depend>
  
  <!--编译时需要依赖以下包-->
  <build_depend>geometry_msgs</build_depend>
  <build_depend>qtbase5-dev</build_depend>
  <build_depend>message_generation</build_depend>
  <build_depend>qt5-qmake</build_depend>
  <build_depend>rosconsole</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>roscpp_serialization</build_depend>
  <build_depend>roslib</build_depend>
  <build_depend>rostime</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>std_srvs</build_depend>
  
  <!--运行时需要依赖以下包-->
  <run_depend>geometry_msgs</run_depend>
  <run_depend>libqt5-core</run_depend>
  <run_depend>libqt5-gui</run_depend>
  <run_depend>message_runtime</run_depend>
  <run_depend>rosconsole</run_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>roscpp_serialization</run_depend>
  <run_depend>roslib</run_depend>
  <run_depend>rostime</run_depend>
  <run_depend>std_msgs</run_depend>
  <run_depend>std_srvs</run_depend>
</package>

ROS2:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>service</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="[email protected]">bigdavid</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>example_interfaces</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

● buildtool_depend:使用ament_cmake替换catkin
● build_depend:使用rclcpp替换roscpp
● build_type:声明编译类型
● 也可以使用depend来指定编译和运行时依赖

3 ROS1 && ROS2 Launch文件

ROS1用xml编写Launch文件
ROS2用python编写Launch文件
ROS2示例:

import os
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare

# 定义函数名称为:generate_launch_description
def generate_launch_description():
    package_name = 'fishbot_description'
    urdf_name = "fishbot_base.urdf"

    ld = LaunchDescription()
    pkg_share = FindPackageShare(package=package_name).find(package_name) 
    urdf_model_path = os.path.join(pkg_share, f'urdf/{urdf_name}')

    robot_state_publisher_node = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        arguments=[urdf_model_path]
        )

    joint_state_publisher_node = Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        name='joint_state_publisher_gui',
        arguments=[urdf_model_path]
        )

    rviz2_node = Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        )

    ld.add_action(robot_state_publisher_node)
    ld.add_action(joint_state_publisher_node)
    ld.add_action(rviz2_node)

    return ld

ROS1示例:

<launch>
  <!--<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>-->
  <arg name="model" default="waffle" doc="model type [burger, waffle, waffle_pi]"/>
  <arg name="x_pos" default="0.0"/>
  <arg name="y_pos" default="0.0"/>
  <arg name="z_pos" default="0.0"/>

  <include file="$(find gazebo_ros)/launch/empty_world.launch">
    <arg name="world_name" value="$(find turtlebot3_gazebo)/worlds/empty.world"/>
    <arg name="paused" value="false"/>
    <arg name="use_sim_time" value="true"/>
    <arg name="gui" value="true"/>
    <arg name="headless" value="false"/>
    <arg name="debug" value="false"/>
  </include>

  <include file="$(find turtlebot3_bringup)/launch/turtlebot3_remote.launch">
    <arg name="model" value="$(arg model)"/>
  </include>

  <node name="rviz" pkg="rviz" type="rviz" args="-d $(find turtlebot3_gazebo)/rviz/turtlebot3_gazebo_model.rviz"/>

  <node pkg="mpc_similar_controller" type="mpc_similar_controller_ros" name="mpc_similar_controller_ros" respawn="false" output="screen" />

  <param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />

  <node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>

4 ROS1 && ROS2 头文件修改

// ros1
#include "ros/ros.h"
#include "ros/time.h"
#include "std_msgs/Bool.h"
#include "std_msgs/String.h"
#include "std_msgs/Float32.h"
#include "std_msgs/Float32MultiArray.h"
#include "std_msgs/Float64MultiArray.h"

// ros2
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/time.hpp"
#include "std_msgs/msg/bool.hpp"
#include "std_msgs/msg/string.hpp"
#include "std_msgs/msg/float32.hpp"
#include "std_msgs/msg/float32_multi_array.hpp"
#include "std_msgs/msg/float64_multi_array.hpp"
#include "std_msgs/msg/header.hpp"

5 ROS1 && ROS2 发布者和订阅者

发布器和订阅器声明和定义

// ros::Subscriber sub_demo;
rclcpp::Subscription<demo::msg>::SharedPtr sub_demo;

// ros::Publisher pub_demo;
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<demo::msg>> pub_demo;	// LCN
// ros1 subscriber: ros::NodeHandle handler;
sub_demo = handler.subscribe("/demo_topic", 1, &SubCallback_Demo, this);
// ros2 subscriber: 
sub_demo = this->create_subscription<demo::msg>(
    "/demo_topic",
    10,
    std::bind(&LifecyclePredict::SubCallback_Demo, this, _1)
);

// ros1 publisher: ros::NodeHandle handler;
pub_demo = handler.advertise<demo::msg>("demo_topic", 1);
// ros2 publisher: 
pub_demo = this->create_publisher<demo::msg>("/demo_topic", 1);

6 ROS1 && ROS2 代码修改——主程序

// 初始化设置
// ros1:
ros::init(argc, argv, "demo_node_name");

// ros2:
rclcpp::init(argc, argv);

// 创建节点
// ros1:
ros::NodeHandle node_handler("your_namespace");
ros::NodeHandle node_handler;

// ros2: 创建节点时是有区别的
std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("demo_node_name");

// 帧率设置
// ros1:
ros::Rate loop_rate(10)

// ros2:
rclcpp::Rate loop_rate(10);

// 节点运行
// ros1:	  				
ros::spin();              
ros::spinOnce();	      
ros::shutdown();    	 
// ros2:
rclcpp::spin(node);		//std::shared_ptr<rclcpp::Node> node
rclcpp::spinOnce(node);	//std::shared_ptr<rclcpp::Node> node
rclcpp::shutdown();

// 时间
// ros1:
#include "ros/time.h"
ros::Time timestamp = ros::Time::now();
double seconds = ros::Time::now().toSec();
double nanoSec = ros::Time::now().toNSec();

// ros2:
#include "rclcpp/time.hpp"
rclcpp::Time timestamp = np->now();
std::shared_ptr<rclcpp::Node> np = rclcpp::Node::make_shared("demo_node_name");

double seconds = rclcpp::Clock().now().seconds();
double nanoSec = rclcpp::Clock().now().nanoseconds();

// ros1:
while (ros::ok())
// ros2
while (rclcpp::ok())

相对于ros1中处理数据的时间戳的运算,ros2需要添加
#include <builtin_interfaces/msg/time.hpp>

7 ROS1 && ROS2 类的使用

ros1中新建的句柄是作为构造函数参数传入类进行使用,而ros2直接继承自rclcpp::Node,在使用node时直接使用this即可

// ros1:
class DemoNode {
public:
	Ros::NodeHandle handler;
	DemoNode(const ros::NodeHandle& node_handler) : nh(node_handler) {};
};

// ros2:
class DemoNode : public rclcpp::Node {
public:
	std::shared_ptr<rclcpp::Node> node = nullptr;
	explicit DemoNode() : node{"demo_node_name"} {};
};

8 ROS1移植到ROS2的一些示例

(1)【四足】ROS1到ROS2的C++代码迁移教程
(2)ROS1 升级到 ROS2 的一个小例子
(3)ROS1到ROS2迁移教程(以rslidar_to_velodyne功能包为例)+ ROS2版本LIO-SAM试跑

思路:
(1)根据功能包package.xml文件确定所需要的依赖,并根据该依赖创建新的ROS2功能包
(2)创建CPP文件并修改对应的CmakeList文件配置
(3)修改CPP文件内容,将ROS1的API转化为ROS2
● 第一步修改头文件
● 第二步修改变量定义(订阅消息、发布消息、消息类型)
● 第三步修改API(ROS2没有句柄):订阅者,发布者,日志函数等

(4)ROS1迁移ROS2经验总结(针对点云神经网络)
ROS2在构建自定义msg时,.msg文件的首字母必须要大写,如要写ObjectDetect.msg

#include<custom_msgs/msg/DetectedObjectArray.h>
#include<visualization_msgs/msg/marker_array.h>
// ros2生成自定义msg头文件与ros1不同,尝试改成下面的 成了
#include <custom_msgs/msg/detected_object.hpp>
#include <custom_msgs/msg/detected_object_array.hpp>

尤为注意,在ROS2中最好不要这么写

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

最好使用 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)【ros/ros2】ros1迁移到ros2的修改记录

● 2.1 CMakeLists.txt
● 2.2 packge.xml
● 2.3 launch文件
● 2.4 代码修改:头文件
● 2.5 代码修改:subscriber/publisher
● 2.6 代码修改:主程序
● 2.7 代码修改:类的使用
● 2.8 代码修改:生命周期节点

(6)Navigation:从ROS到ROS2的变化
移植的软件包:

● amcl: 移植到nav2_amcl
● map_server: 移植到nav2_map_server
● nav2_planner: 取代global_planner,托管 N 规划器插件
● Nav2_controller: 替换local_planner,托管 N 控制器插件
● Navfn: 移植到nav2_navfn_planner
● DWB: 替换DWA,并在nav2_dwb_controller元包下移植到ROS 2
● nav_core: 移植为nav2_core,更新接口
● costmap_2d: 移植为nav2_costmap_2d
新的软件包:
● nav2_bt_navigator: 替换 move_base 状态机
● Nav2_lifeycle_manager: 处理服务器程序生命周期
● nav2_waypoint_follower: 可以通过采取许多航点来执行一个复杂的任务
● nav2_system_tests: 一套用于CI的集成测试和模拟的基本教程
● nav2_rviz_plugins: 用于控制Navigation2服务器、命令、取消和导航的rviz插件
● nav2_experimental: 深度强化学习控制器的实验性(和不完整)工作
● navigation2_behavior_trees: 行为树库的包装器,用于调用ROS动作服务器

9 ROS2说明文档看ROS1迁移到ROS2

ROS 2 Documentation: Humble

  • 迁移包
<package format="2">
  // ros1
  <build_depend>foo</build_depend>
  <build_export_depend>foo</build_export_depend>
  <exec_depend>foo</exec_depend>
  // ros2
  <depend>foo</depend>
  // ros1
  <build_depend>testfoo</build_depend>
  // ros2
  <test_depend>testfoo</test_depend>
  <doc_depend>doxygen</doc_depend>
  <doc_depend>python3-sphinx</doc_depend>
  • 迁移接口
    ROS2中,消息(msg)、服务(srv)、动作(action)统称为接口

在ROS 1中作为内置类型的 duration 和 time 类型已被替换为普通消息定义,必须从builtin_interfaces包中使用

将接口包迁移到ROS2

# ROS1移植到ROS2需要添加的部分
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<depend>message_package</depend> # 对于每个依赖的消息包,添加
  • 迁移C++包
    更新 CMakeLists.txt 使用 ament_cmake
    在package.xml文件的导出部分中设置构建类型
<export>
  <build_type>ament_cmake</build_type>
</export>

# find_package调用替换为catkin
find_package(ament_cmake REQUIRED)
find_package(component1 REQUIRED)
# ...
find_package(componentN REQUIRED)
# 将add_message_files、add_service_files和generate_messages的调用替换为rosidl_generate_interfaces
rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  DEPENDENCIES std_msgs
)

ROS 2的消息、服务和动作的命名空间在包名后使用子命名空间(msg,srv,action)
#include <my_interfaces/msg/my_message.hpp>
C++类型的命名为:my_interfaces::msg::MyMessage
共享指针类型在消息结构体中作为typedef提供:
my_interfaces::msg::MyMessage::SharedPtr
my_interfaces::msg::MyMessage::ConstSharedPtr

总结:
● 在包名称和消息数据类型之间插入子文件夹msg/srv/action
● 将包含的文件名从驼峰式更改为下划线分隔
● 将*.h改为*.hpp

消息、服务和动作

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// # include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/msg/point_stamped.hpp>

// geometry_msgs::PointStamped point_stamped;
geometry_msgs::msg::PointStamped point_stamped;

使用服务对象

ROS 2中的服务回调函数不具有布尔返回值。建议在失败时抛出异常,而不是返回false

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// #include "nav_msgs/GetMap.h"
#include "nav_msgs/srv/get_map.hpp"

// bool service_callback(
//   nav_msgs::GetMap::Request & request,
//   nav_msgs::GetMap::Response & response)
void service_callback(
  const std::shared_ptr<nav_msgs::srv::GetMap::Request> request,
  std::shared_ptr<nav_msgs::srv::GetMap::Response> response)
{
  // ...
  // return true;  // or false for failure
}

ros::Time用法
rclcpp::Time替换ros::Time
(1)将所有的std_msgs::Time实例转换为builtin_interfaces::msg::Time
(2)将所有的#include "std_msgs/time.h"转换为#include “builtin_interfaces/msg/time.hpp”
(3)将所有使用std_msgs::Time字段nsec的实例转换为builtin_interfaces::msg::Time字段nanosec

ros::Rate用法
rclcpp::Rate替换ros::Rate
Boost
希望尽可能利用新的核心功能,并避免对 Boost 的依赖。
共享指针
将共享指针从 boost 转换为标准 C++
#include <boost/shared_ptr.hpp> 替换为 #include <memory>
boost::shared_ptr 替换为 std::shared_ptr
建议使用 using 而不是 typedef。using 在模板逻辑中能够更好地发挥作用

线程 / 互斥锁

boost::thread中得互斥锁是一个常见的boost部分
将boost::mutex::scoped_lock替换为std::unique_lockstd::mutex
将boost::mutex替换为std::mutex
#include <boost/thread/mutex.hpp>替换为#include <mutex>

无序映射

#include <boost/unordered_map.hpp>替换为#include <unordered_map>
boost::unordered_map替换为std::unordered_map

函数

#include <boost/function.hpp>替换为#include <functional>
boost::function替换为std::function

迁移到ROS2:
第一步:更改头文件

//#include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"
//#include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"

第二步:更改C++库调用

//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
rclcpp::init(argc, argv);
auto node = rclcpp::Node::make_shared("talker");

//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter",
1000);
rclcpp::Rate loop_rate(10);

//  std_msgs::String msg;
std_msgs::msg::String msg;

//  while (ros::ok())
while (rclcpp::ok())
msg.data = ss.str();

//    ROS_INFO("%s", msg.data.c_str());
RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());

chatter_pub->publish(msg);

//    ros::spinOnce();
rclcpp::spin_some(node);

demo:

#include <sstream>
// #include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"
// #include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"
int main(int argc, char **argv)
{
//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("talker");
//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
  auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter", 1000);
  rclcpp::Rate loop_rate(10);
  int count = 0;
//  std_msgs::String msg;
  std_msgs::msg::String msg;
//  while (ros::ok())
  while (rclcpp::ok())
  {
    std::stringstream ss;
    ss << "hello world " << count++;
    msg.data = ss.str();
//    ROS_INFO("%s", msg.data.c_str());
    RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());
    chatter_pub->publish(msg);
//    ros::spinOnce();
    rclcpp::spin_some(node);
    loop_rate.sleep();
  }
  return 0;
}

修改package.xml

<!-- <package> -->
<package format="2">
  <name>talker</name>
  <version>0.0.0</version>
  <description>talker</description>
  <maintainer email="[email protected]">Brian Gerkey</maintainer>
  <license>Apache License 2.0</license>
<!--  <buildtool_depend>catkin</buildtool_depend> -->
  <buildtool_depend>ament_cmake</buildtool_depend>
<!--  <build_depend>roscpp</build_depend> -->
<!--  <run_depend>roscpp</run_depend> -->
<!--  <run_depend>std_msgs</run_depend> -->
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

修改CMakeLists.txt

#cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)
project(talker)
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 17)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()
#find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
#catkin_package()
#include_directories(${catkin_INCLUDE_DIRS})
include_directories(include)
add_executable(talker talker.cpp)
#target_link_libraries(talker ${catkin_LIBRARIES})
ament_target_dependencies(talker
  rclcpp
  std_msgs)
#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talker
  DESTINATION lib/${PROJECT_NAME})
install(DIRECTORY include/
  DESTINATION include)
ament_export_include_directories(include)
ament_export_dependencies(std_msgs)
ament_package()

以上系统梳理了ROS1移植到ROS2的一些常见处理

;