Skip to content

Commit dd61101

Browse files
amalnanavatiTaylor Kessler Faulkner
andauthored
Write a nano_bridge (#193)
* Add nano_bridge * Set perception nodes default QoS to best effort, history 1 * Finalize nano_bridge * Add README * Fixes from sim testing --------- Co-authored-by: Taylor Kessler Faulkner <taylorkf@cs.washington.edu>
1 parent 330e356 commit dd61101

26 files changed

+807
-38
lines changed

ada_feeding_perception/ada_feeding_perception/face_detection.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from rclpy.node import Node
2424
from rclpy.parameter import Parameter
2525
from rclpy.executors import MultiThreadedExecutor
26+
from rclpy.qos import QoSProfile, ReliabilityPolicy
2627
from rcl_interfaces.msg import ParameterDescriptor, ParameterType
2728
from sensor_msgs.msg import CompressedImage, CameraInfo, Image
2829
from skspatial.objects import Plane, Points
@@ -159,7 +160,7 @@ def __init__(
159160
image_type,
160161
image_topic,
161162
self.camera_callback,
162-
1,
163+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
163164
callback_group=MutuallyExclusiveCallbackGroup(),
164165
)
165166

@@ -179,7 +180,7 @@ def __init__(
179180
aligned_depth_type,
180181
aligned_depth_topic,
181182
self.depth_callback,
182-
1,
183+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
183184
callback_group=MutuallyExclusiveCallbackGroup(),
184185
)
185186

@@ -192,7 +193,7 @@ def __init__(
192193
CameraInfo,
193194
"~/camera_info",
194195
self.camera_info_callback,
195-
1,
196+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
196197
callback_group=MutuallyExclusiveCallbackGroup(),
197198
)
198199

ada_feeding_perception/ada_feeding_perception/food_on_fork_detection.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class to use and kwargs for the class's constructor; (b) exposes a ROS2 service
2121
from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
2222
from rclpy.executors import MultiThreadedExecutor
2323
from rclpy.node import Node
24+
from rclpy.qos import QoSProfile, ReliabilityPolicy
2425
from sensor_msgs.msg import CameraInfo, CompressedImage, Image
2526
from std_srvs.srv import SetBool
2627
from tf2_ros.buffer import Buffer
@@ -129,7 +130,7 @@ def __init__(self):
129130
CameraInfo,
130131
"~/camera_info",
131132
self.camera_info_callback,
132-
1,
133+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
133134
callback_group=MutuallyExclusiveCallbackGroup(),
134135
)
135136

@@ -150,7 +151,7 @@ def __init__(self):
150151
aligned_depth_type,
151152
aligned_depth_topic,
152153
self.depth_callback,
153-
1,
154+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
154155
callback_group=MutuallyExclusiveCallbackGroup(),
155156
)
156157

@@ -174,7 +175,7 @@ def __init__(self):
174175
image_type,
175176
image_topic,
176177
self.camera_callback,
177-
1,
178+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
178179
callback_group=MutuallyExclusiveCallbackGroup(),
179180
)
180181

ada_feeding_perception/ada_feeding_perception/republisher.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
2626
from rclpy.executors import MultiThreadedExecutor
2727
from rclpy.node import Node
28+
from rclpy.qos import QoSProfile, ReliabilityPolicy
2829

2930
# Local imports
3031
from ada_feeding.helpers import import_from_string
@@ -208,7 +209,9 @@ def __init__(self) -> None:
208209
msg_type=self.in_topic_types[i],
209210
topic=self.from_topics[i],
210211
callback=callback,
211-
qos_profile=1, # TODO: we should get and mirror the QOS profile of the from_topic
212+
qos_profile=QoSProfile(
213+
depth=1, reliability=ReliabilityPolicy.BEST_EFFORT
214+
), # TODO: we should get and mirror the QOS profile of the from_topic
212215
callback_group=MutuallyExclusiveCallbackGroup(),
213216
)
214217
self.subs.append(subscriber)

ada_feeding_perception/ada_feeding_perception/segment_from_point.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from rclpy.executors import MultiThreadedExecutor
2424
from rclpy.node import Node
2525
from rclpy.parameter import Parameter
26+
from rclpy.qos import QoSProfile, ReliabilityPolicy
2627
from segment_anything import sam_model_registry, SamPredictor
2728
from sensor_msgs.msg import CameraInfo, CompressedImage, Image, RegionOfInterest
2829
import torch
@@ -98,7 +99,7 @@ def __init__(self) -> None:
9899
CameraInfo,
99100
"~/camera_info",
100101
self.camera_info_callback,
101-
1,
102+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
102103
callback_group=MutuallyExclusiveCallbackGroup(),
103104
)
104105

