rclcpp 源码详细分析

rclcpp 源码详细分析

工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros2/rclcpp
版本:16.0.19(Humble),子包 4 个,构建类型 ament_cmake,语言 C++17,许可证 Apache 2.0

rclcpp(ROS Client Library for C++)是 ROS 2 C++ 客户端库,几乎所有 C++ 节点、rviz2、Nav2、MoveIt 2 等均构建于此。它在 rcl(C API)之上提供类型安全的 C++ 抽象,并引入 Executorcallback_groupintra-process参数服务 等 ROS 2 特有机制。理解 rclcpp 是掌握 ROS 2 C++ 应用并发模型与通信路径的关键。


1. 总体认识

1.1 核心职责

能力 说明
生命周期 rclcpp::init() / rclcpp::shutdown()Context 封装 rcl_init/rcl_shutdown
Node 创建 pub/sub/service/client/timer,namespace 与 remap
Executor 调度 ready 回调(subscription/timer/service/client/waitable)
CallbackGroup 互斥/可重入分组,控制并发语义
Intra-process 同进程零拷贝/共享指针消息传递
参数 declare/get/set + 标准参数服务(rcl_interfaces
时间 Clock / TimeSource,订阅 /clock 实现 sim time
QoS C++ 封装 rmw_qos_profile_t,支持 qos_overrides
Action / Lifecycle / Components 独立子包扩展

1.2 在 ROS 2 栈中的位置

用户 / 上层框架rclcpp 仓库rcl 层更下层Nav2 / MoveIt2rviz2examples / demosrclcpp 核心rclcpp_actionrclcpp_componentsrclcpp_lifecyclerclrcl_actionrcl_lifecyclermw_implementationrosidl_typesupport_cpprcutils / rcpputilsFast-DDS / CycloneDDS
下层依赖 rclcpp 如何使用
rcl 所有 pub/sub/service/client/timer/wait 均最终调用 rcl_*
rcl_action rclcpp_action 封装 action client/server
rcl_lifecycle rclcpp_lifecycle 封装 lifecycle 状态机
rcl_interfaces 参数服务、parameter_events 消息类型
rosgraph_msgs /clock 话题类型
libstatistics_collector 可选 topic 统计

与 rcl 的分工rcl 提供语言无关 C API 与 wait set;参数服务的实现主体在 rclcppParameterService),rcl 只负责 CLI 参数/YAML 解析。Executor、callback_group、intra-process 均为 rclcpp 独有,不在 rcl 层。


2. 子包结构

1
2
3
4
5
6
7
8
9
rclcpp/
├── rclcpp/ # 核心库 ★
│ ├── include/rclcpp/ # ~85 个顶层头文件 + node_interfaces/ 等
│ ├── include/rclcpp/node_interfaces/ # 11 组 interface
│ ├── src/rclcpp/ # 73 个 .cpp(~11.8K 行)
│ └── src/rclcpp/executors/ # 4 种 Executor 实现
├── rclcpp_action/ # Action C++ API
├── rclcpp_components/ # Composable Node + ComponentManager
└── rclcpp_lifecycle/ # LifecycleNode
版本 职责
rclcpp 16.0.19 Node、Executor、pub/sub/service/timer、参数、QoS、intra-process
rclcpp_action 16.0.19 Client/Server/ClientGoalHandle,封装 rcl_action
rclcpp_components 16.0.19 动态加载 .so 组件,ComponentManager 提供 load/unload/list
rclcpp_lifecycle 16.0.19 LifecycleNode、状态/转移、LifecyclePublisher

