2 Copyright (C) 1997-2017 JDERobot Developers Team 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU Library General Public License for more details. 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 Authors : Okan Asik (asik.okan@gmail.com) 22 from xml.dom
import minidom
24 from visualstates.gui.transition.transitiontype
import TransitionType
25 from visualstates.configs.rospackage
import getPackagePath
26 from visualstates.generators.basegenerator
import BaseGenerator
30 def __init__(self, libraries, config, states, globalNamespace):
31 BaseGenerator.__init__(self, libraries, config, states, globalNamespace)
41 sourceCode =
''.join(stringList)
42 fp = open(projectPath + os.sep + projectName +
'.py',
'w')
45 os.system(
'chmod +x "' +projectPath+
'"' + os.sep + projectName +
'.py')
49 cmakeString =
''.join(stringList)
50 fp = open(projectPath + os.sep +
'CMakeLists.txt',
'w')
55 xmlStr = xmlDoc.toprettyxml(indent=
' ')
56 with open(projectPath + os.sep +
'package.xml',
'w')
as f:
62 mystr =
'''#!/usr/bin/python 63 # -*- coding: utf-8 -*- 64 import sys, threading, time, rospy, signal 66 importStr.append(mystr)
69 for topic
in self.config.getTopics():
70 typeStr = topic[
'type']
71 if typeStr
not in typeSet:
72 if typeStr.find(
'/') >= 0:
73 types = typeStr.split(
'/')
74 importStr.append(
'from ' + types[0] +
'.msg import ' + types[1] +
'\n')
76 importStr.append(
'import ' + typeStr +
'\n')
79 mystr =
'''from visualstates.codegen.python.state import State 80 from visualstates.codegen.python.temporaltransition import TemporalTransition 81 from visualstates.codegen.python.conditionaltransition import ConditionalTransition 82 from visualstates.codegen.python.runtimegui import RunTimeGui 83 from PyQt5.QtWidgets import QApplication 86 importStr.append(mystr)
87 for lib
in self.libraries:
88 importStr.append(
'import ')
90 importStr.append(
'\n')
91 importStr.append(
'\n')
96 rootState = self.getRootState()
97 signalStr.append(
'globalNamespace = None\n')
98 signalStr.append(
'state' + str(rootState.id) +
' = None\n')
99 signalStr.append(
'app = None\n\n')
100 signalStr.append(
'def stopRecursive(state):\n')
101 signalStr.append(
'\tstate.stop()\n')
102 signalStr.append(
'\tfor childState in state.states:\n')
103 signalStr.append(
'\t\tstopRecursive(childState)\n\n')
104 signalStr.append(
'def sigintHandler(signal, frame):\n')
105 signalStr.append(
'\tglobal globalNamespace\n')
106 signalStr.append(
'\tglobal state' + str(rootState.id) +
'\n')
107 signalStr.append(
'\tglobal app\n')
108 signalStr.append(
'\tif app is not None:')
109 signalStr.append(
'\t\tapp.quit()\n')
110 signalStr.append(
'\tstopRecursive(state' + str(rootState.id) +
')\n')
111 signalStr.append(
'\tglobalNamespace.stop()\n\n')
112 signalStr.append(
'signal.signal(signal.SIGINT, sigintHandler)\n\n')
115 for state
in self.getAllStates():
119 stateStr.append(
'class State')
120 stateStr.append(str(state.id))
121 stateStr.append(
'(State):\n')
123 stateStr.append(
'\tdef __init__(self, id, initial, globalNamespace, namespace, cycleDuration, parent=None, gui=None):\n')
124 stateStr.append(
'\t\tState.__init__(self, id, initial, cycleDuration, parent, gui)\n')
125 stateStr.append(
'\t\tself.globalNamespace = globalNamespace\n')
126 stateStr.append(
'\t\tself.namespace = namespace\n\n')
128 stateStr.append(
'\tdef runCode(self):\n')
129 if len(state.getCode()) > 0:
130 for codeLine
in state.getCode().split(
'\n'):
131 stateStr.append(
'\t\t' + codeLine +
'\n')
133 stateStr.append(
'\t\tpass\n')
134 stateStr.append(
'\n\n')
136 stateStr.append(
'class Namespace' + str(state.id) +
'():\n')
137 stateStr.append(
'\tdef __init__(self, globalNamespace):\n')
138 stateStr.append(
'\t\tself.globalNamespace = globalNamespace\n')
140 if(len(state.namespace.variables) > 0):
141 for varLine
in state.namespace.variables.split(
'\n'):
142 stateStr.append(
'\t\t' + varLine +
'\n')
143 stateStr.append(
'\n')
145 if(len(state.namespace.functions) > 0):
146 for funcLine
in state.namespace.functions.split(
'\n'):
147 stateStr.append(
'\t' + funcLine +
'\n')
148 stateStr.append(
'\n')
151 globalNamespaceStr.append(
'class GlobalNamespace():\n')
152 globalNamespaceStr.append(
'\tdef __init__(self):\n')
153 globalNamespaceStr.append(
'\t\trospy.init_node("' + projectName +
'", anonymous=True, disable_signals=True)\n\n')
154 for topic
in self.config.getTopics():
155 if topic[
'opType'] ==
'Publish':
156 typesStr = topic[
'type']
157 types = typesStr.split(
'/')
158 globalNamespaceStr.append(
'\t\tself.' + topic[
'methodname'] +
'Pub = rospy.Publisher("' +
159 topic[
'name'] +
'", ' + types[1] +
', queue_size=10)\n')
160 elif topic[
'opType'] ==
'Subscribe':
161 typesStr = topic[
'type']
162 types = typesStr.split(
'/')
163 globalNamespaceStr.append(
'\t\tself.' + topic[
'variablename'] +
'Sub = rospy.Subscriber("' +
164 topic[
'name'] +
'", ' + types[1] +
', self.' + topic[
'variablename'] +
'Callback)\n')
165 globalNamespaceStr.append(
'\t\tself.' + topic[
'variablename'] +
' = ' + types[1] +
'()\n')
168 variables = self.globalNamespace.getVariables()
169 if len(variables) > 0:
170 for varLine
in variables.split(
'\n'):
171 globalNamespaceStr.append(
'\t\t' + varLine +
'\n')
172 globalNamespaceStr.append(
'\n')
174 globalNamespaceStr.append(
'\t\ttime.sleep(1) # wait for initialization of the node, subscriber, and publisher\n\n')
176 globalNamespaceStr.append(
'\tdef stop(self):\n')
177 globalNamespaceStr.append(
'\t\trospy.signal_shutdown("exit ROS node")\n\n')
180 for topic
in self.config.getTopics():
181 if topic[
'opType'] ==
'Publish':
182 globalNamespaceStr.append(
'\tdef ' + topic[
'methodname'] +
'(self, _' + topic[
'methodname'] +
'):\n')
183 globalNamespaceStr.append(
'\t\tself.' + topic[
'methodname'] +
'Pub.publish(_' + topic[
'methodname'] +
')\n\n')
184 elif topic[
'opType'] ==
'Subscribe':
185 globalNamespaceStr.append(
'\tdef ' + topic[
'variablename'] +
'Callback(self, _' + topic[
'variablename'] +
'):\n')
186 globalNamespaceStr.append(
'\t\tself.' + topic[
'variablename'] +
' = _' + topic[
'variablename'] +
'\n')
187 globalNamespaceStr.append(
'\n\n')
190 functions = self.globalNamespace.getFunctions()
191 if len(functions) > 0:
192 for funcLine
in functions.split(
'\n'):
193 globalNamespaceStr.append(
'\t' + funcLine +
'\n')
194 globalNamespaceStr.append(
'\n\n')
198 for tran
in self.getAllTransitions():
199 if tran.getType() == TransitionType.CONDITIONAL:
200 tranStr.append(
'class Tran' + str(tran.id) +
'(ConditionalTransition):\n')
201 tranStr.append(
'\tdef __init__(self, id, destinationId, globalNamespace, namespace):\n')
202 tranStr.append(
'\t\tConditionalTransition.__init__(self, id, destinationId, globalNamespace, namespace)\n')
203 tranStr.append(
'\tdef checkCondition(self):\n')
204 for checkLine
in tran.getCondition().split(
'\n'):
205 tranStr.append(
'\t\t' + checkLine +
'\n')
207 elif tran.getType() == TransitionType.TEMPORAL:
208 tranStr.append(
'class Tran' + str(tran.id) +
'(TemporalTransition):\n\n')
209 tranStr.append(
'\tdef __init__(self, id, destinationId, elapsedTime, globalNamespace, namespace):\n')
210 tranStr.append(
'\t\tTemporalTransition.__init__(self, id, destinationId, elapsedTime, globalNamespace, namespace)\n')
211 tranStr.append(
'\tdef runCode(self):\n')
212 if len(tran.getCode()) > 0:
213 for codeLine
in tran.getCode().split(
'\n'):
214 tranStr.append(
'\t\t' + codeLine +
'\n')
217 tranStr.append(
'\t\tpass\n\n')
220 mystr =
'''displayGui = False 226 \tfor arg in sys.argv: 227 \t\tsplitedArg = arg.split('=') 228 \t\tif splitedArg[0] == '--displaygui': 229 \t\t\tif splitedArg[1] == 'True' or splitedArg[1] == 'true': 230 \t\t\t\tdisplayGui = True 231 \t\t\t\tprint('runtime gui enabled') 233 \t\t\t\tdisplayGui = False 234 \t\t\t\tprint('runtime gui disabled') 239 \tapp = QApplication(sys.argv) 245 mainStr.append(mystr)
247 mainStr.append(
'if __name__ == "__main__":\n\n')
248 mainStr.append(
'\tglobalNamespace = GlobalNamespace()\n\n')
250 mainStr.append(
'\treadArgs()\n')
251 mainStr.append(
'\tif displayGui:\n')
252 mainStr.append(
'\t\tguiThread = threading.Thread(target=runGui)\n')
253 mainStr.append(
'\t\tguiThread.start()\n\n')
255 mainStr.append(
'\n\tif displayGui:\n')
256 mainStr.append(
'\t\twhile(gui is None):\n')
257 mainStr.append(
'\t\t\ttime.sleep(0.1)\n\n')
259 for state
in self.getAllStates():
260 mainStr.append(
'\t\tgui.addState(' + str(state.id) +
', "' + state.name +
261 '", ' + str(state.initial) +
', ' + str(state.x) +
', ' + str(state.y))
262 if state.parent ==
None:
263 mainStr.append(
', None)\n')
265 mainStr.append(
', ' + str(state.parent.id) +
')\n')
269 for tran
in self.getAllTransitions():
270 mainStr.append(
'\t\tgui.addTransition(' + str(tran.id) +
', "' + tran.name +
'", ' +
271 str(tran.origin.id) +
', ' + str(tran.destination.id) +
272 ', ' + str(tran.x) +
', ' + str(tran.y) +
')\n')
275 mainStr.append(
'\tif displayGui:\n')
276 mainStr.append(
'\t\tgui.emitLoadFromRoot()\n')
277 mainStr.append(
'\t\tgui.emitActiveStateById(0)\n\n')
279 for state
in self.getAllStates():
280 mainStr.append(
'\tnamespace' + str(state.id) +
' = Namespace' + str(state.id) +
'(globalNamespace)\n')
281 mainStr.append(
'\tstate' + str(state.id) +
' = State' + str(state.id) +
282 '(' + str(state.id) +
', ' + str(state.initial) +
', globalNamespace, ')
283 if state.parent ==
None:
284 mainStr.append(
'None, ' + str(state.getTimeStep()) +
', None, gui)\n')
286 mainStr.append(
'namespace' + str(state.parent.id)+
', ' + str(state.getTimeStep()) +
', state' + str(state.parent.id) +
', gui)\n')
290 for tran
in self.getAllTransitions():
291 if tran.getType() == TransitionType.TEMPORAL:
292 mainStr.append(
'\ttran' + str(tran.id) +
' = Tran' + str(tran.id) +
293 '(' + str(tran.id) +
', ' + str(tran.destination.id) +
294 ', ' + str(tran.getTemporalTime()) +
', globalNamespace, namespace' 295 + str(tran.origin.parent.id) +
')\n')
296 elif tran.getType() == TransitionType.CONDITIONAL:
297 mainStr.append(
'\ttran' + str(tran.id) +
' = Tran' + str(tran.id) +
298 '(' + str(tran.id) +
', ' + str(tran.destination.id) +
', globalNamespace, namespace' + str(tran.origin.parent.id) +
')\n')
300 mainStr.append(
'\tstate' + str(tran.origin.id) +
'.addTransition(tran' + str(tran.id) +
')\n\n')
303 for state
in self.states:
304 mainStr.append(
'\tstate' + str(state.id) +
'.startThread()\n')
307 rootState = self.getRootState()
308 mainStr.append(
'\twhile state' + str(rootState.id) +
'.running:\n')
309 mainStr.append(
'\t\ttime.sleep(0.01)\n\n')
312 cmakeStr.append(
'project(')
313 cmakeStr.append(projectName)
314 cmakeStr.append(
')\n\n')
316 cmakeStr.append(
'cmake_minimum_required(VERSION 2.8.3)\n\n')
318 cmakeStr.append(
'find_package(catkin REQUIRED COMPONENTS visualstates\n')
319 for dep
in self.config.getBuildDependencies():
320 cmakeStr.append(
' ' + dep +
'\n')
321 cmakeStr.append(
')\n\n')
322 cmakeStr.append(
'catkin_package()\n')
323 cmakeStr.append(
'include_directories(${catkin_INCLUDE_DIRS})\n')
324 cmakeStr.append(
'install(PROGRAMS ' + projectName +
'.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})\n')
328 doc = minidom.Document()
329 root = doc.createElement(
'package')
330 nameElement = doc.createElement(
'name')
331 nameElement.appendChild(doc.createTextNode(projectName))
332 root.appendChild(nameElement)
333 versionElement = doc.createElement(
'version')
334 versionElement.appendChild(doc.createTextNode(
'0.0.0'))
335 root.appendChild(versionElement)
336 descElement = doc.createElement(
'description')
337 descElement.appendChild(doc.createTextNode(
'The ' + projectName +
' package'))
338 root.appendChild(descElement)
339 maintainerElement = doc.createElement(
'maintainer')
340 maintainerElement.setAttribute(
'email',
'todo@todo.todo')
341 maintainerElement.appendChild(doc.createTextNode(
'todo'))
342 root.appendChild(maintainerElement)
343 licenseElement = doc.createElement(
'license')
344 licenseElement.appendChild(doc.createTextNode(
'TODO (choose one: BSD, MIT, GPLv2, GPLv3 LGPLv3)'))
345 root.appendChild(licenseElement)
346 btoolDepElement = doc.createElement(
'buildtool_depend')
347 btoolDepElement.appendChild(doc.createTextNode(
'catkin'))
348 root.appendChild(btoolDepElement)
349 for bdep
in [
'visualstates']+config.getBuildDependencies():
350 bdepElement = doc.createElement(
'build_depend')
351 bdepElement.appendChild(doc.createTextNode(bdep))
352 root.appendChild(bdepElement)
354 for rdep
in [
'visualstates']+config.getRunDependencies():
355 rdepElement = doc.createElement(
'run_depend')
356 rdepElement.appendChild(doc.createTextNode(rdep))
357 root.appendChild(rdepElement)
360 rdepElement = doc.createElement(
'run_depend')
361 rdepElement.appendChild(doc.createTextNode(
'python-qt5-bindings'))
362 root.appendChild(rdepElement)
364 exportElement = doc.createElement(
'export')
365 root.appendChild(exportElement)
366 doc.appendChild(root)
371 if os.path.exists(projectPath +
'/codegen'):
372 shutil.rmtree(projectPath +
'/codegen')
373 if os.path.exists(projectPath +
'/gui'):
374 shutil.rmtree(projectPath +
'/gui')
375 if os.path.exists(projectPath +
'/core'):
376 shutil.rmtree(projectPath +
'/core')
378 shutil.copytree(
getPackagePath() +
'/lib/python2.7/codegen', projectPath +
'/codegen')
379 shutil.copytree(
getPackagePath() +
'/lib/python2.7/gui', projectPath +
'/gui')
380 shutil.copytree(
getPackagePath() +
'/lib/python2.7/core', projectPath +
'/core')
def generateStateClass(self, state, stateStr)
def __init__(self, libraries, config, states, globalNamespace)
def generatePackageXml(self, config, projectName)
def generateGlobalNamespace(self, globalNamespaceStr, projectName)
def copyRuntime(self, projectPath)
def generateTransitionClasses(self, tranStr)
def generateMain(self, mainStr)
def generate(self, projectPath, projectName)
def generateCmake(self, cmakeStr, projectName)
def generateSignalHandling(self, signalStr)
def generateImports(self, importStr)
def generateStateClasses(self, stateStr)