Skip to content

Commit 5640b1f

Browse files
Fix conflicting validators (PickNikRobotics#336)
1 parent 958446a commit 5640b1f

13 files changed

Lines changed: 251 additions & 76 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ The built-in validator functions provided by this package are:
264264
| gt_eq<> | [value] | parameter >= value |
265265
| one_of<> | [[val1, val2, ...]] | Value is one of the specified values |
266266

267+
Note: `lt<>`, `gt<>`, `lt_eq<>`, or `gt_eq<>` cannot be used together with `bounds<>`.
268+
267269
**String validators**
268270
| Function | Arguments | Description |
269271
| ------------ | ------------------- | ---------------------------------------------- |
@@ -286,6 +288,8 @@ The built-in validator functions provided by this package are:
286288
| lower_element_bounds<> | [lower] | Lower bound for each element (inclusive) |
287289
| upper_element_bounds<> | [upper] | Upper bound for each element (inclusive) |
288290

291+
Note: `element_bounds<>` cannot be mixed with `lower_element_bounds<>` or `upper_element_bounds<>`.
292+
289293
### Custom validator functions
290294
Validators are functions that return a `tl::expected<void, std::string>` type and accept a `rclcpp::Parameter const&` as their first argument and any number of arguments after that can be specified in YAML.
291295
Validators are C++ functions defined in a header file similar to the example shown below.

example/src/parameters.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ admittance_controller:
2929
validation:
3030
gt<>: [0.0]
3131

32+
limit:
33+
type: double_array
34+
description: "specifies limit for x, y and z axis"
35+
default_value: [0.0, 0.0, 0.0]
36+
validation:
37+
fixed_size<>: 3
38+
lower_element_bounds<>: -10.0
39+
upper_element_bounds<>: 10.0
40+
3241
nested_dynamic:
3342
__map_joints:
3443
__map_dof_names:
@@ -223,6 +232,15 @@ admittance_controller:
223232
validation:
224233
element_bounds: [ 0.0001, 100000.0 ]
225234

235+
acceleration_limits:
236+
type: double_array
237+
description: "specifies maximum acceleration limits for x, y and z axis"
238+
default_value: [0.0, 0.0, 0.0]
239+
validation:
240+
fixed_size<>: 3
241+
lower_element_bounds<>: -10.0
242+
upper_element_bounds<>: 10.0
243+
226244
# general settings
227245
enable_parameter_update_without_reactivation:
228246
type: bool
@@ -244,6 +262,20 @@ admittance_controller:
244262
description: "should be a number greater than 15"
245263
validation:
246264
gt<>: [ 15 ]
265+
gt_fifteen_lt_eq_twenty:
266+
type: int
267+
default_value: 20
268+
description: "should be a number greater than 15 and less than or equal to 20"
269+
validation:
270+
gt<>: [ 15 ]
271+
lt_eq<>: [ 20 ]
272+
gt_fifteen_lt_twenty:
273+
type: int
274+
default_value: 16
275+
description: "should be a number greater than 15 and less than 20"
276+
validation:
277+
gt<>: [ 15 ]
278+
lt<>: [ 20 ]
247279
one_number:
248280
type: int
249281
default_value: 14540

example_python/generate_parameter_module_example/parameters.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ admittance_controller:
3535
validation:
3636
gt<>: [0.0]
3737

38+
limit:
39+
type: double_array
40+
description: "specifies limit for x, y and z axis"
41+
default_value: [0.0, 0.0, 0.0]
42+
validation:
43+
fixed_size<>: 3
44+
lower_element_bounds<>: -10.0
45+
upper_element_bounds<>: 10.0
46+
3847
nested_dynamic:
3948
__map_joints:
4049
__map_dof_names:
@@ -226,6 +235,15 @@ admittance_controller:
226235
validation:
227236
element_bounds: [ 0.0001, 100000.0 ]
228237

238+
acceleration_limits:
239+
type: double_array
240+
description: "specifies maximum acceleration limits for x, y and z axis"
241+
default_value: [0.0, 0.0, 0.0]
242+
validation:
243+
fixed_size<>: 3
244+
lower_element_bounds<>: -10.0
245+
upper_element_bounds<>: 10.0
246+
229247
# general settings
230248
enable_parameter_update_without_reactivation:
231249
type: bool
@@ -247,6 +265,20 @@ admittance_controller:
247265
description: "should be a number greater than 15"
248266
validation:
249267
gt<>: [ 15 ]
268+
gt_fifteen_lt_eq_twenty:
269+
type: int
270+
default_value: 20
271+
description: "should be a number greater than 15 and less than or equal to 20"
272+
validation:
273+
gt<>: [ 15 ]
274+
lt_eq<>: [ 20 ]
275+
gt_fifteen_lt_twenty:
276+
type: int
277+
default_value: 16
278+
description: "should be a number greater than 15 and less than 20"
279+
validation:
280+
gt<>: [ 15 ]
281+
lt<>: [ 20 ]
250282
one_number:
251283
type: int
252284
default_value: 14540

generate_parameter_library_py/generate_parameter_library_py/jinja_templates/cpp/declare_parameter

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,41 @@ descriptor.read_only = {{parameter_read_only}};
66
{%- if parameter_additional_constraints|length %}
77
descriptor.additional_constraints = {{parameter_additional_constraints | valid_string_cpp}};
88
{% endif -%}
9-
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
109
{%- if "DOUBLE" in parameter_type %}
10+
{%- set range = namespace(lower=None, upper=None) %}
11+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
1112
{%- if validation.arguments|length == 2 %}
12-
descriptor.floating_point_range.resize({{loop.index}});
13-
descriptor.floating_point_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
14-
descriptor.floating_point_range.at({{loop.index0}}).to_value = {{validation.arguments[1]}};
13+
{%- set range.lower = validation.arguments[0] %}
14+
{%- set range.upper = validation.arguments[1] %}
1515
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
16-
descriptor.floating_point_range.resize({{loop.index}});
17-
descriptor.floating_point_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
18-
descriptor.floating_point_range.at({{loop.index0}}).to_value = std::numeric_limits<double>::max();
16+
{%- set range.lower = validation.arguments[0] %}
1917
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
20-
descriptor.floating_point_range.resize({{loop.index}});
21-
descriptor.floating_point_range.at({{loop.index0}}).from_value = std::numeric_limits<double>::lowest();
22-
descriptor.floating_point_range.at({{loop.index0}}).to_value = {{validation.arguments[0]}};
18+
{%- set range.upper = validation.arguments[0] %}
19+
{%- endif %}
20+
{%- endfor %}
21+
{%- if range.lower is not none or range.upper is not none %}
22+
descriptor.floating_point_range.resize(1);
23+
descriptor.floating_point_range.at(0).from_value = {{range.lower if range.lower is not none else "std::numeric_limits<double>::lowest()"}};
24+
descriptor.floating_point_range.at(0).to_value = {{range.upper if range.upper is not none else "std::numeric_limits<double>::max()"}};
2325
{%- endif %}
2426
{%- elif "INTEGER" in parameter_type %}
27+
{%- set range = namespace(lower=None, upper=None) %}
28+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
2529
{%- if validation.arguments|length == 2 %}
26-
descriptor.integer_range.resize({{loop.index}});
27-
descriptor.integer_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
28-
descriptor.integer_range.at({{loop.index0}}).to_value = {{validation.arguments[1]}};
30+
{%- set range.lower = validation.arguments[0] %}
31+
{%- set range.upper = validation.arguments[1] %}
2932
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
30-
descriptor.integer_range.resize({{loop.index}});
31-
descriptor.integer_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
32-
descriptor.integer_range.at({{loop.index0}}).to_value = std::numeric_limits<int64_t>::max();
33+
{%- set range.lower = validation.arguments[0] %}
3334
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
34-
descriptor.integer_range.resize({{loop.index}});
35-
descriptor.integer_range.at({{loop.index0}}).from_value = std::numeric_limits<int64_t>::lowest();
36-
descriptor.integer_range.at({{loop.index0}}).to_value = {{validation.arguments[0]}};
37-
{%- endif %}
35+
{%- set range.upper = validation.arguments[0] %}
3836
{%- endif %}
3937
{%- endfor %}
38+
{%- if range.lower is not none or range.upper is not none %}
39+
descriptor.integer_range.resize(1);
40+
descriptor.integer_range.at(0).from_value = {{range.lower if range.lower is not none else "std::numeric_limits<int64_t>::lowest()"}};
41+
descriptor.integer_range.at(0).to_value = {{range.upper if range.upper is not none else "std::numeric_limits<int64_t>::max()"}};
42+
{%- endif %}
43+
{%- endif %}
4044
{%- if not parameter_value|length %}
4145
auto parameter = rclcpp::ParameterType::PARAMETER_{{parameter_type}};
4246
{% endif -%}

generate_parameter_library_py/generate_parameter_library_py/jinja_templates/cpp/declare_runtime_parameter

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,41 @@ descriptor.read_only = {{parameter_read_only}};
2222
{%- if parameter_additional_constraints|length %}
2323
descriptor.additional_constraints = {{parameter_additional_constraints | valid_string_cpp}};
2424
{% endif -%}
25-
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
2625
{%- if "DOUBLE" in parameter_type %}
26+
{%- set range = namespace(lower=None, upper=None) %}
27+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
2728
{%- if validation.arguments|length == 2 %}
28-
descriptor.floating_point_range.resize({{loop.index}});
29-
descriptor.floating_point_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
30-
descriptor.floating_point_range.at({{loop.index0}}).to_value = {{validation.arguments[1]}};
29+
{%- set range.lower = validation.arguments[0] %}
30+
{%- set range.upper = validation.arguments[1] %}
3131
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
32-
descriptor.floating_point_range.resize({{loop.index}});
33-
descriptor.floating_point_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
34-
descriptor.floating_point_range.at({{loop.index0}}).to_value = std::numeric_limits<double>::max();
32+
{%- set range.lower = validation.arguments[0] %}
3533
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
36-
descriptor.floating_point_range.resize({{loop.index}});
37-
descriptor.floating_point_range.at({{loop.index0}}).from_value = std::numeric_limits<double>::lowest();
38-
descriptor.floating_point_range.at({{loop.index0}}).to_value = {{validation.arguments[0]}};
34+
{%- set range.upper = validation.arguments[0] %}
35+
{%- endif %}
36+
{%- endfor %}
37+
{%- if range.lower is not none or range.upper is not none %}
38+
descriptor.floating_point_range.resize(1);
39+
descriptor.floating_point_range.at(0).from_value = {{range.lower if range.lower is not none else "std::numeric_limits<double>::lowest()"}};
40+
descriptor.floating_point_range.at(0).to_value = {{range.upper if range.upper is not none else "std::numeric_limits<double>::max()"}};
3941
{%- endif %}
4042
{%- elif "INTEGER" in parameter_type %}
43+
{%- set range = namespace(lower=None, upper=None) %}
44+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
4145
{%- if validation.arguments|length == 2 %}
42-
descriptor.integer_range.resize({{loop.index}});
43-
descriptor.integer_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
44-
descriptor.integer_range.at({{loop.index0}}).to_value = {{validation.arguments[1]}};
46+
{%- set range.lower = validation.arguments[0] %}
47+
{%- set range.upper = validation.arguments[1] %}
4548
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
46-
descriptor.integer_range.resize({{loop.index}});
47-
descriptor.integer_range.at({{loop.index0}}).from_value = {{validation.arguments[0]}};
48-
descriptor.integer_range.at({{loop.index0}}).to_value = std::numeric_limits<int64_t>::max();
49+
{%- set range.lower = validation.arguments[0] %}
4950
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
50-
descriptor.integer_range.resize({{loop.index}});
51-
descriptor.integer_range.at({{loop.index0}}).from_value = std::numeric_limits<int64_t>::lowest();
52-
descriptor.integer_range.at({{loop.index0}}).to_value = {{validation.arguments[0]}};
53-
{%- endif %}
51+
{%- set range.upper = validation.arguments[0] %}
5452
{%- endif %}
5553
{%- endfor %}
54+
{%- if range.lower is not none or range.upper is not none %}
55+
descriptor.integer_range.resize(1);
56+
descriptor.integer_range.at(0).from_value = {{range.lower if range.lower is not none else "std::numeric_limits<int64_t>::lowest()"}};
57+
descriptor.integer_range.at(0).to_value = {{range.upper if range.upper is not none else "std::numeric_limits<int64_t>::max()"}};
58+
{%- endif %}
59+
{%- endif %}
5660
{%- if not default_value|length %}
5761
auto parameter = rclcpp::ParameterType::PARAMETER_{{parameter_type}};
5862
{% endif -%}

generate_parameter_library_py/generate_parameter_library_py/jinja_templates/python/declare_parameter

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,41 @@ descriptor = ParameterDescriptor(description=r"{{parameter_description|valid_str
44
{%- if parameter_additional_constraints|length %}
55
descriptor.additional_constraints = "{{parameter_additional_constraints|valid_string_python}}"
66
{% endif -%}
7-
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
87
{%- if "DOUBLE" in parameter_type %}
8+
{%- set range = namespace(lower=None, upper=None) %}
9+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
910
{%- if validation.arguments|length == 2 %}
10-
descriptor.floating_point_range.append(FloatingPointRange())
11-
descriptor.floating_point_range[-1].from_value = {{validation.arguments[0]}}
12-
descriptor.floating_point_range[-1].to_value = {{validation.arguments[1]}}
11+
{%- set range.lower = validation.arguments[0] %}
12+
{%- set range.upper = validation.arguments[1] %}
1313
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
14-
descriptor.floating_point_range.append(FloatingPointRange())
15-
descriptor.floating_point_range[-1].from_value = {{validation.arguments[0]}}
16-
descriptor.floating_point_range[-1].to_value = float('inf')
14+
{%- set range.lower = validation.arguments[0] %}
1715
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
16+
{%- set range.upper = validation.arguments[0] %}
17+
{%- endif %}
18+
{%- endfor %}
19+
{%- if range.lower is not none or range.upper is not none %}
1820
descriptor.floating_point_range.append(FloatingPointRange())
19-
descriptor.floating_point_range[-1].from_value = -float('inf')
20-
descriptor.floating_point_range[-1].to_value = {{validation.arguments[0]}}
21+
descriptor.floating_point_range[-1].from_value = {{range.lower if range.lower is not none else "-float('inf')"}}
22+
descriptor.floating_point_range[-1].to_value = {{range.upper if range.upper is not none else "float('inf')"}}
2123
{%- endif %}
2224
{%- elif "INTEGER" in parameter_type %}
25+
{%- set range = namespace(lower=None, upper=None) %}
26+
{%- for validation in parameter_validations if ("bounds" in validation.function_name or "lt" in validation.function_name or "gt" in validation.function_name) %}
2327
{%- if validation.arguments|length == 2 %}
24-
descriptor.integer_range.append(IntegerRange())
25-
descriptor.integer_range[-1].from_value = {{validation.arguments[0]}}
26-
descriptor.integer_range[-1].to_value = {{validation.arguments[1]}}
28+
{%- set range.lower = validation.arguments[0] %}
29+
{%- set range.upper = validation.arguments[1] %}
2730
{%- elif ("lower" in validation.function_name or "gt" == validation.function_base_name or "gt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
28-
descriptor.integer_range.append(IntegerRange())
29-
descriptor.integer_range[-1].from_value = {{validation.arguments[0]}}
30-
descriptor.integer_range[-1].to_value = 2**31-1
31+
{%- set range.lower = validation.arguments[0] %}
3132
{%- elif ("upper" in validation.function_name or "lt" == validation.function_base_name or "lt_eq" == validation.function_base_name) and validation.arguments|length == 1 %}
33+
{%- set range.upper = validation.arguments[0] %}
34+
{%- endif %}
35+
{%- endfor %}
36+
{%- if range.lower is not none or range.upper is not none %}
3237
descriptor.integer_range.append(IntegerRange())
33-
descriptor.integer_range[-1].from_value = -2**31-1
34-
descriptor.integer_range[-1].to_value = {{validation.arguments[0]}}
38+
descriptor.integer_range[-1].from_value = {{range.lower if range.lower is not none else "-2**31-1"}}
39+
descriptor.integer_range[-1].to_value = {{range.upper if range.upper is not none else "2**31-1"}}
3540
{%- endif %}
3641
{%- endif %}
37-
{%- endfor %}
3842
{%- if not parameter_value|length %}
3943
parameter = rclpy.Parameter.Type.{{parameter_type}}
4044
{% endif -%}

0 commit comments

Comments
 (0)