Skip to content

Commit 692f41a

Browse files
authored
Support actions in rosbridge protocol (#886)
1 parent 910163b commit 692f41a

34 files changed

+2115
-128
lines changed

ROSBRIDGE_PROTOCOL.md

Lines changed: 145 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Optionally, a message can also provide an arbitrary string or integer ID:
5252

5353
```json
5454
{ "op": "Example",
55-
"id":"fred"
55+
"id": "fred"
5656
}
5757
```
5858

@@ -81,16 +81,24 @@ Rosbridge status messages:
8181

8282
ROS operations:
8383

84-
* **advertise** – advertise that you are publishing a topic
85-
* **unadvertise** – stop advertising that you are publishing topic
86-
* **publish** - a published ROS-message
87-
* **subscribe** - a request to subscribe to a topic
88-
* **unsubscribe** - a request to unsubscribe from a topic
89-
* **call_service** - a service call
90-
* **advertise_service** - advertise an external service server
91-
* **unadvertise_service** - unadvertise an external service server
92-
* **service_request** - a service request
93-
* **service_response** - a service response
84+
* Topics:
85+
* **advertise** – advertise that you are publishing a topic
86+
* **unadvertise** – stop advertising that you are publishing topic
87+
* **publish** - a published ROS-message
88+
* **subscribe** - a request to subscribe to a topic
89+
* **unsubscribe** - a request to unsubscribe from a topic
90+
* Services:
91+
* **advertise_service** - advertise an external service server
92+
* **unadvertise_service** - unadvertise an external service server
93+
* **call_service** - a service call
94+
* **service_response** - a service response
95+
* Actions:
96+
* **advertise_action** - advertise an external action server
97+
* **unadvertise_action** - unadvertise an external action server
98+
* **send_action_goal** - a goal sent to an action server
99+
* **cancel_action_goal** - cancel an in-progress action goal
100+
* **action_feedback** - feedback messages from an action server
101+
* **action_result** - an action result
94102

95103
In general, actions or operations that the client takes (such as publishing and
96104
subscribing) have opcodes which are verbs (subscribe, call_service, unadvertise
@@ -264,8 +272,7 @@ messages that already exist in the current version of rosbridge.
264272

265273
#### 3.3.1 Advertise ( _advertise_ )
266274

267-
If you wish to advertise that you are or will be publishing a topic, then use
268-
the advertise command.
275+
If you wish to advertise that you are or will be publishing a topic, then use the advertise command.
269276

270277
```json
271278
{ "op": "advertise",
@@ -397,7 +404,31 @@ fragmentation size and publishing rate.
397404
If an id is provided, then only the corresponding subscription is unsubscribed.
398405
If no ID is provided, then all subscriptions are unsubscribed.
399406

400-
#### 3.3.6 Call Service
407+
#### 3.3.6 Advertise Service
408+
409+
```json
410+
{ "op": "advertise_service",
411+
"type": <string>,
412+
"service": <string>
413+
}
414+
```
415+
416+
Advertises an external ROS service server. Requests come to the client via Call Service.
417+
418+
* **service** – the name of the service to advertise
419+
* **type** – the advertised service message type
420+
421+
#### 3.3.7 Unadvertise Service
422+
423+
```json
424+
{ "op": "unadvertise_service",
425+
"service": <string>
426+
}
427+
```
428+
429+
#### 3.3.8 Call Service
430+
431+
Calls a ROS service.
401432

402433
```json
403434
{ "op": "call_service",
@@ -409,8 +440,6 @@ If no ID is provided, then all subscriptions are unsubscribed.
409440
}
410441
```
411442

412-
Calls a ROS service
413-
414443
* **service** – the name of the service to call
415444
* **args** – if the service has no args, then args does not have to be
416445
provided, though an empty list is equally acceptable. Args should be a list
@@ -421,34 +450,15 @@ Calls a ROS service
421450
* **compression** – an optional string to specify the compression scheme to be
422451
used on messages. Valid values are "none" and "png"
423452

424-
#### 3.3.7 Advertise Service
425-
426-
```json
427-
{ "op": "advertise_service",
428-
"type": <string>,
429-
"service": <string>
430-
}
431-
```
432-
433-
Advertises an external ROS service server. Requests come to the client via Call Service.
434-
435-
* **service** – the name of the service to advertise
436-
* **type** – the advertised service message type
437-
438-
#### 3.3.8 Unadvertise Service
439-
440-
```json
441-
{ "op": "unadvertise_service",
442-
"service": <string>
443-
}
444-
```
445453

446454
Stops advertising an external ROS service server
447455

448456
* **service** – the name of the service to unadvertise
449457

450458
#### 3.3.9 Service Response
451459

460+
A response to a ROS service call.
461+
452462
```json
453463
{ "op": "service_response",
454464
(optional) "id": <string>,
@@ -458,20 +468,115 @@ Stops advertising an external ROS service server
458468
}
459469
```
460470

461-
A response to a ROS service call
462-
463471
* **service** – the name of the service that was called
464472
* **values** – the return values. If the service had no return values, then
465473
this field can be omitted (and will be by the rosbridge server)
466474
* **id** – if an ID was provided to the service request, then the service
467475
response will contain the ID
468476
* **result** - return value of service callback. true means success, false failure.
469477

478+
#### 3.3.10 Advertise Action
479+
480+
Advertises an external ROS action server.
481+
482+
```json
483+
{ "op": "advertise_action",
484+
"type": <string>,
485+
"action": <string>
486+
}
487+
```
488+
489+
Goals come to the client via the Send Action Goal capability.
490+
491+
* **action** – the name of the action to advertise
492+
* **type** – the advertised action message type
493+
494+
#### 3.3.11 Unadvertise Action
495+
496+
```json
497+
{ "op": "unadvertise_action",
498+
"action": <string>
499+
}
500+
```
501+
502+
#### 3.3.12 Send Action Goal
503+
504+
Sends a goal to a ROS action server.
505+
506+
```json
507+
{ "op": "send_action_goal",
508+
(optional) "id": <string>,
509+
"action": <string>,
510+
"action_type: <string>,
511+
(optional) "args": <list<json>>,
512+
(optional) "feedback": <boolean>
513+
(optional) "fragment_size": <int>,
514+
(optional) "compression": <string>
515+
}
516+
```
517+
518+
* **action** – the name of the action to send a goal to
519+
* **action_type** – the action message type
520+
* **args** – if the goal has no args, then args does not have to be
521+
provided, though an empty list is equally acceptable. Args should be a list of json objects representing the arguments to the service.
522+
* **feedback** – if true, sends feedback messages over rosbridge. Defaults to false.
523+
* **id** – an optional id to distinguish this goal handle
524+
* **fragment_size** – the maximum size that the result and feedback messages can take before they are fragmented
525+
* **compression** – an optional string to specify the compression scheme to be used on messages. Valid values are "none" and "png"
526+
527+
#### 3.3.13 Cancel Action Goal
528+
529+
Cancels an action goal.
530+
531+
```json
532+
{ "op": "cancel_action_goal",
533+
"id": <string>,
534+
"action": <string>,
535+
}
536+
```
537+
538+
The `id` field must match an already in-progress goal.
539+
540+
#### 3.3.14 Action Feedback
541+
542+
Used to send action feedback for a specific goal handle.
543+
544+
```json
545+
{ "op": "action_feedback",
546+
"id": <string>,
547+
"action": <string>,
548+
"values": <json>,
549+
}
550+
```
551+
552+
The `id` field must match an already in-progress goal.
553+
554+
#### 3.3.15 Action Result
555+
556+
A result for a ROS action.
557+
558+
```json
559+
{ "op": "action_result",
560+
"id": <string>,
561+
"action": <string>,
562+
"values": <json>,
563+
"result": <boolean>
564+
}
565+
```
566+
567+
* **action** – the name of the action that was executed
568+
* **values** – the result values. If the service had no return values, then
569+
this field can be omitted (and will be by the rosbridge server)
570+
* **id** – if an ID was provided to the action goal, then the action result will contain the ID
571+
* **result** - return value of the action. true means success, false failure.
572+
573+
---
574+
470575
## 4 Further considerations
471576

472577
Further considerations for the rosbridge protocol are listed below.
473578

474-
### 4.1 Rosbridge psuedo-services
579+
### 4.1 Rosbridge pseudo-services
475580

476581
Rosbridge no longer provides the ROS-api introspection pseudo services that it
477582
previously did. These are, for example rosbridge/topics and rosbridge/services.

rosbridge_library/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<test_depend>builtin_interfaces</test_depend>
3636
<test_depend>diagnostic_msgs</test_depend>
3737
<test_depend>example_interfaces</test_depend>
38+
<test_depend>control_msgs</test_depend>
3839
<test_depend>geometry_msgs</test_depend>
3940
<test_depend>nav_msgs</test_depend>
4041
<test_depend>sensor_msgs</test_depend>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Software License Agreement (BSD License)
2+
#
3+
# Copyright (c) 2023, PickNik Inc.
4+
# All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions
8+
# are met:
9+
#
10+
# * Redistributions of source code must retain the above copyright
11+
# notice, this list of conditions and the following disclaimer.
12+
# * Redistributions in binary form must reproduce the above
13+
# copyright notice, this list of conditions and the following
14+
# disclaimer in the documentation and/or other materials provided
15+
# with the distribution.
16+
# * Neither the name of the copyright holder nor the names of its
17+
# contributors may be used to endorse or promote products derived
18+
# from this software without specific prior written permission.
19+
#
20+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23+
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24+
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29+
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30+
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
# POSSIBILITY OF SUCH DAMAGE.
32+
33+
from rosbridge_library.capability import Capability
34+
from rosbridge_library.internal import message_conversion, ros_loader
35+
from rosbridge_library.protocol import Protocol
36+
37+
38+
class ActionFeedback(Capability):
39+
40+
action_feedback_msg_fields = [
41+
(True, "action", str),
42+
(False, "id", str),
43+
(False, "values", dict),
44+
]
45+
46+
def __init__(self, protocol: Protocol) -> None:
47+
# Call superclass constructor
48+
Capability.__init__(self, protocol)
49+
50+
# Register the operations that this capability provides
51+
protocol.register_operation("action_feedback", self.action_feedback)
52+
53+
def action_feedback(self, message: dict) -> None:
54+
# Typecheck the args
55+
self.basic_type_check(message, self.action_feedback_msg_fields)
56+
57+
# check for the action
58+
action_name = message["action"]
59+
if action_name in self.protocol.external_action_list:
60+
action_handler = self.protocol.external_action_list[action_name]
61+
# parse the message
62+
goal_id = message["id"]
63+
values = message["values"]
64+
# create a message instance
65+
feedback = ros_loader.get_action_feedback_instance(action_handler.action_type)
66+
message_conversion.populate_instance(values, feedback)
67+
# pass along the feedback
68+
action_handler.handle_feedback(goal_id, feedback)
69+
else:
70+
self.protocol.log(
71+
"error",
72+
f"Action {action_name} has not been advertised via rosbridge.",
73+
)

0 commit comments

Comments
 (0)