2.1 源码规模(核心包 rclcpp/rclcpp

指标 数量
公开头文件(.hpp ~148
实现文件(.cpp ~73
核心 .cpp 总行数 ~11,794
最大单文件 executor.cpp(947 行)、node.cpp(607 行)、time_source.cpp(554 行)

3. 依赖关系

3.1 rclcpp/package.xml

1
2
3
4
5
6
7
8
9
10
11
rclcpp
├── rcl # C 客户端库
├── rcl_yaml_param_parser # YAML 参数文件(经 rcl 间接使用)
├── rmw # QoS 类型、GID 等
├── rcutils / rcpputils # 日志、ScopeExit、文件系统
├── rosidl_runtime_cpp # 消息 C++ 运行时
├── rosidl_typesupport_cpp # typesupport 查找
├── rcl_interfaces # 参数 srv/msg
├── rosgraph_msgs # Clock 消息
├── libstatistics_collector # topic 统计
└── tracetools # LTTng 追踪点

3.2 子包额外依赖

子包 关键依赖
rclcpp_action rcl_action, action_msgs, rosidl_runtime_c
rclcpp_components class_loader, composition_interfaces, ament_index_cpp
rclcpp_lifecycle rcl_lifecycle, lifecycle_msgs

4. 核心设计:Node + node_interfaces

4.1 Node 是用户 API 入口

1
2
/// Node is the single point of entry for creating publishers and subscribers.
class Node : public std::enable_shared_from_this<Node>

用户通过 Node::create_publisher()create_subscription() 等创建通信实体;内部不直接持有 rcl_node_t,而是通过 组合式 interface 拆分职责。

4.2 Interface 组合(构造顺序)

Node 构造函数按固定顺序实例化各 interface,并相互注入依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Node::Node(
const std::string & node_name,
const std::string & namespace_,
const NodeOptions & options)
: node_base_(new rclcpp::node_interfaces::NodeBase(...)),
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_.get())),
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get(), node_timers_.get())),
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
node_clock_(new rclcpp::node_interfaces::NodeClock(...)),
node_parameters_(new rclcpp::node_interfaces::NodeParameters(...)),
node_time_source_(new rclcpp::node_interfaces::NodeTimeSource(...)),
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
...
Interface 实现类 职责
NodeBaseInterface NodeBase rcl_node_t 句柄、FQN、context、intra-process 开关
NodeGraphInterface NodeGraph topic/service 图 introspection
NodeLoggingInterface NodeLogging 节点 logger
NodeTimersInterface NodeTimers 创建/管理 timer
NodeTopicsInterface NodeTopics create_publisher / create_subscription
NodeServicesInterface NodeServices create_service / create_client
NodeClockInterface NodeClock 节点 clock
NodeParametersInterface NodeParameters declare/get/set 参数、回调
NodeTimeSourceInterface NodeTimeSource 订阅 /clock、驱动 sim time
NodeWaitablesInterface NodeWaitables 注册 waitable(含 action client 等)

设计动机

  • Component 友好ComponentManager 只需 NodeBaseInterface 等指针即可把节点挂到 Executor
  • 可测试:mock 单个 interface 而不构造完整 Node
  • LifecycleNode 复用rclcpp_lifecycle::LifecycleNode 同样组合这些 interface

4.3 NodeOptions

NodeOptions 集中配置:

  • context()use_intra_process_comms()enable_topic_statistics()
  • start_parameter_services()parameter_overrides()allow_undeclared_parameters()
  • get_rcl_node_options() → 底层 rcl_node_options_t(含 remap、use_global_arguments)
  • QoS 预设:parameter_event_qos()clock_qos()

5. Context 与 init

5.1 全局 init 流程

1
2
3
4
5
6
7
8
9
10
11
void
init(
int argc,
char const * const * argv,
const InitOptions & init_options,
SignalHandlerOptions signal_handler_options)
{
using rclcpp::contexts::get_global_default_context;
get_global_default_context()->init(argc, argv, init_options);
install_signal_handlers(signal_handler_options);
}

rclcpp::init() → 默认 Context::init()rcl_init(),并安装 SIGINT/SIGTERM 处理器(触发 shutdown)。

5.2 Context 封装 rcl_context

