├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── CMakeLists.txt
├── README.md
├── action
└── DoSomething.action
├── launch
└── dummy.launch
├── package.xml
├── requirements.txt
├── scripts
├── __init__.py
├── start_dummy_action_client.py
└── start_dummy_action_server.py
├── setup.py
└── src
├── __init__.py
├── actionlib_demo
├── __init__.py
├── dummy_action_client.py
└── dummy_action_server.py
└── actionlib_demo_tests
├── __init__.py
└── __test_suite__.py
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # --- Created by https://www.gitignore.io/api/ros,python,pycharm
2 |
3 | ### PyCharm ###
4 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
5 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
6 |
7 | # User-specific stuff:
8 | .idea/**/workspace.xml
9 | .idea/**/tasks.xml
10 | .idea/dictionaries
11 |
12 | # Sensitive or high-churn files:
13 | .idea/**/dataSources/
14 | .idea/**/dataSources.ids
15 | .idea/**/dataSources.xml
16 | .idea/**/dataSources.local.xml
17 | .idea/**/sqlDataSources.xml
18 | .idea/**/dynamic.xml
19 | .idea/**/uiDesigner.xml
20 |
21 | # Gradle:
22 | .idea/**/gradle.xml
23 | .idea/**/libraries
24 |
25 | # CMake
26 | cmake-build-debug/
27 |
28 | # Mongo Explorer plugin:
29 | .idea/**/mongoSettings.xml
30 |
31 | ## File-based project format:
32 | *.iws
33 |
34 | ## Plugin-specific files:
35 |
36 | # IntelliJ
37 | /out/
38 |
39 | # mpeltonen/sbt-idea plugin
40 | .idea_modules/
41 |
42 | # JIRA plugin
43 | atlassian-ide-plugin.xml
44 |
45 | # Cursive Clojure plugin
46 | .idea/replstate.xml
47 |
48 | # Crashlytics plugin (for Android Studio and IntelliJ)
49 | com_crashlytics_export_strings.xml
50 | crashlytics.properties
51 | crashlytics-build.properties
52 | fabric.properties
53 |
54 | ### PyCharm Patch ###
55 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
56 |
57 | # *.iml
58 | # modules.xml
59 | # .idea/misc.xml
60 | # *.ipr
61 |
62 | # Sonarlint plugin
63 | .idea/sonarlint
64 |
65 | ### Python ###
66 | # Byte-compiled / optimized / DLL files
67 | __pycache__/
68 | *.py[cod]
69 | *$py.class
70 |
71 | # C extensions
72 | *.so
73 |
74 | # Distribution / packaging
75 | .Python
76 | env/
77 | #build/ # commented out for custom build directory
78 | develop-eggs/
79 | dist/
80 | downloads/
81 | eggs/
82 | .eggs/
83 | lib/
84 | lib64/
85 | parts/
86 | sdist/
87 | var/
88 | wheels/
89 | *.egg-info/
90 | .installed.cfg
91 | *.egg
92 |
93 | # PyInstaller
94 | # Usually these files are written by a python script from a template
95 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
96 | *.manifest
97 | *.spec
98 |
99 | # Installer logs
100 | pip-log.txt
101 | pip-delete-this-directory.txt
102 |
103 | # Unit test / coverage reports
104 | htmlcov/
105 | .tox/
106 | .coverage
107 | .coverage.*
108 | .cache
109 | nosetests.xml
110 | coverage.xml
111 | *,cover
112 | .hypothesis/
113 |
114 | # Translations
115 | *.mo
116 | *.pot
117 |
118 | # Django stuff:
119 | *.log
120 | local_settings.py
121 |
122 | # Flask stuff:
123 | instance/
124 | .webassets-cache
125 |
126 | # Scrapy stuff:
127 | .scrapy
128 |
129 | # Sphinx documentation
130 | docs/_build/
131 |
132 | # PyBuilder
133 | target/
134 |
135 | # Jupyter Notebook
136 | .ipynb_checkpoints
137 |
138 | # pyenv
139 | .python-version
140 |
141 | # celery beat schedule file
142 | celerybeat-schedule
143 |
144 | # SageMath parsed files
145 | *.sage.py
146 |
147 | # dotenv
148 | .env
149 |
150 | # virtualenv
151 | .venv
152 | venv/
153 | ENV/
154 |
155 | # Spyder project settings
156 | .spyderproject
157 | .spyproject
158 |
159 | # Rope project settings
160 | .ropeproject
161 |
162 | # mkdocs documentation
163 | /site
164 |
165 | ### ROS ###
166 | bin/
167 | msg_gen/
168 | srv_gen/
169 | msg/*Action.msg
170 | msg/*ActionFeedback.msg
171 | msg/*ActionGoal.msg
172 | msg/*ActionResult.msg
173 | msg/*Feedback.msg
174 | msg/*Goal.msg
175 | msg/*Result.msg
176 | msg/_*.py
177 |
178 | # Generated by dynamic reconfigure
179 | *.cfgc
180 | /cfg/cpp/
181 | /cfg/*.py
182 |
183 | # Ignore generated docs
184 | *.dox
185 | *.wikidoc
186 |
187 | # eclipse stuff
188 | .project
189 | .cproject
190 |
191 | # qcreator stuff
192 | CMakeLists.txt.user
193 |
194 | srv/_*.py
195 | *.pcd
196 | *.pyc
197 | qtcreator-*
198 | *.user
199 |
200 | /planning/cfg
201 | /planning/docs
202 | /planning/src
203 |
204 | *~
205 |
206 | # Emacs
207 | .#*
208 |
209 | # Catkin custom files
210 | CATKIN_IGNORE
211 |
212 | # --- End of https://www.gitignore.io/api/ros,python,pycharm
213 |
214 | # MyPy Cache
215 | .mypy_cache
216 |
217 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(actionlib_demo)
3 |
4 | ## Compile as C++11, supported in ROS Kinetic and newer
5 | # add_compile_options(-std=c++11)
6 |
7 | ## Find catkin macros and libraries
8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
9 | ## is used, also find other catkin packages
10 | find_package(catkin REQUIRED COMPONENTS
11 | rospy
12 | std_msgs
13 | message_generation
14 | genmsg
15 | actionlib_msgs
16 | actionlib
17 | )
18 |
19 | ## System dependencies are found with CMake's conventions
20 | # find_package(Boost REQUIRED COMPONENTS system)
21 |
22 |
23 | ## Uncomment this if the package has a setup.py. This macro ensures
24 | ## modules and global scripts declared therein get installed
25 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
26 | catkin_python_setup()
27 |
28 | ################################################
29 | ## Declare ROS messages, services and actions ##
30 | ################################################
31 |
32 | ## To declare and build messages, services or actions from within this
33 | ## package, follow these steps:
34 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in
35 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
36 | ## * In the file package.xml:
37 | ## * add a build_depend tag for "message_generation"
38 | ## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
39 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
40 | ## but can be declared for certainty nonetheless:
41 | ## * add a run_depend tag for "message_runtime"
42 | ## * In this file (CMakeLists.txt):
43 | ## * add "message_generation" and every package in MSG_DEP_SET to
44 | ## find_package(catkin REQUIRED COMPONENTS ...)
45 | ## * add "message_runtime" and every package in MSG_DEP_SET to
46 | ## catkin_package(CATKIN_DEPENDS ...)
47 | ## * uncomment the add_*_files sections below as needed
48 | ## and list every .msg/.srv/.action file to be processed
49 | ## * uncomment the generate_messages entry below
50 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
51 |
52 | ## Generate messages in the 'msg' folder
53 | # add_message_files(
54 | # FILES
55 | # Message1.msg
56 | # Message2.msg
57 | # )
58 |
59 | ## Generate services in the 'srv' folder
60 | # add_service_files(
61 | # FILES
62 | # Service1.srv
63 | # Service2.srv
64 | # )
65 |
66 | # Generate actions in the 'action' folder
67 | add_action_files(
68 | FILES
69 | DoSomething.action
70 | )
71 |
72 | ## Generate added messages and services with any dependencies listed here
73 | generate_messages(
74 | DEPENDENCIES
75 | std_msgs # Or other packages containing msgs
76 | actionlib_msgs
77 | )
78 |
79 | ################################################
80 | ## Declare ROS dynamic reconfigure parameters ##
81 | ################################################
82 |
83 | ## To declare and build dynamic reconfigure parameters within this
84 | ## package, follow these steps:
85 | ## * In the file package.xml:
86 | ## * add a build_depend and a run_depend tag for "dynamic_reconfigure"
87 | ## * In this file (CMakeLists.txt):
88 | ## * add "dynamic_reconfigure" to
89 | ## find_package(catkin REQUIRED COMPONENTS ...)
90 | ## * uncomment the "generate_dynamic_reconfigure_options" section below
91 | ## and list every .cfg file to be processed
92 |
93 | ## Generate dynamic reconfigure parameters in the 'cfg' folder
94 | # generate_dynamic_reconfigure_options(
95 | # cfg/DynReconf1.cfg
96 | # cfg/DynReconf2.cfg
97 | # )
98 |
99 | ###################################
100 | ## catkin specific configuration ##
101 | ###################################
102 | ## The catkin_package macro generates cmake config files for your package
103 | ## Declare things to be passed to dependent projects
104 | ## INCLUDE_DIRS: uncomment this if you package contains header files
105 | ## LIBRARIES: libraries you create in this project that dependent projects also need
106 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need
107 | ## DEPENDS: system dependencies of this project that dependent projects also need
108 | catkin_package(
109 | # INCLUDE_DIRS include
110 | LIBRARIES actionlib_demo
111 | CATKIN_DEPENDS rospy std_msgs message_runtime actionlib_msgs
112 | # DEPENDS system_lib
113 | )
114 |
115 | ###########
116 | ## Build ##
117 | ###########
118 |
119 | ## Specify additional locations of header files
120 | ## Your package locations should be listed before other locations
121 | include_directories(
122 | # include
123 | ${catkin_INCLUDE_DIRS}
124 | )
125 |
126 | ## Declare a C++ library
127 | # add_library(${PROJECT_NAME}
128 | # src/${PROJECT_NAME}
129 | # )
130 |
131 | ## Add cmake target dependencies of the library
132 | ## as an example, code may need to be generated before libraries
133 | ## either from message generation or dynamic reconfigure
134 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
135 |
136 | ## Declare a C++ executable
137 | ## With catkin_make all packages are built within a single CMake context
138 | ## The recommended prefix ensures that target names across packages don't collide
139 | # add_executable(${PROJECT_NAME}_node)
140 |
141 | ## Rename C++ executable without prefix
142 | ## The above recommended prefix causes long target names, the following renames the
143 | ## target back to the shorter version for ease of user use
144 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
145 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
146 |
147 | ## Add cmake target dependencies of the executable
148 | ## same as for the library above
149 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
150 |
151 | ## Specify libraries to link a library or executable target against
152 | # target_link_libraries(${PROJECT_NAME}_node
153 | # ${catkin_LIBRARIES}
154 | # )
155 |
156 | #############
157 | ## Install ##
158 | #############
159 |
160 | # all install targets should use catkin DESTINATION variables
161 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
162 |
163 | ## Mark executable scripts (Python etc.) for installation
164 | ## in contrast to setup.py, you can choose the destination
165 | # install(PROGRAMS
166 | # scripts/my_python_script
167 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
168 | # )
169 |
170 | ## Mark executables and/or libraries for installation
171 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
172 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
173 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
174 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
175 | # )
176 |
177 | ## Mark cpp header files for installation
178 | # install(DIRECTORY include/${PROJECT_NAME}/
179 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
180 | # FILES_MATCHING PATTERN "*.h"
181 | # PATTERN ".svn" EXCLUDE
182 | # )
183 |
184 | ## Mark other files for installation (e.g. launch and bag files, etc.)
185 | # install(FILES
186 | # # myfile1
187 | # # myfile2
188 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
189 | # )
190 |
191 | #############
192 | ## Testing ##
193 | #############
194 |
195 | ## Add gtest based cpp test target and link libraries
196 | # catkin_add_gtest(${PROJECT_NAME}-test)
197 | # if(TARGET ${PROJECT_NAME}-test)
198 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
199 | # endif()
200 |
201 | ## Add folders to be run by python nosetests
202 | # catkin_add_nosetests(test)
203 | #catkin_add_nosetests(src/test/example_listener_test.py)
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python Actionlib Demo
2 |
3 | ## Description
4 |
5 | This is a simple demo for showing how to interact with action lib in Python 2.7. Actionlib is a powerfull asynchronous library built in ROS that will allow you to do multithreaded things without dealing with the threading overhead of Python 2.7. This demo will allow you to interact with two different actions independently of each other. You can start them with publishing to a topic, and cancel them by publishing to a different topic. See usage details below.
6 |
7 | ## Running the Nodes
8 |
9 | **Option 1:** Start all nodes with `roslaunch`.
10 |
11 | ```
12 | $ roslaunch actionlib_demo dummy.launch --screen
13 | ```
14 |
15 | _*The `--screen` flag logs output from all nodes to the terminal._
16 |
17 | **Option 2:** Start nodes individually.
18 |
19 | ```
20 | # Terminal 1 - The 'actionlib_demo_client' node.
21 |
22 | $ rosrun actionlib_demo start_dummy_action_client.py
23 | ```
24 |
25 | ```
26 | # Terminal 2 - The 'actionlib_demo_server' node.
27 |
28 | $ rosrun actionlib_demo start_dummy_action_server.py
29 | ```
30 | ## Triggering an Action
31 |
32 | publish a message to topic "trigger_one" from a teminal to start action 1
33 |
34 | ```
35 | $ rostopic pub /trigger_one std_msgs/String "data: ''"
36 | ```
37 |
38 | publish a message to topic "trigger_two" from a terminal to start action 2
39 |
40 | ```
41 | $ rostopic pub /trigger_two std_msgs/String "data: ''"
42 | ```
43 |
44 | ## Cancelling an Action In Progress
45 |
46 | publish a mesage to topic "other_topic_one" from a terminal to cancel action 1
47 |
48 | ```
49 | $ rostopic pub /other_topic_one std_msgs/String "data: ''"
50 | ```
51 |
52 | publish a message to topic "other_topic_two" from a terminal to cancel action 2
53 |
54 | ```
55 | $ rostopic pub /other_topic_two std_msgs/String "data: ''"
56 | ```
57 |
--------------------------------------------------------------------------------
/action/DoSomething.action:
--------------------------------------------------------------------------------
1 | # Define the goal
2 | uint32 how_long_to_do_something # specify how long to do the thing for
3 | ---
4 | # Define the result
5 | bool did_finish_doing_something # specify what the result is
6 | ---
7 | # Define a feedback message
8 | float32 percent_complete # specify a feedback metric
--------------------------------------------------------------------------------
/launch/dummy.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | actionlib_demo
6 | 0.0.0
7 | This is a demo on how to interact with actionlib in python 2.7
8 |
9 |
10 | NickKnack15
11 |
12 |
13 | NickKnack15
14 |
15 |
16 | MIT
17 |
18 |
19 | catkin
20 | rospy
21 | rospy
22 |
23 |
24 | std_msgs
25 | std_msgs
26 |
27 |
28 | message_generation
29 | message_runtime
30 |
31 | actionlib
32 | actionlib
33 |
34 | actionlib_msgs
35 | actionlib_msgs
36 |
37 |
38 | rostest
39 | rosunit
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickKnack15/python-actionlib-demo/ea7b618ee356e0c5c506f2219725b9bc6bf0d164/requirements.txt
--------------------------------------------------------------------------------
/scripts/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickKnack15/python-actionlib-demo/ea7b618ee356e0c5c506f2219725b9bc6bf0d164/scripts/__init__.py
--------------------------------------------------------------------------------
/scripts/start_dummy_action_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import rospy
3 | from actionlib_demo import DummyActionClient
4 |
5 |
6 | def start_actionlib_demo():
7 |
8 | rospy.init_node('dummy_action_client', anonymous=False) # initialize ros node
9 |
10 | dummy_action_client = DummyActionClient()
11 | dummy_action_client.start()
12 |
13 | def stop_dummy_action_client():
14 | dummy_action_client.stop()
15 |
16 | rospy.on_shutdown(stop_dummy_action_client)
17 |
18 | rospy.spin() # spin() simply keeps python from exiting until this node is stopped
19 |
20 |
21 | if __name__ == '__main__':
22 | start_actionlib_demo()
23 |
--------------------------------------------------------------------------------
/scripts/start_dummy_action_server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import rospy
3 | from actionlib_demo import DummyActionServer
4 |
5 |
6 | def start_actionlib_demo():
7 |
8 | rospy.init_node('dummy_action_server', anonymous=False) # initialize ros node
9 |
10 | dummy_action_server = DummyActionServer()
11 | dummy_action_server.start()
12 |
13 | def stop_dummy_action_server():
14 | dummy_action_server.stop()
15 |
16 | rospy.on_shutdown(stop_dummy_action_server)
17 |
18 | rospy.spin() # spin() simply keeps python from exiting until this node is stopped
19 |
20 |
21 | if __name__ == '__main__':
22 | start_actionlib_demo()
23 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
2 |
3 | from distutils.core import setup
4 | from catkin_pkg.python_setup import generate_distutils_setup
5 |
6 | setup_args = generate_distutils_setup(
7 | packages=['actionlib_demo', 'actionlib_demo_tests'],
8 | package_dir={'': 'src'})
9 |
10 | setup(**setup_args)
11 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NickKnack15/python-actionlib-demo/ea7b618ee356e0c5c506f2219725b9bc6bf0d164/src/__init__.py
--------------------------------------------------------------------------------
/src/actionlib_demo/__init__.py:
--------------------------------------------------------------------------------
1 | from .dummy_action_server import DummyActionServer
2 | from .dummy_action_client import DummyActionClient
3 |
--------------------------------------------------------------------------------
/src/actionlib_demo/dummy_action_client.py:
--------------------------------------------------------------------------------
1 | import rospy
2 | import actionlib
3 | import traceback
4 | from std_msgs.msg import String
5 | from actionlib_demo.msg import DoSomethingAction, DoSomethingActionFeedback, DoSomethingActionGoal, \
6 | DoSomethingActionResult, DoSomethingFeedback, DoSomethingGoal, DoSomethingResult
7 |
8 |
9 | class DummyActionClient(object):
10 | def __init__(self):
11 |
12 | self.do_something_client = actionlib.SimpleActionClient('do_something', DoSomethingAction)
13 |
14 | self.do_something_else_client = actionlib.SimpleActionClient('do_something_else', DoSomethingAction)
15 |
16 | self.trigger_one_subscriber = rospy.Subscriber('trigger_one', String, self._trigger_one)
17 | self.trigger_two_subscriber = rospy.Subscriber('trigger_two', String, self._trigger_two)
18 |
19 | self.other_topic_one_subscriber = rospy.Subscriber('other_topic_one', String, self._other_topic_one)
20 | self.other_topic_two_subscriber = rospy.Subscriber('other_topic_two', String, self._other_topic_two)
21 |
22 | def start(self):
23 | self._loginfo('Action Client Started')
24 | self.do_something_client.wait_for_server(rospy.Duration.from_sec(15))
25 | self.do_something_else_client.wait_for_server(rospy.Duration.from_sec(15))
26 |
27 | def stop(self):
28 | self._loginfo('Action Client Stopped')
29 | self.do_something_client = None
30 | self.do_something_else_client = None
31 |
32 | def send_goal_one(self, length):
33 | try:
34 | goal = DoSomethingGoal()
35 | goal.how_long_to_do_something = length
36 | self.do_something_client.send_goal(goal,
37 | active_cb=self._goal_one_active,
38 | feedback_cb=self._goal_one_feedback,
39 | done_cb=self._goal_one_done)
40 |
41 | self._loginfo('goal one has been sent')
42 |
43 | except Exception as e:
44 | print(e.message)
45 | traceback.print_exc()
46 | self._loginfo('Error sending goal one')
47 | self.do_something_client.wait_for_server(rospy.Duration.from_sec(15))
48 | self.send_goal_one(length)
49 |
50 | def _goal_one_active(self):
51 | self._loginfo('goal one has transitioned to active state')
52 |
53 | def _goal_one_feedback(self, feedback):
54 | # type: (DoSomethingFeedback) -> None
55 | self._loginfo('Goal one feedback received: {}'.format(feedback))
56 |
57 | def _goal_one_done(self, state, result):
58 | # type: (actionlib.GoalStatus, DoSomethingResult) -> None
59 | self._loginfo('Goal one done callback triggered')
60 | self._loginfo(str(state))
61 | self._loginfo(str(result))
62 | self._loginfo('Do something result: ' + str(result.did_finish_doing_something))
63 |
64 | def send_goal_two(self, length):
65 | try:
66 | goal = DoSomethingGoal()
67 | goal.how_long_to_do_something = length
68 | self.do_something_else_client.send_goal(goal,
69 | active_cb=self._goal_two_active,
70 | feedback_cb=self._goal_two_feedback,
71 | done_cb=self._goal_two_done)
72 |
73 | except Exception as e:
74 | print(e.message)
75 | traceback.print_exc()
76 | self._loginfo('Error sending goal two')
77 | self.do_something_else_client.wait_for_server(rospy.Duration.from_sec(15))
78 | self.send_goal_one(length)
79 |
80 | def _goal_two_active(self):
81 | self._loginfo('goal two has transitioned to active state')
82 |
83 | def _goal_two_feedback(self, feedback):
84 | # type: (DoSomethingFeedback) -> None
85 | self._loginfo('Goal two feedback received: {}'.format(feedback))
86 |
87 | def _goal_two_done(self, state, result):
88 | # type: (actionlib.GoalStatus, DoSomethingResult) -> None
89 | self._loginfo('Goal two done callback triggered')
90 | self._loginfo(str(state))
91 | self._loginfo(str(result))
92 | self._loginfo('Do something_else result: ' + str(result.did_finish_doing_something))
93 |
94 | def _trigger_one(self, data):
95 | self._loginfo('Trigger one called')
96 | self._loginfo(data)
97 |
98 | self.send_goal_one(30)
99 |
100 | def _trigger_two(self, data):
101 | self._loginfo('Trigger two called')
102 | self._loginfo(data)
103 |
104 | self.send_goal_two(15)
105 |
106 | def _other_topic_one(self, data):
107 | self._loginfo('other_topic_one called')
108 | self._loginfo(data)
109 | self._loginfo('Preempting action do_something goal')
110 | self.do_something_client.cancel_goal()
111 |
112 | def _other_topic_two(self, data):
113 | self._loginfo('other_topic_two called')
114 | self._loginfo(data)
115 | self._loginfo('Preempting action do_something_else goal')
116 | self.do_something_else_client.cancel_goal()
117 |
118 | @staticmethod
119 | def _loginfo(message):
120 | # type: (str) -> None
121 |
122 | rospy.loginfo('DummyActionClient ({}) {}'.format('dummy_client', message))
123 |
--------------------------------------------------------------------------------
/src/actionlib_demo/dummy_action_server.py:
--------------------------------------------------------------------------------
1 | import time
2 | import rospy
3 | import actionlib
4 | from std_msgs.msg import String
5 | from actionlib_demo.msg import DoSomethingResult, DoSomethingGoal, DoSomethingFeedback, DoSomethingActionResult, \
6 | DoSomethingActionGoal, DoSomethingActionFeedback, DoSomethingAction
7 |
8 |
9 | class DummyActionServer(object):
10 | def __init__(self):
11 |
12 | self.do_something_server = actionlib.SimpleActionServer('do_something',
13 | DoSomethingAction,
14 | self.do_something,
15 | auto_start=False)
16 |
17 | self.do_something_else_server = actionlib.SimpleActionServer('do_something_else',
18 | DoSomethingAction,
19 | self.do_something,
20 | auto_start=False)
21 |
22 | self.other_topic_subscriber = rospy.Subscriber('other_topic_one', String, self._other_topic_one)
23 | self.other_topic_two_subscriber = rospy.Subscriber('other_topic_two', String, self._other_topic_two)
24 |
25 | def __del__(self):
26 | self.do_something_server = None
27 | self.do_something_else_server = None
28 |
29 | def start(self):
30 | self._loginfo('Action Server Started')
31 | self.do_something_server.start()
32 | self.do_something_else_server.start()
33 |
34 | def stop(self):
35 | self._loginfo('Action Server Stopped')
36 | self.do_something_server = None
37 | self.do_something_else_server = None
38 |
39 | def do_something(self, goal):
40 | # type: (DoSomethingGoal) -> None
41 | self._loginfo('Action Server received do_something action request')
42 | success = True
43 |
44 | r = rospy.Rate(1)
45 |
46 | start_time = time.time()
47 |
48 | while not rospy.is_shutdown():
49 | if time.time() - start_time > goal.how_long_to_do_something:
50 | break
51 |
52 | if self.do_something_server.is_preempt_requested():
53 | self._loginfo('do_something action preempted')
54 |
55 | self.do_something_server.set_preempted()
56 | success = False
57 | break
58 |
59 | self._loginfo('Doing something action')
60 | r.sleep()
61 |
62 | if success:
63 | self._loginfo('do_something action succeeded')
64 | result = DoSomethingResult()
65 | result.did_finish_doing_something = True
66 | self.do_something_server.set_succeeded(result)
67 |
68 | def do_something_else(self, goal):
69 | # type: (DoSomethingGoal) -> None
70 |
71 | self._loginfo('Action server received do_something_else')
72 | success = True
73 |
74 | r = rospy.Rate(1)
75 |
76 | start_time = time.time()
77 |
78 | while not rospy.is_shutdown():
79 | if time.time() - start_time > goal.how_long_to_do_something:
80 | break
81 |
82 | if self.do_something_else_server.is_preempt_requested():
83 | self._loginfo('do_something_else action preempted')
84 |
85 | self.do_something_else_server.set_preempted()
86 | success = False
87 | break
88 |
89 | self._loginfo('Doing something_else action')
90 | r.sleep()
91 |
92 | if success:
93 | self._loginfo('do_something_else action succeeded')
94 | result = DoSomethingResult()
95 | result.did_finish_doing_something = True
96 | self.do_something_else_server.set_succeeded(result)
97 |
98 | def _other_topic_one(self, data):
99 | self._loginfo('other_topic_one subscriber callback triggered')
100 | self._loginfo(data)
101 |
102 | def _other_topic_two(self, data):
103 | self._loginfo('other_topic_two subscriber callback triggered')
104 | self._loginfo(data)
105 |
106 | @staticmethod
107 | def _loginfo(message):
108 | # type: (str) -> None
109 |
110 | rospy.loginfo('DummyActionServer ({}) {}'.format('dummy_server', message))
111 |
--------------------------------------------------------------------------------
/src/actionlib_demo_tests/__init__.py:
--------------------------------------------------------------------------------
1 | from .__test_suite__ import TestSuite
2 |
--------------------------------------------------------------------------------
/src/actionlib_demo_tests/__test_suite__.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import os
3 |
4 |
5 | class TestSuite(unittest.TestSuite):
6 |
7 | def __init__(self):
8 | super(TestSuite, self).__init__()
9 |
10 | test_directory = os.path.dirname(os.path.abspath(os.path.join(__file__, os.pardir)))
11 | loader = unittest.TestLoader()
12 | self.addTests(loader.discover(test_directory, '*_test.py'))
13 |
--------------------------------------------------------------------------------