创建工作空间:ROS 2 的工作空间是一个目录结构,用于组织和管理你的代码。工作空间通常包含以下目录:
src
:存放源代码。
build
:存放编译生成的中间文件。
install
:存放编译后的可执行文件和库。
log
:存放编译和运行的日志文件。创建包:使用
ros2 pkg create
命令创建一个新的 ROS 2 包。包是 ROS 2 中的基本单元,包含代码、配置文件和依赖项。
1.创建一个新的工作空间目录:
mkdir -p ~/topic_ws/src
cd ~/topic_ws/src
2.使用 ros2 pkg create
创建一个新的 ROS 2 包:
ros2 pkg create --build-type ament_cmake demo_cpp_topic
这会生成一个名为 demo_cpp_topic
的包,包含 package.xml
和 CMakeLists.txt
文件。
ros2 pkg create status_interfaces --dependencies builtin_interfaces rosidl_default_genterators --license Apache-2.0
3. 编写 C++ 代码
1.进入包的目录:
cd demo_cpp_topic
2.创建 src
目录(如果不存在):
mkdir src
3.在 src
目录下创建 turtle_circle.cpp
文件,并编写代码:
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
using namespace std::chrono_literals;
class TurtleCircleNode : public rclcpp::Node
{
public:
TurtleCircleNode() : Node("turtle_circle")
{
publisher_ = this->create_publisher("/turtle1/cmd_vel", 10);
timer_ = this->create_wall_timer(1000ms, std::bind(&TurtleCircleNode::timer_callback, this));
}
private:
void timer_callback()
{
auto msg = geometry_msgs::msg::Twist();
msg.linear.x = 1.0;
msg.angular.z = 0.5;
publisher_->publish(msg);
}
rclcpp::Publisher::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared());
rclcpp::shutdown();
return 0;
}
4. 配置 CMakeLists.txt
定义编译规则:
CMakeLists.txt
文件告诉colcon
如何编译你的代码。它指定了:
可执行文件的名称(如
turtle_circle
)。需要编译的源文件(如
src/turtle_circle.cpp
)。依赖的库(如
rclcpp
和geometry_msgs
)。
1.打开 CMakeLists.txt
文件,添加以下内容以编译 turtle_circle.cpp
:
# 添加可执行文件
add_executable(turtle_circle src/turtle_circle.cpp)
# 链接依赖库
ament_target_dependencies(turtle_circle rclcpp geometry_msgs)
# 安装可执行文件
install(TARGETS
turtle_circle
DESTINATION lib/${PROJECT_NAME})
5. 配置 package.xml
定义包元数据:
package.xml
文件包含了包的元数据,如名称、版本、描述、作者和许可证。声明依赖项:
package.xml
文件还声明了包所依赖的其他 ROS 2 包(如rclcpp
和geometry_msgs
)。这些依赖项会在编译和运行时被自动加载。
1.打开 package.xml
文件,确保以下依赖项已添加:
rclcpp
geometry_msgs
6. 编译工作空间
定义包元数据:
package.xml
文件包含了包的元数据,如名称、版本、描述、作者和许可证。声明依赖项:
package.xml
文件还声明了包所依赖的其他 ROS 2 包(如rclcpp
和geometry_msgs
)。这些依赖项会在编译和运行时被自动加载。
1.返回工作空间根目录:
cd ~/topic_ws
2.使用 colcon build
编译工作空间:
colcon build
如果只想编译 demo_cpp_topic
包,可以使用:
colcon build --packages-select demo_cpp_topic
3.编译完成后,加载工作空间环境:
source install/setup.bash
7. 运行节点
1.启动 turtlesim
仿真器:
ros2 run turtlesim turtlesim_node
2.运行你的节点:
ros2 run demo_cpp_topic turtle_circle
我们来分析一下这段完整的代码
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
using namespace std::chrono_literals;
class TurtleCircleNode : public rclcpp::Node
{
private:
rclcpp::Publisher::SharedPtr publisher_; // 发布者
rclcpp::TimerBase::SharedPtr timer_; // 定时器
public:
explicit TurtleCircleNode(const std::string& node_name) : Node(node_name) // 使用传入的节点名称
{
// 创建发布者,发布到 /turtle1/cmd_vel 话题
publisher_ = this->create_publisher("/turtle1/cmd_vel", 10);
// 创建定时器,每隔 1000ms 调用一次 timer_callback
timer_ = this->create_wall_timer(1000ms, std::bind(&TurtleCircleNode::timer_callback, this));
}
void timer_callback()
{
auto msg = geometry_msgs::msg::Twist(); // 创建 Twist 消息
msg.linear.x = 1.0; // 设置线速度
msg.angular.z = 0.5; // 设置角速度
publisher_->publish(msg); // 发布消息
}
};
int main(int argc, char* argv[])
{
rclcpp::init(argc, argv); // 初始化 ROS 2
auto node = std::make_shared("turtle_circle"); // 创建节点
rclcpp::spin(node); // 进入事件循环
rclcpp::shutdown(); // 关闭 ROS 2
return 0;
}
1. 头文件引入
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
rclcpp/rclcpp.hpp
:ROS 2 的 C++ 客户端库,提供了创建节点、发布者、订阅者等功能的 API。
geometry_msgs/msg/twist.hpp
:ROS 2 中的标准消息类型,用于表示速度(线速度和角速度)。
2. 命名空间
using namespace std::chrono_literals;
std::chrono_literals
:C++ 的时间字面量库,方便表示时间单位(如 1000ms
表示 1000 毫秒)。
class TurtleCircleNode : public rclcpp::Node
{
private:
rclcpp::Publisher::SharedPtr publisher_; // 发布者
rclcpp::TimerBase::SharedPtr timer_; // 定时器
TurtleCircleNode
:自定义的 ROS 2 节点类,继承自 rclcpp::Node
。
publisher_
:用于发布 geometry_msgs::msg::Twist
消息的发布者。
timer_
:定时器,用于定期触发回调函数。
public:
explicit TurtleCircleNode(const std::string& node_name) : Node(node_name)
{
// 创建发布者,发布到 /turtle1/cmd_vel 话题
publisher_ = this->create_publisher("/turtle1/cmd_vel", 10);
// 创建定时器,每隔 1000ms 调用一次 timer_callback
timer_ = this->create_wall_timer(1000ms, std::bind(&TurtleCircleNode::timer_callback, this));
}
Node(node_name)
:调用基类构造函数,初始化节点,节点名称为传入的 node_name
。
create_publisher
:创建一个发布者,发布到 /turtle1/cmd_vel
话题,消息类型为 geometry_msgs::msg::Twist
,队列长度为 10。
create_wall_timer
:创建一个定时器,每隔 1000 毫秒(1 秒)调用一次 timer_callback
函数。
void timer_callback()
{
auto msg = geometry_msgs::msg::Twist(); // 创建 Twist 消息
msg.linear.x = 1.0; // 设置线速度
msg.angular.z = 0.5; // 设置角速度
publisher_->publish(msg); // 发布消息
}
geometry_msgs::msg::Twist()
:创建一个 Twist
消息对象。
msg.linear.x
:设置线速度(x
方向的速度,单位为 m/s)。
msg.angular.z
:设置角速度(绕 z
轴的旋转速度,单位为 rad/s)。
publisher_->publish(msg)
:将消息发布到 /turtle1/cmd_vel
话题,控制海龟运动。
int main(int argc, char* argv[])
{
rclcpp::init(argc, argv); // 初始化 ROS 2
auto node = std::make_shared("turtle_circle"); // 创建节点
rclcpp::spin(node); // 进入事件循环
rclcpp::shutdown(); // 关闭 ROS 2
return 0;
}
rclcpp::init(argc, argv)
:初始化 ROS 2,解析命令行参数。
std::make_shared
:创建 TurtleCircleNode
节点对象,节点名称为 "turtle_circle"
。
rclcpp::spin(node)
:进入事件循环,等待回调函数被触发(如定时器回调)。
rclcpp::shutdown()
:关闭 ROS 2,释放资源。
节点启动后,定时器每隔 1 秒触发一次 timer_callback
。
在 timer_callback
中,创建一个 Twist
消息,设置线速度和角速度。
将消息发布到 /turtle1/cmd_vel
话题,控制海龟运动。
由于线速度和角速度是固定的,海龟会以固定的半径和速度画圆。
CMakeLists.txt
package.xml