diff --git a/tesseract_task_composer/core/CMakeLists.txt b/tesseract_task_composer/core/CMakeLists.txt index 2a60b606070..c05d0b4d9cf 100644 --- a/tesseract_task_composer/core/CMakeLists.txt +++ b/tesseract_task_composer/core/CMakeLists.txt @@ -15,6 +15,7 @@ add_library( src/task_composer_node.cpp src/task_composer_pipeline.cpp src/task_composer_plugin_factory.cpp + src/task_composer_schema.cpp src/task_composer_server.cpp src/task_composer_task.cpp) diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/done_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/done_task.h index d3b4aa4cc99..8a8780d080f 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/done_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/done_task.h @@ -49,6 +49,8 @@ class DoneTask : public TaskComposerTask explicit DoneTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory); ~DoneTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const DoneTask& rhs) const; bool operator!=(const DoneTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/error_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/error_task.h index c24c3c66c7d..48bede2a8ff 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/error_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/error_task.h @@ -49,6 +49,8 @@ class ErrorTask : public TaskComposerTask explicit ErrorTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory); ~ErrorTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const ErrorTask& rhs) const; bool operator!=(const ErrorTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/has_data_storage_entry_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/has_data_storage_entry_task.h index d58ec66656f..bb78c09cea9 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/has_data_storage_entry_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/has_data_storage_entry_task.h @@ -33,6 +33,8 @@ class TESSERACT_TASK_COMPOSER_NODES_EXPORT HasDataStorageEntryTask : public Task const TaskComposerPluginFactory& plugin_factory); ~HasDataStorageEntryTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const HasDataStorageEntryTask& rhs) const; bool operator!=(const HasDataStorageEntryTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/remap_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/remap_task.h index b5953a3f220..a09ba3656ac 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/remap_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/remap_task.h @@ -56,6 +56,8 @@ class RemapTask : public TaskComposerTask explicit RemapTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory); ~RemapTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const RemapTask& rhs) const; bool operator!=(const RemapTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/start_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/start_task.h index 7a238e512d2..3758a08750d 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/start_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/start_task.h @@ -48,6 +48,8 @@ class StartTask : public TaskComposerTask explicit StartTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory); ~StartTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const StartTask& rhs) const; bool operator!=(const StartTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/sync_task.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/sync_task.h index 02a986d8274..1860177957b 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/sync_task.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/nodes/sync_task.h @@ -58,6 +58,8 @@ class SyncTask : public TaskComposerTask explicit SyncTask(std::string name, const YAML::Node& config, const TaskComposerPluginFactory& plugin_factory); ~SyncTask() override = default; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const SyncTask& rhs) const; bool operator!=(const SyncTask& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_graph.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_graph.h index e7ee7235c09..a5c600a79e4 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_graph.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_graph.h @@ -146,6 +146,8 @@ class TaskComposerGraph : public TaskComposerNode const TaskComposerNode* parent = nullptr, const std::map& results_map = {}) const override; + tesseract_common::PropertyTree getSchema() const override final; + bool operator==(const TaskComposerGraph& rhs) const; bool operator!=(const TaskComposerGraph& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_node.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_node.h index 4861ffd06ea..761a7498f47 100644 --- a/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_node.h +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_node.h @@ -166,6 +166,12 @@ class TaskComposerNode const TaskComposerNode* parent = nullptr, const ResultsMap& results_map = ResultsMap()) const; + /** + * @brief Get the tasks schema for yaml validation + * @return The tasks schema + */ + virtual tesseract_common::PropertyTree getSchema() const; + bool operator==(const TaskComposerNode& rhs) const; bool operator!=(const TaskComposerNode& rhs) const; diff --git a/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_schema.h b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_schema.h new file mode 100644 index 00000000000..44f92b80d29 --- /dev/null +++ b/tesseract_task_composer/core/include/tesseract_task_composer/core/task_composer_schema.h @@ -0,0 +1,81 @@ +/** + * @file task_composer_schema.h + * @brief Task composer schema utils + * + * @author Levi Armstrong + * @date June 20. 2025 + * @version TODO + * @bug No known bugs + * + * @copyright Copyright (c) 2025, Levi Armstrong + * + * @par License + * Software License Agreement (Apache License) + * @par + * 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 + * @par + * 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 TESSERACT_TASK_COMPOSER_TASK_COMPOSER_SCHEMA_H +#define TESSERACT_TASK_COMPOSER_TASK_COMPOSER_SCHEMA_H + +#include + +#include + +namespace tesseract_common::property_attribute +{ +constexpr std::string_view TASK_NAME{ "task_name" }; +constexpr std::string_view FACTORY_NAME{ "factory_name" }; +} // namespace tesseract_common::property_attribute + +namespace tesseract_planning +{ +namespace property_name +{ +// General properties +constexpr std::string_view INPUTS{ "inputs" }; +constexpr std::string_view OUTPUTS{ "outputs" }; +constexpr std::string_view CONDITIONAL{ "conditional" }; +constexpr std::string_view TRIGGER_ABORT{ "trigger_abort" }; + +// Input/Output property names +constexpr std::string_view PROGRAM{ "program" }; +constexpr std::string_view ENVIRONMENT{ "environment" }; +constexpr std::string_view PROFILES{ "profiles" }; + +// Graph/Pipeline properties +constexpr std::string_view NODES{ "nodes" }; +constexpr std::string_view EDGES{ "edges" }; +constexpr std::string_view TERMINALS{ "terminals" }; +} // namespace property_name + +tesseract_common::PropertyTree& addConditionalProperty(tesseract_common::PropertyTree& schema, + bool default_value = true); +tesseract_common::PropertyTree& addTriggerAbortProperty(tesseract_common::PropertyTree& schema, + bool default_value = false); +tesseract_common::PropertyTree& addInputsProperty(tesseract_common::PropertyTree& schema, bool required = true); +tesseract_common::PropertyTree& addOutputsProperty(tesseract_common::PropertyTree& schema, bool required = true); + +tesseract_common::PropertyTree& addProgramProperty(tesseract_common::PropertyTree& schema); +tesseract_common::PropertyTree& addEnvironmentProperty(tesseract_common::PropertyTree& schema); +tesseract_common::PropertyTree& addProfilesProperty(tesseract_common::PropertyTree& schema); + +tesseract_common::PropertyTree& addNodesProperty(tesseract_common::PropertyTree& schema); +tesseract_common::PropertyTree& addEdgesProperty(tesseract_common::PropertyTree& schema); +tesseract_common::PropertyTree& addTerminalsProperty(tesseract_common::PropertyTree& schema); + +// Schema + +tesseract_common::PropertyTree getTaskComposerGraphEdgeSchema(); + +} // namespace tesseract_planning + +#endif // TESSERACT_TASK_COMPOSER_TASK_COMPOSER_SCHEMA_H diff --git a/tesseract_task_composer/core/src/nodes/done_task.cpp b/tesseract_task_composer/core/src/nodes/done_task.cpp index e80e11facb6..9f5f598a3f5 100644 --- a/tesseract_task_composer/core/src/nodes/done_task.cpp +++ b/tesseract_task_composer/core/src/nodes/done_task.cpp @@ -29,10 +29,12 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include +#include namespace tesseract_planning { @@ -46,6 +48,27 @@ DoneTask::DoneTask(std::string name, const YAML::Node& config, const TaskCompose { } +tesseract_common::PropertyTree DoneTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "DoneTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "DoneTaskFactory"); + schema.setAttribute(property_attribute::DOC, + "A task which is typically called last to indicate success of a pipeline"); + std::map return_options; + return_options[1] = "Successful"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + return schema; +} + TaskComposerNodeInfo DoneTask::runImpl(TaskComposerContext& /*context*/, OptionalTaskComposerExecutor /*executor*/) const { diff --git a/tesseract_task_composer/core/src/nodes/error_task.cpp b/tesseract_task_composer/core/src/nodes/error_task.cpp index 2ff12be2644..07f3a6f6f50 100644 --- a/tesseract_task_composer/core/src/nodes/error_task.cpp +++ b/tesseract_task_composer/core/src/nodes/error_task.cpp @@ -29,10 +29,12 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include +#include namespace tesseract_planning { @@ -46,6 +48,27 @@ ErrorTask::ErrorTask(std::string name, const YAML::Node& config, const TaskCompo { } +tesseract_common::PropertyTree ErrorTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "ErrorTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "ErrorTaskFactory"); + schema.setAttribute(property_attribute::DOC, + "A task which is typically called last to indicate success of a pipeline"); + std::map return_options; + return_options[0] = "Error"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + return schema; +} + TaskComposerNodeInfo ErrorTask::runImpl(TaskComposerContext& /*context*/, OptionalTaskComposerExecutor /*executor*/) const { diff --git a/tesseract_task_composer/core/src/nodes/has_data_storage_entry_task.cpp b/tesseract_task_composer/core/src/nodes/has_data_storage_entry_task.cpp index a05927c2282..16f8ca6ba5b 100644 --- a/tesseract_task_composer/core/src/nodes/has_data_storage_entry_task.cpp +++ b/tesseract_task_composer/core/src/nodes/has_data_storage_entry_task.cpp @@ -4,12 +4,14 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include #include #include +#include namespace tesseract_planning { @@ -34,6 +36,36 @@ HasDataStorageEntryTask::HasDataStorageEntryTask(std::string name, { } +tesseract_common::PropertyTree HasDataStorageEntryTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "HasDataStorageEntryTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "HasDataStorageEntryTaskFactory"); + schema.setAttribute(property_attribute::DOC, "A task to check for entries in the data storage"); + + std::map return_options; + return_options[0] = "Error"; + return_options[0] = "Successful"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + PropertyTree& inputs = addInputsProperty(schema); + { + auto& prop = inputs[INPUT_KEYS_PORT]; + prop.setAttribute(property_attribute::TYPE, property_type::createList(property_type::STRING)); + prop.setAttribute(property_attribute::DOC, "A list of keys to check for entries in data storage"); + prop.setAttribute(property_attribute::REQUIRED, true); + } + + return schema; +} + TaskComposerNodePorts HasDataStorageEntryTask::ports() { TaskComposerNodePorts ports; diff --git a/tesseract_task_composer/core/src/nodes/remap_task.cpp b/tesseract_task_composer/core/src/nodes/remap_task.cpp index f62f2f5f210..1f358a40df0 100644 --- a/tesseract_task_composer/core/src/nodes/remap_task.cpp +++ b/tesseract_task_composer/core/src/nodes/remap_task.cpp @@ -29,12 +29,14 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include #include #include +#include namespace tesseract_planning { @@ -72,6 +74,51 @@ RemapTask::RemapTask(std::string name, const YAML::Node& config, const TaskCompo copy_ = n.as(); } +tesseract_common::PropertyTree RemapTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "RemapTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "RemapTaskFactory"); + schema.setAttribute(property_attribute::DOC, "A task to remap data stored in data storage from one key to another"); + + std::map return_options; + return_options[0] = "Error"; + return_options[0] = "Successful"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + { + auto& prop = schema["copy"]; + prop.setAttribute(property_attribute::TYPE, property_type::BOOL); + prop.setAttribute(property_attribute::DEFAULT, false); + prop.setAttribute(property_attribute::DOC, "Indicate if data should be copied, otherwise it is moved"); + prop.setAttribute(property_attribute::REQUIRED, false); + } + + PropertyTree& inputs = addInputsProperty(schema); + { + auto& prop = inputs[INOUT_KEYS_PORT]; + prop.setAttribute(property_attribute::TYPE, property_type::createList(property_type::STRING)); + prop.setAttribute(property_attribute::DOC, "A list of keys in data storage to copy/move"); + prop.setAttribute(property_attribute::REQUIRED, true); + } + + PropertyTree& outputs = addInputsProperty(schema); + { + auto& prop = outputs[INOUT_KEYS_PORT]; + prop.setAttribute(property_attribute::TYPE, property_type::createList(property_type::STRING)); + prop.setAttribute(property_attribute::DOC, "A list of keys in data storage to copy/move"); + prop.setAttribute(property_attribute::REQUIRED, true); + } + + return schema; +} + TaskComposerNodePorts RemapTask::ports() { TaskComposerNodePorts ports; diff --git a/tesseract_task_composer/core/src/nodes/start_task.cpp b/tesseract_task_composer/core/src/nodes/start_task.cpp index 0a57cc1ec23..3f0a6e83c9b 100644 --- a/tesseract_task_composer/core/src/nodes/start_task.cpp +++ b/tesseract_task_composer/core/src/nodes/start_task.cpp @@ -29,10 +29,12 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include +#include namespace tesseract_planning { @@ -43,6 +45,28 @@ StartTask::StartTask(std::string name, const YAML::Node& config, const TaskCompo if (conditional_) throw std::runtime_error("StartTask, config is_conditional should not be true"); } + +tesseract_common::PropertyTree StartTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "StartTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "StartTaskFactory"); + schema.setAttribute(property_attribute::DOC, "A syncronization task"); + std::map return_options; + return_options[1] = "Successful"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + /** @todo These should be removed completely for this task */ + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + return schema; +} + TaskComposerNodeInfo StartTask::runImpl(TaskComposerContext& /*context*/, OptionalTaskComposerExecutor /*executor*/) const { diff --git a/tesseract_task_composer/core/src/nodes/sync_task.cpp b/tesseract_task_composer/core/src/nodes/sync_task.cpp index 3bd476c4cb7..f9cd31952f8 100644 --- a/tesseract_task_composer/core/src/nodes/sync_task.cpp +++ b/tesseract_task_composer/core/src/nodes/sync_task.cpp @@ -29,10 +29,12 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include +#include namespace tesseract_planning { @@ -43,6 +45,28 @@ SyncTask::SyncTask(std::string name, const YAML::Node& config, const TaskCompose if (conditional_) throw std::runtime_error("SyncTask, config is_conditional should not be true"); } + +tesseract_common::PropertyTree SyncTask::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "SyncTask"); + schema.setAttribute(property_attribute::FACTORY_NAME, "SyncTaskFactory"); + schema.setAttribute(property_attribute::DOC, "A syncronization task"); + std::map return_options; + return_options[1] = "Successful"; + schema.setAttribute("return_options", YAML::Node(return_options)); + + /** @todo These should be removed completely for this task */ + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + return schema; +} + TaskComposerNodeInfo SyncTask::runImpl(TaskComposerContext& /*context*/, OptionalTaskComposerExecutor /*executor*/) const { diff --git a/tesseract_task_composer/core/src/task_composer_graph.cpp b/tesseract_task_composer/core/src/task_composer_graph.cpp index 85a42019424..5640f39896b 100644 --- a/tesseract_task_composer/core/src/task_composer_graph.cpp +++ b/tesseract_task_composer/core/src/task_composer_graph.cpp @@ -36,7 +36,9 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include -#include +#include +#include +#include #include TESSERACT_COMMON_IGNORE_WARNINGS_POP @@ -48,6 +50,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include #include +#include namespace tesseract_planning { @@ -544,6 +547,31 @@ std::string TaskComposerGraph::dump(std::ostream& os, return {}; } +tesseract_common::PropertyTree TaskComposerGraph::getSchema() const +{ + using namespace tesseract_common; + + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::REQUIRED, true); + schema.setAttribute(property_attribute::TASK_NAME, "TaskComposerGraph"); + schema.setAttribute(property_attribute::FACTORY_NAME, "TaskComposerGraphFactory"); + schema.setAttribute(property_attribute::DOC, "A graph task"); + + /** @todo These should be removed completely for this task */ + addConditionalProperty(schema, false); + addTriggerAbortProperty(schema); + + addInputsProperty(schema, false); + addOutputsProperty(schema, false); + + addNodesProperty(schema); + addEdgesProperty(schema); + addTerminalsProperty(schema); + + return schema; +} + bool TaskComposerGraph::operator==(const TaskComposerGraph& rhs) const { bool equal = true; diff --git a/tesseract_task_composer/core/src/task_composer_node.cpp b/tesseract_task_composer/core/src/task_composer_node.cpp index 6170b9ac3ec..a10f9529b0e 100644 --- a/tesseract_task_composer/core/src/task_composer_node.cpp +++ b/tesseract_task_composer/core/src/task_composer_node.cpp @@ -36,6 +36,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH #include #include #include +#include TESSERACT_COMMON_IGNORE_WARNINGS_POP #include @@ -502,6 +503,8 @@ std::string TaskComposerNode::dump(std::ostream& os, return it->second.dotgraph; } +tesseract_common::PropertyTree TaskComposerNode::getSchema() const { return {}; } + bool TaskComposerNode::operator==(const TaskComposerNode& rhs) const { bool equal = true; diff --git a/tesseract_task_composer/core/src/task_composer_plugin_factory.cpp b/tesseract_task_composer/core/src/task_composer_plugin_factory.cpp index 4655b4b44dc..abeb4e3fb8d 100644 --- a/tesseract_task_composer/core/src/task_composer_plugin_factory.cpp +++ b/tesseract_task_composer/core/src/task_composer_plugin_factory.cpp @@ -32,7 +32,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include -#include +#include #include #include #include diff --git a/tesseract_task_composer/core/src/task_composer_schema.cpp b/tesseract_task_composer/core/src/task_composer_schema.cpp new file mode 100644 index 00000000000..fb6aae986f7 --- /dev/null +++ b/tesseract_task_composer/core/src/task_composer_schema.cpp @@ -0,0 +1,154 @@ +/** + * @file task_composer_schema.cpp + * @brief Task composer schema utils + * + * @author Levi Armstrong + * @date June 20. 2025 + * @version TODO + * @bug No known bugs + * + * @copyright Copyright (c) 2025, Levi Armstrong + * + * @par License + * Software License Agreement (Apache License) + * @par + * 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 + * @par + * 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 +#include + +using namespace tesseract_common; + +namespace tesseract_planning +{ +tesseract_common::PropertyTree& addConditionalProperty(tesseract_common::PropertyTree& schema, bool default_value) +{ + auto& prop = schema[property_name::CONDITIONAL]; + prop.setAttribute(property_attribute::TYPE, property_type::BOOL); + prop.setAttribute(property_attribute::DEFAULT, default_value); + prop.setAttribute(property_attribute::DOC, "Enable conditional execution"); + prop.setAttribute(property_attribute::REQUIRED, false); + return prop; +} + +tesseract_common::PropertyTree& addTriggerAbortProperty(tesseract_common::PropertyTree& schema, bool default_value) +{ + auto& prop = schema[property_name::TRIGGER_ABORT]; + prop.setAttribute(property_attribute::TYPE, property_type::BOOL); + prop.setAttribute(property_attribute::DEFAULT, default_value); + prop.setAttribute(property_attribute::DOC, "Indicate if abort should be triggered if this task is reached"); + prop.setAttribute(property_attribute::REQUIRED, false); + return prop; +} + +tesseract_common::PropertyTree& addInputsProperty(tesseract_common::PropertyTree& schema, bool required) +{ + auto& prop = schema[property_name::INPUTS]; + prop.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + prop.setAttribute(property_attribute::DOC, "Input sources"); + prop.setAttribute(property_attribute::REQUIRED, required); + return prop; +} + +tesseract_common::PropertyTree& addOutputsProperty(tesseract_common::PropertyTree& schema, bool required) +{ + auto& prop = schema[property_name::OUTPUTS]; + prop.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + prop.setAttribute(property_attribute::DOC, "Output sources"); + prop.setAttribute(property_attribute::REQUIRED, required); + return prop; +} + +tesseract_common::PropertyTree& addProgramProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema["program"]; + prop.setAttribute(property_attribute::TYPE, property_type::STRING); + prop.setAttribute(property_attribute::DOC, "The data storage key to locate the program composite instruction"); + prop.setAttribute(property_attribute::REQUIRED, true); + return prop; +} + +tesseract_common::PropertyTree& addEnvironmentProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema["environment"]; + prop.setAttribute(property_attribute::TYPE, property_type::STRING); + prop.setAttribute(property_attribute::DOC, "The data storage key to locate the environment"); + prop.setAttribute(property_attribute::REQUIRED, true); + return prop; +} + +tesseract_common::PropertyTree& addProfilesProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema["profiles"]; + prop.setAttribute(property_attribute::TYPE, property_type::STRING); + prop.setAttribute(property_attribute::DOC, "The data storage key to locate the profiles"); + prop.setAttribute(property_attribute::REQUIRED, true); + return prop; +} + +tesseract_common::PropertyTree& addNodesProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema[property_name::NODES]; + prop.setAttribute(property_attribute::TYPE, "TaskComposerGraphNode{}"); + prop.setAttribute(property_attribute::DOC, "Map of all task nodes"); + prop.setAttribute(property_attribute::REQUIRED, true); + return prop; +} + +tesseract_common::PropertyTree& addEdgesProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema[property_name::EDGES]; + prop.setAttribute(property_attribute::TYPE, "TaskComposerGraphEdge[]"); + prop.setAttribute(property_attribute::DOC, "List of graph edges"); + prop.setAttribute(property_attribute::REQUIRED, true); + prop.addValidator(validateCustomType); + return prop; +} + +tesseract_common::PropertyTree& addTerminalsProperty(tesseract_common::PropertyTree& schema) +{ + auto& prop = schema[property_name::TERMINALS]; + prop.setAttribute(property_attribute::TYPE, property_type::createList(property_type::STRING)); + prop.setAttribute(property_attribute::DOC, "List of terminal tasks"); + prop.setAttribute(property_attribute::REQUIRED, true); + prop.addValidator(validateTypeCast>); + return prop; +} + +tesseract_common::PropertyTree getTaskComposerGraphEdgeSchema() +{ + using namespace tesseract_common; + PropertyTree schema; + schema.setAttribute(property_attribute::TYPE, property_type::CONTAINER); + schema.setAttribute(property_attribute::DOC, "TaskComposerGraphEdge"); + { + auto& prop = schema["source"]; + prop.setAttribute(property_attribute::TYPE, property_type::STRING); + prop.setAttribute(property_attribute::DOC, "The source task name"); + prop.setAttribute(property_attribute::REQUIRED, true); + } + + { + auto& prop = schema["destinations"]; + prop.setAttribute(property_attribute::TYPE, property_type::createList(property_type::STRING)); + prop.setAttribute(property_attribute::DOC, "The list of destination task name"); + prop.setAttribute(property_attribute::REQUIRED, true); + prop.addValidator(validateTypeCast>); + } + + return schema; +} + +} // namespace tesseract_planning + +#include +TESSERACT_REGISTER_SCHEMA(TaskComposerGraphEdge, tesseract_planning::getTaskComposerGraphEdgeSchema) diff --git a/tesseract_task_composer/test/tesseract_task_composer_plugin_factories_unit.cpp b/tesseract_task_composer/test/tesseract_task_composer_plugin_factories_unit.cpp index 279aae450db..ad145034a8d 100644 --- a/tesseract_task_composer/test/tesseract_task_composer_plugin_factories_unit.cpp +++ b/tesseract_task_composer/test/tesseract_task_composer_plugin_factories_unit.cpp @@ -35,7 +35,7 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP #include #include #include -#include +#include using namespace tesseract_planning;