使用Deepseek 编译ros2 rolling 的接口和节点 ----综合案例

问DeepSeek : ros2  rolling  使用python 编写一个 pkg_robot_control   和 pkg_robot_interfaces 。pkg_robot_control内有自己编写的python module实现PID

 

下面是一个完整的ROS2 Rolling项目,包含两个包:pkg_robot_interfaces(定义消息/服务)和pkg_robot_control(实现PID控制器)。请按照以下步骤操作:


1. 创建接口包

bash
 
ros2 pkg create pkg_robot_interfaces \
  --build-type ament_cmake \
  --dependencies std_msgs

添加消息和服务定义:

文件:pkg_robot_interfaces/msg/PIDParams.msg

python
 
float64 kp
float64 ki
float64 kd
float64 set_point

文件:pkg_robot_interfaces/srv/SetPID.srv

python
 
float64 kp
float64 ki
float64 kd
float64 set_point
---
bool success

修改 pkg_robot_interfaces/CMakeLists.txt

find_package 后添加:

cmake
 
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/PIDParams.msg"
  "srv/SetPID.srv"
)

修改 pkg_robot_interfaces/package.xml

添加:

xml
 
 
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>

2. 创建控制包

注意自己编写的接口包也作为依赖项。

bash
 
ros2 pkg create pkg_robot_control \
  --build-type ament_python \
  --dependencies rclpy pkg_robot_interfaces std_msgs

实现PID模块

文件:pkg_robot_control/pkg_robot_control/pid_controller.py

python
 
class PIDController:
    def __init__(self, kp=0.0, ki=0.0, kd=0.0, set_point=0.0):
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.set_point = set_point
        self.prev_error = 0.0
        self.integral = 0.0
        
    def update(self, current_value, dt):
        error = self.set_point - current_value
        self.integral += error * dt
        derivative = (error - self.prev_error) / dt
        
        output = (self.kp * error) + (self.ki * self.integral) + (self.kd * derivative)
        
        self.prev_error = error
        return output
    
    def set_params(self, kp, ki, kd, set_point):
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.set_point = set_point
        self.integral = 0.0  # Reset integral on parameter change
        self.prev_error = 0.0

实现ROS节点

文件:pkg_robot_control/pkg_robot_control/robot_pid_node.py

python
 
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float64
from pkg_robot_interfaces.msg import PIDParams
from pkg_robot_interfaces.srv import SetPID
from .pid_controller import PIDController

class RobotPIDNode(Node):
    def __init__(self):
        super().__init__('robot_pid_node')
        
        # 初始化PID参数(可从参数服务器加载)
        self.declare_parameters(
            namespace='',
            parameters=[
                ('kp', 1.0),
                ('ki', 0.0),
                ('kd', 0.1),
                ('set_point', 5.0)
            ]
        )
        
        # 创建PID控制器实例
        self.pid = PIDController(
            kp=self.get_parameter('kp').value,
            ki=self.get_parameter('ki').value,
            kd=self.get_parameter('kd').value,
            set_point=self.get_parameter('set_point').value
        )
        
        # 创建话题发布者(控制输出)
        self.control_pub = self.create_publisher(Float64, 'control_output', 10)
        
        # 创建话题订阅者(模拟传感器输入)
        self.sensor_sub = self.create_subscription(
            Float64,
            'sensor_input',
            self.sensor_callback,
            10
        )
        
        # 创建服务(动态修改PID参数)
        self.srv = self.create_service(
            SetPID, 
            'set_pid_params', 
            self.set_pid_callback
        )
        
        # 创建定时器(定期发布PID参数)
        self.timer = self.create_timer(1.0, self.publish_pid_params)
        self.params_pub = self.create_publisher(PIDParams, 'pid_params', 10)
        
        self.get_logger().info("PID节点已启动")
    
    def sensor_callback(self, msg):
        # 模拟控制周期(0.1秒)
        control_value = self.pid.update(msg.data, dt=0.1)
        
        # 发布控制指令
        out_msg = Float64()
        out_msg.data = control_value
        self.control_pub.publish(out_msg)
    
    def set_pid_callback(self, request, response):
        self.pid.set_params(
            request.kp,
            request.ki,
            request.kd,
            request.set_point
        )
        response.success = True
        self.get_logger().info(f"PID参数更新: Kp={request.kp}, Ki={request.ki}, Kd={request.kd}, SP={request.set_point}")
        return response
    
    def publish_pid_params(self):
        msg = PIDParams()
        msg.kp = self.pid.kp
        msg.ki = self.pid.ki
        msg.kd = self.pid.kd
        msg.set_point = self.pid.set_point
        self.params_pub.publish(msg)

