moveit2_servo cmakelist 拆解


一、文件整体结构

text

复制代码
cmake_minimum_required(VERSION 3.22)  ← 指定最低 CMake 版本
project(moveit_servo)                  ← 项目名称

【变量定义区】→ 定义所有目标名称
【依赖查找区】→ 查找所有依赖包
【库构建区】  → 构建核心库
【组件节点区】→ 构建 ROS2 组件节点
【可执行文件区】→ 构建独立节点
【安装配置区】→ 安装到工作空间
【测试区】    → 单元测试和集成测试

二、变量定义区(第3-25行)

cmake

复制代码
# 库名称
set(SERVO_LIB_NAME moveit_servo_lib)           # 核心库
set(SERVO_PARAM_LIB_NAME ${SERVO_LIB_NAME}_parameters)  # 参数库
set(POSE_TRACKING pose_tracking)                # 位姿追踪库

# 组件节点(共享库)
set(SERVO_COMPONENT_NODE servo_node)            # 主服务节点
set(SERVO_CONTROLLER_INPUT servo_controller_input) # 手柄输入节点

# 可执行节点
set(SERVO_NODE_MAIN_NAME servo_node_main)       # 主节点入口
set(POSE_TRACKING_DEMO_NAME servo_pose_tracking_demo) # 位姿追踪演示
set(FAKE_SERVO_CMDS_NAME fake_command_publisher) # 模拟命令发布器

设计意图:

  • 使用变量集中管理所有目标名称,便于维护

  • 避免在多处硬编码相同的字符串,降低拼写错误风险

  • 当需要重命名时,只需修改变量定义处


三、依赖查找区(第32-53行)

3.1 引入 MoveIt 公共配置

cmake

复制代码
find_package(moveit_common REQUIRED)
moveit_package()
  • moveit_common 是 MoveIt 的公共 CMake 模块

  • moveit_package() 是自定义宏,设置 MoveIt 包的通用编译选项

3.2 定义并查找所有依赖

cmake

复制代码
set(THIS_PACKAGE_INCLUDE_DEPENDS
  control_msgs          # 控制消息
  control_toolbox       # 控制工具
  geometry_msgs         # 几何消息 (Twist, Pose)
  moveit_core           # MoveIt 核心库
  moveit_msgs           # MoveIt 消息
  moveit_ros_planning   # MoveIt 规划相关
  pluginlib             # 插件加载库
  rclcpp                # ROS2 C++客户端库
  rclcpp_components     # 组件节点支持
  sensor_msgs           # 传感器消息
  std_msgs              # 标准消息
  std_srvs              # 标准服务
  tf2_eigen             # TF2与Eigen转换
  trajectory_msgs       # 轨迹消息
)

# 循环查找每个依赖
foreach(Dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS})
  find_package(${Dependency} REQUIRED)
endforeach()

# 额外的依赖
find_package(eigen3_cmake_module REQUIRED)
find_package(Eigen3 REQUIRED)

为什么要分开写?

  • 集中管理依赖列表,方便增删

  • 避免重复的 find_package 调用

  • ament_target_dependencies 在后续会一次性链接所有这些依赖


四、库构建区(第59-87行)

4.1 参数库 (SERVO_PARAM_LIB_NAME)

cmake

复制代码
add_library(${SERVO_PARAM_LIB_NAME} SHARED
  src/servo_parameters.cpp
  src/parameter_descriptor_builder.cpp
)
ament_target_dependencies(${SERVO_PARAM_LIB_NAME} ${THIS_PACKAGE_INCLUDE_DEPENDS})
  • 负责加载和管理 Servo 的配置参数

  • 独立出来以便其他节点也能加载相同的参数

4.2 核心库 (SERVO_LIB_NAME)

cmake

复制代码
add_library(${SERVO_LIB_NAME} SHARED
  src/collision_check.cpp    # 碰撞检测
  src/enforce_limits.cpp     # 限位约束
  src/servo.cpp              # 核心逻辑
  src/servo_calcs.cpp        # 运动学计算
  src/utilities.cpp          # 工具函数
)
target_link_libraries(${SERVO_LIB_NAME} ${SERVO_PARAM_LIB_NAME})  # 链接参数库
  • 核心计算库,不依赖 ROS2 通信

  • 可以独立测试和复用

