Repository: tier4/agnocast
Pull request #538: fix(component container): enable parameter passing
Author: login: sykwer
Labels: name: run-build-test
description: Run build-test in CI
Created: 2025-03-18T19:49:56Z | Merged: 2025-03-21T16:37:27Z

## Description
実は今まで、AgnocastのComponent Containerには、パラメータを渡せないバグがあった。

## Related links

## How was this PR tested?

- [ ] Autoware (required)
- [x] `bash scripts/e2e_test_1to1_with_ros2sub` (required)
- [x] `bash scripts/e2e_test_2to2` (required)
- [x] sample application
- [x] 各パラメータが適切に渡されていることのチェック

## Notes for reviewers



Diff:
diff --git a/src/agnocastlib/src/agnocast_component_container.cpp b/src/agnocastlib/src/agnocast_component_container.cpp
index 87eccfc5e..757ee594b 100644
--- a/src/agnocastlib/src/agnocast_component_container.cpp
+++ b/src/agnocastlib/src/agnocast_component_container.cpp
@@ -4,21 +4,35 @@
 
 int main(int argc, char * argv[])
 {
-  rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
+  try {
+    rclcpp::init(argc, argv);
 
-  const int get_next_timeout_ms =
-    (node->has_parameter("get_next_timeout_ms"))
-      ? static_cast<int>(node->get_parameter("get_next_timeout_ms").as_int())
-      : 50;
+    rclcpp::NodeOptions options;
+    options.allow_undeclared_parameters(true);
+    options.automatically_declare_parameters_from_overrides(true);
 
-  auto executor = std::make_shared<agnocast::SingleThreadedAgnocastExecutor>(
-    rclcpp::ExecutorOptions{}, get_next_timeout_ms);
+    auto node = std::make_shared<rclcpp_components::ComponentManager>(
+      std::weak_ptr<rclcpp::Executor>(), "ComponentManager", options);
 
-  node->set_executor(executor);
-  executor->add_node(node);
-  executor->spin();
+    const int get_next_timeout_ms = node->get_parameter_or("get_next_timeout_ms", 50);
+
+    auto executor = std::make_shared<agnocast::SingleThreadedAgnocastExecutor>(
+      rclcpp::ExecutorOptions{}, get_next_timeout_ms);
+
+    node->set_executor(executor);
+    executor->add_node(node);
+    executor->spin();
+
+    rclcpp::shutdown();
+  } catch (rclcpp_components::ComponentManagerException & ex) {
+    std::cerr << "Exception caught in main: " << ex.what() << std::endl;
+    close(agnocast::agnocast_fd);
+    return EXIT_FAILURE;
+  } catch (...) {
+    std::cerr << "Unknown exception caught in main: " << std::endl;
+    close(agnocast::agnocast_fd);
+    return EXIT_FAILURE;
+  }
 
-  rclcpp::shutdown();
   return 0;
 }