def main(args=None):
    rclpy.init(args=args)
    node = RobotPIDNode()
    rclpy.spin(node)
    rclpy.shutdown()

if __name__ == '__main__':
    main()

修改 pkg_robot_control/setup.py

确保包含节点入口:

python
 
entry_points={
    'console_scripts': [
        'robot_pid_node = pkg_robot_control.robot_pid_node:main',
    ],
},

3. 编译与测试

bash
 
# 在工作空间根目录
colcon build --packages-select pkg_robot_interfaces pkg_robot_control
source install/setup.bash

测试节点

bash
 
# 终端1: 运行PID节点
ros2 run pkg_robot_control robot_pid_node

# 终端2: 发布模拟传感器数据
ros2 topic pub /sensor_input std_msgs/msg/Float64 "data: 3.0" -r 10

# 终端3: 查看控制输出
ros2 topic echo /control_output

# 终端4: 动态修改PID参数
ros2 service call /set_pid_params pkg_robot_interfaces/srv/SetPID \
  "{kp: 2.0, ki: 0.5, kd: 0.2, set_point: 10.0}"

项目结构

text
 
ros2_ws/
  src/
    pkg_robot_interfaces/
      msg/
        PIDParams.msg
      srv/
        SetPID.srv
      CMakeLists.txt
      package.xml
      
    pkg_robot_control/
      pkg_robot_control/
        pid_controller.py
        robot_pid_node.py
      package.xml
      setup.py

这个实现提供了:

  1. 自定义消息/服务接口

  2. 可重用的PID模块

  3. 动态参数调整服务

  4. 参数服务器集成

  5. 实时控制循环

PID控制器包含抗积分饱和和参数重置功能,适用于机器人控制场景。您可以根据实际需求扩展传感器输入接口和执行器输出协议。

 

问题:ros2 rolling 使用python 编写一个 pkg_robot_control 和 pkg_robot_interfaces 。pkg_robot_control内有自己编写的python包,将PID、滤波功能整合到Python包中。有包结构说明,代码有注释,创建命令行,调试命令等。

 

项目src内的文件树

├── pkg_robot_control
│   ├── launch
│   │   └── controller.launch.py  #编写
│   ├── package.xml#修改
│   ├── pkg_robot_control
│   │   ├── control
│   │   │   ├── controllers.py#编写
│   │   │   ├── filters.py#编写
│   │   │   └── __init__.py#创建
│   │   ├── controller_node.py#编写
│   │   └── __init__.py
│   ├── resource
│   │   └── pkg_robot_control
│   ├── setup.cfg
│   ├── setup.py#修改
│   └── test
│       ├── test_copyright.py
│       ├── test_flake8.py
│       ├── test_pep257.py
│       └── test_xmllint.py
└── pkg_robot_interfaces
    ├── CMakeLists.txt#修改
    ├── include
    │   └── pkg_robot_interfaces
    ├── msg
    │   ├── ControlCommand.msg #编写
    │   └── RobotState.msg #编写
    ├── package.xml #修改
    ├── src
    └── srv

ros2_ws 源代码和说明
 https://files.cnblogs.com/files/blogs/760881/ros2_ws.zip?t=1750846121&download=true

 

