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  # 添加这一行
)
相关推荐
数字化顾问3 分钟前
(138页PPT)流程体系的建设优化与运营(附下载方式)
大数据·运维·人工智能
知了学历孙老师20 分钟前
非全硕士上课怎么安排:周末班、集中班还是网络班
人工智能·考研·福建成考
ksueh31 分钟前
AI网文创作软件实测:蛙趣拼文是我筛完留下的一款
人工智能·ai写作·ai工具·ai写小说
patton_smile31 分钟前
配电网电压预测 GNN 模型优化
深度学习·配电网·图神经网络·电压预测
凯哥Java34 分钟前
写代码怎么避免逻辑漏洞?
java·开发语言·人工智能·自动化
是翎44 分钟前
AI开发工程师面试指南
人工智能·面试·职场和发展
水如烟1 小时前
孤能子视角:AI→SI——一次关系场的剧烈重组
人工智能
Ivanqhz1 小时前
层归一化、残差、前馈网络与激活函数简述
服务器·数据库·人工智能·深度学习·算法
Ai-_Man1 小时前
您您这可以把Dola的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。用AI导出鸭,答案是可以的
开发语言·前端·人工智能·小程序
海宇服务1 小时前
零信任架构实战:基于海宇运营商近3个月欠费次数构建自动化履约能力评估管线
运维·人工智能·架构·自动化