Polling Subscriber#
Agnocast provides agnocast::PollingSubscriber, a pull-based subscription that lets you fetch a message on demand rather than receiving it via a callback. This corresponds to the subscription->take() pattern in rclcpp, but returns a zero-copy shared pointer from shared memory instead of copying data into a provided message.
PollingSubscriber is available at both Stage 1 (rclcpp::Node) and Stage 2 (agnocast::Node).
Migration from rclcpp take()#
Before (rclcpp)#
class MyPollingNode : public rclcpp::Node
{
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
rclcpp::TimerBase::SharedPtr timer_;
void timer_callback()
{
std_msgs::msg::String msg;
rclcpp::MessageInfo msg_info;
if (sub_->take(msg, msg_info)) {
RCLCPP_INFO(get_logger(), "Polled: %s", msg.data.c_str());
}
}
public:
MyPollingNode() : Node("my_polling_node")
{
sub_ = create_subscription<std_msgs::msg::String>(
"/topic", rclcpp::QoS(rclcpp::KeepLast(1)),
[](std_msgs::msg::String::SharedPtr) {}); // dummy callback required by rclcpp
timer_ = create_wall_timer(1s,
std::bind(&MyPollingNode::timer_callback, this));
}
};
After (Agnocast Stage 1)#
class MyPollingNode : public rclcpp::Node
{
agnocast::PollingSubscriber<std_msgs::msg::String>::SharedPtr sub_; // (1)
rclcpp::TimerBase::SharedPtr timer_;
void timer_callback()
{
auto msg = sub_->take_data(); // (2)
if (msg) {
RCLCPP_INFO(get_logger(), "Polled: %s", msg->data.c_str());
}
}
public:
MyPollingNode() : Node("my_polling_node")
{
sub_ = agnocast::create_subscription<std_msgs::msg::String>( // (3)
this, "/topic", rclcpp::QoS(rclcpp::KeepLast(1)));
timer_ = create_wall_timer(1s,
std::bind(&MyPollingNode::timer_callback, this));
}
};
Key changes:
rclcpp::Subscription→agnocast::PollingSubscriber(no dummy callback needed)sub_->take(msg, msg_info)→sub_->take_data()which returns anagnocast::ipc_shared_ptr<const T>(zero-copy)- Use
agnocast::create_subscriptionfree function (no callback argument)
Use a history depth of 1
take_data() returns exactly one message per call, and reads are non-destructive: entries stay
in shared memory while a per-subscriber watermark records how far this subscriber has read. The
search starts at the newest entry and walks back at most depth deliverable entries, and the
oldest entry within that window is returned.
With a depth of 1 the window holds a single entry, so the most recent message is returned, and
the same message is returned again when nothing newer has been published. With a greater depth,
once at least depth messages have been published, the returned message lags the newest one by
exactly depth - 1 and the lag does not recover — so take_data() means "the latest value"
only with a depth of 1.
Deprecated
agnocast::PollingSubscriber reproduces Autoware's polling subscriber, which is an
Autoware-specific API that Agnocast does not intend to maintain as public API. The class is
planned to move to autoware_agnocast_wrapper and be removed from Agnocast, so its entry
points — the polling overloads of create_subscription(), take_data(), and takeData() —
are marked [[deprecated]] and calling them emits a compiler warning. No removal version has
been decided yet.
For new code, use agnocast::TakeSubscription directly: keep the
last returned message on the caller side and call take(false),
which returns the oldest entry within the window not yet received by this subscriber. take(true)
— the mode take_data() uses — exists only for PollingSubscriber and is expected to go with
it, so it logs a one-time warning at runtime.
After (Agnocast Stage 2)#
class MyPollingNode : public agnocast::Node // (1)
{
agnocast::PollingSubscriber<std_msgs::msg::String>::SharedPtr sub_;
agnocast::TimerBase::SharedPtr timer_; // (2)
void timer_callback()
{
auto msg = sub_->take_data();
if (msg) {
RCLCPP_INFO(get_logger(), "Polled: %s", msg->data.c_str());
}
}
public:
MyPollingNode() : Node("my_polling_node")
{
sub_ = this->create_subscription<std_msgs::msg::String>( // (3)
"/topic", rclcpp::QoS(rclcpp::KeepLast(1)));
timer_ = this->create_wall_timer(1s,
std::bind(&MyPollingNode::timer_callback, this));
}
};
Additional changes from Stage 1:
- Base class changes to
agnocast::Node - Timer type changes to
agnocast::TimerBase::SharedPtr - Subscription creation uses member function instead of free function