我开始使用 ROS 并遇到了以下订阅者代码:-
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_subscriber")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
}
private:
void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
{
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
return 0;
}
我的困惑特别在于语法
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
根据我的理解,这是一个ROS节点,用于从名为“topic”的主题中订阅字符串类型的消息,并在有新消息时执行 topic_callback() 。来自一个非常原始的背景,我想问为什么我们甚至需要使用 bind() 函数?我们不能简单地传递 topic_callback 函数或指向该函数的指针作为参数(可能像 Python)吗?
为什么我们需要指定“this”?当我们引用 topic_callback 时,只有存在一个其成员函数为 topic_callback 的 MinimalSubscriber 对象才有意义,因此再次指定它似乎是多余的。与 _1 相同,仅传递 1 个参数,即 String。根据我的说法,可以传递 this->topic_callback 而不是绑定。
我可能在几个方面都错了。我确实看过这个优秀的答案:- std::bind(),但无法完全掌握。
这个问题不是 ROS 特有的。假设您有一个函数接受回调,返回
void
并接受 1 std::string
参数:
void foo(std::function<void(std::string)> callback) {
if (callback) {
callback("foo");
}
}
如果你有一个自由函数
void freeFun(std::string)
,你可以直接传递它foo(freeFun);
,但是如果你有一个类或结构:
struct Foo {
void bar(std::string str) {
std::cout << "bar str = " << str << "\n";
}
static void baz(std::string str) {
std::cout << "baz str = " << str << "\n";
}
void registerCallback();
};
那么你不能简单地使用
bar
作为参数,因为 bar
需要调用 Foo
类型的对象。所以:
int main() {
using namespace std::placeholders;
// foo(&Foo::bar); // nope
foo(&Foo::baz); // ok, because static method doesn't need associated object
Foo myFoo;
foo(std::bind(&Foo::bar, &myFoo, _1)); // ok, but rarely used for practical reasons
}
void Foo::registerCallback() {
foo(std::bind(&Foo::bar, this, _1)); // ok, typical use-case
}
std::bind
将(非正式地)具有签名 bar
的函数 void bar(Foo*, std::string)
转换为内部保存“绑定”参数的对象,并且可以像具有签名 void f(std::string)
的函数一样进行调用。