1
2
3
4
5
6
7
8
9
10
11
12
13
Context::init(
int argc,
char const * const * argv,
const rclcpp::InitOptions & init_options)
{
...
rcl_ret_t ret = rcl_init(argc, argv, init_options.get_rcl_init_options(), context);
...
rcl_context_.reset(context, __delete_context);
if (init_options.auto_initialize_logging()) {
rcl_logging_configure_with_output_handler(...);
}
}
特性 说明
多 Context WeakContextsWrapper 跟踪所有已创建 context,支持多 init 场景
shutdown 回调 add_on_shutdown_callback() 注册清理逻辑
有效性 context->is_valid() 对应 rcl_context_is_valid()
默认 context contexts/default_context.hpp 提供进程级单例

5.3 辅助 API

API 作用
rclcpp::ok() 检查默认 context 是否仍有效
rclcpp::shutdown() 关闭默认 context
rclcpp::remove_ros_arguments() 剥离 ROS 特有 CLI 参数
rclcpp::spin(node) 便捷函数:SingleThreadedExecutor + add_node + spin

6. Executor 架构

Executor 是 rclcpp 并发与调度核心:将「通信图」与「执行模型」解耦——节点创建实体,Executor 决定何时执行回调。

6.1 类层次

文件 特点
Executor executor.hpp / executor.cpp 基类:wait set、实体收集、execute
SingleThreadedExecutor executors/single_threaded_executor.cpp 单线程 spin 循环
MultiThreadedExecutor executors/multi_threaded_executor.cpp N 线程并行 execute
StaticSingleThreadedExecutor executors/static_single_threaded_executor.hpp 静态实体列表,减少每轮重建开销

