Skip to content

Commit a10dbd8

Browse files
committed
Implement ROS1-ROS2 bridges generator
1 parent f3d42dd commit a10dbd8

File tree

5 files changed

+273
-70
lines changed

5 files changed

+273
-70
lines changed

plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/GeneratorHelpers.xtend

Lines changed: 131 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ import ros.impl.ParameterStructMemberImpl
1616
import system.RosNode
1717
import system.SubSystem
1818
import system.System
19+
import system.RosInterface
20+
import system.RosSystemConnection
21+
import system.RosPublisherReference
22+
import system.RosServiceServerReference
23+
import system.RosActionServerReference
24+
import system.RosSubscriberReference
25+
import system.RosServiceClientReference
26+
import system.RosActionClientReference
27+
import org.eclipse.emf.ecore.EObject
28+
import java.util.Arrays
1929

2030
class GeneratorHelpers {
2131

@@ -29,23 +39,36 @@ class GeneratorHelpers {
2939
RosNode node
3040
String[] FromFileInfo
3141
Boolean os_import
32-
42+
43+
String ros1_bridge_name
44+
String ros1_bridge_type
45+
List<EObject> Ros1Ports
46+
3347

3448
def void init_pkg(){
3549
PackageSet=false
3650
}
3751

52+
def boolean generate_yaml(RosNode component){
53+
var yaml_gen=false
54+
for(param:component.rosparameters){
55+
if(param.eContents.get(0).eClass.name.contains("ParameterStruct")){
56+
yaml_gen=true
57+
}
58+
}
59+
if(component.rosparameters.length>5){
60+
yaml_gen=true
61+
}
62+
return yaml_gen
63+
}
64+
3865
def boolean YamlFileGenerated(System rossystem) {
3966
os_import=false
4067
for (component: getRos2Nodes(rossystem)){
41-
for(param:component.rosparameters){
42-
if(param.eContents.get(0).eClass.name.contains("ParameterStruct")){
43-
os_import=true
44-
}
45-
}
46-
if(component.rosparameters.length>5){
47-
os_import=true
48-
}
68+
os_import=generate_yaml(component)
69+
}
70+
if (TopicBridgeGenerated(rossystem) || ServiceFromBridgeGenerated(rossystem) || ServiceToBridgeGenerated(rossystem)){
71+
os_import=true
4972
}
5073
return os_import
5174
}
@@ -62,6 +85,19 @@ class GeneratorHelpers {
6285
}}
6386
return nodeList
6487
}
88+
89+
def <Components> getRos1Nodes (System rossystem) {
90+
val nodeList = new ArrayList<RosNode>
91+
if (!rossystem.components.nullOrEmpty){
92+
for (component: rossystem.components) {
93+
if (component.class.toString.contains("RosNode")){
94+
if((component as RosNode).from.eContainer.eContainer.class.toString.contains("Catkin")){
95+
nodeList.add(component as RosNode)
96+
}
97+
}
98+
}}
99+
return nodeList
100+
}
65101

