From efede63c8746e3e3d9f9fbeebc0c649889446ff0 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Mon, 7 Jun 2021 13:03:09 +0200 Subject: [PATCH 01/11] Added GPIO parsing and test --- .../hardware_interface/hardware_info.hpp | 11 +++-- hardware_interface/src/component_parser.cpp | 3 ++ .../test/test_component_parser.cpp | 42 +++++++++++++++++++ .../components_urdfs.hpp | 36 ++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index 41a5cb4005..f524a3c8c2 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -48,16 +48,16 @@ struct ComponentInfo { /// Name of the component. std::string name; - /// Type of the component: sensor or joint. + /// Type of the component: sensor, joint, or GPIO. std::string type; /** * Name of the command interfaces that can be set, e.g. "position", "velocity", etc. - * Used by joints. + * Used by joints and GPIO. */ std::vector command_interfaces; /** * Name of the state interfaces that can be read, e.g. "position", "velocity", etc. - * Used by Joints and Sensors. + * Used by Joints, Sensors and GPIO. */ std::vector state_interfaces; /// (Optional) Key-value pairs of component parameters, e.g. min/max values or serial number. @@ -84,6 +84,11 @@ struct HardwareInfo * Required for Sensor and optional for System Hardware. */ std::vector sensors; + /** + * Map of GPIO provided by the hardware where the key is a descriptive name of the GPIO. + * Optional for any hardware components. + */ + std::vector gpios; /** * Map of transmissions to calcualte ration between joints and physical actuators. * Optional for Actuator and System Hardware. diff --git a/hardware_interface/src/component_parser.cpp b/hardware_interface/src/component_parser.cpp index 862058eb33..9a33182ed6 100644 --- a/hardware_interface/src/component_parser.cpp +++ b/hardware_interface/src/component_parser.cpp @@ -30,6 +30,7 @@ constexpr const auto kClassTypeTag = "plugin"; constexpr const auto kParamTag = "param"; constexpr const auto kJointTag = "joint"; constexpr const auto kSensorTag = "sensor"; +constexpr const auto kGPIOTag = "gpio"; constexpr const auto kTransmissionTag = "transmission"; constexpr const auto kCommandInterfaceTag = "command_interface"; constexpr const auto kStateInterfaceTag = "state_interface"; @@ -231,6 +232,8 @@ HardwareInfo parse_resource_from_xml(const tinyxml2::XMLElement * ros2_control_i hardware.sensors.push_back(parse_component_from_xml(ros2_control_child_it) ); } else if (!std::string(kTransmissionTag).compare(ros2_control_child_it->Name())) { hardware.transmissions.push_back(parse_component_from_xml(ros2_control_child_it) ); + } else if (!std::string(kGPIOTag).compare(ros2_control_child_it->Name())) { + hardware.gpios.push_back(parse_component_from_xml(ros2_control_child_it) ); } else { throw std::runtime_error("invalid tag name " + std::string(ros2_control_child_it->Name())); } diff --git a/hardware_interface/test/test_component_parser.cpp b/hardware_interface/test/test_component_parser.cpp index 6d2ccde2a7..4bb46cd9cf 100644 --- a/hardware_interface/test/test_component_parser.cpp +++ b/hardware_interface/test/test_component_parser.cpp @@ -497,3 +497,45 @@ TEST_F(TestComponentParser, successfully_parse_valid_urdf_actuator_only) ASSERT_THAT(hardware_info.transmissions[0].parameters, SizeIs(1)); EXPECT_EQ(hardware_info.transmissions[0].parameters.at("joint_to_actuator"), "${1024/PI}"); } + +TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_robot_with_gpio) +{ + std::string urdf_to_test = + std::string(ros2_control_test_assets::urdf_head) + + ros2_control_test_assets::valid_urdf_ros2_control_system_robot_with_gpio + + ros2_control_test_assets::urdf_tail; + const auto control_hardware = parse_control_resources_from_urdf(urdf_to_test); + ASSERT_THAT(control_hardware, SizeIs(1)); + auto hardware_info = control_hardware.front(); + + EXPECT_EQ(hardware_info.name, "RRBotSystemWithGPIO"); + EXPECT_EQ(hardware_info.type, "system"); + EXPECT_EQ( + hardware_info.hardware_class_type, + "ros2_control_demo_hardware/RRBotSystemWithGPIOHardware"); + + ASSERT_THAT(hardware_info.joints, SizeIs(2)); + + EXPECT_EQ(hardware_info.joints[0].name, "joint1"); + EXPECT_EQ(hardware_info.joints[0].type, "joint"); + + EXPECT_EQ(hardware_info.joints[1].name, "joint2"); + EXPECT_EQ(hardware_info.joints[1].type, "joint"); + + ASSERT_THAT(hardware_info.gpios, SizeIs(2)); + + EXPECT_EQ(hardware_info.gpios[0].name, "flange_analog_IOs"); + EXPECT_EQ(hardware_info.gpios[0].type, "gpio"); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces, SizeIs(3)); + EXPECT_THAT(hardware_info.gpios[0].command_interfaces, SizeIs(1)); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces[0].name, "analog_output1"); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces[1].name, "analog_input1"); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces[2].name, "analog_input2"); + + EXPECT_EQ(hardware_info.gpios[1].name, "flange_vacuum"); + EXPECT_EQ(hardware_info.gpios[1].type, "gpio"); + EXPECT_THAT(hardware_info.gpios[1].state_interfaces, SizeIs(1)); + EXPECT_THAT(hardware_info.gpios[1].command_interfaces, SizeIs(1)); + EXPECT_THAT(hardware_info.gpios[1].state_interfaces[0].name, "vacuum"); + EXPECT_THAT(hardware_info.gpios[1].command_interfaces[0].name, "vacuum"); +} diff --git a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp index 526bb8663a..9cd95312de 100644 --- a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp +++ b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp @@ -332,6 +332,42 @@ const auto valid_urdf_ros2_control_actuator_only = )"; +// 10. Industrial Robots with integrated GPIO +const auto valid_urdf_ros2_control_system_robot_with_gpio = + R"( + + + ros2_control_demo_hardware/RRBotSystemWithGPIOHardware + 2 + 2 + + + + -1 + 1 + + + + + + -1 + 1 + + + + + + + + + + + + + + +)"; + // Errors const auto invalid_urdf_ros2_control_invalid_child = R"( From fbe885bd532bb90c3b3f104ed0696a71f4ac42e7 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:22:38 +0200 Subject: [PATCH 02/11] Minor wording --- .../include/hardware_interface/hardware_info.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index f524a3c8c2..8be4393d36 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -52,12 +52,12 @@ struct ComponentInfo std::string type; /** * Name of the command interfaces that can be set, e.g. "position", "velocity", etc. - * Used by joints and GPIO. + * Used by joints and GPIOs. */ std::vector command_interfaces; /** * Name of the state interfaces that can be read, e.g. "position", "velocity", etc. - * Used by Joints, Sensors and GPIO. + * Used by Joints, Sensors and GPIOs. */ std::vector state_interfaces; /// (Optional) Key-value pairs of component parameters, e.g. min/max values or serial number. From 652b48c585ff695bbe283646eaae9c6c7652f643 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:23:55 +0200 Subject: [PATCH 03/11] Minor wording --- hardware_interface/include/hardware_interface/hardware_info.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index 8be4393d36..49ee9a2622 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -31,7 +31,7 @@ struct InterfaceInfo { /** * Name of the command interfaces that can be set, e.g. "position", "velocity", etc. - * Used by joints. + * Used by joints and GPIOs. */ std::string name; /// (Optional) Minimal allowed values of the interface. From 33921fbc8d16e3bb553cc2f6e515576901b09271 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:26:43 +0200 Subject: [PATCH 04/11] Size and data_type parsing --- .../hardware_interface/hardware_info.hpp | 2 + hardware_interface/src/component_parser.cpp | 138 +++++++++++++++++- .../test/test_component_parser.cpp | 72 ++++++++- 3 files changed, 204 insertions(+), 8 deletions(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index 49ee9a2622..a2da0847fe 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -38,6 +38,8 @@ struct InterfaceInfo std::string min; /// (Optional) Maximal allowed values of the interface. std::string max; + /// (Optional) The datatype of the interface, e.g. "bool", "int". Defaults to double. + std::string data_type; }; /** diff --git a/hardware_interface/src/component_parser.cpp b/hardware_interface/src/component_parser.cpp index 9a33182ed6..c721040b34 100644 --- a/hardware_interface/src/component_parser.cpp +++ b/hardware_interface/src/component_parser.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "hardware_interface/hardware_info.hpp" #include "hardware_interface/component_parser.hpp" @@ -36,6 +37,8 @@ constexpr const auto kCommandInterfaceTag = "command_interface"; constexpr const auto kStateInterfaceTag = "state_interface"; constexpr const auto kMinTag = "min"; constexpr const auto kMaxTag = "max"; +constexpr const auto kDataTypeAttribute = "data_type"; +constexpr const auto kSizeAttribute = "size"; constexpr const auto kNameAttribute = "name"; constexpr const auto kTypeAttribute = "type"; } // namespace @@ -104,6 +107,56 @@ std::string get_attribute_value( return get_attribute_value(element_it, attribute_name, std::string(tag_name)); } +/// Parse optional size attribute +/** + * Parses an XMLElement and returns the vector of suffixes to apply. + * + * Example behavior: + * - size="3" returns the suffixes {"1","2","3"} + * - size="1" returns the suffixes {"1"} + * - size="" returns the suffixes {""} + * - size="x y z" returns the suffixes {"x", "y", "z"} + * - size="shoulder elbow wrist" returns the suffixes {"shoulder", "elbow", "wrist"} + * + * + * \param[in] elem XMLElement to check the size attribute to parse. + * \return vector of strings denoting the suffixes. + */ +std::vector parse_size_attribute( + const tinyxml2::XMLElement * elem) +{ + const tinyxml2::XMLAttribute * attr = elem->FindAttribute(kSizeAttribute); + std::vector suffixes; + // Is the attribute null as nothing was found? + if (!attr) { + suffixes.push_back(""); + return suffixes; + } + + // Try to parse it as a whitespace delimited list of strings + std::string s = attr->Value(); + std::regex ws("\\s+"); + std::sregex_token_iterator it(s.begin(), s.end(), ws, -1); + for (; it != std::sregex_token_iterator(); it++) { + suffixes.push_back(it->str()); + } + if (suffixes.size() == 0) { + // Empty value + suffixes.push_back(""); + } else if (suffixes.size() == 1) { + // Regex used since QueryIntValue parses "0 1 2" to value=0. + std::regex int_re("[1-9][0-9]*"); + if (std::regex_match(suffixes[0], int_re)) { + int maxval = std::stoi(suffixes[0]); + suffixes.clear(); + for (int i = 1; i <= maxval; i++) { + suffixes.push_back(std::to_string(i)); + } + } + } + return suffixes; +} + /// Search XML snippet from URDF for parameters. /** * \param[in] params_it pointer to the iterator where parameters info should be found @@ -160,6 +213,37 @@ hardware_interface::InterfaceInfo parse_interfaces_from_xml( interface.max = interface_param->second; } + // Optional data_type attribute + const tinyxml2::XMLAttribute * attr; + attr = interfaces_it->FindAttribute(kDataTypeAttribute); + if (!attr) { + interface.data_type = "double"; + } else { + interface.data_type = interfaces_it->Attribute(kDataTypeAttribute); + } + + return interface; +} + +/// Search XML snippet for interface information. +/** + * \param[in] interfaces_it pointer to the iterator over the interfaces. + * \param[in] suffix suffix to append to the interface name. + * \param[in] data_type data_type of handle. Defaults to double. + * \return InterfaceInfo filled with information about component. + * \throws std::runtime_error if an interface attribute or tag is not found. + */ +hardware_interface::InterfaceInfo parse_interfaces_from_xml( + const tinyxml2::XMLElement * interfaces_it, + std::string suffix, + std::string data_type) +{ + hardware_interface::InterfaceInfo interface; + interface = parse_interfaces_from_xml(interfaces_it); + interface.name += suffix; + if (data_type != "") { + interface.data_type = data_type; + } return interface; } @@ -178,17 +262,32 @@ ComponentInfo parse_component_from_xml(const tinyxml2::XMLElement * component_it component.type = component_it->Name(); component.name = get_attribute_value(component_it, kNameAttribute, component.type); + // Find optional data_type specified by component + std::string data_type = ""; + const char * val = component_it->Attribute(kDataTypeAttribute); + if (val) { + data_type = val; + } + // Parse all command interfaces const auto * command_interfaces_it = component_it->FirstChildElement(kCommandInterfaceTag); while (command_interfaces_it) { - component.command_interfaces.push_back(parse_interfaces_from_xml(command_interfaces_it)); + std::vector suffixes = parse_size_attribute(command_interfaces_it); + for (std::string suffix : suffixes) { + component.command_interfaces.push_back( + parse_interfaces_from_xml(command_interfaces_it, suffix, data_type)); + } command_interfaces_it = command_interfaces_it->NextSiblingElement(kCommandInterfaceTag); } // Parse state interfaces const auto * state_interfaces_it = component_it->FirstChildElement(kStateInterfaceTag); while (state_interfaces_it) { - component.state_interfaces.push_back(parse_interfaces_from_xml(state_interfaces_it)); + std::vector suffixes = parse_size_attribute(state_interfaces_it); + for (std::string suffix : suffixes) { + component.state_interfaces.push_back( + parse_interfaces_from_xml(state_interfaces_it, suffix, data_type)); + } state_interfaces_it = state_interfaces_it->NextSiblingElement(kStateInterfaceTag); } @@ -201,6 +300,21 @@ ComponentInfo parse_component_from_xml(const tinyxml2::XMLElement * component_it return component; } +/// Search XML snippet from URDF for information about a control component. +/** + * \param[in] component_it pointer to the iterator where component + * info should befound + * \param[in] suffix suffix to append to the component name. + */ +ComponentInfo parse_component_from_xml( + const tinyxml2::XMLElement * component_it, + std::string suffix) +{ + ComponentInfo component = parse_component_from_xml(component_it); + component.name += suffix; + return component; +} + /// Parse a control resource from an "ros2_control" tag. /** * \param[in] ros2_control_it pointer to ros2_control element @@ -227,13 +341,25 @@ HardwareInfo parse_resource_from_xml(const tinyxml2::XMLElement * ros2_control_i hardware.hardware_parameters = parse_parameters_from_xml(params_it); } } else if (!std::string(kJointTag).compare(ros2_control_child_it->Name())) { - hardware.joints.push_back(parse_component_from_xml(ros2_control_child_it) ); + std::vector suffixes = parse_size_attribute(ros2_control_child_it); + for (std::string suffix : suffixes) { + hardware.joints.push_back( + parse_component_from_xml(ros2_control_child_it, suffix)); + } } else if (!std::string(kSensorTag).compare(ros2_control_child_it->Name())) { - hardware.sensors.push_back(parse_component_from_xml(ros2_control_child_it) ); + std::vector suffixes = parse_size_attribute(ros2_control_child_it); + for (std::string suffix : suffixes) { + hardware.sensors.push_back( + parse_component_from_xml(ros2_control_child_it, suffix)); + } + } else if (!std::string(kGPIOTag).compare(ros2_control_child_it->Name())) { + std::vector suffixes = parse_size_attribute(ros2_control_child_it); + for (std::string suffix : suffixes) { + hardware.gpios.push_back( + parse_component_from_xml(ros2_control_child_it, suffix)); + } } else if (!std::string(kTransmissionTag).compare(ros2_control_child_it->Name())) { hardware.transmissions.push_back(parse_component_from_xml(ros2_control_child_it) ); - } else if (!std::string(kGPIOTag).compare(ros2_control_child_it->Name())) { - hardware.gpios.push_back(parse_component_from_xml(ros2_control_child_it) ); } else { throw std::runtime_error("invalid tag name " + std::string(ros2_control_child_it->Name())); } diff --git a/hardware_interface/test/test_component_parser.cpp b/hardware_interface/test/test_component_parser.cpp index 4bb46cd9cf..ade325588b 100644 --- a/hardware_interface/test/test_component_parser.cpp +++ b/hardware_interface/test/test_component_parser.cpp @@ -536,6 +536,74 @@ TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_robot_with_gpio EXPECT_EQ(hardware_info.gpios[1].type, "gpio"); EXPECT_THAT(hardware_info.gpios[1].state_interfaces, SizeIs(1)); EXPECT_THAT(hardware_info.gpios[1].command_interfaces, SizeIs(1)); - EXPECT_THAT(hardware_info.gpios[1].state_interfaces[0].name, "vacuum"); - EXPECT_THAT(hardware_info.gpios[1].command_interfaces[0].name, "vacuum"); + +TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_with_size_and_data_type) +{ + std::string urdf_to_test = + std::string(ros2_control_test_assets::urdf_head) + + ros2_control_test_assets::valid_urdf_ros2_control_system_robot_with_size_and_data_type + + ros2_control_test_assets::urdf_tail; + const auto control_hardware = parse_control_resources_from_urdf(urdf_to_test); + ASSERT_THAT(control_hardware, SizeIs(1)); + auto hardware_info = control_hardware.front(); + + EXPECT_EQ(hardware_info.name, "RRBotSystemWithSizeAndDataType"); + EXPECT_EQ(hardware_info.type, "system"); + EXPECT_EQ( + hardware_info.hardware_class_type, + "ros2_control_demo_hardware/RRBotSystemWithSizeAndDataType"); + + ASSERT_THAT(hardware_info.joints, SizeIs(2)); + + EXPECT_EQ(hardware_info.joints[0].name, "joint1"); + EXPECT_EQ(hardware_info.joints[0].type, "joint"); + EXPECT_THAT(hardware_info.joints[0].command_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.joints[0].command_interfaces[0].name, HW_IF_POSITION); + EXPECT_EQ(hardware_info.joints[0].command_interfaces[0].data_type, "double"); + EXPECT_THAT(hardware_info.joints[0].state_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.joints[0].state_interfaces[0].name, HW_IF_POSITION); + EXPECT_EQ(hardware_info.joints[0].state_interfaces[0].data_type, "double"); + EXPECT_EQ(hardware_info.joints[1].name, "joint2"); + EXPECT_EQ(hardware_info.joints[1].type, "joint"); + EXPECT_THAT(hardware_info.joints[1].command_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.joints[1].command_interfaces[0].name, HW_IF_POSITION); + EXPECT_EQ(hardware_info.joints[1].command_interfaces[0].data_type, "double"); + EXPECT_THAT(hardware_info.joints[1].state_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.joints[1].state_interfaces[0].name, HW_IF_POSITION); + EXPECT_EQ(hardware_info.joints[1].state_interfaces[0].data_type, "double"); + + ASSERT_THAT(hardware_info.gpios, SizeIs(1)); + + EXPECT_EQ(hardware_info.gpios[0].name, "flange_IOS"); + EXPECT_EQ(hardware_info.gpios[0].type, "gpio"); + EXPECT_THAT(hardware_info.gpios[0].command_interfaces, SizeIs(2)); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].name, "digital_output1"); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].data_type, "bool"); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[1].name, "digital_output2"); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[1].data_type, "bool"); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces, SizeIs(3)); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].name, "analog_input0"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].data_type, "double"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].name, "analog_input1"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].data_type, "double"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[2].name, "analog_input2"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[2].data_type, "double"); + + ASSERT_THAT(hardware_info.sensors, SizeIs(2)); + + EXPECT_EQ(hardware_info.sensors[0].name, "ft_ee"); + EXPECT_EQ(hardware_info.sensors[0].type, "sensor"); + EXPECT_THAT(hardware_info.sensors[0].state_interfaces, SizeIs(6)); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[0].name, "force.x"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[0].data_type, "double"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[1].name, "force.y"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[1].data_type, "double"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[2].name, "force.z"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[2].data_type, "double"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[3].name, "torque.x"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[3].data_type, "double"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[4].name, "torque.y"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[4].data_type, "double"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[5].name, "torque.z"); + EXPECT_EQ(hardware_info.sensors[0].state_interfaces[5].data_type, "double"); } From be276bc8a0729a9943d458f331c99b77140c3ac6 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:27:51 +0200 Subject: [PATCH 05/11] use same text method as others --- hardware_interface/test/test_component_parser.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hardware_interface/test/test_component_parser.cpp b/hardware_interface/test/test_component_parser.cpp index ade325588b..064c82b60c 100644 --- a/hardware_interface/test/test_component_parser.cpp +++ b/hardware_interface/test/test_component_parser.cpp @@ -528,14 +528,17 @@ TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_robot_with_gpio EXPECT_EQ(hardware_info.gpios[0].type, "gpio"); EXPECT_THAT(hardware_info.gpios[0].state_interfaces, SizeIs(3)); EXPECT_THAT(hardware_info.gpios[0].command_interfaces, SizeIs(1)); - EXPECT_THAT(hardware_info.gpios[0].state_interfaces[0].name, "analog_output1"); - EXPECT_THAT(hardware_info.gpios[0].state_interfaces[1].name, "analog_input1"); - EXPECT_THAT(hardware_info.gpios[0].state_interfaces[2].name, "analog_input2"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].name, "analog_output1"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].name, "analog_input1"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[2].name, "analog_input2"); EXPECT_EQ(hardware_info.gpios[1].name, "flange_vacuum"); EXPECT_EQ(hardware_info.gpios[1].type, "gpio"); EXPECT_THAT(hardware_info.gpios[1].state_interfaces, SizeIs(1)); EXPECT_THAT(hardware_info.gpios[1].command_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.gpios[1].state_interfaces[0].name, "vacuum"); + EXPECT_EQ(hardware_info.gpios[1].command_interfaces[0].name, "vacuum"); +} TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_with_size_and_data_type) { From 37ae98d9fc8b3b6237fce7bd0c26861b188c48c9 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:28:23 +0200 Subject: [PATCH 06/11] test urdf for size and data_type --- .../components_urdfs.hpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp index 9cd95312de..94950ff82a 100644 --- a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp +++ b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp @@ -368,6 +368,30 @@ const auto valid_urdf_ros2_control_system_robot_with_gpio = )"; +// 11. Industrial Robots using size and data_type attributes +const auto valid_urdf_ros2_control_system_robot_with_size_and_data_type = + R"( + + + ros2_control_demo_hardware/RRBotSystemWithSizeAndDataType + 2 + 2 + + + + + + + + + + + + + + +)"; + // Errors const auto invalid_urdf_ros2_control_invalid_child = R"( From 3cea9feac6e43ec24f6494d887a823b206fe19a2 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Tue, 29 Jun 2021 16:36:50 +0200 Subject: [PATCH 07/11] fixed whitespace that somehow got committed --- .../include/ros2_control_test_assets/components_urdfs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp index 94950ff82a..1b1335ca6c 100644 --- a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp +++ b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp @@ -369,7 +369,7 @@ const auto valid_urdf_ros2_control_system_robot_with_gpio = )"; // 11. Industrial Robots using size and data_type attributes -const auto valid_urdf_ros2_control_system_robot_with_size_and_data_type = +const auto valid_urdf_ros2_control_system_robot_with_size_and_data_type = R"( From fd86e34324ad40c644785b0147e3ebb5b7120795 Mon Sep 17 00:00:00 2001 From: Mathias Hauan Arbo Date: Thu, 1 Jul 2021 15:28:12 +0200 Subject: [PATCH 08/11] GPIO Only: size and data_type field in interfaces --- .../hardware_interface/hardware_info.hpp | 4 +- hardware_interface/src/component_parser.cpp | 191 ++++++++---------- .../test/test_component_parser.cpp | 63 +++--- .../components_urdfs.hpp | 32 ++- 4 files changed, 144 insertions(+), 146 deletions(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index a2da0847fe..2325a85369 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -38,8 +38,10 @@ struct InterfaceInfo std::string min; /// (Optional) Maximal allowed values of the interface. std::string max; - /// (Optional) The datatype of the interface, e.g. "bool", "int". Defaults to double. + /// (Optional) The datatype of the interface, e.g. "bool", "int". Used by GPIOs. std::string data_type; + /// (Optional) If the handle is an array, the size of the array. Used by GPIOs. + int size; }; /** diff --git a/hardware_interface/src/component_parser.cpp b/hardware_interface/src/component_parser.cpp index c721040b34..16a9f87fed 100644 --- a/hardware_interface/src/component_parser.cpp +++ b/hardware_interface/src/component_parser.cpp @@ -109,52 +109,57 @@ std::string get_attribute_value( /// Parse optional size attribute /** - * Parses an XMLElement and returns the vector of suffixes to apply. + * Parses an XMLElement and returns the value of the size attribute. + * If not specified, defaults to 1. If not given a positive int, throws an error. * - * Example behavior: - * - size="3" returns the suffixes {"1","2","3"} - * - size="1" returns the suffixes {"1"} - * - size="" returns the suffixes {""} - * - size="x y z" returns the suffixes {"x", "y", "z"} - * - size="shoulder elbow wrist" returns the suffixes {"shoulder", "elbow", "wrist"} - * - * - * \param[in] elem XMLElement to check the size attribute to parse. - * \return vector of strings denoting the suffixes. + * \param[in] elem XMLElement that has the size attribute. + * \return The size. + * \throws std::runtime_error if not given a positive non-zero int as value. */ -std::vector parse_size_attribute( +std::size_t parse_size_attribute( const tinyxml2::XMLElement * elem) { const tinyxml2::XMLAttribute * attr = elem->FindAttribute(kSizeAttribute); - std::vector suffixes; - // Is the attribute null as nothing was found? + std::size_t size; + if (!attr) { - suffixes.push_back(""); - return suffixes; + return 1; } - // Try to parse it as a whitespace delimited list of strings + // Regex used to check for non-zero positive int std::string s = attr->Value(); - std::regex ws("\\s+"); - std::sregex_token_iterator it(s.begin(), s.end(), ws, -1); - for (; it != std::sregex_token_iterator(); it++) { - suffixes.push_back(it->str()); + std::regex int_re("[1-9][0-9]*"); + if (std::regex_match(s, int_re)) { + size = std::stoi(s); + } else { + throw std::runtime_error( + "Could not parse size tag in \"" + std::string(elem->Name()) + "\"." + + "Got \"" + s + "\", but expected a non-zero positive integer."); } - if (suffixes.size() == 0) { - // Empty value - suffixes.push_back(""); - } else if (suffixes.size() == 1) { - // Regex used since QueryIntValue parses "0 1 2" to value=0. - std::regex int_re("[1-9][0-9]*"); - if (std::regex_match(suffixes[0], int_re)) { - int maxval = std::stoi(suffixes[0]); - suffixes.clear(); - for (int i = 1; i <= maxval; i++) { - suffixes.push_back(std::to_string(i)); - } - } + + return size; +} + +/// Parse data_type attribute +/** + * Parses an XMLElement and returns the value of the data_type attribute. + * Defaults to "double" if not specified. + * + * \param[in] elem XMLElement that has the data_type attribute. + * \return string specifying the data type. + */ +std::string parse_data_type_attribute( + const tinyxml2::XMLElement * elem) +{ + const tinyxml2::XMLAttribute * attr = elem->FindAttribute(kDataTypeAttribute); + std::string data_type; + if (!attr) { + data_type = "double"; + } else { + data_type = attr->Value(); } - return suffixes; + + return data_type; } /// Search XML snippet from URDF for parameters. @@ -213,37 +218,10 @@ hardware_interface::InterfaceInfo parse_interfaces_from_xml( interface.max = interface_param->second; } - // Optional data_type attribute - const tinyxml2::XMLAttribute * attr; - attr = interfaces_it->FindAttribute(kDataTypeAttribute); - if (!attr) { - interface.data_type = "double"; - } else { - interface.data_type = interfaces_it->Attribute(kDataTypeAttribute); - } - - return interface; -} + // Default to a single double + interface.data_type = "double"; + interface.size = 1; -/// Search XML snippet for interface information. -/** - * \param[in] interfaces_it pointer to the iterator over the interfaces. - * \param[in] suffix suffix to append to the interface name. - * \param[in] data_type data_type of handle. Defaults to double. - * \return InterfaceInfo filled with information about component. - * \throws std::runtime_error if an interface attribute or tag is not found. - */ -hardware_interface::InterfaceInfo parse_interfaces_from_xml( - const tinyxml2::XMLElement * interfaces_it, - std::string suffix, - std::string data_type) -{ - hardware_interface::InterfaceInfo interface; - interface = parse_interfaces_from_xml(interfaces_it); - interface.name += suffix; - if (data_type != "") { - interface.data_type = data_type; - } return interface; } @@ -262,32 +240,17 @@ ComponentInfo parse_component_from_xml(const tinyxml2::XMLElement * component_it component.type = component_it->Name(); component.name = get_attribute_value(component_it, kNameAttribute, component.type); - // Find optional data_type specified by component - std::string data_type = ""; - const char * val = component_it->Attribute(kDataTypeAttribute); - if (val) { - data_type = val; - } - // Parse all command interfaces const auto * command_interfaces_it = component_it->FirstChildElement(kCommandInterfaceTag); while (command_interfaces_it) { - std::vector suffixes = parse_size_attribute(command_interfaces_it); - for (std::string suffix : suffixes) { - component.command_interfaces.push_back( - parse_interfaces_from_xml(command_interfaces_it, suffix, data_type)); - } + component.command_interfaces.push_back(parse_interfaces_from_xml(command_interfaces_it)); command_interfaces_it = command_interfaces_it->NextSiblingElement(kCommandInterfaceTag); } // Parse state interfaces const auto * state_interfaces_it = component_it->FirstChildElement(kStateInterfaceTag); while (state_interfaces_it) { - std::vector suffixes = parse_size_attribute(state_interfaces_it); - for (std::string suffix : suffixes) { - component.state_interfaces.push_back( - parse_interfaces_from_xml(state_interfaces_it, suffix, data_type)); - } + component.state_interfaces.push_back(parse_interfaces_from_xml(state_interfaces_it)); state_interfaces_it = state_interfaces_it->NextSiblingElement(kStateInterfaceTag); } @@ -300,18 +263,49 @@ ComponentInfo parse_component_from_xml(const tinyxml2::XMLElement * component_it return component; } -/// Search XML snippet from URDF for information about a control component. +/// Search XML snippet from URDF for information about a complex component. /** + * A complex component can have a non-double data type specified on its interfaces, + * and the interface may be an array of a fixed size of the data type. + * * \param[in] component_it pointer to the iterator where component * info should befound - * \param[in] suffix suffix to append to the component name. + * \throws std::runtime_error if a required component attribute or tag is not found. */ -ComponentInfo parse_component_from_xml( - const tinyxml2::XMLElement * component_it, - std::string suffix) +ComponentInfo parse_complex_component_from_xml( + const tinyxml2::XMLElement * component_it) { - ComponentInfo component = parse_component_from_xml(component_it); - component.name += suffix; + ComponentInfo component; + + // Find name, type and class of a component + component.type = component_it->Name(); + component.name = get_attribute_value(component_it, kNameAttribute, component.type); + + // Parse all command interfaces + const auto * command_interfaces_it = component_it->FirstChildElement(kCommandInterfaceTag); + while (command_interfaces_it) { + component.command_interfaces.push_back(parse_interfaces_from_xml(command_interfaces_it)); + component.command_interfaces.back().data_type = + parse_data_type_attribute(command_interfaces_it); + component.command_interfaces.back().size = parse_size_attribute(command_interfaces_it); + command_interfaces_it = command_interfaces_it->NextSiblingElement(kCommandInterfaceTag); + } + + // Parse state interfaces + const auto * state_interfaces_it = component_it->FirstChildElement(kStateInterfaceTag); + while (state_interfaces_it) { + component.state_interfaces.push_back(parse_interfaces_from_xml(state_interfaces_it)); + component.state_interfaces.back().data_type = parse_data_type_attribute(state_interfaces_it); + component.state_interfaces.back().size = parse_size_attribute(state_interfaces_it); + state_interfaces_it = state_interfaces_it->NextSiblingElement(kStateInterfaceTag); + } + + // Parse parameters + const auto * params_it = component_it->FirstChildElement(kParamTag); + if (params_it) { + component.parameters = parse_parameters_from_xml(params_it); + } + return component; } @@ -341,23 +335,12 @@ HardwareInfo parse_resource_from_xml(const tinyxml2::XMLElement * ros2_control_i hardware.hardware_parameters = parse_parameters_from_xml(params_it); } } else if (!std::string(kJointTag).compare(ros2_control_child_it->Name())) { - std::vector suffixes = parse_size_attribute(ros2_control_child_it); - for (std::string suffix : suffixes) { - hardware.joints.push_back( - parse_component_from_xml(ros2_control_child_it, suffix)); - } + hardware.joints.push_back(parse_component_from_xml(ros2_control_child_it) ); } else if (!std::string(kSensorTag).compare(ros2_control_child_it->Name())) { - std::vector suffixes = parse_size_attribute(ros2_control_child_it); - for (std::string suffix : suffixes) { - hardware.sensors.push_back( - parse_component_from_xml(ros2_control_child_it, suffix)); - } + hardware.sensors.push_back(parse_component_from_xml(ros2_control_child_it) ); } else if (!std::string(kGPIOTag).compare(ros2_control_child_it->Name())) { - std::vector suffixes = parse_size_attribute(ros2_control_child_it); - for (std::string suffix : suffixes) { - hardware.gpios.push_back( - parse_component_from_xml(ros2_control_child_it, suffix)); - } + hardware.gpios.push_back( + parse_complex_component_from_xml(ros2_control_child_it)); } else if (!std::string(kTransmissionTag).compare(ros2_control_child_it->Name())) { hardware.transmissions.push_back(parse_component_from_xml(ros2_control_child_it) ); } else { diff --git a/hardware_interface/test/test_component_parser.cpp b/hardware_interface/test/test_component_parser.cpp index 064c82b60c..55891d0a59 100644 --- a/hardware_interface/test/test_component_parser.cpp +++ b/hardware_interface/test/test_component_parser.cpp @@ -556,57 +556,50 @@ TEST_F(TestComponentParser, successfully_parse_valid_urdf_system_with_size_and_d hardware_info.hardware_class_type, "ros2_control_demo_hardware/RRBotSystemWithSizeAndDataType"); - ASSERT_THAT(hardware_info.joints, SizeIs(2)); + ASSERT_THAT(hardware_info.joints, SizeIs(1)); EXPECT_EQ(hardware_info.joints[0].name, "joint1"); EXPECT_EQ(hardware_info.joints[0].type, "joint"); EXPECT_THAT(hardware_info.joints[0].command_interfaces, SizeIs(1)); EXPECT_EQ(hardware_info.joints[0].command_interfaces[0].name, HW_IF_POSITION); EXPECT_EQ(hardware_info.joints[0].command_interfaces[0].data_type, "double"); + EXPECT_EQ(hardware_info.joints[0].command_interfaces[0].size, 1); EXPECT_THAT(hardware_info.joints[0].state_interfaces, SizeIs(1)); EXPECT_EQ(hardware_info.joints[0].state_interfaces[0].name, HW_IF_POSITION); EXPECT_EQ(hardware_info.joints[0].state_interfaces[0].data_type, "double"); - EXPECT_EQ(hardware_info.joints[1].name, "joint2"); - EXPECT_EQ(hardware_info.joints[1].type, "joint"); - EXPECT_THAT(hardware_info.joints[1].command_interfaces, SizeIs(1)); - EXPECT_EQ(hardware_info.joints[1].command_interfaces[0].name, HW_IF_POSITION); - EXPECT_EQ(hardware_info.joints[1].command_interfaces[0].data_type, "double"); - EXPECT_THAT(hardware_info.joints[1].state_interfaces, SizeIs(1)); - EXPECT_EQ(hardware_info.joints[1].state_interfaces[0].name, HW_IF_POSITION); - EXPECT_EQ(hardware_info.joints[1].state_interfaces[0].data_type, "double"); + EXPECT_EQ(hardware_info.joints[0].state_interfaces[0].size, 1); ASSERT_THAT(hardware_info.gpios, SizeIs(1)); EXPECT_EQ(hardware_info.gpios[0].name, "flange_IOS"); EXPECT_EQ(hardware_info.gpios[0].type, "gpio"); - EXPECT_THAT(hardware_info.gpios[0].command_interfaces, SizeIs(2)); - EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].name, "digital_output1"); + EXPECT_THAT(hardware_info.gpios[0].command_interfaces, SizeIs(1)); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].name, "digital_output"); EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].data_type, "bool"); - EXPECT_EQ(hardware_info.gpios[0].command_interfaces[1].name, "digital_output2"); - EXPECT_EQ(hardware_info.gpios[0].command_interfaces[1].data_type, "bool"); - EXPECT_THAT(hardware_info.gpios[0].state_interfaces, SizeIs(3)); - EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].name, "analog_input0"); + EXPECT_EQ(hardware_info.gpios[0].command_interfaces[0].size, 2); + EXPECT_THAT(hardware_info.gpios[0].state_interfaces, SizeIs(2)); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].name, "analog_input"); EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].data_type, "double"); - EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].name, "analog_input1"); - EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].data_type, "double"); - EXPECT_EQ(hardware_info.gpios[0].state_interfaces[2].name, "analog_input2"); - EXPECT_EQ(hardware_info.gpios[0].state_interfaces[2].data_type, "double"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[0].size, 3); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].name, "image"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].data_type, "cv::Mat"); + EXPECT_EQ(hardware_info.gpios[0].state_interfaces[1].size, 1); +} - ASSERT_THAT(hardware_info.sensors, SizeIs(2)); +TEST_F(TestComponentParser, negative_size_throws_error) +{ + std::string urdf_to_test = + std::string(ros2_control_test_assets::urdf_head) + + ros2_control_test_assets::invalid_urdf2_ros2_control_illegal_size + + ros2_control_test_assets::urdf_tail; + ASSERT_THROW(parse_control_resources_from_urdf(urdf_to_test), std::runtime_error); +} - EXPECT_EQ(hardware_info.sensors[0].name, "ft_ee"); - EXPECT_EQ(hardware_info.sensors[0].type, "sensor"); - EXPECT_THAT(hardware_info.sensors[0].state_interfaces, SizeIs(6)); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[0].name, "force.x"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[0].data_type, "double"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[1].name, "force.y"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[1].data_type, "double"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[2].name, "force.z"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[2].data_type, "double"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[3].name, "torque.x"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[3].data_type, "double"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[4].name, "torque.y"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[4].data_type, "double"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[5].name, "torque.z"); - EXPECT_EQ(hardware_info.sensors[0].state_interfaces[5].data_type, "double"); +TEST_F(TestComponentParser, noninteger_size_throws_error) +{ + std::string urdf_to_test = + std::string(ros2_control_test_assets::urdf_head) + + ros2_control_test_assets::invalid_urdf2_ros2_control_illegal_size2 + + ros2_control_test_assets::urdf_tail; + ASSERT_THROW(parse_control_resources_from_urdf(urdf_to_test), std::runtime_error); } diff --git a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp index 1b1335ca6c..ba53d1a415 100644 --- a/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp +++ b/ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp @@ -377,18 +377,15 @@ const auto valid_urdf_ros2_control_system_robot_with_size_and_data_type = 2 2 - + - + + - - - - )"; @@ -497,6 +494,29 @@ const auto invalid_urdf_ros2_control_parameter_empty = )"; +const auto invalid_urdf2_ros2_control_illegal_size = + R"( + + + ros2_control_demo_hardware/RRBotSystemWithIllegalSize + + + + + +)"; + +const auto invalid_urdf2_ros2_control_illegal_size2 = + R"( + + + ros2_control_demo_hardware/RRBotSystemWithIllegalSize2 + + + + + +)"; } // namespace ros2_control_test_assets #endif // ROS2_CONTROL_TEST_ASSETS__COMPONENTS_URDFS_HPP_ From 16016b9c29880822f41b205adfa0ebafef649923 Mon Sep 17 00:00:00 2001 From: mahaarbo Date: Sat, 3 Jul 2021 19:52:01 +0200 Subject: [PATCH 09/11] Update hardware_interface/src/component_parser.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Denis Štogl --- hardware_interface/src/component_parser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hardware_interface/src/component_parser.cpp b/hardware_interface/src/component_parser.cpp index 16a9f87fed..941cf4d3cb 100644 --- a/hardware_interface/src/component_parser.cpp +++ b/hardware_interface/src/component_parser.cpp @@ -110,11 +110,11 @@ std::string get_attribute_value( /// Parse optional size attribute /** * Parses an XMLElement and returns the value of the size attribute. - * If not specified, defaults to 1. If not given a positive int, throws an error. + * If not specified, defaults to 1. If not given a positive integer, throws an error. * * \param[in] elem XMLElement that has the size attribute. * \return The size. - * \throws std::runtime_error if not given a positive non-zero int as value. + * \throws std::runtime_error if not given a positive non-zero integer as value. */ std::size_t parse_size_attribute( const tinyxml2::XMLElement * elem) From 30d8277cc5dac26fa0ad5f8e00b8a361a3d38652 Mon Sep 17 00:00:00 2001 From: mahaarbo Date: Sat, 3 Jul 2021 19:52:10 +0200 Subject: [PATCH 10/11] Update hardware_interface/src/component_parser.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Denis Štogl --- hardware_interface/src/component_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware_interface/src/component_parser.cpp b/hardware_interface/src/component_parser.cpp index 941cf4d3cb..5cdcbbe645 100644 --- a/hardware_interface/src/component_parser.cpp +++ b/hardware_interface/src/component_parser.cpp @@ -120,12 +120,12 @@ std::size_t parse_size_attribute( const tinyxml2::XMLElement * elem) { const tinyxml2::XMLAttribute * attr = elem->FindAttribute(kSizeAttribute); - std::size_t size; if (!attr) { return 1; } + std::size_t size; // Regex used to check for non-zero positive int std::string s = attr->Value(); std::regex int_re("[1-9][0-9]*"); From 688a9f5ba3406b41a7fd735d4c86e297596d4273 Mon Sep 17 00:00:00 2001 From: mahaarbo Date: Sat, 3 Jul 2021 19:53:46 +0200 Subject: [PATCH 11/11] Update hardware_interface/include/hardware_interface/hardware_info.hpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Denis Štogl --- hardware_interface/include/hardware_interface/hardware_info.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware_interface/include/hardware_interface/hardware_info.hpp b/hardware_interface/include/hardware_interface/hardware_info.hpp index 2325a85369..931f7159df 100644 --- a/hardware_interface/include/hardware_interface/hardware_info.hpp +++ b/hardware_interface/include/hardware_interface/hardware_info.hpp @@ -61,7 +61,7 @@ struct ComponentInfo std::vector command_interfaces; /** * Name of the state interfaces that can be read, e.g. "position", "velocity", etc. - * Used by Joints, Sensors and GPIOs. + * Used by joints, sensors and GPIOs. */ std::vector state_interfaces; /// (Optional) Key-value pairs of component parameters, e.g. min/max values or serial number.