6.2 spin 主循环(SingleThreadedExecutor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void
SingleThreadedExecutor::spin()
{
if (spinning.exchange(true)) {
throw std::runtime_error("spin() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
while (rclcpp::ok(this->context_) && spinning.load()) {
rclcpp::AnyExecutable any_executable;
if (get_next_executable(any_executable)) {
execute_any_executable(any_executable);
}
}
}

6.3 get_next_executable 两阶段

1
2
3
4
5
6
7
8
9
10
11
12
13
bool
Executor::get_next_executable(AnyExecutable & any_executable, std::chrono::nanoseconds timeout)
{
bool success = get_next_ready_executable(any_executable);
if (!success) {
wait_for_work(timeout);
if (!spinning.load()) {
return false;
}
success = get_next_ready_executable(any_executable);
}
return success;
}
  1. get_next_ready_executable:按优先级扫描已 ready 实体(timer → subscription → service → client → waitable)
  2. wait_for_work:若无 ready 实体,则 collect_entitiesrcl_wait_set_resizercl_wait()

6.4 wait_for_work 与 rcl wait set

核心步骤(executor.cpp):

  1. memory_strategy_->collect_entities(weak_groups_to_nodes_) — 收集本 Executor 管理的 callback group 内实体
  2. rcl_wait_set_clear / rcl_wait_set_resize — 按实体数量调整 wait set
  3. memory_strategy_->add_handles_to_wait_set — 填入 subscription/timer/service/client/guard_condition 句柄
  4. rcl_wait(&wait_set_, timeout) — 阻塞直至有事件或超时
  5. remove_null_handles — 清理 middleware 标记为 invalid 的句柄

这与 rcl 源码分析 中的 wait set 机制直接对应,rclcpp 在其上增加了 callback group 过滤memory strategy 抽象。

6.5 execute_any_executable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void
Executor::execute_any_executable(AnyExecutable & any_exec)
{
if (!spinning.load()) {
return;
}
if (any_exec.timer) {
execute_timer(any_exec.timer);
}
if (any_exec.subscription) {
execute_subscription(any_exec.subscription);
}
if (any_exec.service) {
execute_service(any_exec.service);
}
if (any_exec.client) {
execute_client(any_exec.client);
}
if (any_exec.waitable) {
any_exec.waitable->execute(any_exec.data);
}
any_exec.callback_group->can_be_taken_from().store(true);
interrupt_guard_condition_.trigger();
}

执行完毕后:

  • 重置 can_be_taken_from(MutuallyExclusive group 在执行前会被置 false)
  • 触发 interrupt_guard_condition_,唤醒可能在 rcl_wait 中阻塞的其他线程

6.6 MultiThreadedExecutor

  • 默认线程数 = hardware_concurrency()(至少 1)
  • 各线程在 wait_mutex_ 保护下调用 get_next_executable
  • 可选 yield_before_execute 减少锁竞争
  • any_exec.callback_group.reset() 避免析构时错误重置 group 状态

6.7 StaticSingleThreadedExecutor

实体列表在 spin() 前通过 StaticExecutorEntitiesCollector 一次性收集,仅在 add/remove node 时更新。适合实体集合固定的生产节点,降低 collect_entities 开销。

6.8 MemoryStrategy

默认 AllocatorMemoryStrategymemory_strategies/allocator_memory_strategy.hpp)负责:

  • 从 callback group → node 映射中收集 handles
  • 在 wait 返回后查找 next ready 实体
  • 可替换为自定义 strategy(测试或特殊调度)

7. CallbackGroup 并发模型

7.1 两种类型

1
2
3
4
5
enum class CallbackGroupType
{
MutuallyExclusive,
Reentrant
};
类型 行为
MutuallyExclusive 同 group 内同一时刻最多一个回调执行;can_be_taken_from_ 原子标志 gate
Reentrant 同 group 内回调可并行(MultiThreadedExecutor 下)

7.2 与 Executor 的关系

  • 每个 subscription/timer/service/client 创建时绑定一个 CallbackGroup
  • 默认 group 由 automatically_add_to_executor_with_node 控制是否随 add_node() 自动注册
  • Executor 维护 weak_groups_to_nodes_ 映射,只调度已 add_callback_group() 的 group
  • MutuallyExclusiveget_next_ready_executable_from_map 选中实体后将 can_be_taken_from 置 false,直到 execute 完成

7.3 典型用法

1
2
3
4
5
6
7
// 互斥:回调不会重叠
auto group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
rclcpp::SubscriptionOptions opts;
opts.callback_group = group;

// 可重入:多线程 Executor 下可并行
auto reentrant = node->create_callback_group(rclcpp::CallbackGroupType::Reentrant);

8. Publisher / Subscription

8.1 模板层次

说明
PublisherBase 非模板基类,持有 rcl_publisher_t,topic 名、QoS、intra-process id
Publisher<MessageT, AllocatorT> 模板发布者,publish() 多重重载
SubscriptionBase 非模板基类,type-erased take/handle
Subscription<MessageT, AllocatorT> 模板订阅者,用户回调

还支持 TypeAdapter(自定义类型适配 ROS 消息)、GenericPublisher/Subscription(运行时类型)。

8.2 发布路径(inter-process)

1
2
3
4
5
Publisher::publish(msg)
→ do_inter_process_publish()
→ rcl_publish()
→ rmw_publish()
→ DDS

8.3 发布路径(intra-process 开启)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
{
if (!intra_process_is_enabled_) {
this->do_inter_process_publish(*msg);
return;
}
bool inter_process_publish_needed =
get_subscription_count() > get_intra_process_subscription_count();

if (inter_process_publish_needed) {
auto shared_msg =
this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
this->do_inter_process_publish(*shared_msg);
} else {
this->do_intra_process_ros_message_publish(std::move(msg));
}
}

策略要点:

  • Volatile durability 允许 intra-process
  • 若存在跨进程订阅者,先 intra 再 inter(降低端到端延迟)
  • unique_ptr 路径优先零拷贝移交所有权

8.4 订阅执行路径(Executor)

execute_subscription() 三条分支(executor.cpp):

模式 方法
Serialized take_serializedhandle_serialized_message
Loaned rcl_take_loaned_message → callback → rcl_return_loaned_message_from_subscription
默认 copy take_type_erasedhandle_messagereturn_message

Intra-process 消息在 handle_message 内通过 MessageInfo.from_intra_process 区分,不经过 DDS take。


9. Intra-process 通信

9.1 IntraProcessManager

位于 rclcpp/experimental/intra_process_manager.hpp,由 Context 持有单例(每 context 一个)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint64_t
IntraProcessManager::add_publisher(rclcpp::PublisherBase::SharedPtr publisher)
{
uint64_t pub_id = IntraProcessManager::get_next_unique_id();
publishers_[pub_id] = publisher;
pub_to_subs_[pub_id] = SplittedSubscriptions();
for (auto & pair : subscriptions_) {
...
if (can_communicate(publisher, subscription)) {
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
}
}
return pub_id;
}

9.2 匹配规则 can_communicate

1
2
3
4
5
6
7
8
9
10
11
12
bool
IntraProcessManager::can_communicate(...) const
{
if (strcmp(pub->get_topic_name(), sub->get_topic_name()) != 0) {
return false;
}
auto check_result = rclcpp::qos_check_compatible(pub->get_actual_qos(), sub->get_actual_qos());
if (check_result.compatibility == rclcpp::QoSCompatibility::Error) {
return false;
}
return true;
}

9.3 数据结构

成员 含义
publishers_ pub_id → weak_ptr PublisherBase
subscriptions_ sub_id → weak_ptr SubscriptionIntraProcessBase
pub_to_subs_ pub_id → {take_shared_subscriptions, take_ownership_subscriptions}

两种 intra subscription 策略:共享指针(多订阅者共享同一份数据)与 所有权转移(unique_ptr 零拷贝)。


10. Service / Client / Timer / Waitable

实体 创建入口 Executor 执行
Service Node::create_service() execute_service → take request → 用户回调 → send response
Client Node::create_client() execute_client → 处理 pending response
Timer Node::create_wall_timer() / create_timer() execute_timertimer->execute_callback()
Waitable Node::create_waitable() 或 action client 内部 waitable->execute(data)

Timer 基于 rcl timer + guard condition:到期时在 wait set 中触发,优先级高于 subscription(get_next_ready_executable_from_map 先查 timer)。

Waitable 是可扩展钩子:rclcpp_action::Client 实现 Waitable 接口,将 action 相关 waitable 实体纳入 Executor 调度,而无需独立 spin 线程。


11. 参数系统

11.1 NodeParameters

NodeParameters 负责:

  • declare_parameter() / get_parameter() / set_parameter()
  • 参数覆盖(CLI、--params-file、节点级 overrides)
  • on_parameters_set 回调链
  • 可选启动 ParameterService/parameter_events 发布者

11.2 ParameterService(标准服务)

1
2
3
4
5
6
7
8
9
10
get_parameters_service_ = create_service<rcl_interfaces::srv::GetParameters>(
node_base, node_services,
node_name + "/" + parameter_service_names::get_parameters,
[node_params](..., Request request, Response response)
{
auto parameters = node_params->get_parameters(request->names);
for (const auto & param : parameters) {
response->values.push_back(param.get_value_message());
}
}, ...);

注册的服务(与 rcl_interfaces 分析 对应):

服务名 类型
get_parameters rcl_interfaces/srv/GetParameters
get_parameter_types GetParameterTypes
set_parameters SetParameters
set_parameters_atomically SetParametersAtomically
describe_parameters DescribeParameters
list_parameters ListParameters

11.3 ParameterClient

远程节点参数访问的客户端封装,内部创建对应 service client,供 ros2 param 等工具链使用。


12. 时间与 Clock

12.1 TimeSource

TimeSourcetime_source.cpp)订阅全局 /clockrosgraph_msgs/msg/Clock):

  • 收到 sim time 时启用 ros_time_active_,更新所有关联 Clock
  • use_sim_time 参数联动(经 NodeTimeSource wiring)
  • 支持独立 clock 线程(use_clock_thread NodeOption)