4.3 位姿追踪库 (POSE_TRACKING)

cmake

复制代码
add_library(${POSE_TRACKING} SHARED src/pose_tracking.cpp)
target_link_libraries(${POSE_TRACKING} ${SERVO_LIB_NAME})
  • 实现位姿追踪功能

  • 链接到核心库,复用计算能力

依赖传递关系

text

复制代码
SERVO_PARAM_LIB_NAME (参数)
        ↓
SERVO_LIB_NAME (核心计算)
        ↓
POSE_TRACKING (位姿追踪)

五、组件节点区(第89-99行)

ROS2 组件节点是可动态加载的共享库,可以在运行时加载到容器进程中。

5.1 主 Servo 节点

cmake

复制代码
add_library(${SERVO_COMPONENT_NODE} SHARED src/servo_node.cpp)
target_link_libraries(${SERVO_COMPONENT_NODE} ${SERVO_LIB_NAME})
rclcpp_components_register_nodes(${SERVO_COMPONENT_NODE} "moveit_servo::ServoNode")
  • rclcpp_components_register_nodes 将节点注册为组件

  • 可以在 launch 文件中用 ComposableNode 加载

5.2 手柄输入节点

cmake

复制代码
add_library(${SERVO_CONTROLLER_INPUT} SHARED src/teleop_demo/joystick_servo_example.cpp)
rclcpp_components_register_nodes(${SERVO_CONTROLLER_INPUT} "moveit_servo::JoyToServoPub")
  • 处理游戏手柄输入

  • 这里就是之前讨论的 joy 包依赖处


六、可执行文件区(第101-119行)

6.1 主节点入口

cmake

复制代码
add_executable(${SERVO_NODE_MAIN_NAME} src/servo_node_main.cpp)
target_link_libraries(${SERVO_NODE_MAIN_NAME} ${SERVO_COMPONENT_NODE})
  • 这是一个独立的可执行文件

  • 直接链接组件库,本质上和加载组件效果相同

6.2 演示程序

cmake

复制代码
add_executable(${POSE_TRACKING_DEMO_NAME} src/cpp_interface_demo/pose_tracking_demo.cpp)
target_link_libraries(${POSE_TRACKING_DEMO_NAME} ${POSE_TRACKING})
  • C++接口演示,不依赖 ROS2 通信

6.3 模拟命令发布器

cmake

复制代码
add_executable(${FAKE_SERVO_CMDS_NAME} test/publish_fake_jog_commands.cpp)
ament_target_dependencies(${FAKE_SERVO_CMDS_NAME}
  rclcpp
  geometry_msgs
  std_srvs
)
  • 仅依赖少量包,用于测试

  • 注意这里没有 列出 THIS_PACKAGE_INCLUDE_DEPENDS,而是单独指定


七、安装配置区(第121-149行)

7.1 安装库文件

cmake