diff --git a/src/agnocastlib/src/agnocast_component_container_mt.cpp b/src/agnocastlib/src/agnocast_component_container_mt.cpp
index f58e61293..7c86d7509 100644
--- a/src/agnocastlib/src/agnocast_component_container_mt.cpp
+++ b/src/agnocastlib/src/agnocast_component_container_mt.cpp
@@ -6,38 +6,45 @@
 
 int main(int argc, char * argv[])
 {
-  using namespace std::chrono;
-
-  rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
-  const int agnocast_next_exec_timeout_ms =
-    (node->has_parameter("agnocast_next_exec_timeout_ms"))
-      ? static_cast<int>(node->get_parameter("agnocast_next_exec_timeout_ms").as_int())
-      : 10;
-
-  auto executor = std::make_shared<agnocast::MultiThreadedAgnocastExecutor>(
-    rclcpp::ExecutorOptions{}, number_of_ros2_threads, number_of_agnocast_threads,
-    yield_before_execute, ros2_next_exec_timeout, agnocast_next_exec_timeout_ms);
-
-  node->set_executor(executor);
-  executor->add_node(node);
-  executor->spin();
-
-  rclcpp::shutdown();
+  try {
+    using namespace std::chrono;
+
+    rclcpp::init(argc, argv);
+
+    rclcpp::NodeOptions options;
+    options.allow_undeclared_parameters(true);
+    options.automatically_declare_parameters_from_overrides(true);
+
+    auto node = std::make_shared<rclcpp_components::ComponentManager>(
+      std::weak_ptr<rclcpp::Executor>(), "ComponentManager", options);
+
+    const size_t number_of_ros2_threads = node->get_parameter_or("number_of_ros2_threads", 0);
+    const size_t number_of_agnocast_threads =
+      node->get_parameter_or("number_of_agnocast_threads", 0);
+    const bool yield_before_execute = node->get_parameter_or("yield_before_execute", false);
+    const nanoseconds ros2_next_exec_timeout_ns =
+      nanoseconds(node->get_parameter_or("ros2_next_exec_timeout_ms", 10) * 1000 * 1000);
+    const int agnocast_next_exec_timeout_ms =
+      node->get_parameter_or("agnocast_next_exec_timeout_ms", 10);
+
+    auto executor = std::make_shared<agnocast::MultiThreadedAgnocastExecutor>(
+      rclcpp::ExecutorOptions{}, number_of_ros2_threads, number_of_agnocast_threads,
+      yield_before_execute, ros2_next_exec_timeout_ns, agnocast_next_exec_timeout_ms);
+
+    node->set_executor(executor);
+    executor->add_node(node);
+    executor->spin();
+
+    rclcpp::shutdown();
+  } catch (rclcpp_components::ComponentManagerException & ex) {
+    std::cerr << "Exception caught in main: " << ex.what() << std::endl;
+    close(agnocast::agnocast_fd);
+    return EXIT_FAILURE;
+  } catch (...) {
+    std::cerr << "Unknown exception caught in main: " << std::endl;
+    close(agnocast::agnocast_fd);
+    return EXIT_FAILURE;
+  }
+
   return 0;
 }


Reviews:
user: login: atsushi421
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T00:21:12Z
user: login: Koichi98
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T00:36:05Z
user: login: Koichi98
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-19T00:36:08Z
user: login: sykwer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T01:04:35Z
user: login: Koichi98
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T01:51:03Z
user: login: sykwer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-19T07:19:33Z
user: login: atsushi421
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-20T01:20:56Z
user: login: sykwer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T08:37:40Z
user: login: sykwer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T13:16:29Z
user: login: atsushi421
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-20T18:27:59Z
user: login: atsushi421
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-20T21:49:53Z
user: login: atsushi421
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-21T00:51:03Z
user: login: atsushi421
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-21T00:51:38Z
user: login: atsushi421
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-03-21T01:03:45Z
user: login: atsushi421
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-21T05:00:33Z
user: login: Koichi98
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-21T05:58:20Z

Review comments:
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: atsushi421
body: （このnode_nameが何に使われるかあまりわかっていないですが）_mt のようにmulti threadであることが分かる命名にする必要は無いですか？
created_at: 2025-03-19T00:21:12Z
author_association: COLLABORATOR
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: Koichi98
body: この疑問が解消されたらLGTMで！
created_at: 2025-03-19T00:36:05Z
author_association: COLLABORATOR
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: sykwer
body: @atsushi421 @Koichi98 
ちょっと僕もわからなくなったので、時間に余裕ができたときに調べます (もしわかったら教えて欲しいです 🙇 )
created_at: 2025-03-19T01:04:35Z
author_association: MEMBER
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: Koichi98
body: この辺が対応箇所ですかね？

- component_container_mt
https://github.com/ros2/rclcpp/blob/d3e6254ff149f96a83e35135d5787445ddae2431/rclcpp_components/src/component_container_mt.cpp#L21

- component_container https://github.com/ros2/rclcpp/blob/d3e6254ff149f96a83e35135d5787445ddae2431/rclcpp_components/src/component_container.cpp#L21

特にnode_nameは設定されていない感じ？
created_at: 2025-03-19T01:51:03Z
author_association: COLLABORATOR
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: sykwer
body: デフォルトの "ComponentManager" という文字列が使われていると思います。
ということは、被ってもよいのだろうか？
created_at: 2025-03-19T07:19:33Z
author_association: MEMBER
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: atsushi421
body: launchファイルに渡されるnameで上書きされるので、ここでは特に気にしなくて良さそうです
https://github.com/ros2/launch_ros/blob/98952b58d570cde78d8cfec8c8d697f331b8c982/launch_ros/launch_ros/actions/composable_node_container.py#L39

