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  # 添加这一行
)
相关推荐
诺伦1 小时前
RiseClaw玄策:GEO优化工程实战,从零搭建生成式引擎优化体系
人工智能·chatgpt
星禾元亨1 小时前
企业 AI 落地 5 步路线图:诊断、企业知识库与 GEO 获客的工程化实施步骤
大数据·人工智能·自动化·创业创新
苏打水com1 小时前
内容合规红线:大模型生成内容,哪些能做哪些会犯法?
人工智能·安全·大模型
南京兴帝文化传媒有限公司1 小时前
本地生活服务商户GEO优化技术实践:AI大模型收录机制与地图POI权重算法拆解
大数据·人工智能·算法·生活·geo优化实操·csdn运营技巧·ai内容收录
2601_962293531 小时前
人工智能 & 神经网络完整入门路线(零基础可走,分阶段)
人工智能·python·深度学习·神经网络·机器学习
平原20181 小时前
AI 鞋履设计升级:一张主图与多角度详情图的生成流程
人工智能
人工智能时代 准备好了吗1 小时前
品牌更名后,旧名称与新名称的AI表现如何连续观察?
人工智能
慧一居士1 小时前
QoderWork 和 QoderWake 区别和使用场景对比
人工智能
余槐i1 小时前
使用Ollama本地部署和测试Kimi、GLM等多款大语言模型实战
人工智能·语言模型·自然语言处理·大模型·api
拓海SEO外贸2 小时前
关键词聚类(Keyword Clustering)怎么做
人工智能·机器学习·聚类