66102
def <Systems> getSubsystems (System rossystem) {
67103
val subSystemsList = new ArrayList<System>
@@ -72,6 +108,92 @@ class GeneratorHelpers {
72108
}
73109
return subSystemsList
74110
}
111+
112+
def boolean TopicBridgeGenerated(System rossystem){
113+
for (connection: rossystem.connections){
114+
if (!getTopicBridgeInterfaces(connection as RosSystemConnection).get(0).empty){
115+
return true
116+
}
117+
}
118+
return false
119+
}
120+
121+
def boolean ServiceFromBridgeGenerated(System rossystem){
122+
for (connection: rossystem.connections){
123+
if (!getServiceFromBridgeInterfaces(connection as RosSystemConnection).get(0).empty){
124+
return true
125+
}
126+
}
127+
return false
128+
}
129+
130+
def boolean ServiceToBridgeGenerated(System rossystem){
131+
for (connection: rossystem.connections){
132+
if (!getServiceToBridgeInterfaces(connection as RosSystemConnection).get(0).empty){
133+
return true
134+
}
135+
}
136+
return false
137+
}
138+
139+
def List<String> getTopicBridgeInterfaces(RosSystemConnection connection){
140+
val from_connection=(connection as RosSystemConnection).from
141+
val to_connection=(connection as RosSystemConnection).to
142+
ros1_bridge_name=""
143+
ros1_bridge_type=""
144+
if (from_connection.reference.eClass.name=='RosPublisherReference'){
145+
var bridge_interface = (from_connection.reference as RosPublisherReference).from
146+
if (bridge_interface.eContainer.eContainer.eContainer.eClass.toString.contains("CatkinPackage")){
147+
ros1_bridge_name=bridge_interface.name
148+
ros1_bridge_type=bridge_interface.message.fullname.replace("/","/msg/")
149+
}
150+
}
151+
if (to_connection.reference.eClass.name=='RosSubscriberReference'){
152+
val bridge_interface = (to_connection.reference as RosSubscriberReference).from
153+
if (bridge_interface.eContainer.eContainer.eContainer.eClass.toString.contains("CatkinPackage")){
154+
ros1_bridge_name=bridge_interface.name
155+
ros1_bridge_type=bridge_interface.message.fullname.replace("/","/msg/")
156+
}
157+
}
158+
return Arrays.asList(ros1_bridge_name, ros1_bridge_type);
159+
}
160+
161+
def List<String> getServiceFromBridgeInterfaces(RosSystemConnection connection){
162+
val from_connection=(connection as RosSystemConnection).from
163+
ros1_bridge_name=""
164+
ros1_bridge_type=""
165+
if (from_connection.reference.eClass.name=='RosServiceServerReference'){
166+
val bridge_interface = (from_connection.reference as RosServiceServerReference).from
167+
if (bridge_interface.eContainer.eContainer.eContainer.eClass.toString.contains("CatkinPackage")){
168+
ros1_bridge_name=bridge_interface.name
169+
ros1_bridge_type=bridge_interface.service.fullname
170+
}
171+
}
172+
return Arrays.asList(ros1_bridge_name, ros1_bridge_type);
173+
}
174+
175+
def List<String> getServiceToBridgeInterfaces(RosSystemConnection connection){
176+
val to_connection=(connection as RosSystemConnection).to
177+
ros1_bridge_name=""
178+
ros1_bridge_type=""
179+
if (to_connection.reference.eClass.name=='RosServiceClientReference'){
180+
val bridge_interface = (to_connection.reference as RosServiceClientReference).from
181+
if (bridge_interface.eContainer.eContainer.eContainer.eClass.toString.contains("CatkinPackage")){
182+
ros1_bridge_name=bridge_interface.name
183+
ros1_bridge_type=bridge_interface.service.fullname
184+
}
185+
}
186+
return Arrays.asList(ros1_bridge_name, ros1_bridge_type);
187+
}
188+
189+
190+
def boolean fromRos1Node(EObject bridge_interface){
191+
if (bridge_interface.eContainer.eContainer.eContainer.eClass.toString.contains("CatkinPackage")){
192+
Ros1Ports.add(bridge_interface)
193+
return true
194+
}
195+
return false
196+
}
75197

