ros / executive_smach Goto Github PK
View Code? Open in Web Editor NEWA procedural python-based task execution framework with ROS integration.
License: Other
A procedural python-based task execution framework with ROS integration.
License: Other
Robot Operating System (ROS) =============================================================================== ROS is a meta-operating system for your robot. It provides language-independent and network-transparent communication for a distributed robot control system. Installation Notes ------------------ For full installation instructions, including system prerequisites and platform-specific help, see: http://wiki.ros.org/ROS/Installation
It's that time of year again.
Some bugfixes are merged so making a release.
Btw I personally haven't used this pkg for awhile, so I refrain from reviewing/merging new feature PRs. Reviewing those PRs is appreciated.
During the migration of my code from fuerte to hydro I observed this behaviour.
Sending a Cancel with
client = actionlib.SimpleActionClient('bring_object', hobbit_msgs.msg.BringObjectAction)
client.wait_for_server()
client.cancel_all_goals()
results in the following error.
[ERROR] [WallTime: 1389093775.666919] Exception in your execute callback: 0
Traceback (most recent call last):
File "/opt/ros/hydro/lib/python2.7/dist-packages/actionlib/simple_action_server.py", line 299, in executeLoop
self.execute_callback(goal)
File "/opt/ros/hydro/lib/python2.7/dist-packages/smach_ros/action_server_wrapper.py", line 237, in execute_cb
setattr(result,from_key,self.userdata[to_key])
File "/opt/ros/hydro/lib/python2.7/dist-packages/smach/user_data.py", line 43, in __getitem__
return self.__getattr__(key)
File "/opt/ros/hydro/lib/python2.7/dist-packages/smach/user_data.py", line 56, in __getattr__
if name[0] == '_':
KeyError: 0
while on fuerte the State machine will simply be preempted.
As far as i can verify it the problem was introduced for #6 by fdf99b1 in file smach_ros/src/smach_ros/action_server_wrapper.py on line 235.
I am using SMACH in that the top-level container is a Concurrency Container. If I want to Ctrl+C the process, it never responds. I believe this is due to the fact that the Concurrency Container is all running in child threads and not in the Main thread.
I run into a 'TypeError: can't pickle _thread.lock objects' - error when trying to execute my state machine.
The state-machine consists of a state that executes a command via subprocess.popen and stores the process in a userdata-variable followed by a concurrent container with random content.
When running the code, it throws the following error:
[INFO] [1601065188.496524]: State machine starting in initial state 'ST1' with userdata:
['process']
[INFO] [1601065188.501100]: State machine transitioning 'ST1':'succeeded'-->'CON_SUB'
[ERROR] [1601065188.503611]: Could not execute transition callback: Traceback (most recent call last):
File "/home/faps/catkin_ws/src/executive_smach/smach/src/smach/container.py", line 175, in call_transition_cbs
cb(self.userdata, self.get_active_states(), *args)
File "/home/faps/catkin_ws/src/executive_smach/smach_ros/src/smach_ros/introspection.py", line 239, in _transition_cb
self._publish_status(info_str)
File "/home/faps/catkin_ws/src/executive_smach/smach_ros/src/smach_ros/introspection.py", line 226, in _publish_status
base64.b64encode(pickle.dumps(self._container.userdata._data, 2)).decode('utf-8'),
TypeError: can't pickle _thread.lock objects
[INFO] [1601065188.504891]: Concurrence starting with userdata:
[]
[INFO] [1601065188.506516]: Concurrent state 'ST2' returned outcome 'succeeded' on termination.
[INFO] [1601065188.508192]: Concurrent Outcomes: {'ST2': 'succeeded'}
[INFO] [1601065188.509342]: State machine terminating 'CON_SUB':'succeeded':'succeeded'
exit-outcome:succeeded
I've tried out a few things and made the following observations:
For you to reproduce, the corresponding code looks as follows:
#!/usr/bin/env python3
import smach
import smach_ros
import subprocess
import rospy
import os
# gets called when ANY child state terminates
def con_term_cb(outcome_map):
# terminate all running states if SM_1 finished with outcome 'goal_reached'
if outcome_map['ST2'] == 'succeeded':
return True
# terminate all running states if SM_1 finished with outcome 'preempted'
if outcome_map['ST2'] == 'preempted':
return True
# in all other case, just keep running, don't terminate anything
return False
# gets called when ALL child states are terminated
def con_out_cb(outcome_map):
if outcome_map['ST2'] == 'succeeded':
return 'succeeded'
elif outcome_map['ST2'] == 'preempted':
return 'preempted'
class st1(smach.State):
def __init__(self, outcomes=['succeeded', 'preempted']):
smach.State.__init__(self, outcomes, input_keys=['in_proc'], output_keys=['out_proc'])
def execute(self, userdata):
if self.preempt_requested():
self.service_preempt()
return 'preempted'
process = subprocess.Popen('rosbag play -l /home/faps/bags/2020-05-07-11-10-22.bag', stdout=subprocess.PIPE,
shell=True, preexec_fn=os.setsid)
userdata.out_proc = process
return 'succeeded'
class st2(smach.State):
def __init__(self, outcomes=['succeeded', 'preempted']):
smach.State.__init__(self, outcomes)
def execute(self, userdata):
# time.sleep(2)
if self.preempt_requested():
self.service_preempt()
return 'preempted'
return 'succeeded'
if __name__ == "__main__":
rospy.init_node('test_state_machine')
sm_1 = smach.StateMachine(outcomes=['succeeded', 'preempted'])
sm_1.userdata.process = None
with sm_1:
con_sub1 = smach.Concurrence(outcomes=['succeeded', 'preempted'],
default_outcome='preempted',
child_termination_cb=con_term_cb,
outcome_cb=con_out_cb
)
with con_sub1:
smach.Concurrence.add('ST2', st2())
smach.StateMachine.add('ST1', st1(),
transitions={'succeeded': 'CON_SUB', 'preempted': 'CON_SUB'},
remapping={'out_proc': 'process'})
smach.StateMachine.add('CON_SUB', con_sub1, transitions={'succeeded': 'succeeded', 'preempted': 'preempted'})
# Execute SMACH plan
# Create and start the introspection server
sis = smach_ros.IntrospectionServer('introspection_server', sm_1, '/SM_ROOT')
sis.start()
outcome = sm_1.execute()
print('exit-outcome:' + outcome)
# Wait for ctrl-c to stop the application
rospy.spin()
sis.stop()
Howdy @jbohren and executive_smach
maintainers!
As you may know the next ROS release Lunar Loggerhead is around the corner 🎉
Is it possible to release executive_smach
in ROS Lunar? Being part of desktop_full
this will be a requirement for Lunar to be released. If you don't have time to make a new release, please consider releasing the current Kinetic version into Lunar asap.
Thanks!
Currently, the SMACH introspection server creates one publisher per SMACH container. For large SMACH machines, this is not very efficient. Instead, all of the status and structure messages should be aggregated and then broadcast at once from a given introspection server.
When using the add_auto
function, the resulting transitions are not as expected from the documentation. I am not sure if it is a bug or I am misreading the text (if so, many of my colleagues have done the exact mistake)
Using this method, I add connector_outcomes
for all the outcomes of the state. I then use transitions
with the intent of overwriting some of the outcomes defined by connector_outcomes
, following the documentation:
@param transitions: A dictionary mapping state outcomes to other state
labels. If one of these transitions follows the connector outcome
specified in the constructor, **the provided transition will override
the automatically generated connector transition**.
However, when running this, the transition specified do not actually overwrite connector_outcomes
and instead are ignored.
Example (modified from the tutorial)
class Foo(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded','failed'])
self.counter = 0
def execute(self, userdata):
rospy.loginfo('Executing state FOO')
if self.counter < 3:
self.counter += 1
return 'succeeded'
else:
return 'failed'
# define state Bar
class Bar(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded'])
def execute(self, userdata):
rospy.loginfo('Executing state BAR')
return 'succeeded'
# main
def main():
rospy.init_node('smach_example_state_machine')
# Create a SMACH state machine
sm = smach.StateMachine(outcomes=['succeeded', 'failed'])
# Open the container
with sm:
# Add states to the container
smach.StateMachine.add_auto('FOO', Foo(),
connector_outcomes=['succeeded', 'failed'],
transitions={'failed': 'failed'})
smach.StateMachine.add('BAR', Bar(),
transitions={'succeeded':'succeeded'})
# Execute SMACH plan
outcome = sm.execute()
if __name__ == '__main__':
main()
My expectation in this case is the Foo
will have transition from succeeded
to BAR
and from failed
to failed
. However, visualizing this SM, I get:
I am using SimpleActionState to call an action server which does not behave as SimpleActionState expects. The server sets the goal status to succeeded (it does have some results to share, so one could argue this to be valid) when preempted.
The problem is that SimpleActionState only run self.service_preempt()
if the state is preempted AND the GoalStatus equals PREEMPTED (at this line). The next time this state is entered, then its just preempts early due to the preempt flag being set (at this line).
The fix is to make sure that self.service_preempt() is called when preempt is requested, regardless of the goal status.
One could also consider changing the outcome of the state is such a situation. Today it results in 'aborted' . I would argue that it should either be 'preempted' since the state is actually preempted, or 'succeeded' since the goal succeeded.
I am happy to provide a PR if we can decide on the behavior.
2to3
Would you mind releasing executive_smach
to ROS Noetic? It looks like all of its dependencies have been released, and recursively 17 repos need it.
I'm not sure how much work it will need. The Noetic Migration Guide or the guide about transitioning ROS packages to Python 3 may be useful.
Hi! First if all, your State Machine is Awesome!
I'm using it to control my robot and here is my architecture so far,
As you can see, after Initializing System, it will change to Task_Monitor State that will read user input from rosservice to determine the next task. My question is, is it a good idea to listen input from user using service/msg? Can I use smach for my robot task controller based on user input and it will run until we terminate the system or is it for single task only (opendoor_fsm, go_somewhere_fsm) and I have to call it from other node? Thankyou!
Hi,
I'm not sure if this is actively maintained or not, but worth to ask.
I think there's an issue with the checks of input keys in statemachines. Example:
I define a StateMachine with defined input keys, and then set the input keys manually on the userdata such as:
sm = smach.StateMachine(outcomes=['aborted','succeded'], input_keys=['a'])
sm.userdata.a = 1
This will trigger an error Userdata key 'a' not available. Available keys are: []
. And this is not fully true, as the keys are there. This seems to come from
executive_smach/smach/src/smach/container.py
Line 104 in 31cc557
There may be the need to still check the input_keys are available or pre-written (or maybe not, as I guess the error would trigger when the keys are used later on by one of the States). This could be done inside check_consistency
.
Happy to make a PR if this makes sense, but would be good to know if there's anyone there to check it and merge it!
See discussion here: http://answers.ros.org/question/11069/smach-introspection-server-fails-in-electric/
I was trying to pickle a State machine in order to save it on a file to be executed later and I saw that it cannot be pickled due to the _state_transitioning_lock
variable. This could be fixed by adding the following to the state_machine class:
def __getstate__(self):
return {k:v for (k, v) in self.__dict__.items() if k is not "_state_transitioning_lock"}
def __setstate__(self, d):
self.__dict__ = d
self._state_transitioning_lock = threading.Lock()
When the request_preempt() of the MonitorState is called just before the execute() clears the trigger_event, then the set of the trigger_event will be lost. In this case the execute() has no way to react on the preempt request any more and will block.
If the goal gets lost (the action client dies abruptly) then self._result_goal
will be None
making it crash when trying to read properties from it (on this line:
I will submit an PR to try to fix issue.
The current workaround I am using is to set the _result_goal
myself in my response_cb
.
My wrapped SMs usually contain other more complex SMs in order to avoid code duplication. I noticed that the feedback publishing does not work nicely with nested SMs. I.e. for each nested SM its feedback gets only published on time, when that SM finishes. I guess that is due to the feedback being published during the transition callback of the wrapped SM.
I just ran into the problem described (and solved) in the question below:
http://answers.ros.org/question/28100/smach_rosmonitorstate-callback-receives-empty-userdata/
Would it be possible to update monitor_state.py so that userdata is accessible? Or if the original poster and myself are just missing something, please explain.
Thanks!
Is it possible to get a jade release soonish? It's on the desktop-full
list:
http://wiki.ros.org/jade/Planning/Maintenance
Thanks.
I'm reading the documents of the generic State class and trying to use it with ROS system. I'm just curious when does the execute
function of the State class get called?
class Foo(smach.State):
def __init__(self, outcomes=['outcome1', 'outcome2']):
# Your state initialization goes here
# When does this function get called? <---------------
def execute(self, userdata):
# Your state execution goes here
if xxxx:
return 'outcome1'
else:
return 'outcome2'
On initialization the SimpleActionState will spin up a thread to wait for the action server to become active. This is the only time the state is waiting and checking for the action server to become available. If this initial check succeeds and the action node dies at a later time, then when the SimpleActionState is executed it will no longer check if the server is active, just send the goal and hang there forever.
executive_smach/smach/src/smach/container.py
Line 122 in 1a44c12
https://github.com/google/styleguide/blob/gh-pages/pyguide.md#2123-cons
This particular case here might not cause any issue, but still, it is a terrible programming style and a common issue for Python beginners.
Hi!
I just came across the following issue. In my state machine I have a bunch of SimpleActionStates that control the behaviour of the robot.
When one of the states is preempted the robot needs to perform a correcting action, that ideally could also be preempted by the user. For simplicity here is the state transition:
A ---preempt---->B---preempt----->C
|
|---success---->D
where:
A - SimpleActionState
B - SimpleActionState
C - State
D - State
In my tests I've found out that when I execute the preempt in the state machine, I can only execute it once. Once we are in B, we cannot execute the preempt anymore (I can confirm that the action servers */cancel
topics receive the cancel signal only once for the first preempt).
Debugging the code I believe the issue comes from the _preempt_current_state function:
def _preempt_current_state(self):
"""Preempt the current state (might not be executing yet).
This also resets the preempt flag on a state that had previously received the preempt, but not serviced it."""
if self._preempted_state != self._current_state:
if self._preempted_state is not None:
# Reset the previously preempted state (that has now terminated)
self._preempted_state.recall_preempt()
# Store the label of the currently active state
self._preempted_state = self._current_state
self._preempted_label = self._current_label
# Request the currently active state to preempt
try:
self._preempted_state.request_preempt()
except:
smach.logerr("Failed to preempt contained state '%s': %s" % (self._preempted_label, traceback.format_exc()))
The first time the above is executed the _preempted_state
is None
and thus the self._preempted_state != self._current_state
check goes through.
However, the second time it's executed both self._preempted_state
and the self._current_state
point to the same object, that is different from the _current_state
we've seen in the previous preempt.
I assume the issue comes from the assignment:
self._preempted_state = self._current_state
Where self._preempted_state starts being a reference to the self._current_state
.
Anyone has any thoughts about it? This point could be highly relevant to the discussion in #52 .
It looks like all of the dependencies for this are available in Melodic, so it would be great to get this released. Thanks in advance!
I believe there are race condition problems with smach containers in general, here demonstrated for Concurrence state.
Scenario:
Below a script that demonstrates the problem, it does not require any ROS code running. The script just creates this state machine.
- Sequence(top)
- Concurrence(Cc)
- Delay1(0.3 seconds) (for demonstration purposes: the only child of Concurrence)
- Delay2(0.5 seconds)
When the script is preempted after approx. 0.3 seconds, I would expect either Delay1 or Delay2 to return 'preempted'.
Test script:
#!/usr/bin/env python
from time import sleep
from smach import State, Concurrence, Sequence
from threading import Timer
class DelayState(State):
"""Delay state for testing purposes"""
def __init__(self, delay):
State.__init__(self, outcomes=['succeeded', 'preempted'])
self.delay = delay
def execute(self, userdata):
# A better delay state should be able to preempt during its sleep state
sleep(self.delay)
if self.preempt_requested():
self.service_preempt()
return 'preempted'
return 'succeeded'
def test_concurrence_preempt():
"""test demonstrating race condition
Creates a state machine:
- Sequence(top)
- Concurrence(Cc)
- Delay1(0.3 seconds) (for demonstration purposes: the only child of Concurrence)
- Delay2(0.5 seconds)
When preempting the state machine after ~0.3 seconds, the machine
is expected to return 'preempted'
"""
def outcome_cb(outcome_map):
if 'preempted' in outcome_map.values():
return 'preempted'
return 'succeeded'
cc = Concurrence(
outcomes=['succeeded', 'preempted'],
default_outcome='succeeded',
outcome_cb=outcome_cb)
with cc:
Concurrence.add('Delay1', DelayState(delay=0.3))
top = Sequence(outcomes=['succeeded', 'preempted'],
connector_outcome='succeeded')
with top:
Sequence.add('Cc', cc)
Sequence.add('Delay2', DelayState(delay=0.5))
# Execute state machine and try cancel after various milliseconds of delay
for msDelay in range(290, 330, 2):
print ('Cancel after delay {}'.format(msDelay))
t = Timer(msDelay/1000.0, top.request_preempt)
t.start()
if top.execute() != 'preempted':
print ('===== TEST FAILED, delay: %sms =====', msDelay)
return
print ('===== TEST OK =====')
test_concurrence_preempt()
The above scenario is one of several cases, where a preempt request is kind of lost. I believe similar problems exist for Sequence container as well.
I will happily work on a pull request, but since this is a quite generic problem for Smach as I see it, it might require some discussion on the right approach.
My setup:
I have a multi-agent application which is like a big state machine: Parcel sorting.
To deliver parcels, we are currently using Actionlib to provide tasks to the UGVs, and the tasks are defined by a simple state machine.
I just bumped into SMACH and wonder if it is suitable for multi-agent systems like my application. For one UGV, it would be super simple to use SMACH, but I do not see how I could use it for multiple agents.
The state machine for each UGVs looks like:
START
* INIT
INIT
* GET_PARCEL
GET_PARCEL
* when parcel_put: SCAN_PARCEL
SCAN_PARCEL
* when parcel_scanned DELIVER_PARCEL
DELIVER_PARCEL
* when parcel_removed: GET_PARCEL
* if timeout: EMERGENCY_GATE
EMERGENCY_GATE
* when parcel_removed: GET_PARCEL
Can we have a new release of the package? It has been more than two years since v2.0.0 and there are a lot of fixes which would be good to have in the released version (at least for ROS kinetic).
Hi,
I wanted to use the preempt_timeout in combination with the SimpleActionState, but it would never work for me. When I was looking through the code I did not really find anything where this value is actually used. Can you please give a hint what is missing to use it?
Thanks
If state machine's state fails with an exception, _is_running flag is not lowered, although the state machine obviously is not running.
Example code:
from smach import StateMachine, State
class FailingState(State):
def execute(self, ud):
0/0 # exception
s = StateMachine(outcomes=[])
with s:
StateMachine.add('foo', FailingState())
try:
s.execute()
except:
pass
print 'running', s.is_running()
Output:
<...>
ZeroDivisionError: integer division or modulo by zero
<...>
running True
Isn't is an issue?
1, if "ctrl+c" pressed, "done_cb" will never be called by SimpleActionClient because rospy was shutdown, action client cannot receive action server's state message. So, it will be blocked by the code:"self._done_cond.wait()".
2, in multi-thread mode, run "SimpleActionState.execute()" in child thread, after "ctrl+c" pressed, call "SimpleActionState.request_preempt()" in main thread is not working because that, rospy was shutdown, call SimpleActionClient.cancel_goal() will be failed, So, it will be blocked by the code:"self._done_cond.wait()" again.
Suggestion:
check rospy's state in SimpleAction.request_preempt() function, if rospy is shutdown, call self._done_cond.notify() to notify SimpleAction.execute() function to return "preempted" state.
Reported at ros/rosdistro#37815 (comment) thanks to @Yadunund
14:15:20 CMake Error at CMakeLists.txt:10 (find_package):
14:15:20 By not providing "Findament_cmake_flake8.cmake" in CMAKE_MODULE_PATH this
14:15:20 project has asked CMake to find a package configuration file provided by
14:15:20 "ament_cmake_flake8", but CMake did not find one.
14:15:20
14:15:20 Could not find a package configuration file provided by
14:15:20 "ament_cmake_flake8" with any of the following names:
14:15:20
14:15:20 ament_cmake_flake8Config.cmake
14:15:20 ament_cmake_flake8-config.cmake
14:15:20
14:15:20 Add the installation prefix of "ament_cmake_flake8" to CMAKE_PREFIX_PATH or
14:15:20 set "ament_cmake_flake8_DIR" to a directory containing one of the above
14:15:20 files. If "ament_cmake_flake8" provides a separate development package or
14:15:20 SDK, be sure it has been installed.
I think this repository should switch maintainer. @mojin-robotics looks like a good candidate to me as they are actively maintaining and developing there fork.
Hello,
I have been working with the smach library I can to use the CBState class.
Now I am not sure how to use the cb_args to pass an argument into the callback function.
Can someone give me an example or explanation?
Hope someone can help me
It would be nice to be able to maintain a single source tree of SMACH that works in electric, fuerte, groovy, and hydro until the dust has settled on catkin. This would involve supporting both rosbuild and catkin in a single checkout, and should be possible.
Hi,
I've been running some concurrence containers, with 3 or 4 children, and I've noticed that sometimes the child terminates before the parent, which then outputs the following error:
[ERROR] [WallTime: 1384915862.954833] InvalidUserCodeError: Could not execute child termination callback: Traceback (most recent call last):
File "/opt/strands/strands_catkin_ws/src/catkinized_smach/smach/src/smach/concurrence.py", line 348, in _state_runner
preempt_others = self._child_termination_cb(self._child_outcomes)
File "/opt/strands/strands_catkin_ws/src/autonomous_patrolling/waypoint_patroller/src/waypoint_patroller/navigation.py", line 157, in child_term_cb
if ( outcome_map['BUMPER_MONITOR'] == 'invalid' or
KeyError: 'BUMPER_MONITOR'
Exception in thread concurrent_split:BATTERY_MONITOR:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 504, in run
self.__target(_self.__args, *_self.__kwargs)
File "/opt/strands/strands_catkin_ws/src/catkinized_smach/smach/src/smach/concurrence.py", line 350, in _state_runner
raise smach.InvalidUserCodeError("Could not execute child termination callback: "+traceback.format_exc())
InvalidUserCodeError: <smach.exceptions.InvalidUserCodeError instance at 0x3af46c8>
In this case, BUMPER_MONITOR terminated before its parent.
This does not affect the execution of the state machine, which continues normally afterwards.
Hi.
Using a Ubuntu with Melodic ROS Distro I'm able to import smach library on python only even not using any ROS functionality.
So, I'm wondering if is it possible to use smach library without ROS on a Windows or Raspbian OS .
Does somebody knows if that's possible?
I noticed that the feedback set by the last state of the wrapped sm does not get published.
Hi,
I read the smach tutorial there is no problem until I run smach_viewer command.
Smach tutorial
rosrun smach_viewer smach_viewer.py
the terminal shows the below error :
[rospack] Error: package 'smach_viewer' not found
I checked the /opt/ros/noetic/share path there is no smach_viewer package. just smach.
the question is: What should I do to see the graphical representation of my smach code?
I'm using ubuntu focal, Noetic ROS, and python3.
thanks a lot for your support.
I have some variables in a state which should not be pickled by the IntrospectionServer
. This is of interest for me, first of all, because I get an PicklingError
right now (it seems that SwigPyObjects
can't be pickled), but more generally, because they are too big and I don't want them to be serialized.
I guess I'm looking for something like this:
sis = smach_ros.IntrospectionServer(
'sis', sm, '/SM_ROOT',
exclude={
BlaState: ["variable1", "variable2"],
FooState: ["variableX"]
}
)
Is there a way to do this? If not, could we implement something like this? I'd be happy to help!
In simple_action_state.py, the construction of class SimpleActionState is as follows:
class SimpleActionState(RosState):
"""Simple action client state.
Use this class to represent an actionlib as a state in a state machine.
"""
# Meta-states for this action
WAITING_FOR_SERVER = 0
INACTIVE = 1
ACTIVE = 2
PREEMPTING = 3
COMPLETED = 4
def __init__(self,
node,
# Action info
action_name,
action_spec,
# Default goal
goal = None,
goal_key = None,
goal_slots = [],
goal_cb = None,
goal_cb_args = [],
goal_cb_kwargs = {},
# Result modes
result_key = None,
result_slots = [],
result_cb = None,
result_cb_args = [],
result_cb_kwargs = {},
# Keys
input_keys = [],
output_keys = [],
outcomes = [],
# Timeouts
exec_timeout = None,
preempt_timeout = Duration(seconds=60.0),
server_wait_timeout = Duration(seconds=60.0)
):
RosState.__init__(self, node, outcomes=['succeeded','aborted','preempted'])
This will cause problem when I define outcomes different from ['succeeded','aborted','preempted']. It should look like:
RosState.__init__(self, node, outcomes=outcomes)
Hey there,
I'm working on a project on which I have concurrent container in which two state machines run concurrently. The states inside those concurrently running state machines need to access and modify the same userdata. A more specific description with code can be found here:
Is there anyway I can use and modify a parent userdata in child-states?
Not sure how intentional that is so I'll let awesome @jbohren do it: http://wiki.ros.org/smach/Tutorials displays entries twice because http://wiki.ros.org/mysmach/Tutorials still exists. You should probably delete all the pages in there. A list of subpages will appear here: http://wiki.ros.org/mysmach/Tutorials?action=DeletePage
Maybe delete only one of the tutorial in mysmach to make sure it does not delete the corresponding one in smach :)
Hi guys,
I am porting all my ROS applications to ROS2, and therefore, as I use SMACH to control some part of my autonomous robot mission, I need to port SMACH to ROS2.
I looked at all the GitHub forks of SMACH but found no ROS2 version.
I will start a ROS2 branch on a fork, and try to port everything to ROS2 during the coming days.
First, have I missed something? Is there a ROS2 version under development?
If not, if anybody wants to contribute in the porting, and/or testing of the ROS2 version, let me know!
Best,
Is it possible to define transitions between states with constant userdata?
I want the input variable var1
of FOO
to be set to test
every time after executing BAR
, without modifying the internals of BAR
.
Something along the lines of:
smach.StateMachine.add('BAR', Bar(),
transitions={'outcome1':'FOO'},
remapping={'bar_counter_in':'sm_counter'},
constants={'var1':'test'})
Or even making the remappings
aware that if some key does not exist as an input or output of BAR
, it should be treated as a constant:
smach.StateMachine.add('BAR', Bar(),
transitions={'outcome1':'FOO'},
remapping={'bar_counter_in':'sm_counter', 'test': 'var1'})
Or even:
smach.StateMachine.add('BAR', Bar(),
transitions={'outcome1':['FOO',{'var1': 'test'}]},
remapping={'bar_counter_in':'sm_counter'})
This would be VERY useful to me, as I have different instances of the same state pointing to another state, but depending on which instance I am coming from, I want different data to be passed in a constant manner.
Hi everyone,
I've been using smach for robotic manipulation and everything works as expected, except SMACH Introspection Server in
combination with smach_viewer
.
I'm using this tutorial to initialize SMACH Introspection Server as described.
After creating StateMachine instance and adding all the states I'm creating introspection server as proposed.
After running my state machine, which is mostly consisted of SimpleActionState classes which wrap my ROS action servers. State machine works and sends goals to wrapped action servers which then execute and propagate as commanded in transitions
dict.
I'm currently not using or passing any UserData. StateMachine is consistent and I should be able to visualize it.
However, upon running rosrun smach_viewer smach_viewer
I'm constantly getting following message:
[ERROR] [1621512586.661582]: Publishing SMACH introspection structure message failed.
However, when inspecting rostopic echo /smach_introspection_server/smach/container_status
I get following:
header:
seq: 1
stamp:
secs: 1621512682
nsecs: 499099016
frame_id: ''
path: "SM_ROOT"
initial_states: [TRIGGER_GO_TO_PREAPPROACH_POSE]
active_states: [TRIGGER_GO_TO_PREAPPROACH_POSE]
local_data: !!binary |
gAJ9cQAu
info: "HEARTBEAT"
Whereas when switching states, message looks like this:
header:
seq: 19
stamp:
secs: 1621512713
nsecs: 225410938
frame_id: ''
path: "SM_ROOT"
initial_states: [TRIGGER_GO_TO_PREAPPROACH_POSE]
active_states: [TRIGGER_SERVO_CONTROL]
local_data: !!binary |
gAJ9cQAu
info: "(<smach.user_data.UserData object at 0x7f0b2040a2d0>, ['TRIGGER_SERVO_CONTROL']),\
\ {}"
I'm not sure what it is, but this local_data
and info
when passing between states are quite suspicious. I'm thinking that maybe missing UserData could be cause for: [ERROR] [1621512586.661582]: Publishing SMACH introspection structure message failed.
My question is:
What causes failure when publishing SMACH introspection structure message to smach_viewer
?
I'm using Linux 18.04 and ROS Melodic.
Might be related to #53
But we discovered this in a bigger state-machine where a concurrent monitoring state is trying to preempt another concurrence container. We expected this container then to finalize with outcome 'preempted'.
However, if at that moment the concurrency container already was terminating and one of the states had an outcome defined already, the resulting outcome is not 'preempted' which made our state machine end up in an undesired state.
Inspired by #53 I created a small script as well to demonstrate this:
#!/usr/bin/env python
from time import sleep
from smach import State, Concurrence
from threading import Timer
class DelayState(State):
"""Delay state for testing purposes"""
def __init__(self, delay):
State.__init__(self, outcomes=['succeeded', 'preempted'])
self.delay = delay
def execute(self, _):
# A better delay state should be able to preempt during its sleep state
sleep(self.delay)
if self.preempt_requested():
self.service_preempt()
return 'preempted'
return 'succeeded'
def test_concurrence_preempt():
cc1 = Concurrence(
outcomes=['succeeded', 'preempted'],
default_outcome='succeeded',
child_termination_cb=lambda *_: True, # Always evaluate outcome_map
outcome_map={'preempted': {'State1': 'preempted',
'State2': 'preempted'}})
with cc1:
Concurrence.add('State1', DelayState(0.1))
Concurrence.add('State2', DelayState(1.0))
t = Timer(0.3, cc1.request_preempt)
t.start()
print(f' Resulting state: {cc1.execute()}')
if __name__ == '__main__':
test_concurrence_preempt()
In this simple example State1
is already done when the concurrence container is asked to preempt and thus the resulting outcome is succeeded
although preempted
would be expected.
In code the case where the concurrence is asked to preempt after all states are terminated is caught already:
but the resulting outcome is not changed.I'll sketch-up a PR as well with a potential fix!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.