moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
package_settings_config.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2021, PickNik Robotics, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of PickNik Robotics nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
36#include <regex>
37
38namespace moveit_setup
39{
40const std::unordered_map<std::string, std::string>
41 BACKWARDS_KEY_LOOKUP({ { "urdf", "URDF" }, { "srdf", "SRDF" }, { "package_settings", "CONFIG" } });
42
43const std::regex MAIL_REGEX("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,63}\\b", std::regex::icase);
44
45void PackageSettingsConfig::loadPrevious(const std::filesystem::path& /*config_package_path*/, const YAML::Node& node)
46{
47 getYamlProperty(node, "author_name", author_name_);
48 getYamlProperty(node, "author_email", author_email_);
49 unsigned long int timestamp_i;
50 getYamlProperty(node, "generated_timestamp", timestamp_i);
52}
53
55{
56 YAML::Node node;
57 node["author_name"] = author_name_;
58 node["author_email"] = author_email_;
59 node["generated_timestamp"] = toEpoch(config_pkg_generated_timestamp_);
60 return node;
61}
62
63void PackageSettingsConfig::setPackagePath(const std::filesystem::path& package_path)
64{
65 config_pkg_path_ = package_path;
66}
67
68void PackageSettingsConfig::setPackageName(const std::string& package_name)
69{
70 new_package_name_ = package_name;
71}
72
73void PackageSettingsConfig::loadExisting(const std::string& package_path_or_name)
74{
75 if (package_path_or_name.empty())
76 {
77 throw std::runtime_error("Please specify a configuration package path to load.");
78 }
79 // Check if it is a path that exists
80 if (std::filesystem::is_directory(package_path_or_name))
81 {
82 // they inputted a full path
83 setPackagePath(package_path_or_name);
84 }
85 else
86 {
87 // Determine the path from a name
88 /* TODO(dlu): Ideally, the package path is in source so that when we write back to it,
89 * the changes will be reflected and then we can check them into git.
90 * However, there's no easy way to determine the source folder from C++.
91 * You could run colcon list -p --packages-select $PACKAGE_NAME but the
92 * results are dependent on what folder you are in and opening an external
93 * process is messy. For now, we just use the share path and rely on the user
94 * to write back to the proper directory in the ConfigurationFiles step
95 */
96 auto share_dir = getSharePath(package_path_or_name);
97
98 // check that the folder exists
99 if (!std::filesystem::is_directory(share_dir))
100 {
101 throw std::runtime_error("The specified path is not a directory or is not accessible.");
102 }
103
104 setPackagePath(share_dir);
105 }
106
107 // Load the package name from the package.xml
108 std::filesystem::path relative_path; // we don't use this output value
110
111 // Load Config Yaml
112 std::filesystem::path config_path = config_pkg_path_ / SETUP_ASSISTANT_FILE;
113 if (!std::filesystem::is_regular_file(config_path))
114 {
115 throw std::runtime_error("The chosen package location exists but was not created using MoveIt Setup Assistant. "
116 "If this is a mistake, provide the missing file: " +
117 config_path.string());
118 }
119
120 std::ifstream input_stream(config_path);
121 if (!input_stream.good())
122 {
123 throw std::runtime_error("Unable to open file for reading " + config_path.string());
124 }
125
126 // Begin parsing
127 try
128 {
129 const YAML::Node& doc = YAML::Load(input_stream);
130 // Get title node
131 const YAML::Node& title_node = doc["moveit_setup_assistant_config"];
132
133 for (const std::string& name : config_data_->getRegisteredNames())
134 {
135 std::string yaml_key = name;
136 /* Generally speaking, we use each config's name as the key to read the yaml from
137 *
138 * However, for backwards compatibility, we also allow for the three legacy keys, which we translate here.
139 * If the name is found in BACKWARDS_KEY_LOOKUP and the legacy key is present in the yaml dictionary,
140 * we load using the legacy key instead.
141 */
142 auto backwards_match = BACKWARDS_KEY_LOOKUP.find(name);
143 if (backwards_match != BACKWARDS_KEY_LOOKUP.end() && title_node[backwards_match->second].IsDefined())
144 {
145 yaml_key = backwards_match->second;
146 }
147
148 // We load the previous regardless of whether the title_node[yaml_key] is actually defined
149 config_data_->get(name)->loadPrevious(config_pkg_path_, title_node[yaml_key]);
150 }
151 }
152 catch (YAML::ParserException& e) // Catch errors, translate to runtime_error
153 {
154 throw std::runtime_error("Error parsing " + config_path.string() + ": " + e.what());
155 }
156}
157
159{
160 emitter << YAML::BeginMap;
161 // Output every available planner ---------------------------------------------------
162 emitter << YAML::Key << "moveit_setup_assistant_config";
163 emitter << YAML::Value << YAML::BeginMap;
164
165 for (const auto& config : parent_.config_data_->getConfigured())
166 {
167 YAML::Node node = config->saveToYaml();
168 if (!node.size())
169 {
170 continue;
171 }
172 emitter << YAML::Key << config->getName();
173 emitter << YAML::Value << node;
174 }
175 emitter << YAML::EndMap;
176 return true;
177}
178
180{
181 package_dependencies_.clear();
182 for (const auto& config : config_data_->getConfigured())
183 {
184 config->collectDependencies(package_dependencies_);
185 }
186}
187
188void PackageSettingsConfig::collectVariables(std::vector<TemplateVariable>& variables)
189{
190 variables.push_back(TemplateVariable("GENERATED_PACKAGE_NAME", new_package_name_));
191
192 // TODO: Add new variables for other fields existing in the package.xml
193 // i.e. read the version so that the version is not overwritten
194 variables.push_back(TemplateVariable("AUTHOR_NAME", author_name_));
195 variables.push_back(TemplateVariable("AUTHOR_EMAIL", author_email_));
196
197 std::stringstream deps;
198 for (const auto& dependency : package_dependencies_)
199 {
200 deps << " <exec_depend>" << dependency << "</exec_depend>\n";
201 }
202 variables.push_back(TemplateVariable("OTHER_DEPENDENCIES", deps.str()));
203}
204
206{
207 // Make sure there is something that isn't just whitespace
208 return author_name_.find_first_not_of(' ') != std::string::npos;
209}
210
212{
213 return std::regex_match(author_email_, MAIL_REGEX);
214}
215
217{
218 config_pkg_generated_timestamp_ = GeneratedTime::clock::now();
219}
220
221} // namespace moveit_setup
222
223#include <pluginlib/class_list_macros.hpp> // NOLINT
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
void collectVariables(std::vector< TemplateVariable > &variables) override
Collect key/value pairs for use in templates.
std::string author_name_
Name of the author of this config.
GeneratedTime config_pkg_generated_timestamp_
Timestamp when configuration package was generated, if it was previously generated.
void setPackagePath(const std::filesystem::path &package_path)
void loadPrevious(const std::filesystem::path &package_path, const YAML::Node &node) override
Overridden method to load THIS config's data variables.
void setPackageName(const std::string &package_name)
std::string author_email_
Email of the author of this config.
YAML::Node saveToYaml() const override
Optionally save "meta" information for saving in the .setup_assistant yaml file.
void loadExisting(const std::string &package_path_or_name)
Method for loading the contents of the .setup_assistant file into all the configs.
std::string new_package_name_
Name of the new package that is being (or going) to be generated, based on user specified save path.
std::filesystem::path config_pkg_path_
Loaded configuration package path - if an existing package was loaded, holds that path.
where all the data for each part of the configuration is stored.
Definition config.hpp:58
std::shared_ptr< DataWarehouse > config_data_
Definition config.hpp:161
long int toEpoch(const GeneratedTime &t)
Convert a GeneratedTime to an integral epoch (using system_clock)
bool getYamlProperty(const YAML::Node &node, const std::string &key, T &storage, const T &default_value=T())
std::filesystem::path getSharePath(const std::string &package_name)
Return a path for the given package's share folder.
Definition utilities.hpp:51
const std::regex MAIL_REGEX("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,63}\\b", std::regex::icase)
bool extractPackageNameFromPath(const std::filesystem::path &path, std::string &package_name, std::filesystem::path &relative_filepath)
Definition utilities.cpp:41
GeneratedTime fromEpoch(long int epoch)
Convert an integral epoch to GeneratedTime (using system_clock)
const std::unordered_map< std::string, std::string > BACKWARDS_KEY_LOOKUP({ { "urdf", "URDF" }, { "srdf", "SRDF" }, { "package_settings", "CONFIG" } })
Simple Key/value pair for templates.
Definition templates.hpp:47