程序代码  pkg_robot_control/setup.py

from setuptools import find_packages, setup
import os #add
from glob import glob #add

package_name = 'pkg_robot_control'

setup(
    name=package_name,
    version='0.0.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        # ('share/ament_index/resource_index/packages',
        #     ['resource/' + package_name]),
        # ('share/' + package_name, ['package.xml']),
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name, 'launch'), 
         glob('launch/*.launch.py')),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='ubuntu',
    maintainer_email='ubuntu@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'controller_node = pkg_robot_control.controller_node:main',#add
        ],
    },
)
View Code
下面是对这个 setup.py 文件的详细解释,包括每个部分的作用和配置选项的含义:
python

from setuptools import find_packages, setup
import os  # 导入操作系统模块,用于路径操作
from glob import glob  # 导入glob模块,用于文件匹配

# 定义包名
package_name = 'pkg_robot_control'

# 调用setup函数配置包
setup(
    # 包的基本信息
    name=package_name,  # 包名称(必须)
    version='0.0.0',  # 包版本(必须)
    
    # 包包含的Python模块
    packages=find_packages(exclude=['test']),  # 自动查找所有包,排除test目录
    
    # 数据文件(非Python代码文件)
    data_files=[
        # ROS 2包索引文件
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        
        # 包XML描述文件
        ('share/' + package_name, ['package.xml']),
        
        # 启动文件(使用glob匹配所有.launch.py文件)
        (os.path.join('share', package_name, 'launch'), 
         glob('launch/*.launch.py')),
    ],
    
    # 安装依赖
    install_requires=['setuptools'],  # 必须的Python依赖
    
    # 其他配置
    zip_safe=True,  # 是否支持zip安全安装(通常为True)
    
    # 维护者信息
    maintainer='ubuntu',  # 维护者名称
    maintainer_email='ubuntu@todo.todo',  # 维护者邮箱
    
    # 包描述信息
    description='TODO: Package description',  # 包的简短描述
    license='TODO: License declaration',  # 许可证声明
    
    # 测试依赖
    tests_require=['pytest'],  # 运行测试需要的依赖
    
    # 入口点(可执行脚本)
    entry_points={
        'console_scripts': [
            # 定义名为'controller_node'的可执行命令
            # 指向pkg_robot_control.controller_node模块的main函数
            'controller_node = pkg_robot_control.controller_node:main',
        ],
    },
)

详细解释
1. 导入模块
python

from setuptools import find_packages, setup
import os
from glob import glob

    find_packages: 自动查找Python包的工具

    setup: 主要的配置函数

    os: 用于操作系统路径操作

    glob: 用于文件路径模式匹配

2. 包名定义
python

package_name = 'pkg_robot_control'

定义ROS 2包的名称,必须与package.xml中的<name>标签一致
3. setup() 函数配置
a. 基本元数据
python

name=package_name,  # 包名(必须)
version='0.0.0',  # 版本号(必须)

b. 包包含内容
python

packages=find_packages(exclude=['test']),

    find_packages(): 自动查找所有Python包

    exclude=['test']: 排除名为'test'的目录(通常用于测试)

c. 数据文件配置
python

data_files=[
    # ROS 2包索引资源文件
    ('share/ament_index/resource_index/packages',
        ['resource/' + package_name]),
    
    # 包XML描述文件
    ('share/' + package_name, ['package.xml']),
    
    # 启动文件
    (os.path.join('share', package_name, 'launch'), 
     glob('launch/*.launch.py')),
],

    第一项: 创建ROS 2包索引资源文件,路径为share/ament_index/resource_index/packages/<package_name>

    第二项: 将package.xml复制到share/<package_name>/目录

    第三项: 将所有.launch.py文件从launch/目录复制到share/<package_name>/launch/目录

        os.path.join('share', package_name, 'launch'): 目标路径

        glob('launch/*.launch.py'): 源文件匹配模式

