Интеграция SCXML в узел ROS с использованием PYSCXML
В последние недели я столкнулся с проблемой, которую я так и не смог найти:
Я выполняю узел ROS, который запускает объект StateMachine из pyscxml. При первом получении этим узлом сообщения от другого узла отправляется событие в StateMachine, и все работает нормально. Но кажется, что SM остается в заблокированном состоянии, и в следующий раз, когда локальный узел получает новое сообщение от другого узла, больше нет шансов "переместить" SM из предыдущего состояния. Кажется, что объект SM всегда один и тот же, но идентификатор потока узла ROS меняется при каждом вызове!!!????? Я пробовал разные варианты создания экземпляра SM (@staticmethod, собственный поток и т. Д.), Но не смог найти решение.
Если я использую клиента, который создает анонимный узел Ros и (например, каждые 3 секунды) отправляет сообщение на узел, где работает SM, это работает!! SM изменяется от состояния к другому в зависимости от события с любой проблемой.
Проблема возникает, когда соединение между двумя узлами закрыто на x секунд, и мы хотим отправить новые события на SM.
Это мой Ros Node и определение схемы SM. В любом случае, похоже, что у схемы scxml нет проблем.
Большое спасибо за Вашу помощь
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
Created on 07/12/2012
@author: frk
'''
import roslib; roslib.load_manifest('beginner_tutorials')
from beginner_tutorials.de.frank.dm.scxml.pyscxml import StateMachine
from beginner_tutorials.de.frank.utils.Logger import LogUtils
from beginner_tutorials.de.frank.utils.constants import RosChannel
from std_msgs.msg._String import String
import rospy
import time
LOG = LogUtils("WorkFlowManager", "stateMachine.log")
sm = None
event = None
receivedEvent = None
## NODE initialization
rospy.init_node(RosChannel.NODE_WORKFLOW)
## Publishers ##
pubMainmenu = rospy.Publisher(RosChannel.TOPIC_START_MENU, String)
pubMusicBox = rospy.Publisher(RosChannel.TOPIC_MUSICBOX, String)
STATE_WAIT = "WAIT"
STATE_RUN = "RUN"
STATE_MUSIC = "MUSIC"
STATE_NEWS = "NEWS"
STATE_FINAL = "FINAL"
STATE_MAIN_MENU = "MAIN_MENU"
def init_machine():
global sm
sm = StateMachine("workflowMain.xml")
sm.start_threaded()
return sm
def getStateMachine():
global sm
if None != sm:
return sm
else:
return init_machine()
def parseRosMsg(message):
event = str(message.data)
sendSafeEventToMachine(event)
LOG.debug("[" + getState() + "]" + " AFTER sending '" + event + "'")
def declareStateMachineStatus(value):
rospy.set_param(RosChannel.P_STATE_MACHINE_STATUS, value)
def getState():
return str(rospy.get_param(RosChannel.P_STATE_MACHINE_STATUS))
def sendSafeEventToMachine(event):
global receivedEvent
receivedEvent = False
index = 0
LOG.debug("[" + getState() + "] Sending to Main STATE MACHINE event: '" + event + "'")
while index < 2: # this is a workaround, it avoids the issue sending sometimes evens that are obviated by the sm
getStateMachine().send(event, 0)
time.sleep(0.5)
index = index + 0.5
def triggerStartMainMenuEvent():
LOG.debug("[" + getState() + "] Publishing 'startMenu'")
pubMainmenu.publish(str("startMenu"))
if __name__ == '__main__':
try:
LOG.debug("Started nodeWorkflow with STATE 'WAIT'")
rospy.set_param(RosChannel.P_STATE_MACHINE_STATUS, STATE_WAIT)
## Subscribers ##
rospy.Subscriber(RosChannel.TOPIC_WORKFLOW, String, parseRosMsg)
rospy.Subscriber(RosChannel.TOPIC_JULIUS, String, parseRosMsg)
rospy.spin()
except rospy.ROSInterruptException:
pass
И это документ SCXML
<script>
from beginner_tutorials.de.frank.dm.mainWorkflowManager import *
</script>
<state id="INITIAL">
<onentry>
<log label="-----[SCXML-Main-Menu]" expr="'in INITIAL'" />
</onentry>
<transition event="startMenu" target="WAIT" />
</state>
<state id="WAIT">
<onentry>
<log label="-----[SCXML-Main-Menu]" expr="'in WAIT'" />
<script>w
declareStateMachineStatus("WAIT")
</script>
</onentry>
<transition event="toMenu" target="MAIN_MENU" />
<transition event="toFinal" target="FINAL" />
</state>
<state id="MAIN_MENU">
<onentry>
<log label="-----[SCXML-Main-Menu]" expr="'in MAIN_MENU'" />
<script>
declareStateMachineStatus("MAIN_MENU")
triggerStartMainMenuEvent()
</script>
</onentry>
<transition event="toWait" target="WAIT" />
<transition event="toFinal" target="FINAL" />
</state>
<final id="FINAL">
<onentry>
<log label="-----[SCXML-Main-Menu]" expr="'in FINAL'" />
<script>
declareStateMachineStatus("FINAL")
</script>
</onentry>
</final>