Skip to content

Commit 27dd785

Browse files
authored
Merge pull request #102 from MisterOwlPT/fix_action_server
Fix bug with action server (issue #95)
2 parents 0ee3205 + fb70657 commit 27dd785

File tree

6 files changed

+96
-24
lines changed

6 files changed

+96
-24
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ jobs:
4141
python -m pip install --no-cache-dir -r requirements-dev.txt
4242
- name: Set up docker containers
4343
run: |
44-
docker build -t gramaziokohler/rosbridge ./docker
45-
docker run -d -p 9090:9090 --name rosbridge gramaziokohler/rosbridge /bin/bash -c "roslaunch /integration-tests.launch"
44+
docker build -t gramaziokohler/rosbridge:integration_tests ./docker
45+
docker run -d -p 9090:9090 --name rosbridge gramaziokohler/rosbridge:integration_tests /bin/bash -c "roslaunch /integration-tests.launch"
4646
docker ps -a
4747
- name: Run linter
4848
run: |

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ Authors
88
* Beverly Lytle `@beverlylytle <https://github.com/beverlylytle>`_
99
* Alexis Jeandeau `@jeandeaual <https://github.com/jeandeaual>`_
1010
* Hiroyuki Obinata `@obi-t4 <https://github.com/obi-t4>`_
11+
* Pedro Pereira `@MisterOwlPT <https://github.com/MisterOwlPT>`_
1112
* Domenic Rodriguez `@DomenicP <https://github.com/DomenicP>`_

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Unreleased
1616

1717
**Fixed**
1818

19+
* Fixed bug with action client/server and now they work as expected.
20+
1921
**Deprecated**
2022

2123
**Removed**

docker/Dockerfile

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
FROM ros:kinetic
1+
FROM ros:noetic
22
LABEL maintainer "Gonzalo Casas <[email protected]>"
33

4+
SHELL ["/bin/bash","-c"]
5+
46
# Install rosbridge
57
RUN apt-get update && apt-get install -y \
6-
ros-kinetic-rosbridge-suite \
7-
ros-kinetic-tf2-web-republisher \
8-
ros-kinetic-ros-tutorials \
8+
ros-noetic-rosbridge-suite \
9+
ros-noetic-tf2-web-republisher \
10+
ros-noetic-ros-tutorials \
11+
ros-noetic-actionlib-tutorials \
912
--no-install-recommends \
1013
# Clear apt-cache to reduce image size
1114
&& rm -rf /var/lib/apt/lists/*
@@ -17,4 +20,4 @@ COPY ./integration-tests.launch /
1720
EXPOSE 9090
1821

1922
ENTRYPOINT ["/ros_entrypoint.sh"]
20-
CMD ["/bin/bash"]
23+
CMD ["bash"]

src/roslibpy/actionlib.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def __init__(self, ros, server_name, action_name):
326326

327327
# Intentionally not publishing immediately and instead
328328
# waiting one interval for the first message
329-
self.ros.call_later(self.STATUS_PUBLISH_INTERVAL, self._publish_status)
329+
self.ros.call_later(self.STATUS_PUBLISH_INTERVAL, self._periodic_publish_status)
330330

331331
def start(self, action_callback):
332332
"""Start the action server.
@@ -349,18 +349,22 @@ def _internal_preempt_callback():
349349
self.on("cancel", _internal_preempt_callback)
350350

351351
def _publish_status(self):
352+
current_time = time.time()
353+
secs = int(math.floor(current_time))
354+
nsecs = int(round(1e9 * (current_time - secs)))
355+
356+
self.status_message["header"]["stamp"]["secs"] = secs
357+
self.status_message["header"]["stamp"]["nsecs"] = nsecs
358+
359+
self.status_publisher.publish(self.status_message)
360+
361+
def _periodic_publish_status(self):
352362
# Status publishing is required for clients to know they've connected
353363
with self._lock:
354-
current_time = time.time()
355-
secs = int(math.floor(current_time))
356-
nsecs = int(round(1e9 * (current_time - secs)))
357-
358-
self.status_message["header"]["stamp"]["secs"] = secs
359-
self.status_message["header"]["stamp"]["nsecs"] = nsecs
360-
self.status_publisher.publish(self.status_message)
364+
self._publish_status()
361365

362366
# Invoke again in the defined interval
363-
self.ros.call_later(self.STATUS_PUBLISH_INTERVAL, self._publish_status)
367+
self.ros.call_later(self.STATUS_PUBLISH_INTERVAL, self._periodic_publish_status)
364368

365369
def _on_goal_message(self, message):
366370
will_cancel = False
@@ -428,14 +432,14 @@ def set_succeeded(self, result):
428432
LOGGER.info("Action server {} setting current goal to SUCCEEDED".format(self.server_name))
429433

430434
with self._lock:
431-
result_message = Message(
432-
{"status": {"goal_id": self.current_goal["goal_id"], "status": GoalStatus.SUCCEEDED}, "result": result}
433-
)
435+
status = dict(goal_id=self.current_goal["goal_id"], status=GoalStatus.SUCCEEDED)
436+
self.status_message["status_list"] = [status]
437+
self._publish_status()
438+
self.status_message["status_list"] = []
434439

440+
result_message = Message({"status": status, "result": result})
435441
self.result_publisher.publish(result_message)
436442

437-
self.status_message["status_list"] = []
438-
439443
if self.next_goal:
440444
self.current_goal = self.next_goal
441445
self.next_goal = None
@@ -465,11 +469,12 @@ def set_preempted(self):
465469
LOGGER.info("Action server {} preempting current goal".format(self.server_name))
466470

467471
with self._lock:
472+
status = dict(goal_id=self.current_goal["goal_id"], status=GoalStatus.PREEMPTED)
473+
self.status_message["status_list"] = [status]
474+
self._publish_status()
468475
self.status_message["status_list"] = []
469-
result_message = Message(
470-
{"status": {"goal_id": self.current_goal["goal_id"], "status": GoalStatus.PREEMPTED}}
471-
)
472476

477+
result_message = Message({"status": status})
473478
self.result_publisher.publish(result_message)
474479

475480
if self.next_goal:

tests/test_actionlib.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from __future__ import print_function
2+
3+
import time
4+
5+
from roslibpy import Ros
6+
from roslibpy.actionlib import ActionClient, Goal, GoalStatus, SimpleActionServer
7+
8+
9+
def test_action_success():
10+
ros = Ros("127.0.0.1", 9090)
11+
ros.run()
12+
13+
server = SimpleActionServer(ros, "/test_action", "actionlib/TestAction")
14+
15+
def execute(goal):
16+
server.set_succeeded({"result": goal["goal"]})
17+
18+
server.start(execute)
19+
20+
client = ActionClient(ros, "/test_action", "actionlib/TestAction")
21+
goal = Goal(client, {"goal": 13})
22+
23+
goal.send()
24+
result = goal.wait(10)
25+
26+
assert result["result"] == 13
27+
assert goal.status["status"] == GoalStatus.SUCCEEDED
28+
29+
client.dispose()
30+
time.sleep(2)
31+
ros.close()
32+
33+
34+
def test_action_preemt():
35+
ros = Ros("127.0.0.1", 9090)
36+
ros.run()
37+
38+
server = SimpleActionServer(ros, "/test_action", "actionlib/TestAction")
39+
40+
def execute(_goal):
41+
while not server.is_preempt_requested():
42+
time.sleep(0.1)
43+
server.set_preempted()
44+
45+
server.start(execute)
46+
47+
client = ActionClient(ros, "/test_action", "actionlib/TestAction")
48+
goal = Goal(client, {"goal": 13})
49+
50+
goal.send()
51+
time.sleep(0.5)
52+
goal.cancel()
53+
54+
result = goal.wait(10)
55+
56+
assert result["result"] == 0
57+
assert goal.status["status"] == GoalStatus.PREEMPTED
58+
59+
client.dispose()
60+
time.sleep(2)
61+
ros.close()

0 commit comments

Comments
 (0)