d. 依赖和配置
python

install_requires=['setuptools'],  # 安装依赖
zip_safe=True,  # 是否支持zip压缩安装

e. 维护者信息
python

maintainer='ubuntu', 
maintainer_email='ubuntu@todo.todo',

这些信息应与package.xml中的一致
f. 描述信息
python

description='TODO: Package description', 
license='TODO: License declaration',

需要替换为实际描述和许可证声明
g. 测试依赖
python

tests_require=['pytest'], 

定义运行测试时需要的依赖
h. 入口点(关键配置)
python

entry_points={
    'console_scripts': [
        'controller_node = pkg_robot_control.controller_node:main',
    ],
},

    console_scripts: 定义可执行命令行工具

    'controller_node': 用户将执行的命令名

    'pkg_robot_control.controller_node:main': 指向Python模块和函数

        pkg_robot_control: 包名

        controller_node: 模块文件名(不带.py)

        main: 该模块中的函数名

针对ROS 2的特别说明

    与package.xml的关系:

        setup.py中的name和version应与package.xml一致

        依赖关系需要在package.xml中声明

        setup.py主要处理Python特定的构建和安装

    ROS 2 Python包结构:
    text

pkg_robot_control/
├── pkg_robot_control/  # Python包目录
│   ├── __init__.py     # 包初始化文件
│   ├── controller_node.py  # 节点实现
│   ├── controllers.py  # 控制器实现
│   └── filters.py      # 滤波器实现
├── launch/             # 启动文件目录
│   └── controller.launch.py
├── package.xml         # ROS包描述文件
└── setup.py            # Python包构建脚本

构建过程:

    colcon build会调用setup.py安装Python包

    可执行脚本会被安装到install/<package_name>/lib/<package_name>/

    数据文件会被安装到install/<package_name>/share/<package_name>/
解读

 

程序代码  pkg_robot_control/package.xml 

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>pkg_robot_control</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
  <license>TODO: License declaration</license>
  
  <!--add-->
  <depend>rclpy</depend>
  <depend>std_msgs</depend>
  <depend>geometry_msgs</depend>
  <depend>pkg_robot_interfaces</depend>
  <exec_depend>launch</exec_depend>
  <!--add end -->

  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>ament_xmllint</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>
源码
下面是对这个 package.xml 文件的详细解释,包括每个元素的作用和配置含义:
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <!-- 包的基本信息 -->
  <name>pkg_robot_control</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
  <license>TODO: License declaration</license>
  
  <!-- 依赖关系 -->
  <depend>rclpy</depend>
  <depend>std_msgs</depend>
  <depend>geometry_msgs</depend>
  <depend>pkg_robot_interfaces</depend>
  <exec_depend>launch</exec_depend>

  <!-- 测试依赖 -->
  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>ament_xmllint</test_depend>
  <test_depend>python3-pytest</test_depend>

  <!-- 导出设置 -->
  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

详细解释
1. 文档声明
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>

    <?xml version="1.0"?>: 声明这是一个XML 1.0文档

    <?xml-model ...>: 关联XML模式定义(XSD),用于验证文件结构

2. 根元素
xml

<package format="3">
  ...
</package>

    format="3": 指定使用ROS 2的第三版包格式规范

3. 包基本信息
xml

<name>pkg_robot_control</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
<license>TODO: License declaration</license>

    <name>: 包的名称,必须唯一,推荐使用小写字母和下划线

    <version>: 包版本号,遵循语义化版本规范(major.minor.patch)

    <description>: 包的简短描述(需要替换为实际描述)

    <maintainer>: 维护者信息,包括邮箱和名称(需要更新为实际信息)

    <license>: 软件许可证(需要替换为实际许可证如Apache-2.0)

4. 依赖关系 (关键部分)
xml

