# Parameters

Autoware ROS nodes have declared parameters which values are provided during the node start up in the form of a parameter file. All the expected parameters with corresponding values should exist in the parameter file. Depending on the application, the parameter values might need to be modified.

Find more information on parameters from the official ROS documentation:

- [Understanding ROS 2 Parameters](<https://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Parameters/Understanding-ROS2-Parameters.html>)
- [About ROS 2 Parameters](<https://docs.ros.org/en/humble/Concepts/Basic/About-Parameters.html>)

## Workflow

A ROS package which uses the [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>) function should:

- use the [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>), without a default value
- create a parameter file
- create a schema file

The rationale behind this workflow is to have a verified single source of truth to pass to the ROS node and to be used in the web documentation. The approach reduces the risk of using invalid parameter values and makes maintenance of documentation easier. This is achieved by:

- [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>) throws an exception if an expected parameter is missing in the parameter file
- the schema validates the parameter file in the CI and renders a parameter table, as depicted in the graphics below

The schema file validates the parameter file in the CI and generates the parameter table of the web documentation.

The `json-schema-check` workflow of Autoware Core and Autoware Universe runs the validation. To render the table, the README of a package calls the `json_to_markdown` macro of the documentation site of Autoware Core or Autoware Universe, with the path of the schema file. For an example, see the README of [`autoware_path_generator`](<https://github.com/autowarefoundation/autoware_core/blob/1.10.0/planning/autoware_path_generator/README.md>).

Note: a parameter value can still be modified and bypass the validation, as there is no validation during runtime.

## Declare Parameter Function

It is the [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>) function which sets the parameter values during a node startup.

```cpp
declare_parameter<INSERT_TYPE>("INSERT_PARAMETER_1_NAME"),
declare_parameter<INSERT_TYPE>("INSERT_PARAMETER_N_NAME")
```

As there is no *default\_value* provided, the function throws an exception if a parameter were to be missing in the provided `*.param.yaml` file. Use a type from the *C++ Type* column in the table below for the [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>) function, replacing *INSERT\_TYPE*.

| ParameterType Enum | C++ Type |
| --- | --- |
| `PARAMETER_BOOL` | `bool` |
| `PARAMETER_INTEGER` | `int64_t` |
| `PARAMETER_DOUBLE` | `double` |
| `PARAMETER_STRING` | `std::string` |
| `PARAMETER_BYTE_ARRAY` | `std::vector<uint8_t>` |
| `PARAMETER_BOOL_ARRAY` | `std::vector<bool>` |
| `PARAMETER_INTEGER_ARRAY` | `std::vector<int64_t>` |
| `PARAMETER_DOUBLE_ARRAY` | `std::vector<double>` |
| `PARAMETER_STRING_ARRAY` | `std::vector<std::string>` |

The table has been derived from [Parameter Type](<https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/ParameterType.msg>) and [Parameter Value](<https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/ParameterValue.msg>).

See example: *GNSS Poser* [declare function](<https://github.com/autowarefoundation/autoware_core/blob/1.10.0/sensing/autoware_gnss_poser/src/gnss_poser_node.cpp#L50-L60>)

## Parameter File

The parameter file is minimal as there is no need to provide the user with additional information, e.g., description or type. This is because the associated schema file provides the additional information. Use the template below as a starting point for a ROS node.

```yaml
/**:
  ros__parameters:
    INSERT_PARAMETER_1_NAME: INSERT_PARAMETER_1_VALUE
    INSERT_PARAMETER_N_NAME: INSERT_PARAMETER_N_VALUE
```

Note: `/**` is used instead of the explicit node namespace, this allows the parameter file to be passed to a ROS node which has been [remapped](<https://design.ros2.org/articles/static_remapping.html>).

To adapt the template to the ROS node, replace each `INSERT_PARAMETER_..._NAME` and `INSERT_PARAMETER_..._VALUE` for all parameters. Each [declare\_parameter(...)](<https://docs.ros.org/en/ros2_packages/humble/api/rclcpp/generated/classrclcpp_1_1Node.html#_CPPv4N6rclcpp4Node17declare_parameterERKNSt6stringERKN6rclcpp14ParameterValueERKN14rcl_interfaces3msg19ParameterDescriptorEb>) takes one parameter as input. All the parameter files should have the `.param.yaml` suffix so that the auto-format can be applied properly.

Autoware has the following two types of parameter files for ROS packages:

- **Node parameter file**

  - Node parameter files store the typical parameters provided for each package in Autoware.

    - For example, [the parameter of `autoware_behavior_path_planner`](<https://github.com/autowarefoundation/autoware_universe/tree/0.53.1/planning/behavior_path_planner/autoware_behavior_path_planner/config>)
  - All nodes in Autoware must have a parameter file if ROS parameters are declared in the node.
  - For `FOO_package`, the parameter is expected to be stored in `FOO_package/config`.
  - The launch file for individual packages must load node parameter by default:

```xml
<launch>
  <arg name="foo_node_param_path" default="$(find-pkg-share FOO_package)/config/foo_node.param.yaml" />

  <node pkg="FOO_package" exec="foo_node">
    ...
    <param from="$(var foo_node_param_path)" />
  </node>
</launch>
```

- **Launch parameter file**

  - When a user creates a launch package for the user's vehicle, the user should copy node parameter files for the nodes that are used in the launch file as "launch parameter files".
  - Launch parameter files are then customized specifically for the user's vehicle.

    - For example, [the customized parameter of `autoware_behavior_path_planner` stored under `autoware_launch`](<https://github.com/autowarefoundation/autoware_launch/tree/0.53.0/autoware_universe_launch/autoware_planning_config/config/scenario_planning/lane_driving/behavior_planning/behavior_path_planner>)
  - Launch parameter files are stored in the `autoware_launch` repository. The files of each component are in an `autoware_universe_launch/autoware_<component>_config` package, for example `autoware_planning_config`. The files of the system, the vehicle, and the simulator are in the `config` folder of the `autoware_launch` package.

### sync-params

Despite being unused in `autoware_launch`, node parameter files must be updated after adding or removing parameters in the node implementations. Each node parameter file serves as the master file for the corresponding launch parameter file.

In most cases, updating launch parameter files are automated by [sync-params](<https://github.com/autowarefoundation/autoware_launch/actions/workflows/sync-params.yaml>) workflow, given that the corresponding node parameter files have been properly updated. The workflow runs every day for all the categories, and you can also run it by hand for one category.

A launch parameter file managed by sync-params workflow has a sync-params comment header starting with `# This file is managed by sync-params workflow`. By default, a launch parameter file is identical to its corresponding node parameter file, except for the header.

#### Adding or removing parameters with sync-params workflow

In general, you should not create a PR for `autoware_launch` when you simply added or removed some node parameters. In such cases, follow these steps:

1. Merge the node PR containing the node parameter file update **first**.
2. Run sync-params workflow with the desired category. To see the available categories, see [the sync-param configuration file](<https://github.com/autowarefoundation/autoware_launch/blob/main/.github/sync-params.yaml>).
3. A PR for the workflow will be created, or the existing PR will be updated if one already exists. The PR is labeled [`tag:sync-params`](<https://github.com/autowarefoundation/autoware_launch/pulls?q=is%3Aopen+is%3Apr+label%3Atag%3Async-params>) label.

#### Overriding parameters with sync-params workflow

Some of the fields should be different from the corresponding node parameter file. Such fields may be marked with `# {OVERRIDE}` or `# {OVERRIDE: <reason>}` comment marker to keep the value different from the upstream node parameter file.

If you naively try to modify the parameter in the launch parameter file as in the next example, the next sync-params workflow run will try to revert the parameter to `foo: 42`, matching to the node parameter file.

```text
 # NG
-foo: 42
+foo: 40
```

To make the change persist, open a PR that updates the launch parameter file as following:

```text
 # OK
-foo: 42
+foo: 40 # {OVERRIDE}
```

If there is already a comment on the line, place the marker before the existing comment:

```text
 # OK
-bar: [1, 2, 3, 4] # existing comment
+bar: [5, 6, 7, 8] # {OVERRIDE} existing comment
```

**Tip**: make the node parameter file as identical as possible to the intended launch parameter file, so that the override can be minimized.

#### Updating sync-params configurations

To add a new pair of a node parameter file and a launch parameter file, update [the sync-param configuration file](<https://github.com/autowarefoundation/autoware_launch/blob/main/.github/sync-params.yaml>), following the next example.

```yaml
perception: # category
  - repository: autowarefoundation/autoware_universe # the source repository
    ref: main
    files:
      - # node parameter file path in the source repository
        source: perception/autoware_image_object_locator/config/bbox_object_locator.param.yaml
        # List of launch parameter file paths in autoware_launch repository
        variants:
          - path: autoware_universe_launch/autoware_perception_config/config/object_recognition/detection/camera_vru_detection/near_range_camera_vru_detector.param.yaml
```

And then run `python .github/scripts/sync_params.py perception` (replace `perception` with your category) locally, which is the script that sync-params workflow uses under the hood. Files in the same category might be updated as well, but commit only the file that you have just added and discard anything else. Other files should be addressed with the autogenerated sync-params PR.

To remove a pair, simply remove the launch parameter file entry from the sync-param config file, and remove the sync-params comment header.

To specify the new upstream, in cases such as when the node package has been moved to a different repository, remove the old pair, and then re-add the launch parameter file with the new upstream.

## JSON Schema

[JSON Schema](<https://json-schema.org/understanding-json-schema/about>) is used to validate the parameter file(s) ensuring that it has the correct structure and content. Using JSON Schema for this purpose is considered best practice for cloud-native development. The schema template below shall be used as a starting point when defining the schema for a ROS node.

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "INSERT_TITLE",
  "type": "object",
  "definitions": {
    "INSERT_ROS_NODE_NAME": {
      "type": "object",
      "properties": {
        "INSERT_PARAMETER_1_NAME": {
          "type": "INSERT_TYPE",
          "description": "INSERT_DESCRIPTION",
          "default": "INSERT_DEFAULT",
          "INSERT_BOUND_CONDITION(S)": INSERT_BOUND_VALUE(S)
        },
        "INSERT_PARAMETER_N_NAME": {
          "type": "INSERT_TYPE",
          "description": "INSERT_DESCRIPTION",
          "default": "INSERT_DEFAULT",
          "INSERT_BOUND_CONDITION(S)": INSERT_BOUND_VALUE(S)
        }
      },
      "required": ["INSERT_PARAMETER_1_NAME", "INSERT_PARAMETER_N_NAME"],
      "additionalProperties": false
    }
  },
  "properties": {
    "/**": {
      "type": "object",
      "properties": {
        "ros__parameters": {
          "$ref": "#/definitions/INSERT_ROS_NODE_NAME"
        }
      },
      "required": ["ros__parameters"],
      "additionalProperties": false
    }
  },
  "required": ["/**"],
  "additionalProperties": false
}
```

The schema file path is `INSERT_PATH_TO_PACKAGE/schema/` and the schema file name is `INSERT_NODE_NAME.schema.json`. To adapt the template to the ROS node, replace each `INSERT_...` and add all parameters `1..N`.

See example: *Image Projection Based Fusion - Pointpainting* [schema](<https://github.com/autowarefoundation/autoware_universe/blob/0.53.1/perception/autoware_image_projection_based_fusion/schema/pointpainting.schema.json>)

### Attributes

Parameters have several attributes, some are required and some optional. The optional attributes are highly encouraged when applicable, as they provide useful information about a parameter and can ensure the value of the parameter is within its bounds.

#### Required

- name
- type

  - see [JSON Schema types](<https://json-schema.org/understanding-json-schema/reference/type>)
- description

#### Optional

- default

  - a tested and verified value, see [JSON Schema default](<https://json-schema.org/understanding-json-schema/reference/annotations>)
- bound(s)

  - type dependent, e.g., [integer](<https://json-schema.org/understanding-json-schema/reference/numeric#integer>), [range](<https://json-schema.org/understanding-json-schema/reference/numeric#range>) and [size](<https://json-schema.org/understanding-json-schema/reference/object#size>)

## Tips and Tricks

Using well established standards enables the use of conventional tooling. Below is an example of how to link a schema to the parameter file(s) using VS Code. This enables a developer with convenient features such as auto-complete and parameter bound validation.

In the root directory of where the project is hosted, create a `.vscode` folder with two files; `extensions.json` containing

```json
{
  "recommendations": ["redhat.vscode-yaml"]
}
```

and `settings.json` containing

```json
{
  "yaml.schemas": {
    "./INSERT_PATH_TO_PACKAGE/schema/INSERT_NODE_NAME.schema.json": "**/INSERT_NODE_NAME/config/*.param.yaml"
  }
}
```

The RedHat YAML extension enables validation of YAML files using JSON Schema and the `"yaml.schemas"` setting associates the `*.schema.json` file with all `*.param.yaml` files in the `config/` folder.
