This commit is contained in:
2026-08-05 18:17:25 +08:00
parent 61796dfa9f
commit b52cee9e39
34 changed files with 866 additions and 309 deletions
+47 -32
View File
@@ -316,51 +316,62 @@ PushRosNamespace('my_ns')
完整示例见 `src/py_params/`,这里讲关键设计:
### 5.1 主节点: `param_node.py`
### 5.1 主节点: `py_params/param_node.py`
```python
class ParamNode(Node):
def __init__(self):
super().__init__('param_node')
class ParamsTalker(Node):
DEFAULT_RATE_HZ = 1.0
DEFAULT_TOPIC = 'params_chatter'
DEFAULT_PREFIX = 'Params:'
def __init__(self, *, node_name='params_talker'):
super().__init__(node_name)
# 1. 声明三个参数(类型自动推断)
self.declare_parameter('publish_rate', 1.0)
self.declare_parameter('topic_name', 'params_chatter')
self.declare_parameter('message_prefix', 'Params:')
self.declare_parameter('publish_rate_hz', self.DEFAULT_RATE_HZ)
self.declare_parameter('topic_name', self.DEFAULT_TOPIC)
self.declare_parameter('message_prefix', self.DEFAULT_PREFIX)
# 2. 读取参数
# 2. 读取参数 + 构造组件
publish_rate_hz = self.get_parameter('publish_rate_hz').value
topic_name = self.get_parameter('topic_name').value
# 3. 用参数构造发布者
self._pub = self.create_publisher(String, topic_name, 10)
self.publisher_ = self.create_publisher(String, topic_name, 10)
# 4. 用参数构造定时器
rate = self.get_parameter('publish_rate').value
self._timer = self.create_timer(1.0 / rate, self._cb)
period = 1.0 / publish_rate_hz if publish_rate_hz > 0 else 1.0
self.timer_ = self.create_timer(period, self._on_timer)
# 5. 注册回调
self.add_on_set_parameters_callback(self._on_change)
# 3. 缓存可变参数 + 注册回调
self._prefix = self.get_parameter('message_prefix').value
self.add_on_set_parameters_callback(self._validate_parameter_change)
```
### 5.2 回调: 拒绝非法值
```python
def _on_change(self, params):
for p in params:
if p.name == 'publish_rate' and p.value <= 0.0:
return SetParametersResult(
successful=False,
reason='publish_rate 必须 > 0'
)
def _validate_parameter_change(self, params):
for param in params:
if param.name == 'publish_rate_hz':
if not isinstance(param.value, (int, float)):
return SetParametersResult(successful=False,
reason=f'publish_rate_hz 必须是数字')
if param.value <= 0.0:
return SetParametersResult(successful=False,
reason=f'publish_rate_hz 必须 > 0')
elif param.name == 'message_prefix':
if not isinstance(param.value, str):
return SetParametersResult(successful=False,
reason='message_prefix 必须是字符串')
self._prefix = param.value
return SetParametersResult(successful=True)
```
### 5.3 YAML 配置: `config/params.yaml`
```yaml
param_node:
params_talker:
ros__parameters:
publish_rate: 2.0
publish_rate_hz: 2.0
topic_name: "params_chatter"
message_prefix: "Configured:"
```
@@ -382,13 +393,15 @@ def generate_launch_description():
return LaunchDescription([
Node(
package='py_params',
executable='param_node',
executable='params_talker',
parameters=[cfg],
output='screen',
),
])
```
> 注:本仓库 launch 文件名是 `params_launch.py`,命令:`ros2 launch py_params params_launch.py`。
---
## 6. 测试策略 (Test)
@@ -398,15 +411,17 @@ def generate_launch_description():
```python
def test_param_declaration():
rclpy.init()
node = ParamNode()
assert node.get_parameter('publish_rate').value == 1.0
node = ParamsTalker()
assert node.get_parameter('publish_rate_hz').value == 1.0
assert node.get_parameter('topic_name').value == 'params_chatter'
assert node.get_parameter('message_prefix').value == 'Params:'
```
### 6.2 单元测试: 合法 set
```python
new_param = Parameter(
name='publish_rate',
name='publish_rate_hz',
value=ParameterValue(type=ParameterType.PARAMETER_DOUBLE, double_value=5.0),
)
result = node.set_parameters([new_param])
@@ -417,12 +432,12 @@ assert result[0].successful is True
```python
bad = Parameter(
name='publish_rate',
name='publish_rate_hz',
value=ParameterValue(type=ParameterType.PARAMETER_DOUBLE, double_value=-1.0),
)
result = node.set_parameters([bad])
assert result[0].successful is False
assert '必须 > 0' in result[0].reason
assert 'publish_rate_hz 必须 > 0' in result[0].reason
```
### 6.4 YAML 集成测试
@@ -431,7 +446,7 @@ assert '必须 > 0' in result[0].reason
def test_yaml_loadable():
with open('config/params.yaml') as f:
cfg = yaml.safe_load(f)
assert cfg['param_node']['ros__parameters']['publish_rate'] == 2.0
assert cfg['params_talker']['ros__parameters']['publish_rate_hz'] == 2.0
```
---
@@ -542,7 +557,7 @@ ros2 pkg prefix py_params
# 查看 install/py_params/share/py_params/config/params.yaml
# 启动时打印实际加载的参数
ros2 param list /param_node # 看实际值
ros2 param list /params_talker # 看实际值
```
### 8.4 浮点精度