<depend>rclpy</depend>
<depend>std_msgs</depend>
<depend>geometry_msgs</depend>
<depend>pkg_robot_interfaces</depend>
<exec_depend>launch</exec_depend>

    <depend>: 表示构建和运行时都需要的依赖

        rclpy: ROS 2 Python客户端库(必须)

        std_msgs: 标准消息类型(包含基本数据类型)

        geometry_msgs: 几何消息类型(用于位置、姿态等)

        pkg_robot_interfaces: 自定义消息接口包

    <exec_depend>: 表示仅在运行时需要的依赖

        launch: ROS 2启动系统支持

5. 测试依赖
xml

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>ament_xmllint</test_depend>
<test_depend>python3-pytest</test_depend>

这些是运行测试时需要的依赖,主要用于代码质量和静态检查:

    ament_copyright: 检查版权声明

    ament_flake8: Python代码风格检查(基于PEP8)

    ament_pep257: 文档字符串检查

    ament_xmllint: XML文件格式验证

    python3-pytest: Python测试框架

6. 导出设置
xml

<export>
  <build_type>ament_python</build_type>
</export>

    <build_type>: 指定构建系统类型

        ament_python: 表示这是一个Python包,使用Python构建系统

        如果是C++包,应使用ament_cmake

需要完善的部分

    描述信息:
    xml

<description>Advanced robot control with PID and filters</description>

维护者信息:
xml

<maintainer email="your.email@example.com">Your Name</maintainer>

许可证声明:
xml

    <license>Apache-2.0</license>

完整的优化后 package.xml
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>pkg_robot_control</name>
  <version>0.0.0</version>
  <description>Advanced robot control with PID and filters</description>
  <maintainer email="your.email@example.com">Your Name</maintainer>
  <license>Apache-2.0</license>
  
  <!-- 核心依赖 -->
  <depend>rclpy</depend>
  <depend>std_msgs</depend>
  <depend>geometry_msgs</depend>
  <depend>pkg_robot_interfaces</depend>
  
  <!-- 运行时依赖 -->
  <exec_depend>launch</exec_depend>
  <exec_depend>launch_ros</exec_depend>
  
  <!-- 测试依赖 -->
  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>ament_xmllint</test_depend>
  <test_depend>python3-pytest</test_depend>

  <!-- 导出设置 -->
  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

重要说明

    依赖类型区别:

        <depend>: 构建和运行时都需要(如消息接口、核心库)

        <build_depend>: 仅在构建时需要(如代码生成工具)

        <exec_depend>: 仅在运行时需要(如启动文件依赖)

        <test_depend>: 仅在测试时需要

    构建类型:

        ament_python: 用于纯Python包

        ament_cmake: 用于C++包或混合语言包

    消息接口依赖:

        pkg_robot_interfaces 必须在同一工作空间内先构建

        在CMakeLists.txt(对于C++包)或setup.py(对于Python包)中也需要声明

    许可证选择:

        ROS 2推荐使用Apache-2.0许可证

        其他选择包括BSD、MIT等,但需确保与依赖包兼容

    版本管理:

        随着包的发展,应更新版本号

        遵循语义化版本规范: MAJOR.MINOR.PATCH

这个package.xml文件是ROS 2包的核心元数据文件,它定义了包的属性、依赖关系和构建方式。正确配置它对于确保包能正确构建、安装和与其他包交互至关重要。
解读

 

程序代码 pkg_robot_interfaces/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(pkg_robot_interfaces)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

# 查找依赖
find_package(rosidl_default_generators REQUIRED)


if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 生成消息
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/ControlCommand.msg"
  "msg/RobotState.msg"
)
# 安装和导出
ament_export_dependencies(rosidl_default_runtime)


ament_package()
源代码
下面是对这个 CMakeLists.txt 文件的详细解读,解释了每一部分的作用和配置含义:
cmake

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.8)

# 定义项目名称
project(pkg_robot_interfaces)

