fix
This commit is contained in:
+47
-32
@@ -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 浮点精度
|
||||
|
||||
Reference in New Issue
Block a user