12.2 Clock 类型

类型 说明
RCL_SYSTEM_TIME 系统 wall clock
RCL_ROS_TIME 仿真时间(由 /clock 驱动)
RCL_STEADY_TIME 单调时钟

Timer 可选择 clock:create_timer(clock, period, callback) vs create_wall_timer()


13. QoS

rclcpp::QoS 封装 rmw_qos_profile_t,提供流式 API:

1
2
3
rclcpp::QoS(10).reliable().transient_local();
rclcpp::SensorDataQoS();
rclcpp::ParametersQoS();

13.1 qos_overrides

节点构造时通过 declare_qos_parameters() 暴露 qos_overrides.<topic>.<policy> 参数,允许运行时覆盖 depth/reliability/durability/history(见 node.cppget_parameter_events_qos)。

13.2 兼容性检查

qos_check_compatible() 在 intra-process 匹配与 rclcpp::QoS 警告中使用,对应 RMW 的 rmw_qos_profile_check_compatible


14. rclcpp_action

依赖 rcl_action C 库,提供类型安全的 C++ Action API。

14.1 主要类型

类型 职责
rclcpp_action::Client<ActionT> 发送 goal、cancel、接收 feedback/result
rclcpp_action::Server<ActionT> 接受 goal、执行、发布 feedback/result
ClientGoalHandle / ServerGoalHandle 单个 goal 的生命周期与状态
create_client() / create_server() 工厂函数