# 设置编译器警告选项(针对GCC和Clang编译器)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# 查找依赖项
find_package(ament_cmake REQUIRED)
# 手动添加其他依赖的示例(已注释)
# find_package(<dependency> REQUIRED)

# 再次查找依赖(重复,但无害)
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# 测试配置部分
if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # 跳过版权检查(注释掉当添加版权声明后)
  set(ament_cmake_copyright_FOUND TRUE)
  # 跳过cpplint检查(注释掉当在git仓库并添加版权声明后)
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# 生成消息接口
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/ControlCommand.msg"
  "msg/RobotState.msg"
)

# 导出依赖关系
ament_export_dependencies(rosidl_default_runtime)

# 生成包配置
ament_package()

详细解释
1. CMake版本要求
cmake

cmake_minimum_required(VERSION 3.8)

    指定构建此包所需的最低CMake版本

    ROS 2 Rolling通常需要CMake 3.16或更高版本,但3.8是最低兼容版本

2. 项目定义
cmake

project(pkg_robot_interfaces)

    定义项目名称,必须与package.xml中的<name>一致

    设置项目名称会影响后续的变量如${PROJECT_NAME}

3. 编译器选项
cmake

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

    条件检查:如果是GCC或Clang编译器

    添加编译选项:

        -Wall:启用所有警告

        -Wextra:启用额外警告

        -Wpedantic:遵循ISO C/C++标准发出警告

    这些选项有助于提高代码质量和捕获潜在错误

4. 查找依赖项
cmake

find_package(ament_cmake REQUIRED)

    查找ROS 2的核心构建系统ament_cmake

    REQUIRED表示如果找不到则构建失败

cmake

find_package(rosidl_default_generators REQUIRED)

    查找ROS 2接口定义语言(IDL)的生成器

    这是生成自定义消息/服务/动作所必需的

5. 测试配置
cmake

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # 跳过版权检查
  set(ament_cmake_copyright_FOUND TRUE)
  # 跳过cpplint检查
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

    BUILD_TESTING:CMake内置变量,控制是否启用测试

    ament_lint_auto:自动包含各种代码检查工具

    跳过特定检查:

        ament_cmake_copyright_FOUND TRUE:临时禁用版权检查

        ament_cmake_cpplint_FOUND TRUE:临时禁用C++代码风格检查

    ament_lint_auto_find_test_dependencies():自动设置测试依赖

6. 生成消息接口
cmake

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/ControlCommand.msg"
  "msg/RobotState.msg"
)

    核心功能:生成自定义消息的代码

    ${PROJECT_NAME}:使用项目名称作为生成接口的命名空间

    消息文件:指定要生成的.msg文件路径

        msg/ControlCommand.msg:控制命令消息

        msg/RobotState.msg:机器人状态消息

    这会自动生成:

        C++头文件(在install目录)

        Python模块(在install目录)

        类型支持代码

7. 导出依赖关系
cmake

ament_export_dependencies(rosidl_default_runtime)

    声明此包依赖于rosidl_default_runtime

    使依赖包能够正确找到此包生成的接口

    确保下游包在构建时能访问必要的头文件和库

8. 生成包配置
cmake

ament_package()

    关键步骤:生成包的CMake配置文件

    必须在所有ament命令之后调用

    执行以下操作:

        安装包资源

        生成CMake配置文件

        设置环境变量

        准备包以供其他包使用

完整优化后的 CMakeLists.txt
cmake

# 设置最低CMake版本要求
cmake_minimum_required(VERSION 3.8)

# 定义项目名称
project(pkg_robot_interfaces)

# 设置编译器警告选项
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# 查找依赖项
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# 测试配置(在最终版本中应启用所有检查)
if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # 启用版权检查(添加版权声明后取消注释)
  # set(ament_cmake_copyright_FOUND TRUE)
  
  # 启用cpplint检查(在git仓库中取消注释)
  # set(ament_cmake_cpplint_FOUND TRUE)
  
  ament_lint_auto_find_test_dependencies()
endif()

