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)			# 修改3install(TARGETStalker												# 修改4DESTINATION 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"     # 自定义3DEPENDENCIES 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="dthomas@osrfoundation.org">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="bigdavid@todo.todo">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="gerkey@osrfoundation.org">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(talkerrclcppstd_msgs)
#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talkerDESTINATION lib/${PROJECT_NAME})
install(DIRECTORY include/DESTINATION include)
ament_export_include_directories(include)
ament_export_dependencies(std_msgs)
ament_package()

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/46535.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【HarmonyOS】鸿蒙中如何获取用户相册图片?photoAccessHelper.PhotoViewPicker

【HarmonyOS】鸿蒙中如何获取用户相册图片&#xff1f;photoAccessHelper.PhotoViewPicker 前言 有同学私聊我说&#xff0c;之前的博客文章提到的没有HarmonyOS白名单帐号&#xff0c;如何在OpenHarmony Gitee开发仓里学习API接口。需要注意一个点&#xff0c;默认看到的文档…

图、图的遍历、最小生成树、最短路径

0、图的概念 **图:**是由顶点集合及顶点间的关系组成的一种数据结构&#xff1a;G (V&#xff0c; E)&#xff0c;其中&#xff1a; 顶点集合V {x|x属于某个数据对象集}是有穷非空集合&#xff1b;边的集合E {(x,y)|x,y属于V}或者E {|x,y属于V && Path(x, y)}是顶…

浅学三次握手

数据要完成传输&#xff0c;必须要建立连接。由于建立TCP连接的过程需要来回3次&#xff0c;所以&#xff0c;将这个过程形象的叫做三次握手。 结合上面的图来看更清楚。 先说三次握手吧&#xff0c;连接是后续数据传输的基础。就像我们打电话一样&#xff0c;必须保证我和对方…

在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位一、数据实时监控的重要性二、PostgreSQ…

shell,重定向与管道符号

文章目录 一&#xff0c;什么是shell二&#xff0c;shell脚本和作用1. shell脚本2. 作用 三&#xff0c;shell脚本的构成内容四&#xff0c;创建和运行Shell脚本五&#xff0c;重定向与管道操作1. 交互式硬件设备2. 重定向操作概览表3. 管道操作 一&#xff0c;什么是shell sh…

Matlab 判断直线上一点

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 判断一个点是否位于一直线上有很多方法,这里使用一种很有趣的坐标:Plucker线坐标,它的定义如下所示: 这个坐标有个很有趣的性质,我们可以使用Plucker坐标矢量构建一个Plucker矩阵: 则它与位于对应线上的齐次点…

排序(三)——归并排序(MergeSort)

欢迎来到繁星的CSDN&#xff0c;本期内容主要包括归并排序(MergeSort)的实现 一、归并排序的主要思路 归并排序和上一期讲的快速排序很像&#xff0c;都利用了分治的思想&#xff0c;将一整个数组拆成一个个小数组&#xff0c;排序完毕后进行再排序&#xff0c;直到整个数组排序…

文章管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;作者管理&#xff0c;文章管理&#xff0c;文章分类管理&#xff0c;论坛&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;文章&#xff0c;论坛&#xff0c;我的 开发系统…

代码随想录算法训练营第五十四天|99.岛屿数量 深搜、广搜、100.岛屿的最大面积

99.岛屿数量 题目链接&#xff1a;99.岛屿数量 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 深搜 思路&#xff1a; 遍历网格&#xff0c;发现岛屿&#xff1a;我们需要遍历整个二维网格&#xff0c;检查每一个位置上的元素。如果在遍历过程中遇到陆地&#xff08;…

计网(1.1~1.4)

1.1计算机网络在信息时代的作用 21世纪的重要特征数字化、网络化和信息化 有三类网络&#xff1a;电信网络、有线电视网络和计算机网络 互联网两个重要基本特点&#xff0c;即连通性和共享 1.2因特网概述 &#xff08;1&#xff09;网络、互联网和互连网 网络:由若干结点和连接…