なので、デフォルト引数使うで良いと思います！
created_at: 2025-03-20T01:20:56Z
author_association: COLLABORATOR
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: sykwer
body: あざます！！
created_at: 2025-03-20T08:37:40Z
author_association: MEMBER
diff_hunk: @@ -9,30 +9,26 @@ int main(int argc, char * argv[])
   using namespace std::chrono;
 
   rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
+
+  rclcpp::NodeOptions options;
+  options.allow_undeclared_parameters(true);
+  options.automatically_declare_parameters_from_overrides(true);
+  std::string node_name = "component_manager" + std::to_string(getpid());
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: sykwer
body: 修正done
@Koichi98 @atsushi421 Approveおねがいします！
created_at: 2025-03-20T13:16:29Z
author_association: MEMBER
diff_hunk: @@ -4,21 +4,33 @@
 
 int main(int argc, char * argv[])
 {
-  rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
+  try {
+    rclcpp::init(argc, argv);
 
-  const int get_next_timeout_ms =
-    (node->has_parameter("get_next_timeout_ms"))
-      ? static_cast<int>(node->get_parameter("get_next_timeout_ms").as_int())
-      : 50;
+    rclcpp::NodeOptions options;
+    options.allow_undeclared_parameters(true);
+    options.automatically_declare_parameters_from_overrides(true);
 
-  auto executor = std::make_shared<agnocast::SingleThreadedAgnocastExecutor>(
-    rclcpp::ExecutorOptions{}, get_next_timeout_ms);
+    auto node = std::make_shared<rclcpp_components::ComponentManager>(
+      std::weak_ptr<rclcpp::Executor>(), "ComponentManager", options);
 
-  node->set_executor(executor);
-  executor->add_node(node);
-  executor->spin();
+    const int get_next_timeout_ms = node->get_parameter_or("get_next_timeout_ms", 50);
+
+    auto executor = std::make_shared<agnocast::SingleThreadedAgnocastExecutor>(
+      rclcpp::ExecutorOptions{}, get_next_timeout_ms);
+
+    node->set_executor(executor);
+    executor->add_node(node);
+    executor->spin();
+
+    rclcpp::shutdown();
+  } catch (rclcpp_components::ComponentManagerException & ex) {
+    std::cerr << "Exception caught in main: " << ex.what() << std::endl;
+    return EXIT_FAILURE;
+  } catch (...) {
+    std::cerr << "Unknown exception caught in main: " << std::endl;
+    return EXIT_FAILURE;
path: src/agnocastlib/src/agnocast_component_container.cpp
user: login: atsushi421
body: ```suggestion
    close(agnocast_fd);
    return EXIT_FAILURE;
  } catch (...) {
    std::cerr << "Unknown exception caught in main: " << std::endl;
    close(agnocast_fd);
    return EXIT_FAILURE;
```
created_at: 2025-03-21T00:51:03Z
author_association: COLLABORATOR
diff_hunk: @@ -6,38 +6,43 @@
 
 int main(int argc, char * argv[])
 {
-  using namespace std::chrono;
-
-  rclcpp::init(argc, argv);
-  auto node = std::make_shared<rclcpp_components::ComponentManager>();
-
-  const size_t number_of_ros2_threads = (node->has_parameter("number_of_ros2_threads"))
-                                          ? node->get_parameter("number_of_ros2_threads").as_int()
-                                          : 0;
-  const size_t number_of_agnocast_threads =
-    (node->has_parameter("number_of_agnocast_threads"))
-      ? node->get_parameter("number_of_agnocast_threads").as_int()
-      : 0;
-  const bool yield_before_execute = (node->has_parameter("yield_before_execute"))
-                                      ? node->get_parameter("yield_before_execute").as_bool()
-                                      : false;
-  const nanoseconds ros2_next_exec_timeout =
-    (node->has_parameter("ros2_next_exec_timeout_ms"))
-      ? nanoseconds(node->get_parameter("ros2_next_exec_timeout_ms").as_int() * 1000 * 1000)
-      : nanoseconds(10 * 1000 * 1000);
-  const int agnocast_next_exec_timeout_ms =
-    (node->has_parameter("agnocast_next_exec_timeout_ms"))
-      ? static_cast<int>(node->get_parameter("agnocast_next_exec_timeout_ms").as_int())
-      : 10;
-
-  auto executor = std::make_shared<agnocast::MultiThreadedAgnocastExecutor>(
-    rclcpp::ExecutorOptions{}, number_of_ros2_threads, number_of_agnocast_threads,
-    yield_before_execute, ros2_next_exec_timeout, agnocast_next_exec_timeout_ms);
-
-  node->set_executor(executor);
-  executor->add_node(node);
-  executor->spin();
-
-  rclcpp::shutdown();
+  try {
+    using namespace std::chrono;
+
+    rclcpp::init(argc, argv);
+
+    rclcpp::NodeOptions options;
+    options.allow_undeclared_parameters(true);
+    options.automatically_declare_parameters_from_overrides(true);
+
+    auto node = std::make_shared<rclcpp_components::ComponentManager>(
+      std::weak_ptr<rclcpp::Executor>(), "ComponentManager", options);
+
+    const size_t number_of_ros2_threads = node->get_parameter_or("number_of_ros2_threads", 0);
+    const size_t number_of_agnocast_threads =
+      node->get_parameter_or("number_of_agnocast_threads", 0);
+    const bool yield_before_execute = node->get_parameter_or("yield_before_execute", false);
+    const nanoseconds ros2_next_exec_timeout_ns =
+      nanoseconds(node->get_parameter_or("ros2_next_exec_timeout_ms", 10) * 1000 * 1000);
+    const int agnocast_next_exec_timeout_ms =
+      node->get_parameter_or("agnocast_next_exec_timeout_ms", 10);
+
+    auto executor = std::make_shared<agnocast::MultiThreadedAgnocastExecutor>(
+      rclcpp::ExecutorOptions{}, number_of_ros2_threads, number_of_agnocast_threads,
+      yield_before_execute, ros2_next_exec_timeout_ns, agnocast_next_exec_timeout_ms);
+
+    node->set_executor(executor);
+    executor->add_node(node);
+    executor->spin();
+
+    rclcpp::shutdown();
+  } catch (rclcpp_components::ComponentManagerException & ex) {
+    std::cerr << "Exception caught in main: " << ex.what() << std::endl;
+    return EXIT_FAILURE;
+  } catch (...) {
+    std::cerr << "Unknown exception caught in main: " << std::endl;
+    return EXIT_FAILURE;
path: src/agnocastlib/src/agnocast_component_container_mt.cpp
user: login: atsushi421
body: ```suggestion
    close(agnocast_fd);
    return EXIT_FAILURE;
  } catch (...) {
    std::cerr << "Unknown exception caught in main: " << std::endl;
    close(agnocast_fd);
    return EXIT_FAILURE;
```
created_at: 2025-03-21T00:51:30Z
author_association: COLLABORATOR

PR comments:
user: login: sykwer
created_at: 2025-03-20T23:46:10Z
body: clang tidyにしたがってmain()をtry-cacheで捕捉するようにしましたが、いまいち自信はありません。
https://github.com/tier4/agnocast/pull/541 のmerge待ち。
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2025-03-21T00:20:03Z
body: ```
------------------------------------------------------------------------------
                           GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File                                       Lines    Exec  Cover   Missing
------------------------------------------------------------------------------
src/agnocastlib/include/agnocast/agnocast.hpp
                                               4       4   100%   
src/agnocastlib/include/agnocast/agnocast_callback_info.hpp
                                              25      22    88%   91,93-94
src/agnocastlib/include/agnocast/agnocast_publisher.hpp
                                              89      57    64%   93,112-114,125,131,135,143-145,148,152-154,161-162,165-167,170-171,174,179,206-207,212-213,216-218,222-223
src/agnocastlib/include/agnocast/agnocast_smart_pointer.hpp
                                              47      47   100%   
src/agnocastlib/src/agnocast.cpp              57      10    17%   19,22,24-30,34-35,38-42,46-47,51-54,57,60,62,65,67-68,73,75-77,80-83,86,88-94,97,107-108
src/agnocastlib/src/agnocast_callback_info.cpp
                                              17      14    82%   29-31
src/agnocastlib/src/agnocast_component_container.cpp
                                              19       0     0%   5,8,10-12,15,17,20,22-24,26-32,35
src/agnocastlib/src/agnocast_component_container_mt.cpp
                                              24       0     0%   7,12,14-16,19,21,23-24,26,28,31-32,34-36,38-44,47
src/agnocastlib/src/agnocast_executor.cpp
                                             101      79    78%   15-16,44-46,74-77,96-98,111-113,123-125,130-133
src/agnocastlib/src/agnocast_multi_threaded_executor.cpp
                                              85      59    69%   18,29-31,40-42,44-46,48-50,52-54,56-58,62,69-70,77-79,148
src/agnocastlib/src/agnocast_publisher.cpp
                                              67       7    10%   10,12,23,26,31,35,37-46,49,52,57-64,73-74,76-80,84,86-89,91,96,100-101,107-112,114,117-118,122,125,127-132,135
src/agnocastlib/src/agnocast_single_threaded_executor.cpp
                                              31      24    77%   16,27-29,36-38
src/agnocastlib/src/agnocast_smart_pointer.cpp
                                              18       0     0%   6,9-16,20,23-30
src/agnocastlib/src/agnocast_subscription.cpp
                                              52       9    17%   6-7,9,12,15,19-30,33-37,40,43,47-52,54-59,61,63,66,70-71,73-74
src/agnocastlib/src/agnocast_utils.cpp        29      26    89%   63,65-66
------------------------------------------------------------------------------
TOTAL                                        665     358    53%
------------------------------------------------------------------------------
```
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-21T04:52:57Z
body: ```
------------------------------------------------------------------------------
                           GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File                                       Lines    Exec  Cover   Missing
------------------------------------------------------------------------------
src/agnocastlib/include/agnocast/agnocast.hpp
                                               4       4   100%   
src/agnocastlib/include/agnocast/agnocast_callback_info.hpp
                                              25      22    88%   91,93-94
src/agnocastlib/include/agnocast/agnocast_publisher.hpp
                                              89      57    64%   93,112-114,125,131,135,143-145,148,152-154,161-162,165-167,170-171,174,179,206-207,212-213,216-218,222-223
src/agnocastlib/include/agnocast/agnocast_smart_pointer.hpp
                                              47      47   100%   
src/agnocastlib/src/agnocast.cpp              57      10    17%   19,22,24-30,34-35,38-42,46-47,51-54,57,60,62,65,67-68,73,75-77,80-83,86,88-94,97,107-108
src/agnocastlib/src/agnocast_callback_info.cpp
                                              17      14    82%   29-31
src/agnocastlib/src/agnocast_component_container.cpp
                                              21       0     0%   5,8,10-12,15,17,20,22-24,26-34,37
src/agnocastlib/src/agnocast_component_container_mt.cpp
                                              26       0     0%   7,12,14-16,19,21,23-24,26,28,31-32,34-36,38-46,49
src/agnocastlib/src/agnocast_executor.cpp
                                             101      79    78%   15-16,44-46,74-77,96-98,111-113,123-125,130-133
src/agnocastlib/src/agnocast_multi_threaded_executor.cpp
                                              85      59    69%   18,29-31,40-42,44-46,48-50,52-54,56-58,62,69-70,77-79,148
src/agnocastlib/src/agnocast_publisher.cpp
                                              67       7    10%   10,12,23,26,31,35,37-46,49,52,57-64,73-74,76-80,84,86-89,91,96,100-101,107-112,114,117-118,122,125,127-132,135
src/agnocastlib/src/agnocast_single_threaded_executor.cpp
                                              31      24    77%   16,27-29,36-38
src/agnocastlib/src/agnocast_smart_pointer.cpp
                                              18       0     0%   6,9-16,20,23-30
src/agnocastlib/src/agnocast_subscription.cpp
                                              52       9    17%   6-7,9,12,15,19-30,33-37,40,43,47-52,54-59,61,63,66,70-71,73-74
src/agnocastlib/src/agnocast_utils.cpp        29      26    89%   63,65-66
------------------------------------------------------------------------------
TOTAL                                        669     358    53%
------------------------------------------------------------------------------
```
author_association: NONE