diff --git a/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/CMakeLists.txt b/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/CMakeLists.txt
new file mode 100644
index 000000000..f640b3ee8
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 3.5)
+project(test_pkg)
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+find_package(ament_cmake REQUIRED)
+find_package(Boost REQUIRED)
+find_package(rclcpp REQUIRED)
+find_package(std_srvs REQUIRED)
+find_package(sensor_msgs REQUIRED)
+
+add_executable(test_node src/test_node.cpp)
+ament_target_dependencies(test_node std_srvs sensor_msgs )
+
+install(TARGETS
+ test_node
+ DESTINATION lib/${PROJECT_NAME})
+
+ament_package()
diff --git a/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/package.xml b/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/package.xml
new file mode 100644
index 000000000..fdc193692
--- /dev/null
+++ b/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/package.xml
@@ -0,0 +1,26 @@
+
+
+
+ test_pkg
+ 0.0.0
+ This package contains the implementation of the node test_node
+ Jane Doe
+ Jane Doe
+ Apache 2.0
+
+ ament_cmake
+
+ boost
+ rclcpp
+ std_srvs
+ sensor_msgs
+
+ ament_lint_auto
+ ament_lint_common
+
+
+ ament_cmake
+
+
diff --git a/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_node.cpp b/plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/src/test_node.cpp
similarity index 100%
rename from plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_node.cpp
rename to plugins/de.fraunhofer.ipa.ros.xtext.tests/resources/ros2generator/test_pkg/src/test_node.cpp
diff --git a/plugins/de.fraunhofer.ipa.ros.xtext.tests/src/de/fraunhofer/ipa/ros/tests/RosGeneratorTest.xtend b/plugins/de.fraunhofer.ipa.ros.xtext.tests/src/de/fraunhofer/ipa/ros/tests/RosGeneratorTest.xtend
index cfa7a4f23..af47365dd 100644
--- a/plugins/de.fraunhofer.ipa.ros.xtext.tests/src/de/fraunhofer/ipa/ros/tests/RosGeneratorTest.xtend
+++ b/plugins/de.fraunhofer.ipa.ros.xtext.tests/src/de/fraunhofer/ipa/ros/tests/RosGeneratorTest.xtend
@@ -63,10 +63,16 @@ class RosGeneratorTest {
val fsa = new InMemoryFileSystemAccess
ros2Generator.doGenerate(model.eResource, fsa, new GeneratorContext)
- Assert.assertTrue(fsa.textFiles.containsKey(CustomOutputProvider::DEFAULT_OUTPUT + "test_node.cpp"))
+ Assert.assertTrue(fsa.textFiles.containsKey(CustomOutputProvider::DEFAULT_OUTPUT + "test_pkg/package.xml"))
Assert.assertEquals(
- new String(Files.readAllBytes(Paths.get(RESOURCES_BASE_DIR, 'ros2generator', 'test_node.cpp'))).trim,
- fsa.textFiles.get(CustomOutputProvider::DEFAULT_OUTPUT + "test_node.cpp").toString.trim)
+ new String(Files.readAllBytes(Paths.get(RESOURCES_BASE_DIR, 'ros2generator/test_pkg/src/','test_node.cpp'))).trim,
+ fsa.textFiles.get(CustomOutputProvider::DEFAULT_OUTPUT + "test_pkg/src/test_node.cpp").toString.trim)
+ Assert.assertEquals(
+ new String(Files.readAllBytes(Paths.get(RESOURCES_BASE_DIR, 'ros2generator/test_pkg/','CMakeLists.txt'))).trim,
+ fsa.textFiles.get(CustomOutputProvider::DEFAULT_OUTPUT + "test_pkg/CMakeLists.txt").toString.trim)
+ Assert.assertEquals(
+ new String(Files.readAllBytes(Paths.get(RESOURCES_BASE_DIR, 'ros2generator/test_pkg/','package.xml'))).trim,
+ fsa.textFiles.get(CustomOutputProvider::DEFAULT_OUTPUT + "test_pkg/package.xml").toString.trim)
}
@Test
diff --git a/plugins/de.fraunhofer.ipa.roscode.generator/src/de/fraunhofer/ipa/roscode/generator/Ros2CodeGenerator.xtend b/plugins/de.fraunhofer.ipa.roscode.generator/src/de/fraunhofer/ipa/roscode/generator/Ros2CodeGenerator.xtend
index 1e7f98458..42ae46692 100644
--- a/plugins/de.fraunhofer.ipa.roscode.generator/src/de/fraunhofer/ipa/roscode/generator/Ros2CodeGenerator.xtend
+++ b/plugins/de.fraunhofer.ipa.roscode.generator/src/de/fraunhofer/ipa/roscode/generator/Ros2CodeGenerator.xtend
@@ -1,16 +1,15 @@
package de.fraunhofer.ipa.roscode.generator
+import java.util.ArrayList
+import java.util.HashSet
+import java.util.List
+import java.util.Set
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.AbstractGenerator
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.generator.IGeneratorContext
-import org.eclipse.xtext.generator.IOutputConfigurationProvider
-import org.eclipse.xtext.generator.OutputConfiguration
-import java.util.Set
-import ros.*
-import java.util.List
-import java.util.ArrayList
-import java.util.HashSet
+import ros.Node
+import ros.Package
/**
* Generates code from your model files on save.
@@ -23,6 +22,7 @@ class Ros2CodeGenerator extends AbstractGenerator {
String import_msgs
int char_i
Node node
+ String pkg_name
List PkgsList
Set set
@@ -35,8 +35,9 @@ class Ros2CodeGenerator extends AbstractGenerator {
fsa.generateFile(pkg.getName().toLowerCase+"/CMakeLists.txt",pkg.compile_CMakeLists)
for (art : pkg.artifact){
node = art.node
- fsa.generateFile(pkg.getName().toLowerCase+"/src/"+node.name+".cpp",node.compile_node)
-
+ pkg_name = pkg.getName().toLowerCase
+ fsa.generateFile(pkg_name+"/src/"+node.name+"_component.cpp",node.compile_node(pkg_name))
+ fsa.generateFile(pkg_name+"/include/"+pkg_name+"/"+node.name+"_component.hpp",node.compile_node_header(pkg_name))
}
}
}
@@ -60,6 +61,7 @@ def compile_package_xml(Package pkg)'''
boost
rclcpp
+ rclcpp_components
«FOR depend_pkg:pkg.getPkgDependencies»
«depend_pkg»
«ENDFOR»
@@ -89,31 +91,45 @@ endif()
find_package(ament_cmake REQUIRED)
find_package(Boost REQUIRED)
find_package(rclcpp REQUIRED)
+find_package(rclcpp_components REQUIRED)
«FOR depend_pkg:pkg.getPkgDependencies»
find_package(«depend_pkg» REQUIRED)
«ENDFOR»
+include_directories(include)
+
+# create ament index resource which references the libraries in the binary dir
+set(node_plugins "")
+
«FOR art:pkg.artifact»
-add_executable(«art.name» src/«art.node.name».cpp)
-ament_target_dependencies(«art.name» «FOR depend_pkg:pkg.getPkgDependencies»«depend_pkg» «ENDFOR»)
+add_library(«art.node.name»_component SHARED
+ src/«art.node.name»_component.cpp)
+ament_target_dependencies(«art.node.name»_component
+ rclcpp
+ rclcpp_components
+ «FOR depend_pkg:pkg.getPkgDependencies»
+ «depend_pkg»
+«ENDFOR»)
+rclcpp_components_register_nodes(«art.node.name»_component "«pkg.name»::«art.node.name»")
+set(node_plugins "${node_plugins}«pkg.name»::«art.node.name»;$\n")
+ «ENDFOR»
install(TARGETS
- «art.name»
- DESTINATION lib/${PROJECT_NAME})
-«ENDFOR»
+ «FOR art:pkg.artifact»
+ «art.node.name»_component
+ «ENDFOR»
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin)
ament_package()
'''
-def compile_node(Node node) '''
-#include
-#include
-#include
-#include
-#include
+def compile_node_header(Node node, String pkg_name) '''
+#ifndef «pkg_name.toUpperCase»__«node.name.toUpperCase»_COMPONENT_HPP_
+#define «pkg_name.toUpperCase»__«node.name.toUpperCase»_COMPONENT_HPP_
#include "rclcpp/rclcpp.hpp"
-#include "rcutils/cmdline_parser.h"
«FOR pub : node.publisher»
#include <«pub.message.package.name»/msg/«check_message_include(pub.message.name)».hpp>
«ENDFOR»
@@ -127,74 +143,25 @@ def compile_node(Node node) '''
#include <«srvclient.service.package.name»/srv/«check_message_include(srvclient.service.name)».hpp>
«ENDFOR»
-using namespace std::chrono_literals;
-using std::placeholders::_1;
-using std::placeholders::_2;
-using std::placeholders::_3;
-
-void print_usage()
-{
- printf("Usage for «node.name» app:\n");
- printf("..... \n");
- printf("..... \n");
- printf("..... \n");
-}
+namespace «pkg_name» {
- class «node.name» : public rclcpp::Node {
+ class «node.name» : public rclcpp::Node {
public:
- «node.name»() : Node("«node.name»") {
- «FOR pub : node.publisher»
- «check_name(pub.name)»_ = this->create_publisher<«pub.message.package.name»::msg::«pub.message.name»>("«pub.name»",10);
- «ENDFOR»
- «FOR sub : node.subscriber»
- «check_name(sub.name)»_ = this->create_subscription<«sub.message.package.name»::msg::«sub.message.name»>("«sub.name»", 10, std::bind(&«node.name»::«check_name(sub.name)»_callback, this, _1));
- «ENDFOR»
- «FOR client : node.serviceclient»
- «check_name(client.name)»_ = this->create_client<«client.service.package.name»::srv::«client.service.name»>("«client.name»");
- «ENDFOR»
- «FOR service : node.serviceserver»
- «check_name(service.name)»_ = this->create_service<«service.service.package.name»::srv::«service.service.name»>("«service.name»", std::bind(&«node.name»::«check_name(service.name)»_handle, this, _1, _2, _3));
- «ENDFOR»
-
- «IF node.publisher.length > 0»
- timer_ = this->create_wall_timer(500ms, std::bind(&«node.name»::timer_callback, this));
- «ENDIF»
-
- «FOR client : node.serviceclient»
- // Service client
- while (!«check_name(client.name)»_->wait_for_service(std::chrono::seconds(10))){
- RCLCPP_ERROR(this->get_logger(), "Client interrupted while waiting for service '%s' to appear.", "«client.name»");
- }
- auto request = std::make_shared<«client.service.package.name»::srv::«client.service.name»::Request>();
- // request-> ... = ....;
- auto result_future = «check_name(client.name)»_->async_send_request(request);
- auto result = result_future.get();
- RCLCPP_INFO(this->get_logger(), "Service called, service: '%s'", "«client.name»");
- «ENDFOR»
- }
+ «node.name»(rclcpp::NodeOptions options);
private:
«FOR sub : node.subscriber»
// Subscriber callback
- void «check_name(sub.name)»_callback(const «sub.message.package.name»::msg::«sub.message.name»::SharedPtr msg) const {
- RCLCPP_INFO(this->get_logger(), "«sub.name» topic got a message");
- }
-
+ void «check_name(sub.name)»_callback(const «sub.message.package.name»::msg::«sub.message.name»::SharedPtr msg) const;
rclcpp::Subscription<«sub.message.package.name»::msg::«sub.message.name»>::SharedPtr «check_name(sub.name)»_ ;
+
«ENDFOR»
«FOR pub : node.publisher»
rclcpp::Publisher<«pub.message.package.name»::msg::«pub.message.name»>::SharedPtr «check_name(pub.name)»_;
«ENDFOR»
«IF node.publisher.length > 0»
// Timer Callback
- void timer_callback(){
- «FOR pub : node.publisher»
- auto «check_name(pub.name)»_msg = «pub.message.package.name»::msg::«pub.message.name»();
- //«check_name(pub.name)»_msg = ...
- «check_name(pub.name)»_->publish(«check_name(pub.name)»_msg);
- RCLCPP_INFO(this->get_logger(), "«pub.name» publisher active");
- «ENDFOR»
- }
+ void timer_callback();
rclcpp::TimerBase::SharedPtr timer_;
«ENDIF»
@@ -213,13 +180,101 @@ void print_usage()
«ENDFOR»
};
-int main(int argc, char * argv[])
+} // namespace «pkg_name»
+
+#endif // «pkg_name.toUpperCase»__«node.name.toUpperCase»_COMPONENT_HPP_
+'''
+
+def compile_node(Node node, String pkg_name) '''
+#include
+#include
+#include
+#include
+#include
+
+#include "«pkg_name»/«node.name»_component.hpp"
+
+using namespace std::chrono_literals;
+using std::placeholders::_1;
+using std::placeholders::_2;
+using std::placeholders::_3;
+
+void print_usage()
{
- rclcpp::init(argc, argv);
- rclcpp::spin(std::make_shared<«node.name»>());
- rclcpp::shutdown();
- return 0;
+ printf("Usage for «node.name» app:\n");
+ printf("..... \n");
+ printf("..... \n");
+ printf("..... \n");
}
+
+namespace «pkg_name» {
+
+«node.name»::«node.name»(rclcpp::NodeOptions options) : Node("«node.name»", options) {
+ «FOR pub : node.publisher»
+ «check_name(pub.name)»_ = this->create_publisher<«pub.message.package.name»::msg::«pub.message.name»>("«pub.name»",10);
+ «ENDFOR»
+ «FOR sub : node.subscriber»
+ «check_name(sub.name)»_ = this->create_subscription<«sub.message.package.name»::msg::«sub.message.name»>("«sub.name»", 10, std::bind(&«node.name»::«check_name(sub.name)»_callback, this, _1));
+ «ENDFOR»
+ «FOR client : node.serviceclient»
+ «check_name(client.name)»_ = this->create_client<«client.service.package.name»::srv::«client.service.name»>("«client.name»");
+ «ENDFOR»
+ «FOR service : node.serviceserver»
+ «check_name(service.name)»_ = this->create_service<«service.service.package.name»::srv::«service.service.name»>("«service.name»", std::bind(&«node.name»::«check_name(service.name)»_handle, this, _1, _2, _3));
+ «ENDFOR»
+
+ «IF node.publisher.length > 0»
+ timer_ = this->create_wall_timer(500ms, std::bind(&«node.name»::timer_callback, this));
+ «ENDIF»
+
+ «FOR client : node.serviceclient»
+ // Service client
+ while (!«check_name(client.name)»_->wait_for_service(std::chrono::seconds(10))){
+ RCLCPP_ERROR(this->get_logger(), "Client interrupted while waiting for service '%s' to appear.", "«client.name»");
+ }
+ auto request = std::make_shared<«client.service.package.name»::srv::«client.service.name»::Request>();
+ // request-> ... = ....;
+ auto result_future = «check_name(client.name)»_->async_send_request(request);
+ auto result = result_future.get();
+ RCLCPP_INFO(this->get_logger(), "Service called, service: '%s'", "«client.name»");
+«ENDFOR»
+}
+
+«FOR sub : node.subscriber»
+// Subscriber callback
+void «node.name»::«check_name(sub.name)»_callback(const «sub.message.package.name»::msg::«sub.message.name»::SharedPtr msg) const {
+ (void)msg; // supress warnings for unused variables
+ RCLCPP_INFO(this->get_logger(), "«sub.name» topic got a message");
+}
+
+«ENDFOR»
+«IF node.publisher.length > 0»
+// Timer Callback
+void «node.name»::timer_callback(){
+ «FOR pub : node.publisher»
+ auto «check_name(pub.name)»_msg = «pub.message.package.name»::msg::«pub.message.name»();
+ //«check_name(pub.name)»_msg = ...
+ «check_name(pub.name)»_->publish(«check_name(pub.name)»_msg);
+ RCLCPP_INFO(this->get_logger(), "«pub.name» publisher active");
+«ENDFOR»
+}
+«ENDIF»
+
+«FOR service : node.serviceserver»
+// Service Handler
+void «node.name»::«check_name(service.name)»_handle( const std::shared_ptr request_header,
+ const std::shared_ptr<«service.service.package.name»::srv::«service.service.name»::Request> request_,
+ const std::shared_ptr<«service.service.package.name»::srv::«service.service.name»::Response> response_){
+ (void)request_header;
+ RCLCPP_INFO( this->get_logger(), "trigger service '%s'","«service.name»");
+}
+«ENDFOR»
+
+} // namespace «pkg_name»
+
+#include "rclcpp_components/register_node_macro.hpp"
+
+RCLCPP_COMPONENTS_REGISTER_NODE(«pkg_name»::«node.name»)
'''
def List getPkgDependencies(Package pkg){