76198
def ArrayList<String> getAllRepos(System system) {
77199
RepoList = new ArrayList<String>()

plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/LaunchFileCompiler_ROS2.xtend

Lines changed: 106 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -39,71 +39,118 @@ from launch.launch_description_sources import PythonLaunchDescriptionSource
3939
from launch.substitutions import LaunchConfiguration, PythonExpression, PathJoinSubstitution, TextSubstitution
4040

4141
def generate_launch_description():
42-
ld = LaunchDescription()
42+
ld = LaunchDescription()
43+
44+
# *** PARAMETERS ***
45+
«FOR component:getRos2Nodes(system)»«IF generate_yaml(component
46+
«component.name»_config = os.path.join(
47+
get_package_share_directory('«system.getName().toLowerCase»'),
48+
'config',
49+
'«component.name».yaml'
50+
)
51+
«ELSE»
52+
«FOR parameter:component.rosparameters»
53+
«parameter.name»_arg = DeclareLaunchArgument(
54+
parameter.name»", default_value=TextSubstitution(text="«get_param_value(parameter.value,parameter.name)»")
55+
)
56+
ld.add_actionparameter.name»_arg)
57+
«ENDFOR»
58+
«ENDIF»
59+
«ENDFOR»
4360

44-
«FOR component:getRos2Nodes(system)»«IF generate_yaml(component
45-
«component.name»_config = os.path.join(
46-
get_package_share_directory('«system.getName().toLowerCase»'),
47-
'config',
48-
'«component.name».yaml'
49-
)
50-
«ELSE»
51-
«FOR parameter:component.rosparameters»
52-
«parameter.name»_arg = DeclareLaunchArgument(
53-
parameter.name»", default_value=TextSubstitution(text="«get_param_value(parameter.value,parameter.name)»")
54-
)
55-
ld.add_actionparameter.name»_arg)
56-
«ENDFOR»
57-
«ENDIF»
58-
«ENDFOR»
61+
# *** ROS 2 nodes ***
62+
«FOR component:getRos2Nodes(system
63+
«(component as RosNode).name» = Node(
64+
package="«((component as RosNode).from.eContainer.eContainer as AmentPackageImpl).name»",«IF !component.namespace.nullOrEmpty»
65+
namespace="«component.namespace»",«ENDIF»
66+
executable="«((component as RosNode).from.eContainer as Artifact).name»",
67+
prefix = 'xterm -e',
68+
output='screen',
69+
name="«(component as RosNode).name»"«compile_remappings_str(component as RosNode, system.connections)»«IF !component.rosparameters.nullOrEmpty»«IF generate_yaml(component)»,
70+
parameters = [«component.name»_config]«ELSE»,
71+
parameters=[{«FOR param:component.rosparameters»
72+
"«param.from.name»": LaunchConfiguration("«param.name»"),«ENDFOR»}]«ENDIF»«ENDIF»
73+
)
74+
«ENDFOR»
5975

60-
«FOR component:getRos2Nodes(system
61-
«(component as RosNode).name» = Node(
62-
package="«((component as RosNode).from.eContainer.eContainer as AmentPackageImpl).name»",«IF !component.namespace.nullOrEmpty»
63-
namespace="«component.namespace»",«ENDIF»
64-
executable="«((component as RosNode).from.eContainer as Artifact).name»",
65-
prefix = 'xterm -e',
66-
output='screen',
67-
name="«(component as RosNode).name»"«compile_remappings_str(component as RosNode, system.connections)»«IF !component.rosparameters.nullOrEmpty»,
68-
«IF generate_yaml(component)» parameters = [«component.name»_config]
69-
«ELSE» parameters=[{«FOR param:component.rosparameters»
70-
"«param.from.name»": LaunchConfiguration("«param.name»"),«ENDFOR»}]«ENDIF»«ENDIF»
71-
)
72-
«ENDFOR»
73-
«FOR subsystem:getSubsystems(system)»
74-
«IF subsystem.fromFile.nullOrEmpty»
75-
include_«subsystem.name»= IncludeLaunchDescription(
76-
PythonLaunchDescriptionSource([ get_package_share_directory('«subsystem.name»') + '/launch/«subsystem.name».launch.py'])
77-
)
78-
«ELSE»
79-
include_«subsystem.name»= IncludeLaunchDescription(
80-
PythonLaunchDescriptionSource([get_package_share_directory('«subsystem.fromFile.split("/",2).get(0)»') + '/«subsystem.fromFile.split("/",2).get(1)»'])
81-
)
82-
«ENDIF»
83-
«ENDFOR»
76+
# *** ROS 2 subsystems (include launch files)***
77+
«FOR subsystem:getSubsystems(system)»
78+
«IF subsystem.fromFile.nullOrEmpty»
79+
include_«subsystem.name»= IncludeLaunchDescription(
80+
PythonLaunchDescriptionSource([ get_package_share_directory('«subsystem.name»') + '/launch/«subsystem.name».launch.py'])
81+
)
82+
«ELSE»
83+
include_«subsystem.name»= IncludeLaunchDescription(
84+
PythonLaunchDescriptionSource([get_package_share_directory('«subsystem.fromFile.split("/",2).get(0)»') + '/«subsystem.fromFile.split("/",2).get(1)»'])
85+
)
86+
«ENDIF»
87+
88+
# *** ROS 1 to ROS 2 bridges ***
89+
«ENDFOR»«IF TopicBridgeGenerated(system) || ServiceFromBridgeGenerated(system)|| ServiceToBridgeGenerated(system) »
90+
«system.name»_ros1_bridge_config = os.path.join(
91+
get_package_share_directory('«system.getName().toLowerCase»'),
92+
'config',
93+
'ros1_bridges.yaml'
94+
ENDIF»«IF TopicBridgeGenerated(system)»
95+
ros1_topic_bridge_parameter_bridge = Node(
96+
package='ros1_bridge',
97+
executable='parameter_bridge',
98+
name='ros1_topic_bridge_parameter_bridge',
99+
namespace='bridge_«system.name»_topic',
100+
output='screen',
101+
parameters=[
102+
{'__ns': 'bridge_«system.name»_topic'},
103+
{'__name': 'bridge_«system.name»_topic'}
104+
],
105+
arguments=[
106+
'--ros-args', '-r', '__name:=bridge_«system.name»_topic'
107+
]
108+
ENDIF»«IF ServiceFromBridgeGenerated(system)»
109+
ros1_service_from_bridge_parameter_bridge = Node(
110+
package='ros1_bridge',
111+
executable='parameter_bridge',
112+
name='ros1_service_from_bridge_parameter_bridge',
113+
namespace='bridge_«system.name»_from_services',
114+
output='screen',
115+
parameters=[
116+
{'__ns': 'bridge_«system.name»_from_services'},
117+
{'__name': 'bridge_«system.name»_from_services'}
118+
],
119+
arguments=[
120+
'--ros-args', '-r', '__name:=bridge_«system.name»_from_services'
121+
]
122+
ENDIF»«IF ServiceToBridgeGenerated(system)»
123+
ros1_service_to_bridge_parameter_bridge = Node(
124+
package='ros1_bridge',
125+
executable='parameter_bridge',
126+
name='ros1_service_to_bridge_parameter_bridge',
127+
namespace='bridge_«system.name»_to_services',
128+
output='screen',
129+
parameters=[
130+
{'__ns': 'bridge_«system.name»_to_services'},
131+
{'__name': 'bridge_«system.name»_to_services'}
132+
],
133+
arguments=[
134+
'--ros-args', '-r', '__name:=bridge_«system.name»_to_services'
135+
]
136+
ENDIF»
84137

85-
«FOR component:getRos2Nodes(system)»
86-
ld.add_action(«(component as RosNode).name»)
87-
«ENDFOR»«FOR subsystem:getSubsystems(system)»
88-
ld.add_action(include_«subsystem.name»)
89-
«ENDFOR»
138+
# *** Add actions ***
139+
«FOR component:getRos2Nodes(system)»
140+
ld.add_action(«(component as RosNode).name»)
141+
«ENDFOR»«FOR subsystem:getSubsystems(system)»
142+
ld.add_action(include_«subsystem.name»)
143+
«ENDFOR»«IF TopicBridgeGenerated(system)»
144+
ld.add_action(ros1_topic_bridge_parameter_bridge)
145+
«ENDIF»«IF ServiceFromBridgeGenerated(system)»
146+
ld.add_action(ros1_service_from_bridge_parameter_bridge)
147+
«ENDIF»«IF ServiceToBridgeGenerated(system)»
148+
ld.add_action(ros1_service_to_bridge_parameter_bridge)
149+
«ENDIF»
90150

91-
return ld
151+
return ld
92152
'''
93153
94-
def Boolean generate_yaml(RosNode component){
95-
var yaml_gen=false
96-
for(param:component.rosparameters){
97-
if(param.eContents.get(0).eClass.name.contains("ParameterStruct")){
98-
yaml_gen=true
99-
}
100-
}
101-
if(component.rosparameters.length>5){
102-
yaml_gen=true
103-
}
104-
return yaml_gen
105-
}
106-
107154
// def void compile_list_of_ROS2components(RosSystem system, ComponentStack stack) {
108155
// components_tmp_.clear;
109156
// Ros2components.clear;

plugins/de.fraunhofer.ipa.rossystem.xtext/src/de/fraunhofer/ipa/rossystem/generator/PackageXmlCompiler.xtend

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ class PackageXmlCompiler{
4949
<exec_depend>launch</exec_depend>
5050
«FOR pkg:system.getPkgsDependencies»
5151
<exec_depend>«pkg»</exec_depend>
52-
«ENDFOR»
53-
52+
«ENDFOR»«IF TopicBridgeGenerated(system) || ServiceFromBridgeGenerated(system) || ServiceToBridgeGenerated(system)»<exec_depend>ros1_bridge</exec_depend>«ENDIF»
5453
<!--test_depend>ament_copyright</test_depend>
5554
<test_depend>ament_flake8</test_depend>
5655
<test_depend>ament_pep257</test_depend>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package de.fraunhofer.ipa.rossystem.generator
2+
3+
import com.google.inject.Inject
4+
import system.System
5+
import system.RosSystemConnection
6+
7+
class Ros1BridgesYamlFileCompiler {
8+
9+
@Inject extension GeneratorHelpers
10+
11+
def compile_ROS1bridges_config(System system)'''«IF TopicBridgeGenerated(system
12+
bridge_«system.name»_topics/topics:«FOR connection:system.connections»«IF !getTopicBridgeInterfaces(connection as RosSystemConnection).get(0).empty»
13+
- topic: «getTopicBridgeInterfaces(connection as RosSystemConnection).get(0
14+
type: «getTopicBridgeInterfaces(connection as RosSystemConnection).get(1
15+
«ENDIF»«ENDFOR»«ENDIF»«IF ServiceFromBridgeGenerated(system
16+
bridge_«system.name»_from_services/services_2_to_1:«FOR connection:system.connections»«IF !getServiceFromBridgeInterfaces(connection as RosSystemConnection).get(0).empty»
17+
- service: «getServiceFromBridgeInterfaces(connection as RosSystemConnection).get(0
18+
type: «getServiceFromBridgeInterfaces(connection as RosSystemConnection).get(1
19+
«ENDIF»«ENDFOR»«ENDIF»«IF ServiceToBridgeGenerated(system
20+
bridge_«system.name»_to_services/services_2_to_1:«FOR connection:system.connections»«IF !getServiceToBridgeInterfaces(connection as RosSystemConnection).get(0).empty»
21+
- service: «getServiceToBridgeInterfaces(connection as RosSystemConnection).get(0
22+
type: «getServiceToBridgeInterfaces(connection as RosSystemConnection).get(1
23+
«ENDIF»«ENDFOR»«ENDIF»
24+
'''
25+
26+
}

0 commit comments

Comments
 (0)