Skip to content

Commit

Permalink
First implementation of the PlantUML generator
Browse files Browse the repository at this point in the history
  • Loading branch information
ipa-nhg committed Mar 7, 2024
1 parent b2cbe8d commit cf880ab
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Publications:

- Combine components to form a ROS System
- [Create manually a new RosSystem description](docu/RosSystemModelDescription.md)
- [Visualize a system using PlantUML](docu/PlantUML.md)

- Examples:
- [Simple publisher-subscriber](docu/Example_PubSub.md)
Expand Down
8 changes: 8 additions & 0 deletions docu/PlantUML.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## System Models visualization

The visualization of the models is built on top of the [PlantUML](https://plantuml.com/eclipse) viewer for Eclipse. To install this plugin the Eclipse Marketplace can be used. This tool can be easily opened under the menu Help->Eclipse Marketplace. Then Search the "PlantUML plugin" and install it.

The RosTooling will generate for every rossystem file a new PlaUML textual model compatible with the viewer. By default, the RosSystem compiler creates for every valid system model a file under src-gen/**SystemName**/resources/ called **SystemName**.puml.

The file can be opened with a standard textual editor and the corresponding model can be visualized by opening the visualizer, under "Window"->"Show View"->"Other" and searching for "PlantUML".
:bangbang the file with the extension *.puml must be open, otherwise, the visualizer will not detect it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package de.fraunhofer.ipa.rossystem.generator

import system.System
import com.google.inject.Inject
import system.RosNode
import system.impl.RosInterfaceImpl
import system.RosInterface
import system.impl.RosSystemConnectionImpl

class PlantUMLCompiler{

@Inject extension GeneratorHelpers

def compile_plantuml(System system) '''«init_pkg()»
@startuml

/'SUBSYSTEMS'/
«FOR subsystem:system.subsystems»
component «subsystem.name» {
«FOR component:getNodes(subsystem)»
component «(component as RosNode).name» {

/' PORTS DEFINED AS AVAILABLE IN THE ROSSYSTEM FILE '/
«FOR port:(component as RosNode).rosinterfaces»
«IF port_type(port)=="INPUT"» portin «get_valid_name(component.name, port.name)» as "«port.name»"«
IF (port as RosInterfaceImpl).reference.toString.contains("RosSubscriberReference")» #blue«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceServerReference")» #orange«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosActionServerReference")» #green«ENDIF»«ENDIF»
«IF port_type(port)=="OUTPUT"» portout «get_valid_name(component.name, port.name)» as "«port.name»"«
IF (port as RosInterfaceImpl).reference.toString.contains("RosPublisherReference")» #blue«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceClientReference")» #orange«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosActionClientReference")» #green«ENDIF»«ENDIF»
«ENDFOR»

/' PORTS FROM THE ORIGINAL NODE '/
«FOR sub:(component as RosNode).from.subscriber» portin «get_valid_name(component.name, sub.name)» as "«sub.name»" #line:blue
«ENDFOR»
«FOR ss:(component as RosNode).from.serviceserver» portin «get_valid_name(component.name, ss.name)» as "«ss.name»" #line:orange
«ENDFOR»
«FOR acts:(component as RosNode).from.actionserver» portin «get_valid_name(component.name, acts.name)» as "«acts.name»" #line:green
«ENDFOR»
«FOR pub:(component as RosNode).from.publisher» portout «get_valid_name(component.name, pub.name)» as "«pub.name»" #line:blue
«ENDFOR»
«FOR sc:(component as RosNode).from.serviceclient» portout «get_valid_name(component.name, sc.name)» as "«sc.name»" #line:orange
«ENDFOR»
«FOR actc:(component as RosNode).from.actionclient» portout «get_valid_name(component.name, actc.name)» as "«actc.name»" #line:green«ENDFOR»
}
«ENDFOR»
}

«ENDFOR»

«FOR component:getNodes(system)»
component «(component as RosNode).name» {

/' PORTS DEFINED AS AVAILABLE IN THE ROSSYSTEM FILE '/
«FOR port:(component as RosNode).rosinterfaces»
«IF port_type(port)=="INPUT"» portin «get_valid_name(component.name, port.name)» as "«port.name»"«
IF (port as RosInterfaceImpl).reference.toString.contains("RosSubscriberReference")» #blue«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceServerReference")» #orange«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosActionServerReference")» #green«ENDIF»«ENDIF»
«IF port_type(port)=="OUTPUT"» portout «get_valid_name(component.name, port.name)» as "«port.name»"«
IF (port as RosInterfaceImpl).reference.toString.contains("RosPublisherReference")» #blue«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosServiceClientReference")» #orange«ENDIF»«
IF (port as RosInterfaceImpl).reference.toString.contains("RosActionClientReference")» #green«ENDIF»«ENDIF»
«ENDFOR»

/' PORTS FROM THE ORIGINAL NODE '/
«FOR sub:(component as RosNode).from.subscriber» portin «get_valid_name(component.name, sub.name)» as "«sub.name»" #line:blue
«ENDFOR»
«FOR ss:(component as RosNode).from.serviceserver» portin «get_valid_name(component.name, ss.name)» as "«ss.name»" #line:orange
«ENDFOR»
«FOR acts:(component as RosNode).from.actionserver» portin «get_valid_name(component.name, acts.name)» as "«acts.name»" #line:green
«ENDFOR»
«FOR pub:(component as RosNode).from.publisher» portout «get_valid_name(component.name, pub.name)» as "«pub.name»" #line:blue
«ENDFOR»
«FOR sc:(component as RosNode).from.serviceclient» portout «get_valid_name(component.name, sc.name)» as "«sc.name»" #line:orange
«ENDFOR»
«FOR actc:(component as RosNode).from.actionclient» portout «get_valid_name(component.name, actc.name)» as "«actc.name»" #line:green«ENDFOR»
}
«ENDFOR»
«FOR connection:system.connections» «get_connection_port((connection as RosSystemConnectionImpl).from)» --> «get_connection_port((connection as RosSystemConnectionImpl).to)»
«ENDFOR»

@enduml'''
def String port_type (RosInterface rosinterface){
if ((rosinterface as RosInterfaceImpl).reference.toString.matches
(".*RosSubscriberReferenceImpl.*|.*RosServiceServerReference.*|.*RosActionServerReference.*")){
return "INPUT"
}else {
return "OUTPUT"
}
}
def get_valid_name (String componentName, String PortName){
val identifier = (componentName+"."+PortName).replace("/","_").replace("~","_")
return identifier
}
def get_connection_port (RosInterface port){
val componentName=(port.eContainer as RosNode).name
return get_valid_name (componentName, port.name)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ class RosSystemGenerator extends AbstractGenerator {
@Inject extension PackageXmlCompiler
@Inject extension CMakeListsCompiler
@Inject extension READMECompiler
@Inject extension PlantUMLCompiler

override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
for (system : resource.allContents.toIterable.filter(System)){
fsa.generateFile(
system.getName().toLowerCase+"/README.md",
compile_toREADME(system).toString().replace("\t"," ")
)
fsa.generateFile(
system.getName().toLowerCase+"/resource/" + system.getName().toLowerCase + ".puml",
compile_plantuml(system)
)
if (system.fromFile.isNullOrEmpty) {
fsa.generateFile(
system.getName().toLowerCase+"/launch/"+system.getName()+".launch.py",
Expand Down

0 comments on commit cf880ab

Please sign in to comment.