Skip to content

Commit 6b2d3ef

Browse files
committed
Add navigation data to foxglove.
Signed-off-by: Jelmer de Wolde <jelmer.de.wolde@alliander.com>
1 parent c3d9bda commit 6b2d3ef

File tree

5 files changed

+128
-33
lines changed

5 files changed

+128
-33
lines changed

alliander_core/src/alliander_utilities/alliander_utilities/config_objects.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,12 @@ class VisualizationConfig(Config):
358358
359359
Attributes:
360360
rviz (bool): Whether to enable RViz visualization.
361+
foxglove (bool): Whether to enable Foxglove visualization.
361362
vizanti (bool): Whether to enable Vizanti visualization.
362363
gui (bool): Whether to enable GUI.
363364
"""
364365

365-
rviz: bool = True
366+
rviz: bool = False
367+
foxglove: bool = True
366368
vizanti: bool = False
367369
gui: bool = False

alliander_visualization/src/alliander_visualization/alliander_visualization/foxglove.py

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ class Foxglove:
1010
"""A class to dynammically manage the Foxglove layout.
1111
1212
Attributes:
13-
layout (dict): The default Foxglove layout.
13+
topics (list): The topics to bridge.
14+
services (list): The services to bridge.
15+
layout (dict): The Foxglove layout.
1416
"""
1517

18+
topics: list = ["/clock", "/tf", "/tf_static"]
19+
services: list = [""]
1620
layout: dict
1721

1822
with open(
@@ -37,26 +41,26 @@ def create_layout_file() -> None:
3741
reference = references[0]
3842
direction = "row" if reference["direction"] == "column" else "column"
3943
if places < len(panels):
40-
if reference["first"] == {}:
41-
reference["first"] = {
44+
if reference["second"] == {}:
45+
reference["second"] = {
4246
"first": {},
4347
"second": {},
4448
"direction": direction,
4549
}
46-
references.append(reference["first"])
50+
references.append(reference["second"])
4751
else:
48-
reference["second"] = {
52+
reference["first"] = {
4953
"first": {},
5054
"second": {},
5155
"direction": direction,
5256
}
53-
references.append(reference["second"])
57+
references.append(reference["first"])
5458
references.pop(0)
5559
places += 1
56-
elif reference["first"] == {}:
57-
reference["first"] = panels.pop(0)
60+
elif reference["second"] == {}:
61+
reference["second"] = panels.pop()
5862
else:
59-
reference["second"] = panels.pop(0)
63+
reference["first"] = panels.pop()
6064
references.pop(0)
6165

6266
Foxglove.layout["layout"] = layout
@@ -70,6 +74,7 @@ def add_platform_model(namespace: str) -> None:
7074
Args:
7175
namespace (str): The namespace of the robot.
7276
"""
77+
Foxglove.topics.append([f"/{namespace}/robot_description"])
7378
Foxglove.layout["configById"]["3D"]["layers"][f"urdf-{namespace}"] = {
7479
"layerId": "foxglove.Urdf",
7580
"sourceType": "topic",
@@ -78,19 +83,104 @@ def add_platform_model(namespace: str) -> None:
7883
}
7984

