系列文章目录
留空
前言
自用
一、创建工作空间和功能包
1、工作空间
(1)Ctrl+Win+T
开启终端
(2)创建一个叫towm_ws
的工作空间
mkdir -p towm_ws
(3)进入工作空间
cd towm_ws
(4)在工作空间中创建一个文件夹src
存放功能包
mkdir -p src
(5)编译工作空间
colcon build
在执行colcon build之前,通常需要先进入工作空间并创建一个空的src文件夹。colcon build命令会自动生成install、build、log文件夹。
2、功能包
(1)进入src
文件夹
cd src
(2)创建一个基于C++
的learning_node
功能包
ros2 pkg create learning_node --build-type ament_cmake --dependencies rclcpp
(3)在Vscode
中打开src
打开后可以看见刚刚创建的功能包
二、使用RCLCPP编写节点
1、创建节点
在vscode中,learning_node
-> 新建文件
-> wang2_node.cpp
2、编写代码
(1)完整代码
#include "rclcpp/rclcpp.hpp"
class LearningNode : public rclcpp::Node
{
public:
LearningNode(std::string name) : Node(name)
{
RCLCPP_INFO(this->get_logger(),"节点%s已启动",name.c_str());
}
private:
};
int main(int argc,char** argv)
{
rclcpp::init(argc,argv);
auto node = std::make_shared<LearningNode>("wang2");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
(2)每次编写完代码记得修改CmakeLists.txt
,添加以下代码
add_executable(wang2_node src/wang2.cpp)
ament_target_dependencies(wang2_node rclcpp)
install(TARGETS
wang2_node
DESTINATION lib/${PROJECT_NAME}
)
三、分析代码
1、主函数:程序的入口
编写主函数的步骤:
(1)初始化rclcpp
(2)产生一个节点
(3)运行节点
(4)停止运行
(5)return 0
int main(int argc,char** argv)
{
rclcpp::init(argc,argv);
auto node = std::make_shared<LearningNode>("wang2");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
(1)初始化ROS2客户端库。这是创建ROS2节点之前必须做的第一步
rclcpp::init(argc,argv);
可以看看这篇文章:理解argc和argv是什么
(2)创建一个叫“wang2”的节点
auto node = std::make_shared<LearningNode>("wang2");
std::make_shared<LearningNode>("wang2")
:这部分代码使用std::make_shared
函数创建了一个指向LearningNode
对象的shared_ptr
智能指针。LearningNode
是一个自定义的类,继承自ROS2的rclcpp::Node
类。在这里,通过make_shared
函数创建了一个名为node
的智能指针,并将其初始化为指向一个具有名称"wang2
"的LearningNode
对象。
auto node = ...
:使用auto
关键字可以让编译器根据右侧表达式的类型推断出node
的类型,这里推断出node
是一个指向LearningNode
对象的shared_ptr
智能指针。
综合起来,这行代码的作用是创建一个名为node
的智能指针,指向一个具有名称"wang2
"的LearningNode
对象(这样就是创建了一个ROS 2节点),并赋予了节点一个特定的名称,以便在程序中引用和操作该节点。
(3)使节点进入事件循环,开始运行节点的回调函数并处理 ROS2中的事件。这个循环会持续运行,直到被外部因素(如程序结束或收到信号)打断。
rclcpp::spin(node);
(4)关闭ROS2系统,清理资源并终止节点运行。
rclcpp::shutdown();
2、LearningNode类
class LearningNode : public rclcpp::Node
{
public:
LearningNode(std::string name) : Node(name)
{
RCLCPP_INFO(this->get_logger(),"节点%s已启动",name.c_str());
}
private:
};
(1)定义了一个继承自rclcpp::Node
的类LearningNode
class LearningNode : public rclcpp::Node
class LearningNode
:定义了一个名为LearningNode
的类
: public rclcpp::Node
:表示LearningNode
类继承自rclcpp::Node
类。这意味着LearningNode
类将获得rclcpp::Node
类的所有成员变量和方法,同时还可以添加自己的成员变量和方法。
(2) 表示接下来的成员变量和方法在类的访问权限部分
public/private:
pubilc
:接下来的成员变量和方法是类的公共访问权限部分,可以被外部访问。
private
:接下来的成员变量和方法是类的私有访问权限部分,只能在类的内部访问。
(3)这是LearningNode
类中公有的构造函数
LearningNode(std::string name) : Node(name)
{
}
LearningNode(std::string name)
: 这是LearningNode
类的构造函数,它接受一个 std::string
类型的参数name
。
: Node(name)
: 这部分代码调用基类rclcpp::Node
的构造函数,并将前部分代码的name
参数传递给它。这意味着当你创建一个LearningNode
对象时,它首先会调用rclcpp::Node
的构造函数来初始化基类部分。
(4)打印一条消息(类似于C语言中的"printf")
RCLCPP_INFO(this->get_logger(),"节点%s已启动",name.c_str());
RCLCPP_INFO
: 这是一个ROS 2的宏,用于记录信息级别的日志。在ROS 2中,日志系统用于记录不同级别的信息,如调试、信息、警告和错误等。
this->get_logger()
: this
是一个指向当前对象的指针。get_logger()
是从基类 rclcpp::Node
继承的一个方法,它返回一个与当前节点关联的日志记录器对象。通过这个日志记录器,我们可以记录与节点相关的日志信息。
"节点%s已启动"
: 这是一个格式字符串,用于定义日志消息的格式。%s
是一个占位符,它将被后面的参数替换。在这个例子中,%s
将被替换为节点的名称。
name.c_str()
: name
是一个 std::strin
g 类型的变量,它包含了节点的名称。c_str()
是 std::string
类的一个方法,用于返回一个指向以空字符结尾的字符数组的指针,这个字符数组就是该字符串的C风格表示。这是因为RCLCPP_INFO
宏的格式化字符串参数需要C风格的字符串(即 char* 类型)。
综上所述,这行代码的作用是:使用当前节点的日志记录器,输出一条信息级别的日志,内容大致为“节点[节点名称]已启动”,其中[节点名称]是传递给构造函数的name
参数的值。
四、编译
下面是简洁的叙述,想要了解深入一点,可以看看这篇ROS2编译运行节点代码
打开终端,输入命令行
(1)进入工作空间
cd towm_ws
(2)这个命令告诉计算机去构建一个叫做learning_node
的ROS2软件包。就像在工厂里生产一个特定的产品一样。
colcon build --packages-select learning_node
(3)这个命令告诉计算机设置一些东西,让它知道在哪里找到刚刚构建好的软件包。这就像是在告诉工厂工人,新生产的产品应该放在哪个仓库或货架上,以便后续可以轻松地找到并使用它们。
source install/setup.bash
(4)这个命令告诉计算机去运行learning_node
软件包中的wang2
节点,
ros2 run learning_node wang2_node
(5)运行结果
[INFO] [1714027571.680855970] [wang2]: 节点wang2已启动
到此,我们就成功的运行了一个节点!
总结
自用