企业全历史行为数据 让你对竞争对手的一切清清楚楚

关于商业竞争&#xff0c;在刚进入信息时代的那些年&#xff0c;人们说“现代商战就是信息战”&#xff0c;强调用非对称的或者更快获得的信息来赢得竞争&#xff1b;近些年进入大数据时代&#xff0c;人们又说“得数据者得天下”&#xff0c;发现“数据算法”有很多妙用&#…

2024 Q1:AVP时代下全球XR头显市场动态与展望

随着苹果Vision Pro&#xff08;AVP&#xff09;的发布&#xff0c;空间计算时代正式拉开序幕&#xff0c;全球扩展现实&#xff08;XR&#xff09;产业迎来新的发展机遇与挑战。尽管苹果的加入激发了市场活力&#xff0c;但2024年第一季度的XR头显市场却呈现出复杂多变的格局&…

压缩视频的最佳方法,视频压縮大小不影响画质

在数字媒体时代&#xff0c;视频已成为我们记录生活和传递信息的重要方式。但随着视频分辨率的提升和拍摄时长的增加&#xff0c;视频文件的大小也随之“膨胀”。大视频文件不仅占用大量存储空间&#xff0c;还在分享和传输过程中造成不便。如何在保证画质的前提下&#xff0c;…

《基于 LatentFactor + Redis + ES 实现动态药房分配方法》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;欢迎多多交流。&am…

LabVIEW液压数据采集测试系统

液压系统是装载机的重要组成部分&#xff0c;通过液压传动和控制实现各项作业功能&#xff0c;如提升、倾斜、转向等。液压系统的性能直接影响装载机的作业效率和稳定性。为了保证装载机液压系统的正常运行和优化设计&#xff0c;需要对其进行数据采集和测试。本文介绍了一套基…

昇思20天

K近邻算法实现红酒聚类 1. K近邻算法&#xff08;KNN&#xff09; 基本概念&#xff1a;用于分类和回归的非参数统计方法 K近邻算法&#xff08;K-Nearest-Neighbor, KNN&#xff09;是一种用于分类和回归的非参数统计方法&#xff0c;最初由 Cover和Hart于1968年提出(Cover等…

vue学习day09-自定义指令、插槽

29、自定义指令 &#xff08;1&#xff09;概念&#xff1a;自己定义的指令&#xff0c;可以封装一些dom操作&#xff0c;扩展额外的功能。 &#xff08;2&#xff09;分类&#xff1a; 1&#xff09;全局注册 2&#xff09;局部注册 3&#xff09;示例&#xff1a; 让表…

gorm多表联合查询 Joins方法 LEFT JOIN , RIGHT JOIN , INNER JOIN, FULL JOIN 使用总结

gorm中多表联合查询&#xff0c;我们可以使用Joins来完成&#xff0c;这个Joins方法很灵活&#xff0c;我们可以非常方便的多多表进行联合查询&#xff0c; 我们先来看看这个方法的官方定义和使用示例&#xff1a; Joins方法定义和使用示例 当然我们这里要说的使用方式是官方示…

CUDA编程 - clock 学习记录

clock 学习记录 一、完整代码二、核函数流程三、main 函数流程四、学习总结&#xff08;共享内存的声明和使用&#xff09;&#xff1a;4.1、例子4.2、数据从全局内存复制到共享内存&#xff1a; 该程序利用CUDA并行计算能力&#xff0c;执行归约操作以找到每个块内的最小值&am…

C# - 异步编程和同步编程总结

在Windows Forms或WPF等桌面应用中&#xff0c;Invoke 和 BeginInvoke 是用来在创建控件的UI线程上安全地执行代码的关键方法&#xff0c;主要是为了处理多线程环境下的UI交互。 Invoke: 它是一个同步操作。当你调用 Invoke 时&#xff0c;当前线程会被阻塞&#xff0c;直到UI线…