14.2 与 Executor 集成

Action client/server 内部创建多个 pub/sub/service 及 Waitable 实体,注册到 callback group 后由 Executor 统一调度,无需用户手动 spin action 专用线程。

14.3 依赖链

1
2
3
rclcpp_action → rclcpp → rcl
→ rcl_action → rcl
→ action_msgs(UUID 等)

15. rclcpp_components

15.1 动机

Composable Node 允许在 单进程 内加载多个节点组件,配合 intra-process 减少序列化与 DDS hop。

15.2 ComponentManager

1
2
3
4
5
6
7
8
ComponentManager::ComponentManager(...)
: Node(std::move(node_name), node_options),
executor_(executor)
{
loadNode_srv_ = create_service<LoadNode>("~/_container/load_node", ...);
unloadNode_srv_ = create_service<UnloadNode>("~/_container/unload_node", ...);
listNodes_srv_ = create_service<ListNodes>("~/_container/list_nodes", ...);
}
服务 接口包
~/_container/load_node composition_interfaces/srv/LoadNode
~/_container/unload_node UnloadNode
~/_container/list_nodes ListNodes

15.3 加载流程

  1. ament_index 查找包内注册的组件资源(rclcpp_components_register_nodes CMake 宏)
  2. class_loader::ClassLoader 动态加载 .so
  3. NodeFactory 实例化组件(RCLCPP_COMPONENTS_REGISTER_NODE 宏)
  4. executor->add_node() 将新节点纳入调度

15.4 容器可执行文件

可执行文件 Executor
component_container SingleThreadedExecutor
component_container_mt MultiThreadedExecutor
component_container_isolated 每组件独立 Executor

16. rclcpp_lifecycle

16.1 LifecycleNode

继承/组合与 Node 相同的 interface,额外实现 LifecycleNodeInterface

主状态 说明
Unconfigured 初始
Inactive 已 configure,未 activate
Active 正常运行
Finalized 已 cleanup/shutdown

转移:configureactivatedeactivatecleanupshutdown 等,底层调用 rcl_lifecycle

16.2 LifecyclePublisher

仅在 Active 状态下真正 publish;Inactive 时 publish 被忽略或缓存(取决于配置),便于安全切换。

16.3 与 Nav2 / 工业场景

生命周期节点是托管节点(managed node)模式的基础,配合 lifecycle_manager 统一拉起/关闭。


17. 关键数据路径

17.1 订阅回调端到端

User callbackExecutorrcl wait setrclDDS / RMWUser callbackExecutorrcl wait setrclDDS / RMW数据到达 subscriptionsubscription 就绪rcl_wait()返回 readyget_next_ready_executable()rcl_take / take_loanedmessagesubscription->handle_message()can_be_taken_from = true

17.2 发布端到端(含 intra-process)

Publisher::publish()IntraProcessManagerIntra subscription callbacksrcl_publishDDS

17.3 进程启动典型顺序

1
2
3
4
5
6
7
8
9
10
11
main()
→ rclcpp::init(argc, argv)
→ Context::init → rcl_init
→ auto node = std::make_shared<Node>(...)
→ NodeBase → rcl_node_init
→ NodeParameters → 声明参数 / 启动 ParameterService
→ NodeTimeSource → 订阅 /clock
→ rclcpp::spin(node)
→ SingleThreadedExecutor::add_node
→ spin loop (wait + execute)
→ rclcpp::shutdown()

