diff --git a/README.md b/README.md index 80970cd..febccd5 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,24 @@ View the gripper in RViz: ros2 launch robotiq_description view_gripper.launch.py ``` +## Foxglove usage (user interface) + +You can find the json configuration file in utils/ui/capra_ui.json. You need to load it into foxglove. On the device that you want to be connected (a.k.a. the jetson), you need to run the following command : + + +You can make it as a service and start at boot : + +```bash +./utils/install.sh +``` + +Otherwise, to start use the user interface with a development laptop, you can run it by only launching the launchfile : + +```bash +ros2 launch rove_launch_handler launch_handler.py +``` + + ## Adding New Packages To add a package for Rove, create it using the ROS2 command ([Creating Your First ROS2 Package](https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html)). Name it starting with `rove_` to ensure Git tracking. For non-Rove specific packages, create a separate repository and add it to `rove.repos`. diff --git a/src/rove_description/urdf/flipper.urdf.xacro b/src/rove_description/urdf/flipper.urdf.xacro index 8e07784..eb26c22 100644 --- a/src/rove_description/urdf/flipper.urdf.xacro +++ b/src/rove_description/urdf/flipper.urdf.xacro @@ -42,6 +42,13 @@ + + + + + + + diff --git a/src/rove_description/urdf/rove.urdf.xacro b/src/rove_description/urdf/rove.urdf.xacro index 5b3dad7..ea73cd1 100644 --- a/src/rove_description/urdf/rove.urdf.xacro +++ b/src/rove_description/urdf/rove.urdf.xacro @@ -20,6 +20,13 @@ + + + + + + + @@ -40,11 +47,10 @@ - + - diff --git a/src/rove_description/urdf/track.urdf.xacro b/src/rove_description/urdf/track.urdf.xacro index fa5a904..3c9d9b8 100644 --- a/src/rove_description/urdf/track.urdf.xacro +++ b/src/rove_description/urdf/track.urdf.xacro @@ -32,6 +32,13 @@ + + + + + + + diff --git a/src/rove_launch_handler/CMakeLists.txt b/src/rove_launch_handler/CMakeLists.txt new file mode 100644 index 0000000..06f6299 --- /dev/null +++ b/src/rove_launch_handler/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.5) +project(rove_launch_handler) + +find_package(ament_cmake REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rosidl_default_generators REQUIRED) +find_package(rclpy REQUIRED) + +# Convert message files to be used in python +rosidl_generate_interfaces(${PROJECT_NAME} + "srv/LaunchRequest.srv" + "srv/LaunchListRequest.srv" +) + +# Install Python executables +install(PROGRAMS + scripts/launch_handler.py + DESTINATION lib/${PROJECT_NAME} +) + +install( + DIRECTORY launch srv + DESTINATION share/${PROJECT_NAME} +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/src/rove_launch_handler/launch/launch_handler.launch.py b/src/rove_launch_handler/launch/launch_handler.launch.py new file mode 100644 index 0000000..e0f6178 --- /dev/null +++ b/src/rove_launch_handler/launch/launch_handler.launch.py @@ -0,0 +1,25 @@ +from launch import LaunchDescription +from launch_ros.actions import Node +from launch.actions import IncludeLaunchDescription +from launch_xml.launch_description_sources import XMLLaunchDescriptionSource +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + rosbridge_launch_file = os.path.join( + get_package_share_directory('foxglove_bridge'), + 'launch', + 'foxglove_bridge_launch.xml' + ) + + return LaunchDescription([ + IncludeLaunchDescription( + XMLLaunchDescriptionSource(rosbridge_launch_file) + ), + Node( + package='rove_launch_handler', + executable='launch_handler.py', + name='launch_handler', + output='screen' + ) + ]) diff --git a/src/rove_launch_handler/package.xml b/src/rove_launch_handler/package.xml new file mode 100644 index 0000000..ec61d5b --- /dev/null +++ b/src/rove_launch_handler/package.xml @@ -0,0 +1,25 @@ + + + rove_launch_handler + 0.0.0 + The rove_launch_handler package + Capra + MIT + + ament_cmake + + rclpy + rosidl_default_generators + + rclpy + rosidl_default_runtime + + ament_lint_auto + ament_lint_common + + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/rove_launch_handler/resource/rove_launch_handler b/src/rove_launch_handler/resource/rove_launch_handler new file mode 100644 index 0000000..e69de29 diff --git a/src/rove_launch_handler/scripts/launch_handler.py b/src/rove_launch_handler/scripts/launch_handler.py new file mode 100755 index 0000000..333a5d3 --- /dev/null +++ b/src/rove_launch_handler/scripts/launch_handler.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +import time +import rclpy +from rclpy.node import Node +import signal +import subprocess +import os +from rove_launch_handler.srv import LaunchRequest, LaunchListRequest + +launched_files = {} + +class LaunchFile: + def __init__(self, package, file_name, pid): + self.package = package + self.file_name = file_name + self.pid = pid + +class LaunchMsg: + def __init__(self): + self.message = "" + self.is_launched = False + self.file_name = "" + +def launch_file(package, file_name): + command = f"ros2 launch {package} {file_name}" + + p = subprocess.Popen(command, shell=True, preexec_fn=os.setsid) + + launch_msg = LaunchMsg() + # Sleep to make sure the launch command has time to fail if there's an error + time.sleep(1) + state = p.poll() + launch_msg.file_name = file_name + if state is None: + launch_msg.message = f"{file_name} was launched" + launched_files[file_name] = LaunchFile(package, file_name, p.pid) + launch_msg.is_launched = True + else: + launch_msg.message = f"{file_name} was not launched" + launch_msg.is_launched = False + return launch_msg + +def kill_launch_file(file_name): + launch_msg = LaunchMsg() + launch_msg.file_name = file_name + if file_name in launched_files: + pid = launched_files[file_name].pid + try: + os.killpg(os.getpgid(pid), signal.SIGINT) + del launched_files[file_name] + launch_msg.message = f"{file_name} was killed" + launch_msg.is_launched = False + except ProcessLookupError as e: + launch_msg.message = f"Failed to kill {file_name}: {str(e)}" + launch_msg.is_launched = False + else: + launch_msg.message = f"{file_name} was not launched" + launch_msg.is_launched = False + return launch_msg + +def kill_all(): + for file_name in list(launched_files.keys()): + kill_launch_file(file_name) + +class LaunchHandlerService(Node): + def __init__(self): + super().__init__('launch_handler_service') + self.srv_launch = self.create_service(LaunchRequest, 'launchHandler/launchFile', self.launch_callback) + self.srv_list = self.create_service(LaunchListRequest, 'launchHandler/getAllLaunchedFiles', self.get_launched_files) + self.get_logger().info("LaunchHandlerService node has been started.") + + def launch_callback(self, request, response): + package = request.package + file_name = request.file_name + if file_name not in launched_files: + launch_msg = launch_file(package, file_name) + else: + launch_msg = kill_launch_file(file_name) + response.message = launch_msg.message + response.is_launched = launch_msg.is_launched + response.file_name = launch_msg.file_name + return response + + def get_launched_files(self, request, response): + response.packages = [lf.package for lf in launched_files.values()] + response.files = list(launched_files.keys()) + return response + +def main(args=None): + rclpy.init(args=args) + node = LaunchHandlerService() + rclpy.get_default_context().on_shutdown(kill_all) + rclpy.spin(node) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/src/rove_launch_handler/scripts/launch_script.service b/src/rove_launch_handler/scripts/launch_script.service new file mode 100755 index 0000000..6cd0e14 --- /dev/null +++ b/src/rove_launch_handler/scripts/launch_script.service @@ -0,0 +1,13 @@ +[Unit] +Descript=Robot launch script +After=network.target + +[Service] +Environment="ROS_LOG_DIR=/var/log/ros2; ROS_DOMAIN_ID=96" +ExecStart=/bin/bash -c 'source /home/simon/Workspace/capra/rove/install/setup.bash; ros2 launch rove_launch_handler launch_handler.launch.py;' +RemainAfterExit=no +Restart=on-failure +RestartSec=2s + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/src/rove_launch_handler/srv/LaunchListRequest.srv b/src/rove_launch_handler/srv/LaunchListRequest.srv new file mode 100644 index 0000000..4481e2f --- /dev/null +++ b/src/rove_launch_handler/srv/LaunchListRequest.srv @@ -0,0 +1,3 @@ +--- +string[] packages +string[] files diff --git a/src/rove_launch_handler/srv/LaunchRequest.srv b/src/rove_launch_handler/srv/LaunchRequest.srv new file mode 100644 index 0000000..687d578 --- /dev/null +++ b/src/rove_launch_handler/srv/LaunchRequest.srv @@ -0,0 +1,6 @@ +string package +string file_name +--- +string message +bool is_launched +string file_name diff --git a/src/rove_launch_handler/test/test_copyright.py b/src/rove_launch_handler/test/test_copyright.py new file mode 100644 index 0000000..97a3919 --- /dev/null +++ b/src/rove_launch_handler/test/test_copyright.py @@ -0,0 +1,25 @@ +# Copyright 2015 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. + +from ament_copyright.main import main +import pytest + + +# Remove the `skip` decorator once the source file(s) have a copyright header +@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/src/rove_launch_handler/test/test_flake8.py b/src/rove_launch_handler/test/test_flake8.py new file mode 100644 index 0000000..27ee107 --- /dev/null +++ b/src/rove_launch_handler/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/src/rove_launch_handler/test/test_pep257.py b/src/rove_launch_handler/test/test_pep257.py new file mode 100644 index 0000000..b234a38 --- /dev/null +++ b/src/rove_launch_handler/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 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. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/utils/install.sh b/utils/install.sh new file mode 100755 index 0000000..afd033a --- /dev/null +++ b/utils/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +sudo mkdir -p /var/log/ros2 +sudo chmod 775 /var/log/ros2 +sudo cp ./src/rove_launch_handler/scripts/launch_script.service /lib/systemd/system/launch_script.service +sudo systemctl daemon-reload +sudo systemctl enable launch_script.service +sudo systemctl start launch_script.service \ No newline at end of file diff --git a/utils/ui/capra_ui.json b/utils/ui/capra_ui.json index 2105a1f..b132a3f 100644 --- a/utils/ui/capra_ui.json +++ b/utils/ui/capra_ui.json @@ -1,25 +1,41 @@ { "configById": { - "Publish!1b7sy1a": { - "buttonText": "Front LED ON", - "buttonTooltip": "", - "advancedView": false, - "value": "{}", - "foxglovePanelTitle": "Front LED ON" + "Gauge!3mhnam3": { + "path": "/diff_drive_controller/cmd_vel_unstamped.linear.x", + "minValue": 0, + "maxValue": 2, + "colorMap": "red-yellow-green", + "colorMode": "colormap", + "gradient": [ + "#0000ff", + "#ff00ff" + ], + "reverse": false, + "foxglovePanelTitle": "Speed" }, - "Indicator!360e2e8": { + "Indicator!3iqk2un": { "path": "", "style": "bulb", - "fallbackColor": "#a0a0a0", - "fallbackLabel": "False", + "fallbackColor": "#0045f5", + "fallbackLabel": "Track", "rules": [ { "operator": "=", "rawValue": "true", - "color": "#68e24a", - "label": "True" + "color": "#61cc47", + "label": "Arm" } - ] + ], + "foxglovePanelTitle": "Mode" + }, + "Publish!1b7sy1a": { + "buttonText": "Front LED ON", + "buttonTooltip": "", + "advancedView": false, + "value": "{\n \"linear\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": 0\n },\n \"angular\": {\n \"x\": 0,\n \"y\": 0,\n \"z\": 0\n }\n}", + "foxglovePanelTitle": "Front LED ON", + "topicName": "/cmd_vel.linear.x", + "datatype": "geometry_msgs/msg/Twist" }, "Publish!gkhilm": { "buttonText": "Front LED OFF", @@ -28,21 +44,6 @@ "value": "{}", "foxglovePanelTitle": "Front LED OFF" }, - "Indicator!3iqk2un": { - "path": "", - "style": "bulb", - "fallbackColor": "#a0a0a0", - "fallbackLabel": "False", - "rules": [ - { - "operator": "=", - "rawValue": "true", - "color": "#68e24a", - "label": "True" - } - ], - "foxglovePanelTitle": "Mode" - }, "Publish!2vkw4zk": { "buttonText": "Back LED ON", "buttonTooltip": "", @@ -50,6 +51,13 @@ "value": "{}", "foxglovePanelTitle": "Back LED ON" }, + "Publish!22modxz": { + "buttonText": "Back LED OFF", + "buttonTooltip": "", + "advancedView": false, + "value": "{}", + "foxglovePanelTitle": "Back LED OFF" + }, "Indicator!l0f2va": { "path": "", "style": "bulb", @@ -65,13 +73,6 @@ ], "foxglovePanelTitle": "Flipper" }, - "Publish!22modxz": { - "buttonText": "Back LED OFF", - "buttonTooltip": "", - "advancedView": false, - "value": "{}", - "foxglovePanelTitle": "Back LED OFF" - }, "Indicator!1srygfi": { "path": "", "style": "bulb", @@ -91,7 +92,8 @@ "batteryTopic": "", "topic": { "batteryTopic": "" - } + }, + "foxglovePanelTitle": "Battery Level" }, "Indicator!38j960d": { "path": "", @@ -107,31 +109,6 @@ } ] }, - "CallService!qyzghd": { - "requestPayload": "{}", - "layout": "vertical", - "timeoutSeconds": 10, - "editingMode": false, - "foxglovePanelTitle": "ESTOP", - "buttonTooltip": "", - "buttonColor": "#ff0000", - "buttonText": "ESTOP" - }, - "Indicator!21d1yds": { - "path": "", - "style": "bulb", - "fallbackColor": "#a0a0a0", - "fallbackLabel": "False", - "rules": [ - { - "operator": "=", - "rawValue": "true", - "color": "#68e24a", - "label": "True" - } - ], - "foxglovePanelTitle": "Estop status" - }, "Image!3b8t5ua": { "cameraState": { "distance": 20, @@ -218,32 +195,65 @@ "poseEstimateThetaDeviation": 0.26179939 }, "imageMode": { - "imageTopic": "/zed/zed_node/rgb/image_rect_color", + "imageTopic": "/zed/zed_node/depth/depth_registered", "calibrationTopic": "/zed/zed_node/depth/camera_info" } }, + "Joystick Panel.Joystick!4cyq4bd": { + "foxglovePanelTitle": "Gamepad", + "publishMode": true, + "subJoyTopic": "/joy", + "pubJoyTopic": "/joy", + "publishFrameId": "", + "dataSource": "gamepad", + "displayMode": "custom", + "debugGamepad": false, + "layoutName": "steamdeck", + "mapping_name": "TODO", + "gamepadId": 0 + }, + "Joystick Panel.Joystick!31gwyzo": { + "foxglovePanelTitle": "Keyboard", + "subJoyTopic": "/joy", + "pubJoyTopic": "/joy", + "publishMode": false, + "publishFrameId": "", + "dataSource": "sub-joy-topic", + "displayMode": "auto", + "debugGamepad": false, + "layoutName": "steamdeck", + "mapping_name": "TODO", + "gamepadId": 0 + }, + "virtual-joystick.Virtual Joystick!9rfrv4": { + "publishRate": 5, + "maxLinearSpeed": 1, + "maxAngularSpeed": 1, + "topic": "/joy_vel", + "messageSchema": "geometry_msgs/msg/Twist" + }, "3D!wd5ayb": { "cameraState": { - "distance": 15.475618749968437, "perspective": true, - "phi": 53.72454709424579, + "distance": 6.811232525735649, + "phi": 31.92629541215902, + "thetaOffset": 17.30470174315372, + "targetOffset": [ + -0.5219563017849245, + -0.17697123429486802, + 6.817176424810392e-16 + ], "target": [ 0, 0, 0 ], - "targetOffset": [ - -1.0352265201029487, - 0.690125189613747, - -6.717353809730597e-17 - ], "targetOrientation": [ 0, 0, 0, 1 ], - "thetaOffset": 39.94897959183675, "fovy": 45, "near": 0.5, "far": 5000 @@ -253,7 +263,62 @@ "meshUpAxis": "z_up", "labelScaleFactor": 0 }, - "transforms": {}, + "transforms": { + "frame:odom": { + "visible": false + }, + "frame:base_link": { + "visible": false + }, + "frame:map": { + "visible": false + }, + "frame:flipper_fl": { + "visible": false + }, + "frame:flipper_fr": { + "visible": false + }, + "frame:flipper_rl": { + "visible": false + }, + "frame:flipper_rr": { + "visible": false + }, + "frame:sensor_link": { + "visible": false + }, + "frame:camera_link": { + "visible": false + }, + "frame:track_l": { + "visible": false + }, + "frame:track_fl": { + "visible": false + }, + "frame:track_r": { + "visible": false + }, + "frame:track_fr": { + "visible": false + }, + "frame:track_rl": { + "visible": false + }, + "frame:track_rr": { + "visible": false + }, + "frame:velodyne_link": { + "visible": false + }, + "frame:velodyne_laser": { + "visible": false + }, + "frame:zed_camera_link": { + "visible": false + } + }, "topics": { "/scan": { "visible": false, @@ -343,6 +408,22 @@ }, "/base/scan": { "visible": false + }, + "/global_path": { + "visible": false + }, + "/plan": { + "visible": false, + "lineWidth": 0.24 + }, + "/local_plan": { + "visible": false + }, + "/local_path": { + "visible": false + }, + "/received_global_plan": { + "visible": true } }, "layers": { @@ -386,8 +467,8 @@ } }, "publish": { - "type": "point", - "poseTopic": "/move_base_simple/goal", + "type": "pose", + "poseTopic": "/goal_pose", "pointTopic": "/clicked_point", "poseEstimateTopic": "/initialpose", "poseEstimateXDeviation": 0.5, @@ -395,28 +476,243 @@ "poseEstimateThetaDeviation": 0.26179939 }, "imageMode": {}, - "followTf": "base_link" + "followTf": "map" + }, + "Publish!2onj1sc": { + "buttonText": "ESTOP", + "buttonTooltip": "", + "advancedView": false, + "value": "{\n \"data\": false\n}", + "topicName": "/estop", + "datatype": "std_msgs/msg/Bool", + "buttonColor": "#f90000", + "foxglovePanelTitle": "estop" }, "map!60yjuv": { "center": { - "lat": 38.16148014673053, - "lon": -122.45464324951172 + "lat": 38.161016176890456, + "lon": -122.45567321777345 }, "customTileUrl": "", "disabledTopics": [], "followTopic": "/gps", "layer": "map", "topicColors": {}, - "zoomLevel": 16, + "zoomLevel": 10, "maxNativeZoom": 18 }, - "Table!1xg0s4v": { - "topicPath": "" + "3D!ac8om2": { + "cameraState": { + "perspective": true, + "distance": 6.147137354499581, + "phi": 32.42241754677333, + "thetaOffset": 42.76397535505056, + "targetOffset": [ + -0.14852471988960536, + -0.20361223586685062, + 7.604074847577668e-18 + ], + "target": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "fovy": 45, + "near": 0.5, + "far": 5000 + }, + "followMode": "follow-pose", + "scene": {}, + "transforms": { + "frame:map": { + "visible": false + }, + "frame:odom": { + "visible": false + }, + "frame:sensor_link": { + "visible": false + }, + "frame:camera_link": { + "visible": false + }, + "frame:base_link": { + "visible": false + }, + "frame:track_l": { + "visible": false + }, + "frame:track_fl": { + "visible": false + }, + "frame:track_r": { + "visible": false + }, + "frame:track_fr": { + "visible": false + }, + "frame:track_rl": { + "visible": false + }, + "frame:track_rr": { + "visible": false + }, + "frame:velodyne_link": { + "visible": false + }, + "frame:velodyne_laser": { + "visible": false + }, + "frame:zed_camera_link": { + "visible": false + }, + "frame:flipper_fl": { + "visible": false + }, + "frame:flipper_fr": { + "visible": false + }, + "frame:flipper_rl": { + "visible": false + }, + "frame:flipper_rr": { + "visible": false + } + }, + "topics": {}, + "layers": { + "grid": { + "visible": true, + "frameLocked": true, + "label": "Grid", + "instanceId": "ffebde8e-3ad9-4faf-b77b-fe3c45a445eb", + "layerId": "foxglove.Grid", + "size": 10, + "divisions": 10, + "lineWidth": 1, + "color": "#248eff", + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ] + } + }, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + }, + "imageMode": {} + }, + "CallService!2b4k70w": { + "requestPayload": "{\n \"package\" : \"rove_bringup\",\n \"file_name\" : \"sim.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "simulation", + "buttonText": "Simulation", + "buttonColor": "#ff0000" + }, + "CallService!3utg1bx": { + "requestPayload": "{\n \"package\" : \"rove_bringup\",\n \"file_name\" : \"real.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "simulation", + "buttonText": "Real", + "buttonColor": "#ff0000" + }, + "Blank Panel.Blank!4iybw25": { + "showLogo": false, + "foxglovePanelTitle": " " + }, + "CallService!1z631qn": { + "requestPayload": "{\n \"package\" : \"rove_navigation\",\n \"file_name\" : \"navigation.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "navigation", + "buttonText": "navigation", + "buttonColor": "#ff0000" + }, + "CallService!2kij9dp": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"slam3d_full.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "slam", + "buttonText": "slam3d", + "buttonColor": "#ff0000" + }, + "CallService!90e1se": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"velodyne_3d.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "slam", + "buttonText": "slam3d - lidar", + "buttonColor": "#ff0000" + }, + "CallService!6jl54y": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"icp_zed.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "simulation", + "buttonText": "slam3d - zed", + "buttonColor": "#ff0000" + }, + "CallService!43dz0yr": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"slam3d_full.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "Scenario", + "buttonText": "Reconnoitring of structures", + "buttonColor": "#ff0000" }, - "RosOut!14blizg": { - "searchTerms": [], - "minLogLevel": 1, - "nameFilter": {} + "CallService!2qnnpsv": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"slam3d_full.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "Scenario", + "buttonText": "Transport – Mule", + "buttonColor": "#ff0000" + }, + "CallService!6ywrf4": { + "requestPayload": "{\n \"package\" : \"rove_slam\",\n \"file_name\" : \"slam3d_full.launch.py\"\n}", + "layout": "vertical", + "timeoutSeconds": 20, + "serviceName": "/launchHandler/launchFile", + "editingMode": false, + "foxglovePanelTitle": "Scenario", + "buttonText": "Search & Rescue", + "buttonColor": "#ff0000" }, "Tab!2iobm2s": { "activeTabIdx": 0, @@ -426,57 +722,45 @@ "layout": { "first": { "first": { - "first": "Publish!1b7sy1a", - "second": "Indicator!360e2e8", + "first": "Gauge!3mhnam3", + "second": "Indicator!3iqk2un", "direction": "column", - "splitPercentage": 55.757575757575765 + "splitPercentage": 48.589341692789965 }, "second": { - "first": "Publish!gkhilm", - "second": "Indicator!3iqk2un", - "direction": "column", - "splitPercentage": 55.757575757575765 + "first": "Publish!1b7sy1a", + "second": "Publish!gkhilm", + "direction": "column" }, - "direction": "row" + "direction": "row", + "splitPercentage": 65.39306574571636 }, "second": { "first": { "first": { "first": "Publish!2vkw4zk", - "second": "Indicator!l0f2va", - "direction": "column", - "splitPercentage": 56.36363636363636 + "second": "Publish!22modxz", + "direction": "column" }, "second": { - "first": "Publish!22modxz", + "first": "Indicator!l0f2va", "second": "Indicator!1srygfi", - "direction": "column", - "splitPercentage": 56.36363636363636 + "direction": "column" }, "direction": "row", - "splitPercentage": 51.956429780033865 + "splitPercentage": 46.42574229279043 }, "second": { - "first": { - "first": "Battery Indicator.Battery display!2ungb0h", - "second": "Indicator!38j960d", - "direction": "column", - "splitPercentage": 56.42909625275533 - }, - "second": { - "first": "CallService!qyzghd", - "second": "Indicator!21d1yds", - "direction": "column", - "splitPercentage": 56.96969696969697 - }, - "direction": "row", - "splitPercentage": 59.009099648981575 + "first": "Battery Indicator.Battery display!2ungb0h", + "second": "Indicator!38j960d", + "direction": "column", + "splitPercentage": 56.42909625275533 }, "direction": "row", - "splitPercentage": 49.00497512437809 + "splitPercentage": 69.21645622777145 }, "direction": "row", - "splitPercentage": 33.881578947368425 + "splitPercentage": 45.17799352750809 } }, { @@ -489,6 +773,23 @@ } ] }, + "Tab!1w9p6uc": { + "activeTabIdx": 0, + "tabs": [ + { + "title": "Gamepad", + "layout": "Joystick Panel.Joystick!4cyq4bd" + }, + { + "title": "Keyboard", + "layout": "Joystick Panel.Joystick!31gwyzo" + }, + { + "title": "Joystick", + "layout": "virtual-joystick.Virtual Joystick!9rfrv4" + } + ] + }, "Tab!1dud6cr": { "activeTabIdx": 0, "tabs": [ @@ -497,17 +798,61 @@ "layout": { "first": "3D!wd5ayb", "second": { + "first": "Publish!2onj1sc", + "second": "map!60yjuv", + "direction": "column", + "splitPercentage": 16.765578635014837 + }, + "direction": "row", + "splitPercentage": 61.47652076855616 + } + }, + { + "title": "Arm", + "layout": "3D!ac8om2" + }, + { + "title": "launch", + "layout": { + "first": { "first": { - "first": "map!60yjuv", - "second": "Table!1xg0s4v", - "direction": "row" + "first": "CallService!2b4k70w", + "second": "CallService!3utg1bx", + "direction": "column" }, - "second": "RosOut!14blizg", + "second": { + "first": "Blank Panel.Blank!4iybw25", + "second": { + "first": { + "first": "CallService!1z631qn", + "second": "CallService!2kij9dp", + "direction": "column" + }, + "second": { + "first": "CallService!90e1se", + "second": "CallService!6jl54y", + "direction": "column" + }, + "direction": "column" + }, + "direction": "row", + "splitPercentage": 69.34679409175952 + }, + "direction": "row", + "splitPercentage": 22.561529751795238 + }, + "second": { + "first": { + "first": "CallService!43dz0yr", + "second": "CallService!2qnnpsv", + "direction": "column" + }, + "second": "CallService!6ywrf4", "direction": "column", - "splitPercentage": 48.263254113345525 + "splitPercentage": 64.83679525222553 }, "direction": "row", - "splitPercentage": 50.911458333333336 + "splitPercentage": 85.62162162162163 } } ] @@ -519,9 +864,14 @@ "speed": 1 }, "layout": { - "first": "Tab!2iobm2s", + "first": { + "first": "Tab!2iobm2s", + "second": "Tab!1w9p6uc", + "direction": "row", + "splitPercentage": 84.48648648648648 + }, "second": "Tab!1dud6cr", "direction": "column", - "splitPercentage": 25.259067357512954 + "splitPercentage": 30.723488602576808 } } \ No newline at end of file