【ROS2】初级:客户端-使用类中的参数(C++)
目标:使用 C++创建并运行一个带有 ROS 参数的类。
教程级别:初学者
时间:20 分钟
目录
背景
先决条件
任务
1. 创建一个包
2. 编写 C++ 节点
3. 建立并运行
摘要
下一步
背景
在创建您自己的节点时,有时需要添加可以从启动文件设置的参数。
这个教程将向您展示如何在 C++类中创建这些参数,以及如何在启动文件中设置它们。
先决条件
在之前的教程中,您学习了如何创建工作空间和创建软件包。您还了解了参数及其在 ROS 2 系统中的功能。
任务
1. 创建一个包
打开一个新的终端并且初始化您的 ROS 2 安装,这样 ros2
命令就会生效。
按照这些指示创建一个名为 ros2_ws
的新工作区。
请记住,包应该在 src
目录中创建,而不是在工作区的根目录中。导航到 ros2_ws/src
并创建一个新包:
cxy@ubuntu2404-cxy:~/ros2_ws/src$ ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_parameters --dependencies rclcpp
going to create a new package
package name: cpp_parameters
destination directory: /home/cxy/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['cxy <cxy@todo.todo>']
licenses: ['Apache-2.0']
build type: ament_cmake
dependencies: ['rclcpp']
creating folder ./cpp_parameters
creating ./cpp_parameters/package.xml
creating source and include folder
creating folder ./cpp_parameters/src
creating folder ./cpp_parameters/include/cpp_parameters
creating ./cpp_parameters/CMakeLists.txt
您的终端将返回一条消息,确认您的包 cpp_parameters
及其所有必要的文件和文件夹已创建。
` --dependencies
`参数将自动向` package.xml
`和` CMakeLists.txt
`添加必要的依赖行。
1.1 更新 package.xml
因为在创建包时您使用了 --dependencies
选项,所以您无需手动添加依赖项到 package.xml
或 CMakeLists.txt
。
一如既往,不过,请确保将描述、维护者电子邮件和姓名以及许可信息添加到 package.xml
。
<description>C++ parameter tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache-2.0</license>
2. 编写 C++ 节点
在 ros2_ws/src/cpp_parameters/src
目录中,创建一个名为 cpp_parameters_node.cpp
的新文件,并将以下代码粘贴其中:
#include <chrono> // 包含chrono库,用于处理时间
#include <functional> // 包含functional库,用于使用函数对象
#include <string> // 包含string库,用于使用字符串类型
#include <rclcpp/rclcpp.hpp> // 包含rclcpp库,用于ROS 2节点的创建和管理
using namespace std::chrono_literals; // 使用std::chrono_literals命名空间,允许使用后缀ms表示毫秒
class MinimalParam : public rclcpp::Node // 定义一个MinimalParam类,继承自rclcpp::Node类
{
public:
MinimalParam()
: Node("minimal_param_node") // 构造函数,初始化节点名为"minimal_param_node"
{
this->declare_parameter("my_parameter", "world"); // 声明一个参数"my_parameter",默认值为"world"
auto timer_callback = [this](){ // 定义一个定时器回调函数
std::string my_param = this->get_parameter("my_parameter").as_string(); // 获取参数"my_parameter"的值,并转换为字符串
RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str()); // 使用节点的日志记录器输出信息
std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")}; // 创建一个新的参数向量,并重新设置"my_parameter"
this->set_parameters(all_new_parameters); // 设置新的参数向量
};
timer_ = this->create_wall_timer(1000ms, timer_callback); // 创建一个定时器,每1000毫秒调用一次timer_callback函数
}
private:
rclcpp::TimerBase::SharedPtr timer_; // 定义一个定时器指针成员变量
};
int main(int argc, char ** argv) // 主函数
{
rclcpp::init(argc, argv); // 初始化ROS 2
rclcpp::spin(std::make_shared<MinimalParam>()); // 创建MinimalParam类的实例,并使节点开始运行
rclcpp::shutdown(); // 关闭ROS 2
return 0; // 返回0,表示程序正常结束
}
检查代码 2.1
顶部的 #include
语句是包依赖。
下一段代码创建了类和构造函数。构造函数的第一行创建了一个名为 my_parameter
的参数,其默认值为 world
。参数类型是根据默认值推断出来的,所以在这种情况下它会被设置为字符串类型。接下来,声明了一个名为 timer_callback
的 lambda 函数。它通过引用捕获当前对象 this
,不接受输入参数并返回 void。我们的 timer_callback
函数的第一行从节点获取参数 my_parameter
,并将其存储在 my_param
中。然后, RCLCPP_INFO
函数确保事件被记录。 set_parameters
函数将参数 my_parameter
重置为默认字符串值 world
。如果用户在外部更改了参数,这确保它总是被重置回原来的值。最后, timer_
被初始化为 1000ms 的周期,这导致 timer_callback
函数每秒执行一次。
class MinimalParam : public rclcpp::Node
{
public:
MinimalParam()
: Node("minimal_param_node")
{
this->declare_parameter("my_parameter", "world");
auto timer_callback = [this](){
std::string my_param = this->get_parameter("my_parameter").as_string();
RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str());
std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")};
this->set_parameters(all_new_parameters);
};
timer_ = this->create_wall_timer(1000ms, timer_callback);
}
最后是 timer_
的声明。
private:
rclcpp::TimerBase::SharedPtr timer_;
继我们的 MinimalParam
之后是我们的 main
。这里初始化了 ROS 2,构建了 MinimalParam
类的一个实例, rclcpp::spin
开始处理来自节点的数据。
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalParam>());
rclcpp::shutdown();
return 0;
}
2.1.1(可选)添加参数描述符
您可以选择为参数设置一个描述符。描述符允许您指定参数及其约束的文本描述,例如使其只读,指定范围等。为此,构造函数中的代码必须更改为:
class MinimalParam : public rclcpp::Node // 定义一个MinimalParam类,继承自rclcpp::Node类
{
public:
MinimalParam()
: Node("minimal_param_node") // 构造函数,初始化节点名为"minimal_param_node"
{
auto param_desc = rcl_interfaces::msg::ParameterDescriptor{}; // 创建一个参数描述符对象
param_desc.description = "This parameter is mine!"; // 设置参数描述信息
this->declare_parameter("my_parameter", "world", param_desc); // 声明一个带描述的参数"my_parameter",默认值为"world"
auto timer_callback = [this](){ // 定义一个定时器回调函数
std::string my_param = this->get_parameter("my_parameter").as_string(); // 获取参数"my_parameter"的值,并转换为字符串
RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str()); // 使用节点的日志记录器输出信息
std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")}; // 创建一个新的参数向量,并重新设置"my_parameter"
this->set_parameters(all_new_parameters); // 设置新的参数向量
};
timer_ = this->create_wall_timer(1000ms, timer_callback); // 创建一个定时器,每1000毫秒调用一次timer_callback函数
}
代码的其余部分保持不变。一旦运行了节点,你就可以运行 ros2 param describe /minimal_param_node my_parameter
来查看类型和描述。
2.2 添加可执行文件
现在打开 CMakeLists.txt
文件。在依赖项 find_package(rclcpp REQUIRED)
下面添加以下代码行。
add_executable(minimal_param_node src/cpp_parameters_node.cpp)
ament_target_dependencies(minimal_param_node rclcpp)
install(TARGETS
minimal_param_node
DESTINATION lib/${PROJECT_NAME}
)
3. 构建并运行
在工作区的根目录运行 rosdep
( ros2_ws
)以检查构建前缺失的依赖项是一个好习惯:
rosdep install -i --from-path src --rosdistro jazzy -y
返回到您的工作区根目录, ros2_ws
,然后构建您的新包:
cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select cpp_parameters
Starting >>> cpp_parameters
Finished <<< cpp_parameters [7.02s]
Summary: 1 package finished [7.76s]
打开一个新的终端,导航到 ros2_ws
,并且导入设置文件:
source install/setup.bash
现在运行节点:
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 run cpp_parameters minimal_param_node
[INFO] [1720323417.584053341] [minimal_param_node]: Hello world!
[INFO] [1720323418.584192088] [minimal_param_node]: Hello world!
[INFO] [1720323419.584106135] [minimal_param_node]: Hello world!
现在您可以看到参数的默认值,但您希望能够自己设置它。有两种方法可以做到这一点。
3.1 通过控制台进行更改
这部分将使用你从关于参数的教程中获得的知识 https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Parameters/Understanding-ROS2-Parameters.html ,并将其应用到你刚刚创建的节点上。
确保节点正在运行:
ros2 run cpp_parameters minimal_param_node
打开另一个终端,再次从 ros2_ws
内部获取设置文件,并输入以下行:
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 param list
/minimal_param_node:
my_parameter
qos_overrides./parameter_events.publisher.depth
qos_overrides./parameter_events.publisher.durability
qos_overrides./parameter_events.publisher.history
qos_overrides./parameter_events.publisher.reliability
start_type_description_service
use_sim_time
在那里,您将看到自定义参数 my_parameter
。要更改它,只需在控制台中运行以下行:
ros2 param set /minimal_param_node my_parameter earth
3.2 通过启动文件进行更改
您也可以在启动文件中设置参数,但首先您需要添加启动目录。在 ros2_ws/src/cpp_parameters/
目录内,创建一个名为 launch
的新目录。在那里,创建一个名为 cpp_parameters_launch.py
的新文件。
# 导入LaunchDescription类,用于描述launch文件内容
from launch import LaunchDescription
# 导入Node类,用于描述一个ROS节点的启动配置
from launch_ros.actions import Node
# 定义一个函数generate_launch_description,这个函数将会返回LaunchDescription对象
def generate_launch_description():
# 创建LaunchDescription对象实例,并向其中添加一个Node对象
return LaunchDescription([
Node(
# 指定节点所属的包名
package="cpp_parameters",
# 指定节点可执行文件的名称
executable="minimal_param_node",
# 为节点设置一个名称
name="custom_minimal_param_node",
# 设置节点的输出选项,"screen"表示将输出打印到屏幕
output="screen",
# 设置emulate_tty为True,以模拟TTY输出(使得输出更易读)
emulate_tty=True,
# 设置节点的参数,这里定义了一个名为"my_parameter"的参数,其值为"earth"
parameters=[
{"my_parameter": "earth"}
]
)
])
在这里您可以看到,当我们启动节点 minimal_param_node
时,我们将 my_parameter
设置为 earth
。通过添加下面两行代码,我们确保输出打印在控制台上。
output="screen",
emulate_tty=True,
现在打开 CMakeLists.txt
文件。在您之前添加的那些行下面,添加以下代码行。
install(
DIRECTORY launch
DESTINATION share/${PROJECT_NAME}
)
# 指定CMake的最低版本要求
cmake_minimum_required(VERSION 3.8)
# 定义项目名称
project(cpp_parameters)
# 如果使用的是GNU编译器或Clang编译器,添加编译选项
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# 查找依赖包
# ament_cmake是ROS2中用于构建和测试ROS包的工具
find_package(ament_cmake REQUIRED)
# rclcpp是ROS2中C++客户端库的包
find_package(rclcpp REQUIRED)
# 添加一个可执行文件目标,指定源文件为src/cpp_parameters_node.cpp
add_executable(minimal_param_node src/cpp_parameters_node.cpp)
# 将rclcpp作为目标依赖添加到minimal_param_node目标上
ament_target_dependencies(minimal_param_node rclcpp)
# 安装目标文件,将minimal_param_node可执行文件安装到lib/${PROJECT_NAME}目录下
install(TARGETS
minimal_param_node
DESTINATION lib/${PROJECT_NAME}
)
# 安装launch目录,将其安装到share/${PROJECT_NAME}目录下
install(
DIRECTORY launch
DESTINATION share/${PROJECT_NAME}
)
# 如果构建测试被启用,则查找ament_lint_auto包,并设置一些lint选项
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# 跳过版权检查linter(当所有源文件添加了版权和许可时,取消注释此行)
set(ament_cmake_cpplint_FOUND TRUE)
# 跳过cpplint检查(只在git仓库中有效,当包在git仓库中且所有源文件添加了版权和许可时,取消注释此行)
set(ament_cmake_cpplint_FOUND TRUE)
# 查找并添加lint测试依赖项
ament_lint_auto_find_test_dependencies()
endif()
# 调用ament_package()函数,处理安装和测试等工作
ament_package()
打开控制台并导航到您的工作区的根目录, ros2_ws
,然后构建您的新包:
cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select cpp_parameters
Starting >>> cpp_parameters
Finished <<< cpp_parameters [1.53s]
Summary: 1 package finished [1.76s]
然后在新终端中导入设置文件:
source install/setup.bash
现在使用我们刚刚创建的启动文件运行节点:
ros2 launch cpp_parameters cpp_parameters_launch.py
终端应该在第一次返回以下消息:
cxy@ubuntu2404-cxy:~/ros2_ws$ source install/setup.bash
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 launch cpp_parameters cpp_parameters_launch.py
[INFO] [launch]: All log files can be found below /home/cxy/.ros/log/2024-07-07-11-49-18-433664-ubuntu2404-cxy-19434
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [minimal_param_node-1]: process started with pid [19437]
[minimal_param_node-1] [INFO] [1720324159.753973339] [custom_minimal_param_node]: Hello earth!
[minimal_param_node-1] [INFO] [1720324160.753977739] [custom_minimal_param_node]: Hello world!
进一步的输出应该每秒显示 [INFO] [minimal_param_node]: Hello world!
。
摘要
您创建了一个带有自定义参数的节点,该参数可以从启动文件或命令行中设置。您将依赖项、可执行文件和启动文件添加到包配置文件中,以便您可以构建并运行它们,并看到参数在实际中的应用。
下一步
现在您已经拥有了一些包和自己的 ROS 2 系统,下一个教程 https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Getting-Started-With-Ros2doctor.html 将向您展示如何在遇到问题时检查环境和系统中的问题。
原文地址:https://blog.csdn.net/cxyhjl/article/details/140259281
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!