复制代码
install(
  TARGETS
    ${SERVO_LIB_NAME}
    ${SERVO_LIB_NAME}_parameters
    ${POSE_TRACKING}
    ${SERVO_COMPONENT_NODE}
    ${SERVO_CONTROLLER_INPUT}
  EXPORT export_${PROJECT_NAME}  # 导出用于其他包
  LIBRARY DESTINATION lib        # 安装到 lib/
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

7.2 安装可执行文件

cmake

复制代码
install(
  TARGETS
    ${SERVO_NODE_MAIN_NAME}
    ${CPP_DEMO_NAME}        # 注意:这个变量未在开头定义!
    ${POSE_TRACKING_DEMO_NAME}
    ${FAKE_SERVO_CMDS_NAME}
  RUNTIME DESTINATION lib/${PROJECT_NAME}  # 安装到 lib/moveit_servo/
)

⚠️ 注意 :${CPP_DEMO_NAME} 变量在开头没有定义,这是一个 CMake 警告,可能是开发者忘记删除。

7.3 安装目录

cmake

复制代码
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
install(DIRECTORY config DESTINATION share/${PROJECT_NAME})
  • 头文件:include/ → install/include/moveit_servo/

  • launch 文件:launch/ → install/share/moveit_servo/launch/

  • config 文件:config/ → install/share/moveit_servo/config/

7.4 导出配置

cmake

复制代码
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
  • 其他包可以通过 find_package(moveit_servo) 找到这个包

  • 自动传递依赖关系


八、测试区(第151-194行)

8.1 禁用部分 Lint 测试

cmake

复制代码
set(ament_cmake_copyright_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)
set(ament_cmake_flake8_FOUND TRUE)
set(ament_cmake_uncrustify_FOUND TRUE)
  • 强制让这些测试通过(即使代码不完美)

  • 常见于大型项目,避免测试阻塞 CI

8.2 三种测试类型

测试名 类型 说明
test_servo_integration 集成测试 测试 Servo 完整功能
test_servo_collision 集成测试 测试碰撞检测
test_servo_pose_tracking 集成测试 测试位姿追踪
servo_calcs_unit_tests 单元测试 测试计算函数

cmake

复制代码
# 集成测试示例
ament_add_gtest_executable(test_servo_integration
    test/test_servo_interface.cpp
    test/servo_launch_test_common.hpp
)
target_link_libraries(test_servo_integration ${SERVO_PARAM_LIB_NAME})
add_ros_test(test/launch/test_servo_integration.test.py TIMEOUT 120 ...)
  • add_ros_test 是 ROS2 扩展,可以启动 ROS 节点进行测试

  • TIMEOUT 120 限制测试最长运行时间


九、设计模式总结

设计模式 体现
分层架构 核心库 → 组件节点 → 可执行文件
组件化 使用 rclcpp_components 支持动态加载
依赖管理 集中定义 THIS_PACKAGE_INCLUDE_DEPENDS
可测试性 核心库与ROS解耦,支持纯单元测试
可复用性 导出 export_${PROJECT_NAME} 供其他包使用

十、潜在问题

  1. ${CPP_DEMO_NAME} 未定义:在 install 中使用了未声明的变量

  2. joy 包未声明 :虽然 joystick_servo_example.cpp 依赖 /joy 话题,但 CMake 中未显式声明(因为话题不强制编译依赖)

改进建议:

cmake

复制代码
# 在依赖列表中添加 joy(如果需要编译依赖)
set(THIS_PACKAGE_INCLUDE_DEPENDS
  ...
  joy  # 添加这一行
)
相关推荐
Liaiyang661 分钟前
空圈容错视角 :AI 几乎就是一个“天然的小空圈”
人工智能·大模型·1024程序员节·认知科学·ai幻觉·自我意识·空圈容错理论
WenGyyyL3 分钟前
从零理解强化学习:为什么 AI 需要 Advantage,而不只是 Reward?
人工智能·python·深度学习·机器学习·nlp
程序猿阿森7 分钟前
RAG 落地实践:离线索引 + 在线 FAQ 与混合检索全流程拆解
数据库·人工智能·rag
惊鸿一博11 分钟前
目标检测指标评估_mAP(mean Average Precision平均精度均值)计算方法
人工智能·目标检测·均值算法
Shulex15 分钟前
备战黑五:如何用 AI 智能客服守住独立站转化率与退换货成本?
人工智能·智能客服·跨境电商
Navicat中国17 分钟前
如何将 Navicat 的 AI 助手连接到本地 LLM
数据库·人工智能·navicat·本地llm
网易易盾19 分钟前
广告合规系统如何选?检出能力、接入成本与运营闭环评估
大数据·人工智能
深圳市益普科技有限公司20 分钟前
Micro-LED量产线MES,中试线转量产要不要重做一遍
人工智能
GitCode官方21 分钟前
稀缺真机|AtomGit × 启元机器人具身智能原创内容征文活动
机器人·开源·具身智能·atomgit·启元