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);
});
● 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
- 迁移包
<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的一些常见处理