AS: adding first phase of orientation
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'examples-rclpy-minimal-action-server==0.15.3','console_scripts','server'
|
||||
import re
|
||||
import sys
|
||||
|
||||
# for compatibility with easy_install; see #2198
|
||||
__requires__ = 'examples-rclpy-minimal-action-server==0.15.3'
|
||||
|
||||
try:
|
||||
from importlib.metadata import distribution
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import distribution
|
||||
except ImportError:
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
|
||||
def importlib_load_entry_point(spec, group, name):
|
||||
dist_name, _, _ = spec.partition('==')
|
||||
matches = (
|
||||
entry_point
|
||||
for entry_point in distribution(dist_name).entry_points
|
||||
if entry_point.group == group and entry_point.name == name
|
||||
)
|
||||
return next(matches).load()
|
||||
|
||||
|
||||
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(load_entry_point('examples-rclpy-minimal-action-server==0.15.3', 'console_scripts', 'server')())
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'examples-rclpy-minimal-action-server==0.15.3','console_scripts','server_defer'
|
||||
import re
|
||||
import sys
|
||||
|
||||
# for compatibility with easy_install; see #2198
|
||||
__requires__ = 'examples-rclpy-minimal-action-server==0.15.3'
|
||||
|
||||
try:
|
||||
from importlib.metadata import distribution
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import distribution
|
||||
except ImportError:
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
|
||||
def importlib_load_entry_point(spec, group, name):
|
||||
dist_name, _, _ = spec.partition('==')
|
||||
matches = (
|
||||
entry_point
|
||||
for entry_point in distribution(dist_name).entry_points
|
||||
if entry_point.group == group and entry_point.name == name
|
||||
)
|
||||
return next(matches).load()
|
||||
|
||||
|
||||
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(load_entry_point('examples-rclpy-minimal-action-server==0.15.3', 'console_scripts', 'server_defer')())
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'examples-rclpy-minimal-action-server==0.15.3','console_scripts','server_not_composable'
|
||||
import re
|
||||
import sys
|
||||
|
||||
# for compatibility with easy_install; see #2198
|
||||
__requires__ = 'examples-rclpy-minimal-action-server==0.15.3'
|
||||
|
||||
try:
|
||||
from importlib.metadata import distribution
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import distribution
|
||||
except ImportError:
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
|
||||
def importlib_load_entry_point(spec, group, name):
|
||||
dist_name, _, _ = spec.partition('==')
|
||||
matches = (
|
||||
entry_point
|
||||
for entry_point in distribution(dist_name).entry_points
|
||||
if entry_point.group == group and entry_point.name == name
|
||||
)
|
||||
return next(matches).load()
|
||||
|
||||
|
||||
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(load_entry_point('examples-rclpy-minimal-action-server==0.15.3', 'console_scripts', 'server_not_composable')())
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'examples-rclpy-minimal-action-server==0.15.3','console_scripts','server_queue_goals'
|
||||
import re
|
||||
import sys
|
||||
|
||||
# for compatibility with easy_install; see #2198
|
||||
__requires__ = 'examples-rclpy-minimal-action-server==0.15.3'
|
||||
|
||||
try:
|
||||
from importlib.metadata import distribution
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import distribution
|
||||
except ImportError:
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
|
||||
def importlib_load_entry_point(spec, group, name):
|
||||
dist_name, _, _ = spec.partition('==')
|
||||
matches = (
|
||||
entry_point
|
||||
for entry_point in distribution(dist_name).entry_points
|
||||
if entry_point.group == group and entry_point.name == name
|
||||
)
|
||||
return next(matches).load()
|
||||
|
||||
|
||||
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(load_entry_point('examples-rclpy-minimal-action-server==0.15.3', 'console_scripts', 'server_queue_goals')())
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'examples-rclpy-minimal-action-server==0.15.3','console_scripts','server_single_goal'
|
||||
import re
|
||||
import sys
|
||||
|
||||
# for compatibility with easy_install; see #2198
|
||||
__requires__ = 'examples-rclpy-minimal-action-server==0.15.3'
|
||||
|
||||
try:
|
||||
from importlib.metadata import distribution
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import distribution
|
||||
except ImportError:
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
|
||||
def importlib_load_entry_point(spec, group, name):
|
||||
dist_name, _, _ = spec.partition('==')
|
||||
matches = (
|
||||
entry_point
|
||||
for entry_point in distribution(dist_name).entry_points
|
||||
if entry_point.group == group and entry_point.name == name
|
||||
)
|
||||
return next(matches).load()
|
||||
|
||||
|
||||
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(load_entry_point('examples-rclpy-minimal-action-server==0.15.3', 'console_scripts', 'server_single_goal')())
|
||||
@@ -0,0 +1,19 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: examples-rclpy-minimal-action-server
|
||||
Version: 0.15.3
|
||||
Summary: Examples of action servers using rclpy.
|
||||
Home-page: UNKNOWN
|
||||
Author: Jacob Perron
|
||||
Author-email: jacob@openrobotics.org
|
||||
Maintainer: Aditya Pande, Shane Loretz
|
||||
Maintainer-email: aditya.pande@openrobotics.org, shane@openrobotics.org
|
||||
License: Apache License, Version 2.0
|
||||
Keywords: ROS
|
||||
Platform: UNKNOWN
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Software Development
|
||||
|
||||
UNKNOWN
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package.xml
|
||||
setup.cfg
|
||||
setup.py
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/PKG-INFO
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/SOURCES.txt
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/dependency_links.txt
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/entry_points.txt
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/requires.txt
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/top_level.txt
|
||||
../../../../../build/examples_rclpy_minimal_action_server/examples_rclpy_minimal_action_server.egg-info/zip-safe
|
||||
examples_rclpy_minimal_action_server/__init__.py
|
||||
examples_rclpy_minimal_action_server/server.py
|
||||
examples_rclpy_minimal_action_server/server_defer.py
|
||||
examples_rclpy_minimal_action_server/server_not_composable.py
|
||||
examples_rclpy_minimal_action_server/server_queue_goals.py
|
||||
examples_rclpy_minimal_action_server/server_single_goal.py
|
||||
resource/examples_rclpy_minimal_action_server
|
||||
test/test_copyright.py
|
||||
test/test_flake8.py
|
||||
test/test_pep257.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[console_scripts]
|
||||
server = examples_rclpy_minimal_action_server.server:main
|
||||
server_defer = examples_rclpy_minimal_action_server.server_defer:main
|
||||
server_not_composable = examples_rclpy_minimal_action_server.server_not_composable:main
|
||||
server_queue_goals = examples_rclpy_minimal_action_server.server_queue_goals:main
|
||||
server_single_goal = examples_rclpy_minimal_action_server.server_single_goal:main
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
setuptools
|
||||
@@ -0,0 +1 @@
|
||||
examples_rclpy_minimal_action_server
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,107 @@
|
||||
# Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
|
||||
from example_interfaces.action import Fibonacci
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionServer, CancelResponse, GoalResponse
|
||||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||||
from rclpy.executors import MultiThreadedExecutor
|
||||
from rclpy.node import Node
|
||||
|
||||
|
||||
class MinimalActionServer(Node):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('minimal_action_server')
|
||||
|
||||
self._action_server = ActionServer(
|
||||
self,
|
||||
Fibonacci,
|
||||
'fibonacci',
|
||||
execute_callback=self.execute_callback,
|
||||
callback_group=ReentrantCallbackGroup(),
|
||||
goal_callback=self.goal_callback,
|
||||
cancel_callback=self.cancel_callback)
|
||||
|
||||
def destroy(self):
|
||||
self._action_server.destroy()
|
||||
super().destroy_node()
|
||||
|
||||
def goal_callback(self, goal_request):
|
||||
"""Accept or reject a client request to begin an action."""
|
||||
# This server allows multiple goals in parallel
|
||||
self.get_logger().info('Received goal request')
|
||||
return GoalResponse.ACCEPT
|
||||
|
||||
def cancel_callback(self, goal_handle):
|
||||
"""Accept or reject a client request to cancel an action."""
|
||||
self.get_logger().info('Received cancel request')
|
||||
return CancelResponse.ACCEPT
|
||||
|
||||
async def execute_callback(self, goal_handle):
|
||||
"""Execute a goal."""
|
||||
self.get_logger().info('Executing goal...')
|
||||
|
||||
# Append the seeds for the Fibonacci sequence
|
||||
feedback_msg = Fibonacci.Feedback()
|
||||
feedback_msg.sequence = [0, 1]
|
||||
|
||||
# Start executing the action
|
||||
for i in range(1, goal_handle.request.order):
|
||||
if goal_handle.is_cancel_requested:
|
||||
goal_handle.canceled()
|
||||
self.get_logger().info('Goal canceled')
|
||||
return Fibonacci.Result()
|
||||
|
||||
# Update Fibonacci sequence
|
||||
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
|
||||
|
||||
self.get_logger().info('Publishing feedback: {0}'.format(feedback_msg.sequence))
|
||||
|
||||
# Publish the feedback
|
||||
goal_handle.publish_feedback(feedback_msg)
|
||||
|
||||
# Sleep for demonstration purposes
|
||||
time.sleep(1)
|
||||
|
||||
goal_handle.succeed()
|
||||
|
||||
# Populate result message
|
||||
result = Fibonacci.Result()
|
||||
result.sequence = feedback_msg.sequence
|
||||
|
||||
self.get_logger().info('Returning result: {0}'.format(result.sequence))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
minimal_action_server = MinimalActionServer()
|
||||
|
||||
# Use a MultiThreadedExecutor to enable processing goals concurrently
|
||||
executor = MultiThreadedExecutor()
|
||||
|
||||
rclpy.spin(minimal_action_server, executor=executor)
|
||||
|
||||
minimal_action_server.destroy()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,121 @@
|
||||
# Copyright 2018 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
|
||||
from example_interfaces.action import Fibonacci
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionServer, CancelResponse, GoalResponse
|
||||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||||
from rclpy.executors import MultiThreadedExecutor
|
||||
from rclpy.node import Node
|
||||
|
||||
|
||||
class MinimalActionServer(Node):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('minimal_action_server')
|
||||
|
||||
self._goal_handle = None
|
||||
|
||||
self._action_server = ActionServer(
|
||||
self,
|
||||
Fibonacci,
|
||||
'fibonacci',
|
||||
execute_callback=self.execute_callback,
|
||||
callback_group=ReentrantCallbackGroup(),
|
||||
goal_callback=self.goal_callback,
|
||||
handle_accepted_callback=self.handle_accepted_callback,
|
||||
cancel_callback=self.cancel_callback)
|
||||
|
||||
def destroy(self):
|
||||
self._action_server.destroy()
|
||||
super().destroy_node()
|
||||
|
||||
def goal_callback(self, goal_request):
|
||||
"""Accept or reject a client request to begin an action."""
|
||||
self.get_logger().info('Received goal request')
|
||||
return GoalResponse.ACCEPT
|
||||
|
||||
def handle_accepted_callback(self, goal_handle):
|
||||
"""Provide a handle to an accepted goal."""
|
||||
self.get_logger().info('Deferring execution...')
|
||||
self._goal_handle = goal_handle
|
||||
self._timer = self.create_timer(3.0, self.timer_callback)
|
||||
|
||||
def cancel_callback(self, goal_handle):
|
||||
"""Accept or reject a client request to cancel an action."""
|
||||
self.get_logger().info('Received cancel request')
|
||||
return CancelResponse.ACCEPT
|
||||
|
||||
def timer_callback(self):
|
||||
# Execute the defered goal
|
||||
if self._goal_handle is not None:
|
||||
self._goal_handle.execute()
|
||||
self._timer.cancel()
|
||||
|
||||
async def execute_callback(self, goal_handle):
|
||||
"""Execute a goal."""
|
||||
self.get_logger().info('Executing goal...')
|
||||
|
||||
# Append the seeds for the Fibonacci sequence
|
||||
feedback_msg = Fibonacci.Feedback()
|
||||
feedback_msg.sequence = [0, 1]
|
||||
|
||||
# Start executing the action
|
||||
for i in range(1, goal_handle.request.order):
|
||||
if goal_handle.is_cancel_requested:
|
||||
goal_handle.canceled()
|
||||
self.get_logger().info('Goal canceled')
|
||||
return Fibonacci.Result()
|
||||
|
||||
# Update Fibonacci sequence
|
||||
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
|
||||
|
||||
self.get_logger().info('Publishing feedback: {0}'.format(feedback_msg.sequence))
|
||||
|
||||
# Publish the feedback
|
||||
goal_handle.publish_feedback(feedback_msg)
|
||||
|
||||
# Sleep for demonstration purposes
|
||||
time.sleep(1)
|
||||
|
||||
goal_handle.succeed()
|
||||
|
||||
# Populate result message
|
||||
result = Fibonacci.Result()
|
||||
result.sequence = feedback_msg.sequence
|
||||
|
||||
self.get_logger().info('Returning result: {0}'.format(result.sequence))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
minimal_action_server = MinimalActionServer()
|
||||
|
||||
# Use a MultiThreadedExecutor to enable processing goals concurrently
|
||||
executor = MultiThreadedExecutor()
|
||||
|
||||
rclpy.spin(minimal_action_server, executor=executor)
|
||||
|
||||
minimal_action_server.destroy()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,99 @@
|
||||
# Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
|
||||
from example_interfaces.action import Fibonacci
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionServer, CancelResponse
|
||||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||||
from rclpy.executors import MultiThreadedExecutor
|
||||
|
||||
|
||||
logger = None
|
||||
|
||||
|
||||
def cancel_callback(goal_handle):
|
||||
logger.info('Received cancel request')
|
||||
return CancelResponse.ACCEPT
|
||||
|
||||
|
||||
async def execute_callback(goal_handle):
|
||||
"""Execute the goal."""
|
||||
logger.info('Executing goal...')
|
||||
|
||||
# Append the seeds for the fibonacci sequence
|
||||
feedback_msg = Fibonacci.Feedback()
|
||||
feedback_msg.sequence = [0, 1]
|
||||
|
||||
# Start executing the action
|
||||
for i in range(1, goal_handle.request.order):
|
||||
if goal_handle.is_cancel_requested:
|
||||
goal_handle.canceled()
|
||||
logger.info('Goal canceled')
|
||||
return Fibonacci.Result()
|
||||
|
||||
# Update Fibonacci sequence
|
||||
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
|
||||
|
||||
logger.info('Publishing feedback: {0}'.format(feedback_msg.sequence))
|
||||
|
||||
# Publish feedback
|
||||
goal_handle.publish_feedback(feedback_msg)
|
||||
|
||||
# Sleep for demonstration purposes
|
||||
time.sleep(1)
|
||||
|
||||
goal_handle.succeed()
|
||||
|
||||
# Populate result message
|
||||
result = Fibonacci.Result()
|
||||
result.sequence = feedback_msg.sequence
|
||||
|
||||
logger.info('Returning result: {0}'.format(result.sequence))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main(args=None):
|
||||
global logger
|
||||
rclpy.init(args=args)
|
||||
|
||||
node = rclpy.create_node('minimal_action_server')
|
||||
logger = node.get_logger()
|
||||
|
||||
# Use a ReentrantCallbackGroup to enable processing multiple goals concurrently
|
||||
# Default goal callback accepts all goals
|
||||
# Default cancel callback rejects cancel requests
|
||||
action_server = ActionServer(
|
||||
node,
|
||||
Fibonacci,
|
||||
'fibonacci',
|
||||
execute_callback=execute_callback,
|
||||
cancel_callback=cancel_callback,
|
||||
callback_group=ReentrantCallbackGroup())
|
||||
|
||||
# Use a MultiThreadedExecutor to enable processing goals concurrently
|
||||
executor = MultiThreadedExecutor()
|
||||
|
||||
rclpy.spin(node, executor=executor)
|
||||
|
||||
action_server.destroy()
|
||||
node.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,137 @@
|
||||
# Copyright 2018-2020 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import collections
|
||||
import threading
|
||||
import time
|
||||
|
||||
from example_interfaces.action import Fibonacci
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionServer, CancelResponse, GoalResponse
|
||||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||||
from rclpy.executors import MultiThreadedExecutor
|
||||
from rclpy.node import Node
|
||||
|
||||
|
||||
class MinimalActionServer(Node):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('minimal_action_server')
|
||||
self._goal_queue = collections.deque()
|
||||
self._goal_queue_lock = threading.Lock()
|
||||
self._current_goal = None
|
||||
|
||||
self._action_server = ActionServer(
|
||||
self,
|
||||
Fibonacci,
|
||||
'fibonacci',
|
||||
handle_accepted_callback=self.handle_accepted_callback,
|
||||
execute_callback=self.execute_callback,
|
||||
goal_callback=self.goal_callback,
|
||||
cancel_callback=self.cancel_callback,
|
||||
callback_group=ReentrantCallbackGroup())
|
||||
|
||||
def destroy(self):
|
||||
self._action_server.destroy()
|
||||
super().destroy_node()
|
||||
|
||||
def handle_accepted_callback(self, goal_handle):
|
||||
"""Start or defer execution of an already accepted goal."""
|
||||
with self._goal_queue_lock:
|
||||
if self._current_goal is not None:
|
||||
# Put incoming goal in the queue
|
||||
self._goal_queue.append(goal_handle)
|
||||
self.get_logger().info('Goal put in the queue')
|
||||
else:
|
||||
# Start goal execution right away
|
||||
self._current_goal = goal_handle
|
||||
self._current_goal.execute()
|
||||
|
||||
def goal_callback(self, goal_request):
|
||||
"""Accept or reject a client request to begin an action."""
|
||||
self.get_logger().info('Received goal request')
|
||||
return GoalResponse.ACCEPT
|
||||
|
||||
def cancel_callback(self, goal_handle):
|
||||
"""Accept or reject a client request to cancel an action."""
|
||||
self.get_logger().info('Received cancel request')
|
||||
return CancelResponse.ACCEPT
|
||||
|
||||
def execute_callback(self, goal_handle):
|
||||
"""Execute a goal."""
|
||||
try:
|
||||
self.get_logger().info('Executing goal...')
|
||||
|
||||
# Append the seeds for the Fibonacci sequence
|
||||
feedback_msg = Fibonacci.Feedback()
|
||||
feedback_msg.sequence = [0, 1]
|
||||
|
||||
# Start executing the action
|
||||
for i in range(1, goal_handle.request.order):
|
||||
if goal_handle.is_cancel_requested:
|
||||
goal_handle.canceled()
|
||||
self.get_logger().info('Goal canceled')
|
||||
return Fibonacci.Result()
|
||||
|
||||
# Update Fibonacci sequence
|
||||
feedback_msg.sequence.append(
|
||||
feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
|
||||
|
||||
self.get_logger().info(
|
||||
'Publishing feedback: {0}'.format(feedback_msg.sequence))
|
||||
|
||||
# Publish the feedback
|
||||
goal_handle.publish_feedback(feedback_msg)
|
||||
|
||||
# Sleep for demonstration purposes
|
||||
time.sleep(1)
|
||||
|
||||
goal_handle.succeed()
|
||||
|
||||
# Populate result message
|
||||
result = Fibonacci.Result()
|
||||
result.sequence = feedback_msg.sequence
|
||||
|
||||
self.get_logger().info(
|
||||
'Returning result: {0}'.format(result.sequence))
|
||||
|
||||
return result
|
||||
finally:
|
||||
with self._goal_queue_lock:
|
||||
try:
|
||||
# Start execution of the next goal in the queue.
|
||||
self._current_goal = self._goal_queue.popleft()
|
||||
self.get_logger().info('Next goal pulled from the queue')
|
||||
self._current_goal.execute()
|
||||
except IndexError:
|
||||
# No goal in the queue.
|
||||
self._current_goal = None
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
minimal_action_server = MinimalActionServer()
|
||||
|
||||
executor = MultiThreadedExecutor()
|
||||
|
||||
rclpy.spin(minimal_action_server, executor=executor)
|
||||
|
||||
minimal_action_server.destroy()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,131 @@
|
||||
# Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
from example_interfaces.action import Fibonacci
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionServer, CancelResponse, GoalResponse
|
||||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||||
from rclpy.executors import MultiThreadedExecutor
|
||||
from rclpy.node import Node
|
||||
|
||||
|
||||
class MinimalActionServer(Node):
|
||||
"""Minimal action server that processes one goal at a time."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('minimal_action_server')
|
||||
self._goal_handle = None
|
||||
self._goal_lock = threading.Lock()
|
||||
self._action_server = ActionServer(
|
||||
self,
|
||||
Fibonacci,
|
||||
'fibonacci',
|
||||
execute_callback=self.execute_callback,
|
||||
goal_callback=self.goal_callback,
|
||||
handle_accepted_callback=self.handle_accepted_callback,
|
||||
cancel_callback=self.cancel_callback,
|
||||
callback_group=ReentrantCallbackGroup())
|
||||
|
||||
def destroy(self):
|
||||
self._action_server.destroy()
|
||||
super().destroy_node()
|
||||
|
||||
def goal_callback(self, goal_request):
|
||||
"""Accept or reject a client request to begin an action."""
|
||||
self.get_logger().info('Received goal request')
|
||||
return GoalResponse.ACCEPT
|
||||
|
||||
def handle_accepted_callback(self, goal_handle):
|
||||
with self._goal_lock:
|
||||
# This server only allows one goal at a time
|
||||
if self._goal_handle is not None and self._goal_handle.is_active:
|
||||
self.get_logger().info('Aborting previous goal')
|
||||
# Abort the existing goal
|
||||
self._goal_handle.abort()
|
||||
self._goal_handle = goal_handle
|
||||
|
||||
goal_handle.execute()
|
||||
|
||||
def cancel_callback(self, goal):
|
||||
"""Accept or reject a client request to cancel an action."""
|
||||
self.get_logger().info('Received cancel request')
|
||||
return CancelResponse.ACCEPT
|
||||
|
||||
def execute_callback(self, goal_handle):
|
||||
"""Execute the goal."""
|
||||
self.get_logger().info('Executing goal...')
|
||||
|
||||
# Append the seeds for the Fibonacci sequence
|
||||
feedback_msg = Fibonacci.Feedback()
|
||||
feedback_msg.sequence = [0, 1]
|
||||
|
||||
# Start executing the action
|
||||
for i in range(1, goal_handle.request.order):
|
||||
# If goal is flagged as no longer active (ie. another goal was accepted),
|
||||
# then stop executing
|
||||
if not goal_handle.is_active:
|
||||
self.get_logger().info('Goal aborted')
|
||||
return Fibonacci.Result()
|
||||
|
||||
if goal_handle.is_cancel_requested:
|
||||
goal_handle.canceled()
|
||||
self.get_logger().info('Goal canceled')
|
||||
return Fibonacci.Result()
|
||||
|
||||
# Update Fibonacci sequence
|
||||
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
|
||||
|
||||
self.get_logger().info('Publishing feedback: {0}'.format(feedback_msg.sequence))
|
||||
|
||||
# Publish the feedback
|
||||
goal_handle.publish_feedback(feedback_msg)
|
||||
|
||||
# Sleep for demonstration purposes
|
||||
time.sleep(1)
|
||||
|
||||
with self._goal_lock:
|
||||
if not goal_handle.is_active:
|
||||
self.get_logger().info('Goal aborted')
|
||||
return Fibonacci.Result()
|
||||
|
||||
goal_handle.succeed()
|
||||
|
||||
# Populate result message
|
||||
result = Fibonacci.Result()
|
||||
result.sequence = feedback_msg.sequence
|
||||
|
||||
self.get_logger().info('Returning result: {0}'.format(result.sequence))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
action_server = MinimalActionServer()
|
||||
|
||||
# We use a MultiThreadedExecutor to handle incoming goal requests concurrently
|
||||
executor = MultiThreadedExecutor()
|
||||
rclpy.spin(action_server, executor=executor)
|
||||
|
||||
action_server.destroy()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
example_interfaces:rclpy
|
||||
@@ -0,0 +1 @@
|
||||
prepend-non-duplicate;AMENT_PREFIX_PATH;
|
||||
@@ -0,0 +1,3 @@
|
||||
# generated from colcon_powershell/shell/template/hook_prepend_value.ps1.em
|
||||
|
||||
colcon_prepend_unique_value AMENT_PREFIX_PATH "$env:COLCON_CURRENT_PREFIX"
|
||||
@@ -0,0 +1,3 @@
|
||||
# generated from colcon_core/shell/template/hook_prepend_value.sh.em
|
||||
|
||||
_colcon_prepend_unique_value AMENT_PREFIX_PATH "$COLCON_CURRENT_PREFIX"
|
||||
@@ -0,0 +1 @@
|
||||
prepend-non-duplicate;PYTHONPATH;lib/python3.10/site-packages
|
||||
@@ -0,0 +1,3 @@
|
||||
# generated from colcon_powershell/shell/template/hook_prepend_value.ps1.em
|
||||
|
||||
colcon_prepend_unique_value PYTHONPATH "$env:COLCON_CURRENT_PREFIX\lib/python3.10/site-packages"
|
||||
@@ -0,0 +1,3 @@
|
||||
# generated from colcon_core/shell/template/hook_prepend_value.sh.em
|
||||
|
||||
_colcon_prepend_unique_value PYTHONPATH "$COLCON_CURRENT_PREFIX/lib/python3.10/site-packages"
|
||||
@@ -0,0 +1,31 @@
|
||||
# generated from colcon_bash/shell/template/package.bash.em
|
||||
|
||||
# This script extends the environment for this package.
|
||||
|
||||
# a bash script is able to determine its own path if necessary
|
||||
if [ -z "$COLCON_CURRENT_PREFIX" ]; then
|
||||
# the prefix is two levels up from the package specific share directory
|
||||
_colcon_package_bash_COLCON_CURRENT_PREFIX="$(builtin cd "`dirname "${BASH_SOURCE[0]}"`/../.." > /dev/null && pwd)"
|
||||
else
|
||||
_colcon_package_bash_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
|
||||
fi
|
||||
|
||||
# function to source another script with conditional trace output
|
||||
# first argument: the path of the script
|
||||
# additional arguments: arguments to the script
|
||||
_colcon_package_bash_source_script() {
|
||||
if [ -f "$1" ]; then
|
||||
if [ -n "$COLCON_TRACE" ]; then
|
||||
echo "# . \"$1\""
|
||||
fi
|
||||
. "$@"
|
||||
else
|
||||
echo "not found: \"$1\"" 1>&2
|
||||
fi
|
||||
}
|
||||
|
||||
# source sh script of this package
|
||||
_colcon_package_bash_source_script "$_colcon_package_bash_COLCON_CURRENT_PREFIX/share/examples_rclpy_minimal_action_server/package.sh"
|
||||
|
||||
unset _colcon_package_bash_source_script
|
||||
unset _colcon_package_bash_COLCON_CURRENT_PREFIX
|
||||
@@ -0,0 +1,6 @@
|
||||
source;share/examples_rclpy_minimal_action_server/hook/pythonpath.ps1
|
||||
source;share/examples_rclpy_minimal_action_server/hook/pythonpath.dsv
|
||||
source;share/examples_rclpy_minimal_action_server/hook/pythonpath.sh
|
||||
source;share/examples_rclpy_minimal_action_server/hook/ament_prefix_path.ps1
|
||||
source;share/examples_rclpy_minimal_action_server/hook/ament_prefix_path.dsv
|
||||
source;share/examples_rclpy_minimal_action_server/hook/ament_prefix_path.sh
|
||||
@@ -0,0 +1,116 @@
|
||||
# generated from colcon_powershell/shell/template/package.ps1.em
|
||||
|
||||
# function to append a value to a variable
|
||||
# which uses colons as separators
|
||||
# duplicates as well as leading separators are avoided
|
||||
# first argument: the name of the result variable
|
||||
# second argument: the value to be prepended
|
||||
function colcon_append_unique_value {
|
||||
param (
|
||||
$_listname,
|
||||
$_value
|
||||
)
|
||||
|
||||
# get values from variable
|
||||
if (Test-Path Env:$_listname) {
|
||||
$_values=(Get-Item env:$_listname).Value
|
||||
} else {
|
||||
$_values=""
|
||||
}
|
||||
$_duplicate=""
|
||||
# start with no values
|
||||
$_all_values=""
|
||||
# iterate over existing values in the variable
|
||||
if ($_values) {
|
||||
$_values.Split(";") | ForEach {
|
||||
# not an empty string
|
||||
if ($_) {
|
||||
# not a duplicate of _value
|
||||
if ($_ -eq $_value) {
|
||||
$_duplicate="1"
|
||||
}
|
||||
if ($_all_values) {
|
||||
$_all_values="${_all_values};$_"
|
||||
} else {
|
||||
$_all_values="$_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# append only non-duplicates
|
||||
if (!$_duplicate) {
|
||||
# avoid leading separator
|
||||
if ($_all_values) {
|
||||
$_all_values="${_all_values};${_value}"
|
||||
} else {
|
||||
$_all_values="${_value}"
|
||||
}
|
||||
}
|
||||
|
||||
# export the updated variable
|
||||
Set-Item env:\$_listname -Value "$_all_values"
|
||||
}
|
||||
|
||||
# function to prepend a value to a variable
|
||||
# which uses colons as separators
|
||||
# duplicates as well as trailing separators are avoided
|
||||
# first argument: the name of the result variable
|
||||
# second argument: the value to be prepended
|
||||
function colcon_prepend_unique_value {
|
||||
param (
|
||||
$_listname,
|
||||
$_value
|
||||
)
|
||||
|
||||
# get values from variable
|
||||
if (Test-Path Env:$_listname) {
|
||||
$_values=(Get-Item env:$_listname).Value
|
||||
} else {
|
||||
$_values=""
|
||||
}
|
||||
# start with the new value
|
||||
$_all_values="$_value"
|
||||
# iterate over existing values in the variable
|
||||
if ($_values) {
|
||||
$_values.Split(";") | ForEach {
|
||||
# not an empty string
|
||||
if ($_) {
|
||||
# not a duplicate of _value
|
||||
if ($_ -ne $_value) {
|
||||
# keep non-duplicate values
|
||||
$_all_values="${_all_values};$_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# export the updated variable
|
||||
Set-Item env:\$_listname -Value "$_all_values"
|
||||
}
|
||||
|
||||
# function to source another script with conditional trace output
|
||||
# first argument: the path of the script
|
||||
# additional arguments: arguments to the script
|
||||
function colcon_package_source_powershell_script {
|
||||
param (
|
||||
$_colcon_package_source_powershell_script
|
||||
)
|
||||
# source script with conditional trace output
|
||||
if (Test-Path $_colcon_package_source_powershell_script) {
|
||||
if ($env:COLCON_TRACE) {
|
||||
echo ". '$_colcon_package_source_powershell_script'"
|
||||
}
|
||||
. "$_colcon_package_source_powershell_script"
|
||||
} else {
|
||||
Write-Error "not found: '$_colcon_package_source_powershell_script'"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# a powershell script is able to determine its own path
|
||||
# the prefix is two levels up from the package specific share directory
|
||||
$env:COLCON_CURRENT_PREFIX=(Get-Item $PSCommandPath).Directory.Parent.Parent.FullName
|
||||
|
||||
colcon_package_source_powershell_script "$env:COLCON_CURRENT_PREFIX\share/examples_rclpy_minimal_action_server/hook/pythonpath.ps1"
|
||||
colcon_package_source_powershell_script "$env:COLCON_CURRENT_PREFIX\share/examples_rclpy_minimal_action_server/hook/ament_prefix_path.ps1"
|
||||
|
||||
Remove-Item Env:\COLCON_CURRENT_PREFIX
|
||||
@@ -0,0 +1,87 @@
|
||||
# generated from colcon_core/shell/template/package.sh.em
|
||||
|
||||
# This script extends the environment for this package.
|
||||
|
||||
# function to prepend a value to a variable
|
||||
# which uses colons as separators
|
||||
# duplicates as well as trailing separators are avoided
|
||||
# first argument: the name of the result variable
|
||||
# second argument: the value to be prepended
|
||||
_colcon_prepend_unique_value() {
|
||||
# arguments
|
||||
_listname="$1"
|
||||
_value="$2"
|
||||
|
||||
# get values from variable
|
||||
eval _values=\"\$$_listname\"
|
||||
# backup the field separator
|
||||
_colcon_prepend_unique_value_IFS=$IFS
|
||||
IFS=":"
|
||||
# start with the new value
|
||||
_all_values="$_value"
|
||||
# workaround SH_WORD_SPLIT not being set in zsh
|
||||
if [ "$(command -v colcon_zsh_convert_to_array)" ]; then
|
||||
colcon_zsh_convert_to_array _values
|
||||
fi
|
||||
# iterate over existing values in the variable
|
||||
for _item in $_values; do
|
||||
# ignore empty strings
|
||||
if [ -z "$_item" ]; then
|
||||
continue
|
||||
fi
|
||||
# ignore duplicates of _value
|
||||
if [ "$_item" = "$_value" ]; then
|
||||
continue
|
||||
fi
|
||||
# keep non-duplicate values
|
||||
_all_values="$_all_values:$_item"
|
||||
done
|
||||
unset _item
|
||||
# restore the field separator
|
||||
IFS=$_colcon_prepend_unique_value_IFS
|
||||
unset _colcon_prepend_unique_value_IFS
|
||||
# export the updated variable
|
||||
eval export $_listname=\"$_all_values\"
|
||||
unset _all_values
|
||||
unset _values
|
||||
|
||||
unset _value
|
||||
unset _listname
|
||||
}
|
||||
|
||||
# since a plain shell script can't determine its own path when being sourced
|
||||
# either use the provided COLCON_CURRENT_PREFIX
|
||||
# or fall back to the build time prefix (if it exists)
|
||||
_colcon_package_sh_COLCON_CURRENT_PREFIX="/root/ros2_ws/install/examples_rclpy_minimal_action_server"
|
||||
if [ -z "$COLCON_CURRENT_PREFIX" ]; then
|
||||
if [ ! -d "$_colcon_package_sh_COLCON_CURRENT_PREFIX" ]; then
|
||||
echo "The build time path \"$_colcon_package_sh_COLCON_CURRENT_PREFIX\" doesn't exist. Either source a script for a different shell or set the environment variable \"COLCON_CURRENT_PREFIX\" explicitly." 1>&2
|
||||
unset _colcon_package_sh_COLCON_CURRENT_PREFIX
|
||||
return 1
|
||||
fi
|
||||
COLCON_CURRENT_PREFIX="$_colcon_package_sh_COLCON_CURRENT_PREFIX"
|
||||
fi
|
||||
unset _colcon_package_sh_COLCON_CURRENT_PREFIX
|
||||
|
||||
# function to source another script with conditional trace output
|
||||
# first argument: the path of the script
|
||||
# additional arguments: arguments to the script
|
||||
_colcon_package_sh_source_script() {
|
||||
if [ -f "$1" ]; then
|
||||
if [ -n "$COLCON_TRACE" ]; then
|
||||
echo "# . \"$1\""
|
||||
fi
|
||||
. "$@"
|
||||
else
|
||||
echo "not found: \"$1\"" 1>&2
|
||||
fi
|
||||
}
|
||||
|
||||
# source sh hooks
|
||||
_colcon_package_sh_source_script "$COLCON_CURRENT_PREFIX/share/examples_rclpy_minimal_action_server/hook/pythonpath.sh"
|
||||
_colcon_package_sh_source_script "$COLCON_CURRENT_PREFIX/share/examples_rclpy_minimal_action_server/hook/ament_prefix_path.sh"
|
||||
|
||||
unset _colcon_package_sh_source_script
|
||||
unset COLCON_CURRENT_PREFIX
|
||||
|
||||
# do not unset _colcon_prepend_unique_value since it might be used by non-primary shell hooks
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>examples_rclpy_minimal_action_server</name>
|
||||
<version>0.15.3</version>
|
||||
<description>Examples of minimal action servers using rclpy.</description>
|
||||
<maintainer email="sloretz@openrobotics.org">Shane Loretz</maintainer>
|
||||
<maintainer email="aditya.pande@openrobotics.org">Aditya Pande</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<author email="jacob@openrobotics.org">Jacob Perron</author>
|
||||
|
||||
<exec_depend>example_interfaces</exec_depend>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
|
||||
<!-- These test dependencies are optional
|
||||
Their purpose is to make sure that the code passes the linters -->
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,42 @@
|
||||
# generated from colcon_zsh/shell/template/package.zsh.em
|
||||
|
||||
# This script extends the environment for this package.
|
||||
|
||||
# a zsh script is able to determine its own path if necessary
|
||||
if [ -z "$COLCON_CURRENT_PREFIX" ]; then
|
||||
# the prefix is two levels up from the package specific share directory
|
||||
_colcon_package_zsh_COLCON_CURRENT_PREFIX="$(builtin cd -q "`dirname "${(%):-%N}"`/../.." > /dev/null && pwd)"
|
||||
else
|
||||
_colcon_package_zsh_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
|
||||
fi
|
||||
|
||||
# function to source another script with conditional trace output
|
||||
# first argument: the path of the script
|
||||
# additional arguments: arguments to the script
|
||||
_colcon_package_zsh_source_script() {
|
||||
if [ -f "$1" ]; then
|
||||
if [ -n "$COLCON_TRACE" ]; then
|
||||
echo "# . \"$1\""
|
||||
fi
|
||||
. "$@"
|
||||
else
|
||||
echo "not found: \"$1\"" 1>&2
|
||||
fi
|
||||
}
|
||||
|
||||
# function to convert array-like strings into arrays
|
||||
# to workaround SH_WORD_SPLIT not being set
|
||||
colcon_zsh_convert_to_array() {
|
||||
local _listname=$1
|
||||
local _dollar="$"
|
||||
local _split="{="
|
||||
local _to_array="(\"$_dollar$_split$_listname}\")"
|
||||
eval $_listname=$_to_array
|
||||
}
|
||||
|
||||
# source sh script of this package
|
||||
_colcon_package_zsh_source_script "$_colcon_package_zsh_COLCON_CURRENT_PREFIX/share/examples_rclpy_minimal_action_server/package.sh"
|
||||
unset convert_zsh_to_array
|
||||
|
||||
unset _colcon_package_zsh_source_script
|
||||
unset _colcon_package_zsh_COLCON_CURRENT_PREFIX
|
||||
Reference in New Issue
Block a user