diff --git a/system/diagnostic_graph_aggregator/CMakeLists.txt b/system/diagnostic_graph_aggregator/CMakeLists.txt index c4a67032541b2..574978ec5adce 100644 --- a/system/diagnostic_graph_aggregator/CMakeLists.txt +++ b/system/diagnostic_graph_aggregator/CMakeLists.txt @@ -22,10 +22,17 @@ ament_auto_add_executable(converter ) target_include_directories(converter PRIVATE src/common) -ament_auto_add_executable(tool - src/tool/tool.cpp +ament_auto_add_executable(tree + src/tool/tree.cpp + src/tool/utils/loader.cpp ) -target_include_directories(tool PRIVATE src/common) +target_include_directories(tree PRIVATE src/common) + +ament_auto_add_executable(plantuml + src/tool/plantuml.cpp + src/tool/utils/loader.cpp +) +target_include_directories(plantuml PRIVATE src/common) if(BUILD_TESTING) get_filename_component(RESOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test/files ABSOLUTE) diff --git a/system/diagnostic_graph_aggregator/README.md b/system/diagnostic_graph_aggregator/README.md index 4dc44feaafc33..cc49ed88ba98f 100644 --- a/system/diagnostic_graph_aggregator/README.md +++ b/system/diagnostic_graph_aggregator/README.md @@ -53,20 +53,33 @@ This feature breaks the generality of the graph and may be changed to a plugin o ## Examples -- [example_0.yaml](./example/example_0.yaml) -- [example_1.yaml](./example/example_1.yaml) -- [example_2.yaml](./example/example_2.yaml) +This is an example of a diagnostic graph configuration. The configuration can be split into multiple files. + +- [main.yaml](./example/graph/main.yaml) +- [module1.yaml](./example/graph/module1.yaml) +- [module2.yaml](./example/graph/module2.yaml) + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml +``` + +You can reuse the graph by making partial edits. For example, disable hardware checks for simulation. + +- [edit.yaml](./example/graph/edit.yaml) ```bash -ros2 launch diagnostic_graph_aggregator example.launch.xml +ros2 launch diagnostic_graph_aggregator example-edit.launch.xml ``` +## Debug tools + +- [dump](./doc/tool/dump.md) +- [converter](./doc/tool/converter.md) +- [tree](./doc/tool/tree.md) + ## Graph file format -- [GraphFile](./doc/format/graph-file.md) -- [Path](./doc/format/path.md) -- [Node](./doc/format/node.md) - - [Diag](./doc/format/diag.md) - - [Unit](./doc/format/unit.md) - - [And](./doc/format/and.md) - - [Or](./doc/format/or.md) +- [graph](./doc/format/graph.md) +- [path](./doc/format/path.md) +- [node](./doc/format/node.md) +- [edit](./doc/format/edit.md) diff --git a/system/diagnostic_graph_aggregator/doc/format/and.md b/system/diagnostic_graph_aggregator/doc/format/and.md deleted file mode 100644 index a92aa2817832e..0000000000000 --- a/system/diagnostic_graph_aggregator/doc/format/and.md +++ /dev/null @@ -1,11 +0,0 @@ -# Unit - -And is a node that is evaluated as the AND of the input nodes. - -## Format - -| Name | Type | Required | Description | -| ---- | ------------------------------------------ | -------- | ------------------------------------- | -| type | string | yes | Specify `and` when using this object. | -| name | string | yes | Name of diagnostic status. | -| list | List<[Diag](./diag.md)\|[Unit](./unit.md)> | yes | List of input node references. | diff --git a/system/diagnostic_graph_aggregator/doc/format/diag.md b/system/diagnostic_graph_aggregator/doc/format/diag.md deleted file mode 100644 index 04e850129cbbf..0000000000000 --- a/system/diagnostic_graph_aggregator/doc/format/diag.md +++ /dev/null @@ -1,10 +0,0 @@ -# Diag - -Diag is a node that refers to a source diagnostics. - -## Format - -| Name | Type | Required | Description | -| ---- | ------ | -------- | -------------------------------------- | -| type | string | yes | Specify `diag` when using this object. | -| diag | string | yes | Name of diagnostic status. | diff --git a/system/diagnostic_graph_aggregator/doc/format/edit.md b/system/diagnostic_graph_aggregator/doc/format/edit.md new file mode 100644 index 0000000000000..71ea8a96bc17f --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/edit.md @@ -0,0 +1,14 @@ +# Edit + +The `edit` is a base object that edits the existing diagnostic graph. +Any derived object can be used where a edit object is required. + +## Format + +| Name | Type | Required | Description | +| ------ | -------- | -------- | ------------------------------------------------- | +| `type` | `string` | yes | The string indicating the type of derived object. | + +## Derived objects + +- [remove](./edit/remove.md) diff --git a/system/diagnostic_graph_aggregator/doc/format/edit/remove.md b/system/diagnostic_graph_aggregator/doc/format/edit/remove.md new file mode 100644 index 0000000000000..6cd4b25e98828 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/edit/remove.md @@ -0,0 +1,10 @@ +# Remove + +The `remove` object is a edit that removes other nodes. + +## Format + +| Name | Type | Required | Description | +| ------ | -------- | -------- | ---------------------------------------- | +| `type` | `string` | yes | Specify `remove` when using this object. | +| `path` | `string` | yes | The path of the node to remove. | diff --git a/system/diagnostic_graph_aggregator/doc/format/graph-file.md b/system/diagnostic_graph_aggregator/doc/format/graph-file.md deleted file mode 100644 index 3c4cfec996a4a..0000000000000 --- a/system/diagnostic_graph_aggregator/doc/format/graph-file.md +++ /dev/null @@ -1,10 +0,0 @@ -# GraphFile - -GraphFile is the top level object that makes up the configuration file. - -## Format - -| Name | Type | Required | Description | -| ----- | ----------------------- | -------- | ------------------------------ | -| files | List<[Path](./path.md)> | no | Paths of the files to include. | -| nodes | List<[Node](./node.md)> | no | Nodes of the diagnostic graph. | diff --git a/system/diagnostic_graph_aggregator/doc/format/graph.md b/system/diagnostic_graph_aggregator/doc/format/graph.md new file mode 100644 index 0000000000000..9dace8a2f0e6d --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/graph.md @@ -0,0 +1,11 @@ +# Graph + +The graph object is the top level structure that makes up the configuration file. + +## Format + +| Name | Type | Required | Description | +| ------- | -------------------------------------- | -------- | ------------------------------------------------- | +| `files` | list\[[path](./path.md)\] | no | List of path objects for importing subgraphs. | +| `nodes` | list\[[node](./node.md)\] | no | List of node objects that make up the graph. | +| `edits` | list\[[edit](./edit.md)\] | no | List of edit objects to partially edit the graph. | diff --git a/system/diagnostic_graph_aggregator/doc/format/node.md b/system/diagnostic_graph_aggregator/doc/format/node.md index da8e8e57b111f..0f4b52b9b8a72 100644 --- a/system/diagnostic_graph_aggregator/doc/format/node.md +++ b/system/diagnostic_graph_aggregator/doc/format/node.md @@ -1,9 +1,25 @@ # Node -Node is a base object that makes up the diagnostic graph. +The `node` is a base object that makes up the diagnostic graph. +Any derived object can be used where a node object is required. ## Format -| Name | Type | Required | Description | -| ---- | ------ | -------- | ------------------------------------------- | -| type | string | yes | Node type. See derived objects for details. | +| Name | Type | Required | Description | +| ------ | -------- | -------- | ------------------------------------------------- | +| `type` | `string` | yes | The string indicating the type of derived object. | +| `path` | `string` | no | Any string to reference from other nodes. | + +## Derived objects + +- [diag](./node/diag.md) +- [and](./node/and.md) +- [or](./node/or.md) +- [remapping](./node/remap.md) + - warn-to-ok + - warn-to-error +- [constant](./node/const.md) + - ok + - warn + - error + - stale diff --git a/system/diagnostic_graph_aggregator/doc/format/node/and.md b/system/diagnostic_graph_aggregator/doc/format/node/and.md new file mode 100644 index 0000000000000..562018bf0995b --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/and.md @@ -0,0 +1,17 @@ +# And + +The `and` object is a node that is evaluated as the maximum error level of the input nodes. +Note that error level `stale` is treated as `error`. + +## Format + +| Name | Type | Required | Description | +| ------ | -------------------------------------- | -------- | ------------------------------------------------------------ | +| `type` | string | yes | Specify `and` or `short-circuit-and` when using this object. | +| `list` | list\[[node](../node.md)] | yes | List of input node objects. | + +## Short-circuit evaluation + +!!! warning + + The`short-circuit-and` is work in progress (WIP). diff --git a/system/diagnostic_graph_aggregator/doc/format/node/const.md b/system/diagnostic_graph_aggregator/doc/format/node/const.md new file mode 100644 index 0000000000000..13495be6cdbda --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/const.md @@ -0,0 +1,18 @@ +# Constant + +The constant object is a node with a fixed error level. + +## Format + +| Name | Type | Required | Description | +| ------ | -------- | -------- | ------------------------------------------- | +| `type` | `string` | yes | Specify error level when using this object. | + +## Error levels + +The supported error levels are as follows. + +- `ok` +- `warn` +- `error` +- `stale` diff --git a/system/diagnostic_graph_aggregator/doc/format/node/diag.md b/system/diagnostic_graph_aggregator/doc/format/node/diag.md new file mode 100644 index 0000000000000..beba8ed0df5b4 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/diag.md @@ -0,0 +1,10 @@ +# Diag + +The `diag` object is a node that refers to a specific status within the source diagnostics. + +## Format + +| Name | Type | Required | Description | +| ------ | -------- | -------- | -------------------------------------- | +| `type` | `string` | yes | Specify `diag` when using this object. | +| `diag` | `string` | yes | The name of the diagnostic status. | diff --git a/system/diagnostic_graph_aggregator/doc/format/node/link.md b/system/diagnostic_graph_aggregator/doc/format/node/link.md new file mode 100644 index 0000000000000..c23aa92575e54 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/link.md @@ -0,0 +1,10 @@ +# Link + +The `link` object is a node that refers to other nodes. + +## Format + +| Name | Type | Required | Description | +| ------ | -------- | -------- | -------------------------------------- | +| `type` | `string` | yes | Specify `link` when using this object. | +| `link` | `string` | yes | The path of the node to reference. | diff --git a/system/diagnostic_graph_aggregator/doc/format/node/or.md b/system/diagnostic_graph_aggregator/doc/format/node/or.md new file mode 100644 index 0000000000000..74e94ffd628e3 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/or.md @@ -0,0 +1,11 @@ +# Or + +The `or` object is a node that is evaluated as the minimum error level of the input nodes. +Note that error level `stale` is treated as `error`. + +## Format + +| Name | Type | Required | Description | +| ------ | -------------------------------------- | -------- | ------------------------------------ | +| `type` | string | yes | Specify `or` when using this object. | +| `list` | list\[[node](../node.md)] | yes | List of input node objects. | diff --git a/system/diagnostic_graph_aggregator/doc/format/node/remap.md b/system/diagnostic_graph_aggregator/doc/format/node/remap.md new file mode 100644 index 0000000000000..abf0d11fae12d --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/format/node/remap.md @@ -0,0 +1,21 @@ +# Constant + +!!! warning + + This object is under development. It may be removed in the future. + +The remapping object is a node that converts error levels. + +## Format + +| Name | Type | Required | Description | +| ------ | -------------------------------------- | -------- | ---------------------------------------------------- | +| `type` | `string` | yes | Specify remapping type when using this object. | +| `list` | list\[[node](../node.md)] | yes | List of input node objects. The list size must be 1. | + +## Remapping types + +The supported remapping types are as follows. + +- `warn-to-ok` +- `warn-to-error` diff --git a/system/diagnostic_graph_aggregator/doc/format/or.md b/system/diagnostic_graph_aggregator/doc/format/or.md deleted file mode 100644 index 3e668b686c9e8..0000000000000 --- a/system/diagnostic_graph_aggregator/doc/format/or.md +++ /dev/null @@ -1,11 +0,0 @@ -# Unit - -Or is a node that is evaluated as the OR of the input nodes. - -## Format - -| Name | Type | Required | Description | -| ---- | ------------------------------------------ | -------- | ------------------------------------ | -| type | string | yes | Specify `or` when using this object. | -| name | string | yes | Name of diagnostic status. | -| list | List<[Diag](./diag.md)\|[Unit](./unit.md)> | yes | List of input node references. | diff --git a/system/diagnostic_graph_aggregator/doc/format/path.md b/system/diagnostic_graph_aggregator/doc/format/path.md index 1f27accefa35a..6ca32a7eaad80 100644 --- a/system/diagnostic_graph_aggregator/doc/format/path.md +++ b/system/diagnostic_graph_aggregator/doc/format/path.md @@ -1,10 +1,19 @@ # Path -Path is an object that indicates the path of the file to include. +The path object specifies the file path of the subgraph to be imported. +The structure of the subgraph file should be [graph object](./graph.md). ## Format -| Name | Type | Required | Description | -| ------- | ------ | -------- | ----------------------------- | -| package | string | yes | Package name. | -| path | string | yes | Relative path in the package. | +| Name | Type | Required | Description | +| ------ | -------- | -------- | ------------------------------ | +| `path` | `string` | yes | The file path of the subgraph. | + +## Substitutions + +File paths can contain substitutions like ROS 2 launch. The supported substitutions are as follows. + +| Substitution | Description | +| ----------------------------- | -------------------------------- | +| `$(dirname)` | The path of this file directory. | +| `$(find-pkg-share )` | The path of the package. | diff --git a/system/diagnostic_graph_aggregator/doc/format/unit.md b/system/diagnostic_graph_aggregator/doc/format/unit.md deleted file mode 100644 index 791689aa2d98a..0000000000000 --- a/system/diagnostic_graph_aggregator/doc/format/unit.md +++ /dev/null @@ -1,10 +0,0 @@ -# Unit - -Diag is a node that refers to a functional unit. - -## Format - -| Name | Type | Required | Description | -| ---- | ------ | -------- | -------------------------------------- | -| type | string | yes | Specify `unit` when using this object. | -| name | string | yes | Name of diagnostic status. | diff --git a/system/diagnostic_graph_aggregator/doc/tool/converter.md b/system/diagnostic_graph_aggregator/doc/tool/converter.md new file mode 100644 index 0000000000000..2351bc1e01054 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/converter.md @@ -0,0 +1,29 @@ +# Converter tool + +This tool converts `/diagnostics_graph` to `/diagnostics_agg` so it can be read by tools such as `rqt_runtime_monitor` and `rqt_robot_monitor`. + +## Usage + +```bash +ros2 launch diagnostic_graph_aggregator converter.launch.xml complement:=false +``` + +The `complement` argument specifies whether to add an intermediate path that does not exist. +This means that if the graph contains paths `/A/B` and `/A/B/C/D/E`, the intermediate paths `/A`, `/A/B/C` and `/A/B/C/D` will be added. +This is useful for tree view in `rqt_robot_monitor`. The completed node has an error level of `STALE`. + +## Examples + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml complement:=false +ros2 run rqt_runtime_monitor rqt_runtime_monitor --ros-args -r diagnostics:=diagnostics_agg +``` + +![rqt_runtime_monitor](./images/rqt_runtime_monitor.png) + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml complement:=true +ros2 run rqt_robot_monitor rqt_robot_monitor +``` + +![rqt_robot_monitor](./images/rqt_robot_monitor.png) diff --git a/system/diagnostic_graph_aggregator/doc/tool/dump.md b/system/diagnostic_graph_aggregator/doc/tool/dump.md new file mode 100644 index 0000000000000..33f05ff866603 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/dump.md @@ -0,0 +1,36 @@ +# Dump tool + +This tool displays `/diagnostics_graph` in table format. + +## Usage + +```bash +ros2 run diagnostic_graph_aggregator dump +``` + +## Examples + +```bash +ros2 launch diagnostic_graph_aggregator example-main.launch.xml +ros2 run diagnostic_graph_aggregator dump +``` + +```txt +| ----- | ----- | -------------------------------- | ----- | +| index | level | name | links | +| ----- | ----- | -------------------------------- | ----- | +| 0 | OK | /sensing/radars/front | | +| 1 | OK | /sensing/lidars/front | | +| 2 | ERROR | /sensing/lidars/top | | +| 3 | OK | /functions/obstacle_detection | 1 0 | +| 4 | ERROR | /functions/pose_estimation | 2 | +| 5 | OK | /external/remote_command | | +| 6 | OK | /external/joystick_command | | +| 7 | ERROR | /autoware/modes/pull_over | 4 3 | +| 8 | OK | /autoware/modes/comfortable_stop | 3 | +| 9 | OK | /autoware/modes/emergency_stop | | +| 10 | OK | /autoware/modes/remote | 5 | +| 11 | OK | /autoware/modes/local | 6 | +| 12 | ERROR | /autoware/modes/autonomous | 4 3 | +| 13 | OK | /autoware/modes/stop | | +``` diff --git a/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png new file mode 100644 index 0000000000000..e4aa169f02add Binary files /dev/null and b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_robot_monitor.png differ diff --git a/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png new file mode 100644 index 0000000000000..768fee688f594 Binary files /dev/null and b/system/diagnostic_graph_aggregator/doc/tool/images/rqt_runtime_monitor.png differ diff --git a/system/diagnostic_graph_aggregator/doc/tool/tree.md b/system/diagnostic_graph_aggregator/doc/tool/tree.md new file mode 100644 index 0000000000000..79fa61f527038 --- /dev/null +++ b/system/diagnostic_graph_aggregator/doc/tool/tree.md @@ -0,0 +1,40 @@ +# Tree tool + +This tool displays the graph structure of the configuration file in tree format. + +## Usage + +```bash +ros2 run diagnostic_graph_aggregator tree +``` + +## Examples + +```bash +ros2 run diagnostic_graph_aggregator tree system/diagnostic_graph_aggregator/example/graph/main.yaml +``` + +```txt +===== root nodes ================================= +- /autoware/modes/local (and) + - /external/joystick_command (diag) +- /autoware/modes/comfortable_stop (and) + - /functions/obstacle_detection (or) +- /autoware/modes/pull_over (and) + - /functions/pose_estimation (and) + - /functions/obstacle_detection (or) +- /autoware/modes/autonomous (and) + - /functions/pose_estimation (and) + - /functions/obstacle_detection (or) +- /autoware/modes/remote (and) + - /external/remote_command (diag) +===== intermediate nodes ========================= +- /functions/obstacle_detection (or) + - /sensing/lidars/front (diag) + - /sensing/radars/front (diag) +- /functions/pose_estimation (and) + - /sensing/lidars/top (diag) +===== isolated nodes ============================= +- /autoware/modes/stop (const) +- /autoware/modes/emergency_stop (const) +``` diff --git a/system/diagnostic_graph_aggregator/example/example_diags.py b/system/diagnostic_graph_aggregator/example/dummy-diags.py similarity index 93% rename from system/diagnostic_graph_aggregator/example/example_diags.py rename to system/diagnostic_graph_aggregator/example/dummy-diags.py index 52d6189a63f30..08f81bcd738ed 100755 --- a/system/diagnostic_graph_aggregator/example/example_diags.py +++ b/system/diagnostic_graph_aggregator/example/dummy-diags.py @@ -59,6 +59,9 @@ def create_status(name: str): "external_command_checker: joystick_command", "external_command_checker: remote_command", ] - rclpy.init() - rclpy.spin(DummyDiagnostics(diags)) - rclpy.shutdown() + try: + rclpy.init() + rclpy.spin(DummyDiagnostics(diags)) + rclpy.shutdown() + except KeyboardInterrupt: + pass diff --git a/system/diagnostic_graph_aggregator/example/example-edit.launch.xml b/system/diagnostic_graph_aggregator/example/example-edit.launch.xml new file mode 100644 index 0000000000000..c168b76f19c21 --- /dev/null +++ b/system/diagnostic_graph_aggregator/example/example-edit.launch.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/system/diagnostic_graph_aggregator/example/example-main.launch.xml b/system/diagnostic_graph_aggregator/example/example-main.launch.xml new file mode 100644 index 0000000000000..cdc1bc8afca53 --- /dev/null +++ b/system/diagnostic_graph_aggregator/example/example-main.launch.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/system/diagnostic_graph_aggregator/example/example.launch.xml b/system/diagnostic_graph_aggregator/example/example.launch.xml deleted file mode 100644 index 71e59a1833d6e..0000000000000 --- a/system/diagnostic_graph_aggregator/example/example.launch.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/system/diagnostic_graph_aggregator/example/graph/edit.yaml b/system/diagnostic_graph_aggregator/example/graph/edit.yaml new file mode 100644 index 0000000000000..2fbdbffca438d --- /dev/null +++ b/system/diagnostic_graph_aggregator/example/graph/edit.yaml @@ -0,0 +1,6 @@ +files: + - { path: $(find-pkg-share diagnostic_graph_aggregator)/example/graph/main.yaml } + +edits: + - path: /functions/obstacle_detection + type: remove diff --git a/system/diagnostic_graph_aggregator/example/example_0.yaml b/system/diagnostic_graph_aggregator/example/graph/main.yaml similarity index 83% rename from system/diagnostic_graph_aggregator/example/example_0.yaml rename to system/diagnostic_graph_aggregator/example/graph/main.yaml index 7b01883723c76..2bea907d9c119 100644 --- a/system/diagnostic_graph_aggregator/example/example_0.yaml +++ b/system/diagnostic_graph_aggregator/example/graph/main.yaml @@ -1,6 +1,6 @@ files: - - { path: $(find-pkg-share diagnostic_graph_aggregator)/example/example_1.yaml } - - { path: $(find-pkg-share diagnostic_graph_aggregator)/example/example_2.yaml } + - { path: $(dirname)/module1.yaml } + - { path: $(dirname)/module2.yaml } nodes: - path: /autoware/modes/stop diff --git a/system/diagnostic_graph_aggregator/example/example_1.yaml b/system/diagnostic_graph_aggregator/example/graph/module1.yaml similarity index 100% rename from system/diagnostic_graph_aggregator/example/example_1.yaml rename to system/diagnostic_graph_aggregator/example/graph/module1.yaml diff --git a/system/diagnostic_graph_aggregator/example/example_2.yaml b/system/diagnostic_graph_aggregator/example/graph/module2.yaml similarity index 100% rename from system/diagnostic_graph_aggregator/example/example_2.yaml rename to system/diagnostic_graph_aggregator/example/graph/module2.yaml diff --git a/system/diagnostic_graph_aggregator/launch/diagnostic_graph_aggregator.launch.xml b/system/diagnostic_graph_aggregator/launch/aggregator.launch.xml similarity index 100% rename from system/diagnostic_graph_aggregator/launch/diagnostic_graph_aggregator.launch.xml rename to system/diagnostic_graph_aggregator/launch/aggregator.launch.xml diff --git a/system/diagnostic_graph_aggregator/launch/converter.launch.xml b/system/diagnostic_graph_aggregator/launch/converter.launch.xml new file mode 100644 index 0000000000000..9111338bf622a --- /dev/null +++ b/system/diagnostic_graph_aggregator/launch/converter.launch.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/system/diagnostic_graph_aggregator/script/dump.py b/system/diagnostic_graph_aggregator/script/dump.py index 3e639cbce104d..9abcaeb7a080c 100755 --- a/system/diagnostic_graph_aggregator/script/dump.py +++ b/system/diagnostic_graph_aggregator/script/dump.py @@ -84,7 +84,6 @@ def callback(self, msg): if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--topic", default="/diagnostics_graph") - parser.add_argument("--order", default="index") args, unparsed = parser.parse_known_args() try: diff --git a/system/diagnostic_graph_aggregator/src/node/aggregator.cpp b/system/diagnostic_graph_aggregator/src/node/aggregator.cpp index 48f489c186bdb..cd16ce8e33e59 100644 --- a/system/diagnostic_graph_aggregator/src/node/aggregator.cpp +++ b/system/diagnostic_graph_aggregator/src/node/aggregator.cpp @@ -20,7 +20,7 @@ namespace diagnostic_graph_aggregator { -MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") +AggregatorNode::AggregatorNode() : Node("aggregator") { // Init diagnostics graph. { @@ -39,7 +39,7 @@ MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") const auto qos_input = rclcpp::QoS(declare_parameter("input_qos_depth")); const auto qos_graph = rclcpp::QoS(declare_parameter("graph_qos_depth")); - const auto callback = std::bind(&MainNode::on_diag, this, _1); + const auto callback = std::bind(&AggregatorNode::on_diag, this, _1); sub_input_ = create_subscription("/diagnostics", qos_input, callback); pub_graph_ = create_publisher("/diagnostics_graph", qos_graph); @@ -51,12 +51,12 @@ MainNode::MainNode() : Node("diagnostic_graph_aggregator_aggregator") debug_ = declare_parameter("use_debug_mode"); } -MainNode::~MainNode() +AggregatorNode::~AggregatorNode() { // for unique_ptr } -void MainNode::on_timer() +void AggregatorNode::on_timer() { const auto stamp = now(); pub_graph_->publish(graph_.report(stamp)); @@ -64,7 +64,7 @@ void MainNode::on_timer() if (modes_) modes_->update(stamp); } -void MainNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) +void AggregatorNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) { graph_.callback(now(), *msg); } @@ -73,10 +73,10 @@ void MainNode::on_diag(const DiagnosticArray::ConstSharedPtr msg) int main(int argc, char ** argv) { - using diagnostic_graph_aggregator::MainNode; + using diagnostic_graph_aggregator::AggregatorNode; rclcpp::init(argc, argv); rclcpp::executors::SingleThreadedExecutor executor; - auto node = std::make_shared(); + auto node = std::make_shared(); executor.add_node(node); executor.spin(); executor.remove_node(node); diff --git a/system/diagnostic_graph_aggregator/src/node/aggregator.hpp b/system/diagnostic_graph_aggregator/src/node/aggregator.hpp index dd64809e939cc..6bf9aead9754d 100644 --- a/system/diagnostic_graph_aggregator/src/node/aggregator.hpp +++ b/system/diagnostic_graph_aggregator/src/node/aggregator.hpp @@ -26,11 +26,11 @@ namespace diagnostic_graph_aggregator { -class MainNode : public rclcpp::Node +class AggregatorNode : public rclcpp::Node { public: - MainNode(); - ~MainNode(); + AggregatorNode(); + ~AggregatorNode(); private: Graph graph_; diff --git a/system/diagnostic_graph_aggregator/src/node/converter.cpp b/system/diagnostic_graph_aggregator/src/node/converter.cpp index 89acfce31a5ab..f0b2108374017 100644 --- a/system/diagnostic_graph_aggregator/src/node/converter.cpp +++ b/system/diagnostic_graph_aggregator/src/node/converter.cpp @@ -14,8 +14,7 @@ #include "converter.hpp" -#include -#include +#include namespace diagnostic_graph_aggregator { @@ -35,18 +34,46 @@ std::string level_to_string(DiagnosticLevel level) return "UNKNOWN"; } -ToolNode::ToolNode() : Node("diagnostic_graph_aggregator_converter") +std::string parent_path(const std::string & path) +{ + return path.substr(0, path.rfind('/')); +} + +auto create_tree(const DiagnosticGraph & graph) +{ + std::map, std::greater> tree; + for (const auto & node : graph.nodes) { + tree.emplace(node.status.name, std::make_unique(true)); + } + for (const auto & node : graph.nodes) { + std::string path = node.status.name; + while (path = parent_path(path), !path.empty()) { + if (tree.count(path)) break; + tree.emplace(path, std::make_unique(false)); + } + } + for (const auto & [path, node] : tree) { + const auto parent = parent_path(path); + node->parent = parent.empty() ? nullptr : tree[parent].get(); + } + return tree; +} + +ConverterNode::ConverterNode() : Node("converter") { using std::placeholders::_1; const auto qos_graph = rclcpp::QoS(1); const auto qos_array = rclcpp::QoS(1); - const auto callback = std::bind(&ToolNode::on_graph, this, _1); + const auto callback = std::bind(&ConverterNode::on_graph, this, _1); sub_graph_ = create_subscription("/diagnostics_graph", qos_graph, callback); - pub_array_ = create_publisher("/diagnostics_array", qos_array); + pub_array_ = create_publisher("/diagnostics_agg", qos_array); + + initialize_tree_ = false; + complement_tree_ = declare_parameter("complement_tree"); } -void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) +void ConverterNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) { DiagnosticArray message; message.header.stamp = msg->stamp; @@ -63,6 +90,31 @@ void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) } } } + + if (complement_tree_ && !initialize_tree_) { + initialize_tree_ = true; + tree_ = create_tree(*msg); + } + + if (complement_tree_) { + for (const auto & [path, node] : tree_) { + node->level = DiagnosticStatus::OK; + } + for (const auto & node : msg->nodes) { + tree_[node.status.name]->level = node.status.level; + } + for (const auto & [path, node] : tree_) { + if (!node->parent) continue; + node->parent->level = std::max(node->parent->level, node->level); + } + for (const auto & [path, node] : tree_) { + if (node->leaf) continue; + message.status.emplace_back(); + message.status.back().name = path; + message.status.back().level = node->level; + } + } + pub_array_->publish(message); } @@ -70,10 +122,10 @@ void ToolNode::on_graph(const DiagnosticGraph::ConstSharedPtr msg) int main(int argc, char ** argv) { - using diagnostic_graph_aggregator::ToolNode; + using diagnostic_graph_aggregator::ConverterNode; rclcpp::init(argc, argv); rclcpp::executors::SingleThreadedExecutor executor; - auto node = std::make_shared(); + auto node = std::make_shared(); executor.add_node(node); executor.spin(); executor.remove_node(node); diff --git a/system/diagnostic_graph_aggregator/src/node/converter.hpp b/system/diagnostic_graph_aggregator/src/node/converter.hpp index 7a3e8e4e58033..1f98abed4d619 100644 --- a/system/diagnostic_graph_aggregator/src/node/converter.hpp +++ b/system/diagnostic_graph_aggregator/src/node/converter.hpp @@ -19,15 +19,32 @@ #include +#include +#include // Use map for sorting keys. +#include +#include +#include + namespace diagnostic_graph_aggregator { -class ToolNode : public rclcpp::Node +struct TreeNode +{ + explicit TreeNode(bool leaf) : leaf(leaf) {} + bool leaf; + TreeNode * parent; + uint8_t level; +}; + +class ConverterNode : public rclcpp::Node { public: - ToolNode(); + ConverterNode(); private: + bool initialize_tree_; + bool complement_tree_; + std::map, std::greater> tree_; rclcpp::Subscription::SharedPtr sub_graph_; rclcpp::Publisher::SharedPtr pub_array_; void on_graph(const DiagnosticGraph::ConstSharedPtr msg); diff --git a/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp b/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp new file mode 100644 index 0000000000000..bfbb382a78fcb --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/plantuml.cpp @@ -0,0 +1,49 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/loader.hpp" + +#include + +namespace diagnostic_graph_aggregator +{ + +void dump_root(const std::string & path) +{ + const auto graph = load_graph_nodes(path); + const auto color = "#FFFFFF"; + + for (const auto & node : graph.nodes) { + std::cout << "card " << node << " " << color << " [" << std::endl; + std::cout << node->path << std::endl; + std::cout << "]" << std::endl; + } + + for (const auto & node : graph.nodes) { + for (const auto & child : node->children) { + std::cout << node << " --> " << child << std::endl; + } + } +} + +} // namespace diagnostic_graph_aggregator + +int main(int argc, char ** argv) +{ + if (argc != 2) { + std::cerr << "usage: plantuml " << std::endl; + return 1; + } + diagnostic_graph_aggregator::dump_root(argv[1]); +} diff --git a/system/diagnostic_graph_aggregator/src/tool/tool.cpp b/system/diagnostic_graph_aggregator/src/tool/tool.cpp deleted file mode 100644 index 657f76c2d91b7..0000000000000 --- a/system/diagnostic_graph_aggregator/src/tool/tool.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 The Autoware Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "graph/graph.hpp" -#include "graph/types.hpp" -#include "graph/units.hpp" - -#include -#include -#include - -namespace diagnostic_graph_aggregator -{ - -struct GraphNode -{ - using UniquePtr = std::unique_ptr; - std::string type; - std::string path; - std::vector children; - std::vector parents; -}; - -struct GraphRoot -{ - std::vector owner; - std::vector nodes; -}; - -GraphRoot load_graph_nodes(const std::string & path) -{ - GraphRoot result; - { - std::unordered_map mapping; - Graph graph; - graph.init(path); - - for (const auto & node : graph.nodes()) { - auto data = std::make_unique(); - data->path = node->path(); - data->type = node->type(); - mapping[node] = std::move(data); - } - - for (const auto & [node, data] : mapping) { - for (const auto & link : node->children()) { - const auto parent = data.get(); - const auto child = mapping.at(link).get(); - child->parents.push_back(parent); - parent->children.push_back(child); - } - } - - for (auto & [node, data] : mapping) { - result.owner.push_back(std::move(data)); - } - for (const auto & node : result.owner) { - result.nodes.push_back(node.get()); - } - } - return result; -} - -void dump_plantuml_path(const std::string & path) -{ - const auto graph = load_graph_nodes(path); - const auto color = "#FFFFFF"; - - for (const auto & node : graph.nodes) { - std::cout << "card " << node << " " << color << " [" << std::endl; - std::cout << node->path << std::endl; - std::cout << "]" << std::endl; - } - - for (const auto & node : graph.nodes) { - for (const auto & child : node->children) { - std::cout << node << " --> " << child << std::endl; - } - } -} - -void dump_tree_node(const GraphNode * node, const std::string & indent = "", bool root = true) -{ - const auto path = node->path.empty() ? "" : node->path + " "; - const auto type = "(" + node->type + ")"; - std::cout << indent << "- " << path << type << std::endl; - - if (root || node->parents.size() == 1) { - for (const auto child : node->children) { - dump_tree_node(child, indent + " ", false); - } - } -} - -void dump_tree_path(const std::string & path) -{ - const auto graph = load_graph_nodes(path); - - std::cout << "===== root nodes =================================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() == 0 && node->children.size() != 0) { - dump_tree_node(node); - } - } - std::cout << "===== intermediate nodes =========================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() >= 2) { - dump_tree_node(node); - } - } - - std::cout << "===== isolated nodes =============================" << std::endl; - for (const auto & node : graph.nodes) { - if (node->parents.size() == 0 && node->children.size() == 0) { - dump_tree_node(node); - } - } -} - -} // namespace diagnostic_graph_aggregator - -int main(int argc, char ** argv) -{ - if (argc != 2) { - std::cerr << "usage: " << argv[0] << " " << std::endl; - return 1; - } - diagnostic_graph_aggregator::dump_tree_path(argv[1]); -} diff --git a/system/diagnostic_graph_aggregator/src/tool/tree.cpp b/system/diagnostic_graph_aggregator/src/tool/tree.cpp new file mode 100644 index 0000000000000..9dbbc539b3b91 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/tree.cpp @@ -0,0 +1,69 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/loader.hpp" + +#include + +namespace diagnostic_graph_aggregator +{ + +void dump_node(const GraphNode * node, const std::string & indent = "", bool root = true) +{ + const auto path = node->path.empty() ? "" : node->path + " "; + const auto type = "(" + node->type + ")"; + std::cout << indent << "- " << path << type << std::endl; + + if (root || node->parents.size() == 1) { + for (const auto child : node->children) { + dump_node(child, indent + " ", false); + } + } +} + +void dump_root(const std::string & path) +{ + const auto graph = load_graph_nodes(path); + + std::cout << "===== root nodes =================================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() == 0 && node->children.size() != 0) { + dump_node(node); + } + } + std::cout << "===== intermediate nodes =========================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() >= 2) { + dump_node(node); + } + } + + std::cout << "===== isolated nodes =============================" << std::endl; + for (const auto & node : graph.nodes) { + if (node->parents.size() == 0 && node->children.size() == 0) { + dump_node(node); + } + } +} + +} // namespace diagnostic_graph_aggregator + +int main(int argc, char ** argv) +{ + if (argc != 2) { + std::cerr << "usage: tree " << std::endl; + return 1; + } + diagnostic_graph_aggregator::dump_root(argv[1]); +} diff --git a/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp b/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp new file mode 100644 index 0000000000000..a2e6ce8b85334 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/utils/loader.cpp @@ -0,0 +1,57 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "loader.hpp" + +#include +#include + +namespace diagnostic_graph_aggregator +{ + +GraphRoot load_graph_nodes(const std::string & path) +{ + GraphRoot result; + { + std::unordered_map mapping; + Graph graph; + graph.init(path); + + for (const auto & node : graph.nodes()) { + auto data = std::make_unique(); + data->path = node->path(); + data->type = node->type(); + mapping[node] = std::move(data); + } + + for (const auto & [node, data] : mapping) { + for (const auto & link : node->children()) { + const auto parent = data.get(); + const auto child = mapping.at(link).get(); + child->parents.push_back(parent); + parent->children.push_back(child); + } + } + + for (auto & [node, data] : mapping) { + result.owner.push_back(std::move(data)); + } + for (const auto & node : result.owner) { + result.nodes.push_back(node.get()); + } + } + return result; +} + +} // namespace diagnostic_graph_aggregator diff --git a/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp b/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp new file mode 100644 index 0000000000000..70e01ec2a77b4 --- /dev/null +++ b/system/diagnostic_graph_aggregator/src/tool/utils/loader.hpp @@ -0,0 +1,48 @@ +// Copyright 2023 The Autoware Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TOOL__UTILS__LOADER_HPP_ +#define TOOL__UTILS__LOADER_HPP_ + +#include "graph/graph.hpp" +#include "graph/types.hpp" +#include "graph/units.hpp" + +#include +#include +#include + +namespace diagnostic_graph_aggregator +{ + +struct GraphNode +{ + using UniquePtr = std::unique_ptr; + std::string type; + std::string path; + std::vector children; + std::vector parents; +}; + +struct GraphRoot +{ + std::vector owner; + std::vector nodes; +}; + +GraphRoot load_graph_nodes(const std::string & path); + +} // namespace diagnostic_graph_aggregator + +#endif // TOOL__UTILS__LOADER_HPP_