@@ -118,7 +119,7 @@ def __init__(self) -> None:
118119
aligned_depth_type,
119120
aligned_depth_topic,
120121
self.depth_image_callback,
121-
1,
122+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
122123
callback_group=MutuallyExclusiveCallbackGroup(),
123124
)
124125

@@ -137,7 +138,7 @@ def __init__(self) -> None:
137138
image_type,
138139
image_topic,
139140
self.image_callback,
140-
1,
141+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
141142
callback_group=MutuallyExclusiveCallbackGroup(),
142143
)
143144

ada_feeding_perception/ada_feeding_perception/table_detection.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
1717
from rclpy.executors import MultiThreadedExecutor
1818
from rclpy.node import Node
19+
from rclpy.qos import QoSProfile, ReliabilityPolicy
1920
from rcl_interfaces.msg import ParameterDescriptor, ParameterType
2021
from sensor_msgs.msg import CameraInfo, CompressedImage, Image
2122
from std_srvs.srv import SetBool
@@ -85,7 +86,7 @@ def __init__(self):
8586
CameraInfo,
8687
"~/camera_info",
8788
self.camera_info_callback,
88-
1,
89+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
8990
callback_group=MutuallyExclusiveCallbackGroup(),
9091
)
9192

@@ -104,7 +105,7 @@ def __init__(self):
104105
aligned_depth_type,
105106
aligned_depth_topic,
106107
self.depth_image_callback,
107-
1,
108+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
108109
callback_group=MutuallyExclusiveCallbackGroup(),
109110
)
110111

@@ -123,7 +124,7 @@ def __init__(self):
123124
image_type,
124125
image_topic,
125126
self.image_callback,
126-
1,
127+
QoSProfile(depth=1, reliability=ReliabilityPolicy.BEST_EFFORT),
127128
callback_group=MutuallyExclusiveCallbackGroup(),
128129
)
129130

ada_feeding_perception/config/republisher.yaml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,24 @@ republisher:
33
ros__parameters:
44
# The name of the topics to republish from
55
from_topics:
6-
- /camera/color/image_raw/compressed
7-
- /camera/color/camera_info
8-
- /camera/aligned_depth_to_color/image_raw/compressedDepth
96
- /camera/aligned_depth_to_color/camera_info
107
- /local/camera/aligned_depth_to_color/image_raw/compressedDepth
118

129
# The types of topics to republish from
1310
in_topic_types:
14-
- sensor_msgs.msg.CompressedImage
15-
- sensor_msgs.msg.CameraInfo
16-
- sensor_msgs.msg.CompressedImage
1711
- sensor_msgs.msg.CameraInfo
1812
- sensor_msgs.msg.CompressedImage
1913

2014
# If the republisher should convert types, specify the output type.
2115
# Currently, the republisher only supports conversions from
2216
# Image->CompressedImage and vice-versa.
2317
out_topic_types:
24-
- ""
25-
- ""
26-
- ""
2718
- ""
2819
- sensor_msgs.msg.Image
2920

3021
# The name of the topics to republish to. NOTE: the `prefix` in the launchfile
3122
# must match the below pattern!
3223
to_topics:
33-
- /local/camera/color/image_raw/compressed
34-
- /local/camera/color/camera_info
35-
- /local/camera/aligned_depth_to_color/image_raw/compressedDepth
3624
- /local/camera/aligned_depth_to_color/camera_info
3725
- /local/camera/aligned_depth_to_color/depth_octomap
3826

@@ -41,9 +29,6 @@ republisher:
4129
target_rates:
4230
- 0
4331
- 0
44-
- 0
45-
- 0
46-
- 0
4732

4833
# The names of a post-processing functions to apply to the message before
4934
# republishing it. Current options are:
@@ -58,9 +43,6 @@ republisher:
5843
# Any of these post-processing functions can be combined in a comma-separated list.
5944
# If an empty string, no post-processors are applied.
6045
post_processors:
61-
- ""
62-
- ""
63-
- ""
6446
- ""
6547
- threshold,mask,temporal,spatial # Apply filters to the depth image for the Octomap
6648
# The binary mask used for "mask" post-processing. This mask will get scaled,