# 生成消息接口
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/ControlCommand.msg"
  "msg/RobotState.msg"
  # 可以添加更多消息或服务
  # "srv/GetStatus.srv"
  # "action/Navigate.action"
)

# 导出依赖关系
ament_export_dependencies(rosidl_default_runtime)

# 生成包配置
ament_package()

关键注意事项

    消息生成过程:

        构建时,ROS 2会处理.msg文件

        生成语言特定的接口代码(C++、Python等)

        输出到build和install目录

    目录结构要求:
    text

pkg_robot_interfaces/
├── CMakeLists.txt
├── msg/
│   ├── ControlCommand.msg
│   └── RobotState.msg
└── package.xml

    消息文件必须放在msg/目录

    服务文件放在srv/目录

    动作文件放在action/目录

依赖关系:

    在package.xml中必须声明:
    xml

    <build_depend>rosidl_default_generators</build_depend>
    <exec_depend>rosidl_default_runtime</exec_depend>
    <member_of_group>rosidl_interface_packages</member_of_group>

使用自定义消息:

    在其他包中使用这些消息时,需要在package.xml中添加:
    xml

<depend>pkg_robot_interfaces</depend>

在CMakeLists.txt中:
cmake

        find_package(pkg_robot_interfaces REQUIRED)
        ament_target_dependencies(your_target pkg_robot_interfaces)

    最佳实践:

        最终版本中应启用所有代码检查

        为所有文件添加版权声明

        遵循ROS 2命名规范(小写字母,下划线分隔)

        为消息字段添加详细的注释说明

这个CMakeLists.txt文件是ROS 2接口包的核心构建脚本,它定义了如何生成和使用自定义消息类型。正确配置它对于确保消息能在不同语言和节点之间正确传递至关重要。
解读和代码

  

程序代码 pkg_robot_interfaces/package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>pkg_robot_interfaces</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>
  <!--add-->
  <build_depend>rosidl_default_generators</build_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>


  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>
源代码
下面是对这个 package.xml 文件的详细解读,解释了每个部分的作用和配置含义:
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <!-- 包的基本信息 -->
  <name>pkg_robot_interfaces</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
  <license>TODO: License declaration</license>

  <!-- 构建工具依赖 -->
  <buildtool_depend>ament_cmake</buildtool_depend>
  
  <!-- 新增部分 -->
  <build_depend>rosidl_default_generators</build_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

  <!-- 测试依赖 -->
  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <!-- 导出设置 -->
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

详细解读
1. 文档声明
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>

    <?xml version="1.0"?>: 声明这是一个XML 1.0文档

    <?xml-model ...>: 关联XML模式定义(XSD),用于验证文件结构符合ROS 2规范

2. 包基本信息
xml

<name>pkg_robot_interfaces</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
<license>TODO: License declaration</license>

    <name>: 包的名称,必须唯一,推荐使用小写字母和下划线

    <version>: 包版本号,遵循语义化版本规范(major.minor.patch)

    <description>: 包的简短描述(需要替换为实际描述)

    <maintainer>: 维护者信息(需要更新为实际信息)

    <license>: 软件许可证(需要替换为实际许可证如Apache-2.0)

3. 构建工具依赖
xml

<buildtool_depend>ament_cmake</buildtool_depend>

    ament_cmake: ROS 2的CMake构建系统扩展

    这是CMake包的必需依赖,提供ROS 2特定的构建功能

4. 新增部分(关键接口依赖)
xml

<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>

    <build_depend>rosidl_default_generators</build_depend>:

        构建时依赖,用于生成消息/服务/动作的代码

        这是定义自定义接口的必需依赖

    <exec_depend>rosidl_default_runtime</exec_depend>:

        运行时依赖,提供接口的运行时支持

        确保在运行时可以正确解析和使用接口

    <member_of_group>rosidl_interface_packages</member_of_group>:

        声明此包属于ROS接口包组

        这是ROS 2接口包的关键标识

        使此包可以被识别为包含自定义消息/服务/动作的包