8085
@staticmethod
81-
def add_camera(namespace: str) -> None:
86+
def add_street_map(namespace: str) -> None:
87+
"""Add a street map to the Foxglove 3D panel.
88+
89+
Args:
90+
namespace (str): The namespace of the platform.
91+
"""
92+
Foxglove.topics.append(f"/{namespace}/gps/fix")
93+
Foxglove.topics.append(f"/{namespace}/gps/filtered")
94+
Foxglove.layout["configById"]["3D"]["layers"]["map"] = {
95+
"layerId": "foxglove.TiledMap",
96+
"visible": True,
97+
"serverConfig": "map",
98+
"label": "Map",
99+
}
100+
101+
@staticmethod
102+
def add_image(namespace: str) -> None:
82103
"""Add a camera feed to the Foxglove layout.
83104
84105
Args:
85-
namespace (str): The namespace of the robot.
106+
namespace (str): The namespace of the platform.
86107
"""
87-
Foxglove.layout["configById"][f"Image_{namespace}"] = {
108+
Foxglove.topics.append(f"/{namespace}/color/image_raw")
109+
Foxglove.topics.append(f"/{namespace}/color/camera_info")
110+
Foxglove.layout["configById"][f"Image!{namespace}"] = {
88111
"imageMode": {
89-
"imageTopic": f"/{namespace}/zed/color/image_raw",
90-
"calibrationTopic": f"/{namespace}/zed/color/camera_info",
112+
"imageTopic": f"/{namespace}/color/image_raw",
113+
"calibrationTopic": f"/{namespace}/color/camera_info",
91114
}
92115
}
93116

117+
@staticmethod
118+
def add_pointcloud(namespace: str) -> None:
119+
"""Add a pointcloud to the Foxglove 3D panel.
120+
121+
Args:
122+
namespace (str): The namespace of the platform.
123+
"""
124+
Foxglove.topics.append(f"/{namespace}/scan/points")
125+
Foxglove.layout["configById"]["3D"]["topics"][f"/{namespace}/scan/points"] = {
126+
"visible": True,
127+
"colorMode": "colormap",
128+
"colorMap": "rainbow",
129+
"colorField": "intensity",
130+
}
131+
132+
@staticmethod
133+
def add_map(topic: str) -> None:
134+
"""Add a map to the Foxglove 3D panel.
135+
136+
Args:
137+
topic (str): The topic of the costmap.
138+
"""
139+
Foxglove.topics.append(topic)
140+
Foxglove.layout["configById"]["3D"]["topics"][topic] = {
141+
"visible": True,
142+
"colorMode": "costmap",
143+
}
144+
145+
@staticmethod
146+
def add_path(topic: str) -> None:
147+
"""Add a path to the Foxglove 3D panel.
148+
149+
Args:
150+
topic (str): The topic of the path.
151+
"""
152+
Foxglove.topics.append(topic)
153+
Foxglove.layout["configById"]["3D"]["topics"][topic] = {
154+
"visible": True,
155+
"lineWidth": 0.03,
156+
"gradient": ["#00ff00ff", "#00ff00ff"],
157+
}
158+
159+
@staticmethod
160+
def add_polygon(topic: str) -> None:
161+
"""Add a polygon to the Foxglove 3D panel.
162+
163+
Args:
164+
topic (str): The topic of the polygon.
165+
"""
166+
Foxglove.topics.append(topic)
167+
168+
@staticmethod
169+
def add_trigger_service(name: str, service: str) -> None:
170+
"""Add a service call panel to the Foxglove layout.
171+
172+
Args:
173+
name (str): The name of the button.
174+
service (str): The service to call when the button is pressed.
175+
"""
176+
Foxglove.services.append(service)
177+
Foxglove.layout["configById"][f"CallService!{name}"] = {
178+
"serviceName": service,
179+
"foxglovePanelTitle": service,
180+
"editingMode": False,
181+
"buttonText": name,
182+
}
183+
94184
@staticmethod
95185
def add_joystick(namespace: str) -> None:
96186
"""Add a virtual joystick to the Foxglove layout.

alliander_visualization/src/alliander_visualization/alliander_visualization/tool_manager.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def __init__(self, config: VisualizationConfig, platform_list: PlatformList):
5151
self.add_lidar(Lidar.from_str(platform.to_str()))
5252
case "Camera":
5353
self.add_depth_camera(Camera.from_str(platform.to_str()))
54-
Foxglove.add_camera(platform.namespace)
5554
case "GPS":
5655
self.add_gps(GPS.from_str(platform.to_str()))
5756
case _:
@@ -62,11 +61,12 @@ def __init__(self, config: VisualizationConfig, platform_list: PlatformList):
6261
if config.rviz:
6362
Rviz.create_rviz_file()
6463

64+
if config.foxglove:
65+
Foxglove.create_layout_file()
66+
6567
if config.vizanti:
6668
Vizanti.create_config_file()
6769

68-
Foxglove.create_layout_file()
69-
7070
# TODO: refactor this
7171
@staticmethod
7272
def add_description(
@@ -128,13 +128,19 @@ def add_vehicle(platform: Vehicle) -> None:
128128
ns = platform.namespace
129129
nav2 = platform.nav2_config
130130
Vizanti.add_platform_model(ns)
131+
Foxglove.topics.append(f"/{ns}/cmd_vel")
131132

132133
if (nav2.navigation or nav2.slam) and not nav2.gps:
133134
Rviz.add_map(f"/{ns}/map")
134135

135136
if nav2.navigation:
136137
Rviz.add_map(f"/{ns}/global_costmap/costmap")
137138
Rviz.add_path(f"/{ns}/plan")
139+
140+
Foxglove.add_map(f"/{ns}/global_costmap/costmap")
141+
Foxglove.add_path(f"/{ns}/plan")
142+
Foxglove.add_trigger_service("Stop", f"/{ns}/nav2_manager/stop")
143+
138144
Vizanti.add_button("Stop", f"/{ns}/waypoint_follower_controller/stop")
139145
Vizanti.add_initial_pose()
140146
Vizanti.add_goal_pose()
@@ -150,6 +156,9 @@ def add_vehicle(platform: Vehicle) -> None:
150156
Rviz.add_polygon(f"/{ns}/polygon_slower")
151157
Rviz.add_polygon(f"/{ns}/velocity_polygon_stop")
152158

159+
Foxglove.add_polygon(f"/{ns}/polygon_slower")
160+
Foxglove.add_polygon(f"/{ns}/velocity_polygon_stop")
161+
153162
@staticmethod
154163
def add_lidar(platform: Lidar) -> None:
155164
"""Add lidar configurations to RViz and Vizanti.
@@ -158,6 +167,7 @@ def add_lidar(platform: Lidar) -> None:
158167
platform (Lidar): The lidar platform configuration.
159168
"""
160169
Rviz.add_laser_scan(platform.namespace)
170+
Foxglove.add_pointcloud(platform.namespace)
161171

162172
@staticmethod
163173
def add_depth_camera(platform: Camera) -> None:
@@ -173,6 +183,8 @@ def add_depth_camera(platform: Camera) -> None:
173183
f"/{platform.namespace}/depth/image_rect_raw",
174184
)
175185

186+
Foxglove.add_image(platform.namespace)
187+
176188
@staticmethod
177189
def add_gps(platform: GPS) -> None:
178190
"""Add GPS configurations to RViz and Vizanti.
@@ -181,3 +193,4 @@ def add_gps(platform: GPS) -> None:
181193
platform (GPS): The GPS platform configuration.
182194
"""
183195
Rviz.add_satellite(f"/{platform.namespace}/gps/fix")
196+
Foxglove.add_street_map(platform.namespace)

alliander_visualization/src/alliander_visualization/config/foxglove_layout.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"scene": {
99
"transforms": {
1010
"visible": false
11-
}
11+
},
12+
"backgroundColor": "#454545"
1213
},
1314
"transforms": {},
1415
"topics": {},

alliander_visualization/src/alliander_visualization/launch/visualization.launch.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from alliander_utilities.launch_utils import SKIP
77
from alliander_utilities.register import Register, RegisteredLaunchDescription
88
from alliander_utilities.ros_utils import get_file_path
9-
from alliander_visualization.tool_manager import ApplyConfigurations
9+
from alliander_visualization.tool_manager import ApplyConfigurations, Foxglove
1010
from launch import LaunchContext, LaunchDescription
1111
from launch.actions import OpaqueFunction
1212
from launch_ros.actions import Node, SetParameter
@@ -44,24 +44,13 @@ def launch_setup(context: LaunchContext) -> list:
4444
parameters=[{"platform_list": platforms.to_str()}],
4545
)
4646

47-
topic_whitelist = ["/clock", "/tf", "/tf_static"]
48-
for platform in platforms.platforms:
49-
topic_whitelist.append([f"/{platform.namespace}/robot_description"])
50-
match platform.platform_type:
51-
case "Vehicle":
52-
topic_whitelist.append(f"/{platform.namespace}/cmd_vel")
53-
case "Camera":
54-
topic_whitelist.append(f"/{platform.namespace}/color/image_raw")
55-
case "Lidar":
56-
topic_whitelist.append(f"/{platform.namespace}/scan/points")
57-
5847
foxglove = Node(
5948
package="foxglove_bridge",
6049
executable="foxglove_bridge",
6150
parameters=[
6251
{
63-
"topic_whitelist": topic_whitelist,
64-
"service_whitelist": [""],
52+
"topic_whitelist": Foxglove.topics,
53+
"service_whitelist": Foxglove.services,
6554
"param_whitelist": [""],
6655
"client_topic_whitelist": [""],
6756
}

0 commit comments

Comments
 (0)