ada_feeding_perception/launch/ada_feeding_perception.launch.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@
99
from launch_ros.actions import Node
1010
from launch_ros.parameter_descriptions import ParameterValue
1111
from launch import LaunchDescription
12-
from launch.actions import DeclareLaunchArgument
12+
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
1313
from launch.conditions import IfCondition
14-
from launch.substitutions import LaunchConfiguration, PythonExpression
14+
from launch.launch_description_sources import AnyLaunchDescriptionSource
15+
from launch.substitutions import (
16+
LaunchConfiguration,
17+
PathJoinSubstitution,
18+
PythonExpression,
19+
)
1520

1621

1722
# pylint: disable=too-many-locals
@@ -47,6 +52,20 @@ def generate_launch_description():
4752
)
4853
launch_description.add_action(republisher)
4954

55+
# Add the nano_bridge receiver node
56+
nano_bridge_receiver = IncludeLaunchDescription(
57+
AnyLaunchDescriptionSource(
58+
PathJoinSubstitution(
59+
[
60+
get_package_share_directory("nano_bridge"),
61+
"launch",
62+
"receiver.launch.xml",
63+
]
64+
),
65+
),
66+
)
67+
launch_description.add_action(nano_bridge_receiver)
68+
5069
# Remap from the perception nodes to the realsense topics
5170
prefix = "/local" # NOTE: must match the topic names in the yaml file!
5271
realsense_remappings = [
@@ -58,7 +77,9 @@ def generate_launch_description():
5877
),
5978
(
6079
"~/camera_info",
61-
PythonExpression(expression=["'", prefix, "/camera/color/camera_info'"]),
80+
PythonExpression(
81+
expression=["'", prefix, "/camera/aligned_depth_to_color/camera_info'"]
82+
),
6283
),
6384
]
6485
aligned_depth_remapping = [

ada_planning_scene/ada_planning_scene/workspace_walls.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,10 +1057,9 @@ def initialize(
10571057
success = self.__update_robot_configuration_bounds(
10581058
rate_hz=rate_hz,
10591059
timeout=get_remaining_time(self.__node, start_time, timeout),
1060-
# For repeatability, during initialization we don't account for the
1061-
# current robot config, but during every other update, we do if
1062-
# the parameter is set.
1063-
include_current_robot_config=False,
1060+
# Although accounting for the current configuration during initialization
1061+
# harms repeatability, it does ensure the robot will always be able to move.
1062+
include_current_robot_config=True,
10641063
)
10651064
if not success:
10661065
self.__node.get_logger().info(

nano_bridge/CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(nano_bridge)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
# find dependencies
9+
find_package(ament_cmake REQUIRED)
10+
find_package(rosidl_default_generators REQUIRED)
11+
find_package(sensor_msgs REQUIRED)
12+
13+
rosidl_generate_interfaces(${PROJECT_NAME}
14+
"msg/CompressedImage.msg"
15+
DEPENDENCIES sensor_msgs
16+
)
17+
18+
# Install Python executables
19+
install(PROGRAMS
20+
nano_bridge/sender.py
21+
nano_bridge/sender_compressed_image.py
22+
nano_bridge/receiver.py
23+
nano_bridge/receiver_compressed_image.py
24+
DESTINATION lib/${PROJECT_NAME}
25+
)
26+
27+
# Install launch files.
28+
install(DIRECTORY
29+
launch
30+
DESTINATION share/${PROJECT_NAME}/
31+
)
32+
33+
# Install config files.
34+
install(DIRECTORY
35+
config
36+
DESTINATION share/${PROJECT_NAME}/
37+
)
38+
39+
ament_package()

nano_bridge/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# nano_bridge
2+
3+
This package is very particular to our computer setting, intended to account for the fact that the publication rate of one of the two image topics (RGB and depth) becomes very unreliable when you have one subscriber each (which is common). See this issue for more: https://github.com/personalrobotics/ada_feeding/issues/73
4+
5+
`sender` and `receiver` are generic nodes that can serialize any number of ROS topics of any type into one ROS topic. However, pickle serialization can take ~0.2s, which can slow down the publisher. Hence, `sender_compressed_image` and `receiver_compressed_image` can combine any number of CompressedImage topics into one, but can only do it for those topics (and it doesn't have the overhead of serialization).
6+
7+
A future TODO is to create a generic way to handle cases where the input types are the same and are different, and to create a unified sender and receiver class.

0 commit comments

Comments
 (0)