5. 测试依赖
xml

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

    ament_lint_auto: 自动运行一系列代码质量检查

    ament_lint_common: 提供常用的代码检查工具集

    这些依赖仅在运行测试时使用(colcon test)

6. 导出设置
xml

<export>
  <build_type>ament_cmake</build_type>
</export>

    <build_type>: 指定构建系统类型

        ament_cmake: 表示这是一个CMake包(区别于Python包的ament_python)

        正确设置此值对ROS 2构建系统至关重要

需要完善的部分

    描述信息:
    xml

<description>Custom ROS 2 interfaces for robot control and state</description>

维护者信息:
xml

<maintainer email="your.email@example.com">Your Name</maintainer>

许可证声明:
xml

    <license>Apache-2.0</license>

完整优化后的 package.xml
xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>pkg_robot_interfaces</name>
  <version>0.0.0</version>
  <description>Custom ROS 2 interfaces for robot control and state monitoring</description>
  <maintainer email="your.email@example.com">Your Name</maintainer>
  <license>Apache-2.0</license>

  <!-- 构建工具依赖 -->
  <buildtool_depend>ament_cmake</buildtool_depend>
  
  <!-- 接口生成依赖 -->
  <build_depend>rosidl_default_generators</build_depend>
  
  <!-- 运行时依赖 -->
  <exec_depend>rosidl_default_runtime</exec_depend>
  
  <!-- 声明为接口包 -->
  <member_of_group>rosidl_interface_packages</member_of_group>

  <!-- 测试依赖 -->
  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <!-- 导出设置 -->
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

ROS 2接口包的关键特点

    接口定义:

        包含在msg/, srv/, action/目录中的定义文件

        支持的消息类型:

            ControlCommand.msg: 控制命令消息

            RobotState.msg: 机器人状态消息

    构建过程:
    图表
    代码

    graph LR
    A[.msg/.srv文件] --> B[rosidl_generate_interfaces]
    B --> C[C++头文件]
    B --> D[Python模块]
    B --> E[类型支持代码]

    依赖关系:
    依赖类型    包名    作用    何时需要
    buildtool    ament_cmake    构建系统框架    始终
    build    rosidl_default_generators    生成接口代码    构建时
    exec    rosidl_default_runtime    接口运行时支持    运行时
    test    ament_lint_*    代码质量检查    测试时

    使用流程:

        定义消息文件(.msg)

        在CMakeLists.txt中调用rosidl_generate_interfaces()

        在package.xml中声明接口包依赖

        构建包:colcon build --packages-select pkg_robot_interfaces

        在其他包中引用:<depend>pkg_robot_interfaces</depend>

重要说明

    接口包的作用:

        定义节点间通信的标准格式

        提供跨语言支持(C++, Python等)

        确保数据类型的兼容性和一致性

    member_of_group的重要性:

        明确声明此包是接口包

        使ROS 2构建系统正确处理接口生成

        允许其他包正确依赖此接口

    目录结构要求:
    text

    pkg_robot_interfaces/
    ├── CMakeLists.txt
    ├── msg/
    │   ├── ControlCommand.msg
    │   └── RobotState.msg
    ├── package.xml
    └── ...

        消息文件必须放在msg/目录

        服务文件放在srv/目录

        动作文件放在action/目录

    最佳实践:

        为所有消息字段添加注释

        使用有意义的字段名称

        遵循ROS 2命名规范(小写字母,下划线分隔)

        在描述中说明每个消息的用途

这个package.xml文件是ROS 2接口包的核心配置文件,它定义了包的元数据、依赖关系和构建方式。正确配置它对于确保接口能被其他包正确生成和使用至关重要。
解读

 

 

 

 

 

 

 

 

 

 


 

 

posted @ 2025-06-25 18:10  辛河  阅读(53)  评论(0)    收藏  举报