【ROS2】ROS2 与 ROS1 编码方式对比(C++实现)

server/2024/11/28 14:44:45/

目录

  • 一、初始化和关闭节点
  • 二、发布者和订阅者
  • 三、服务和客户端
  • 四、参数管理
  • 五、日志记录
  • 六、生命周期管理

ROS1 主要使用roscpprospy作为客户端库,分别用于C++和Python语言。

ROS2 引入了新的客户端库rclcpp(C++)和rclpy(Python),它们提供了与ROS1类似的API,但更加现代化且功能更加强大。此外,ROS2还支持更多的编程语言,如Java、JavaScript等。

不仅客户端库有不同,ROS2 在代码编写方式上相对于ROS1也有了一些重要的变化,包括一些核心概念和实践方法的调整。ROS1代码编写方式更倾向于过程式思想,ROS2则使用了更多的面向对象的方式,也添加了更多的现代编程思想的使用。

ROS2 在 C++ 编程中引入了一些新的概念和 API,这些变化使得代码更加模块化和易于维护。特别是 rclcpp 库提供了更丰富的功能和更好的错误处理机制,同时支持异步编程模型。如果你已经熟悉 ROS1 的 C++ 编程,这些变化应该不会太难适应。主要的区别在于初始化、节点管理、服务和客户端的创建和调用方式。

一、初始化和关闭节点

ROS1:

#include "ros/ros.h"int main(int argc, char **argv) 
{ros::init(argc, argv, "my_node");ros::NodeHandle nh;// 节点逻辑ros::spin();return 0;
}

ROS2:

#include "rclcpp/rclcpp.hpp"int main(int argc, char **argv) 
{rclcpp::init(argc, argv);auto node = rclcpp::Node::make_shared("my_node");// 节点逻辑rclcpp::spin(node);rclcpp::shutdown();return 0;
}

二、发布者和订阅者

ROS1:

// 发布者
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter", 10);// 订阅者
ros::Subscriber sub = nh.subscribe("chatter", 10, chatterCallback);
void chatterCallback(const std_msgs::String::ConstPtr& msg) 
{ROS_INFO("I heard: [%s]", msg->data.c_str());
}

ROS2:

// 发布者
auto pub = node->create_publisher<std_msgs::msg::String>("chatter", 10);// lambda函数版订阅者
auto sub = node->create_subscription<std_msgs::msg::String>("chatter", 10, [](const std_msgs::msg::String::SharedPtr msg){RCLCPP_INFO(rclcpp::get_logger("my_node"), "I heard: '%s'", msg->data.c_str());}
);// 成员函数版订阅者
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
void topic_callback(const std_msgs::msg::String &msg) const
{RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg.data.c_str());
}

三、服务和客户端

ROS1:

// 服务
ros::ServiceServer service = nh.advertiseService("add_two_ints", add_two_ints_callback);
bool add_two_ints_callback(srv::AddTwoInts::Request &req, srv::AddTwoInts::Response &res) 
{res.sum = req.a + req.b;ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);ROS_INFO("sending back response: [%ld]", (long int)res.sum);return true;
}// 客户端
client = nh.serviceClient<srv::AddTwoInts>("add_two_ints");
srv::AddTwoInts srv;
srv.request.a = 1;
srv.request.b = 2;
if (client.call(srv)) 
{ROS_INFO("Sum: %ld", (long int)srv.response.sum);
} 
else 
{ROS_ERROR("Failed to call service add_two_ints");
}

ROS2:

// 服务
auto service = node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", add);
void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request, std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response) 
{response->sum = request->a + request->b;RCLCPP_INFO(node->get_logger(), "request: x=%ld, y=%ld", request->a, request->b);RCLCPP_INFO(node->get_logger(), "sending back response: [%ld]", response->sum);
}// 客户端
auto client = node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
request->a = 1;
request->b = 2;auto future = client->async_send_request(request);
if (rclcpp::spin_until_future_complete(node, future) == rclcpp::FutureReturnCode::SUCCESS) 
{RCLCPP_INFO(node->get_logger(), "Sum: %ld", future.get()->sum);
} 
else 
{RCLCPP_ERROR(node->get_logger(), "Failed to call service add_two_ints");
}

四、参数管理

ROS1:

std::string param_value;
nh.getParam("param_name", param_value);

ROS2:

auto param_value = node->get_parameter("param_name").as_string();

五、日志记录

ROS1:

ROS_INFO("This is an info message.");
ROS_DEBUG("This is a DEBUG message");
ROS_INFO("This is an INFO message");
ROS_WARN("This is a WARN message");
ROS_ERROR("This is an ERROR message");
ROS_FATAL("This is a FATAL message");

ROS2:

RCLCPP_INFO(this->get_logger(), "This is an info message.");
RCLCPP_DEBUG(this->get_logger(), "This is a DEBUG message");
RCLCPP_INFO(this->get_logger(), "This is an INFO message");
RCLCPP_WARN(this->get_logger(), "This is a WARN message");
RCLCPP_ERROR(this->get_logger(), "This is an ERROR message");
RCLCPP_FATAL(this->get_logger(), "This is a FATAL message");

六、生命周期管理

ROS1:

ROS1 没有内置的生命周期管理功能,通常需要开发者自己实现节点的生命周期管理。

ROS2:

ROS2 引入了生命周期节点的概念,允许更精细地控制节点的启动和停止过程。

class LifecycleNode : public rclcpp_lifecycle::LifecycleNode 
{
public:LifecycleNode() : LifecycleNode("lifecycle_node") {}LifecycleNode(std::string name) : rclcpp_lifecycle::LifecycleNode(name) {}rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override {RCLCPP_INFO(get_logger(), "on_configure() is called.");return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;}rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override {RCLCPP_INFO(get_logger(), "on_activate() is called.");return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;}// 其他生命周期回调函数...
};

rclcpp_lifecycle是一个提供生命周期管理功能的库,它允许节点(Node)在不同的状态之间转换,如激活(active)、非激活(inactive)、配置(configuring)等。这种功能对于需要复杂启动和关闭序列的机器人或应用程序特别有用。

rclcpp_lifecycle::LifecycleNoderclcpp_lifecycle库中的一个核心类,它扩展了ROS 2的rclcpp::Node类,添加了生命周期管理的功能。通过使用LifecycleNode,开发者可以定义节点在生命周期状态转换时应执行的操作。



欢迎大家加QQ群,一起讨论学习:894013891


http://www.ppmy.cn/server/145648.html

相关文章

iOS开发之修改已有项目的项目名和类名前缀

一、修改项目名称 1、Xcode打开项目修改项目名称 直接选中项目&#xff0c;点击enter&#xff0c;直接修改项目名称 把buydodo改成xiedodo&#xff0c;点击enter Rename完了点继续&#xff0c;只有框框内的部分变了 2、退出Xcode关闭项目&#xff0c;修改剩下的项目名称 找…

论文笔记(五十七)Diffusion Model Predictive Control

Diffusion Model Predictive Control 文章概括摘要1. Introduction2. Related work3. 方法3.1 模型预测控制3.2. 模型学习3.3. 规划&#xff08;Planning&#xff09;3.4. 适应 4. 实验&#xff08;Experiments&#xff09;4.1. 对于固定奖励&#xff0c;D-MPC 可与其他离线 RL…

element-plus弹窗二次封装踩坑

1 基于element-plus的二次封装弹窗很常见。代码如下&#xff1a; 父组件&#xff1a; import Dialog from ./components/Dialogs/testDailog.vueconst showref(false) const openDialog()>{show.valuetrue}<button click"openDialog" >打开dialoag</bu…

git merge 排除文件

方法一&#xff1a; 在Git中&#xff0c;如果你想在合并时排除特定文件&#xff0c;你可以使用.gitattributes文件来指定合并策略。你可以设置一个自定义合并策略来忽略特定文件的合并。 首先&#xff0c;在仓库的根目录下创建或编辑.gitattributes文件&#xff0c;并添加以…

微服务上下线动态感知实现的技术解析

序言 随着微服务架构的广泛应用&#xff0c;服务的动态管理和监控变得尤为重要。在微服务架构中&#xff0c;服务的上下线是一个常见的操作&#xff0c;如何实时感知这些变化&#xff0c;确保系统的稳定性和可靠性&#xff0c;成为了一个关键技术挑战。本文将深入探讨微服务上…

【C++】string类练习

test1:反转字母 给你一个字符串 s &#xff0c;根据下述规则反转字符串&#xff1a; 所有非英文字母保留在原有位置。所有英文字母&#xff08;小写或大写&#xff09;位置反转。 返回反转后的 s 。 示例 1&#xff1a; 输入&#xff1a;s "ab-cd" 输出&#xff1a;…

后端并发编程操作简述 Java高并发程序设计 六类并发容器 七种线程池 四种阻塞队列

目录 并发集合 1. ConcurrentHashMap&#xff1a; 2. CopyOnWriteArrayList&#xff1a; 3. CopyOnWriteArraySet&#xff1a; 4. BlockingQueue系列&#xff1a; 5. ConcurrentSkipListMap 和 ConcurrentSkipListSet&#xff1a; 6. ConcurrentLinkedDeque&#xff1a;…

LSA详情与特殊区域

LSA是构成LSDB的重要原材料&#xff0c;在OSPF中发挥很大作用。 报文 通用头部 LS age&#xff1a;LSA寿命&#xff0c;0-3600s Options&#xff1a;可选项 LS type&#xff1a;LSA类型&#xff0c;三要素之一 Link State ID&#xff1a;LSAID 三要素之一 Advertising Ro…