18. 目录与模块索引

18.1 include/rclcpp/ 主要头文件

模块 头文件
节点 node.hpp, node_options.hpp
执行器 executor.hpp, executors/*.hpp, any_executable.hpp
通信 publisher.hpp, subscription.hpp, service.hpp, client.hpp, timer.hpp
并发 callback_group.hpp, waitable.hpp
实验特性 experimental/intra_process_manager.hpp
参数 parameter.hpp, parameter_service.hpp, parameter_client.hpp
时间 clock.hpp, time_source.hpp, duration.hpp
QoS qos.hpp, qos_event.hpp
上下文 context.hpp, utilities.hpp
内存 memory_strategy.hpp, message_memory_strategy.hpp

18.2 src/rclcpp/ 核心实现

文件 行数 职责
executor.cpp 947 wait/execute/spin 核心
node.cpp 607 Node 构造、create_* 委托
time_source.cpp 554 /clock 与 sim time
parameter_client.cpp 545 远程参数
context.cpp 527 Context 生命周期
subscription_base.cpp 459 take/handle 基础设施
intra_process_manager.cpp 230 进程内路由
parameter_service.cpp 158 标准参数服务

19. 与 rcl / rcl_interfaces 对照

功能 rcl rclcpp
init/shutdown rcl_init Context::init, rclcpp::init
wait rcl_wait, rcl_wait_set_t Executor::wait_for_work
publish rcl_publish PublisherBase::do_inter_process_publish
take rcl_take SubscriptionBase::take_type_erased
参数服务 ParameterService + rcl_interfaces srv
Executor 完整调度栈
intra-process IntraProcessManager

20. 调试与追踪

  • 日志RCLCPP_* 宏 → rcutils logging;节点 logger 名来自 NodeLogging
  • 追踪TRACEPOINT(rclcpp_executor_*) 等,依赖 tracetools
  • Topic 统计libstatistics_collector 可选编译,经 subscription 回调统计
  • 常见问题
    • 回调不触发 → 检查 Executor 是否 add_node、callback group 是否注册
    • 死锁 → MutuallyExclusive group 内回调再次 spin 或阻塞同 group 实体
    • intra-process 不生效 → QoS durability 非 Volatile、topic 名/QoS 不匹配

21. 推荐阅读顺序

  1. utilities.cpp + context.cpp — 理解 init/shutdown 与默认 context
  2. node.cpp + node_interfaces/node_topics.cpp — Node 如何创建 pub/sub
  3. executors/single_threaded_executor.cpp + executor.cpp — spin / wait / execute 全流程
  4. callback_group.hpp + executor.cpp(get_next_ready_executable_from_map) — 并发语义
  5. publisher.hpp + intra_process_manager.cpp — 发布与进程内优化
  6. parameter_service.cpp + node_interfaces/node_parameters.cpp — 参数栈
  7. time_source.cpp — sim time
  8. rclcpp_action/client.hpp — action 如何挂到 Executor
  9. rclcpp_components/component_manager.cpp — 动态组件
  10. rclcpp_lifecycle/lifecycle_node.hpp — 生命周期
  11. 对照 examples/rclcpp_*rcl 源码分析 下层行为

22. 小结

rclcpp 是 ROS 2 C++ 应用的主 API 层,核心模式为:

  • Node + node_interfaces 创建与管理通信实体
  • Executor 通过 rcl_wait 驱动 callback_group 内的回调
  • IntraProcessManager 在同进程内绕过 DDS 实现低延迟数据路径
  • ParameterService / TimeSource 等将 ROS 2 系统服务集成进节点生命周期

掌握 Executor + callback_group 的交互,是理解 ROS 2 C++ 并发模型的关键;排查通信问题时,应沿 publish/take → rcl → rmw 链向下追踪,并区分 inter-process 与 intra-process 路径。

文章互动

阅读 --

留言

0 条留言

正在加载留言…