From 6ee86a5aead6950e70334ed3b69a0cdc7369cd62 Mon Sep 17 00:00:00 2001 From: patates-cipsi418 Date: Sat, 22 Jun 2024 00:20:11 -0400 Subject: [PATCH 1/9] Can launch some files but have problems to kill indevidual process --- src/rove_manager/CMakeLists.txt | 24 ++++ src/rove_manager/package.xml | 22 ++++ src/rove_manager/src/rove_manager_node.cpp | 134 +++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 src/rove_manager/CMakeLists.txt create mode 100644 src/rove_manager/package.xml create mode 100644 src/rove_manager/src/rove_manager_node.cpp diff --git a/src/rove_manager/CMakeLists.txt b/src/rove_manager/CMakeLists.txt new file mode 100644 index 0000000..826cf63 --- /dev/null +++ b/src/rove_manager/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.5) +project(rove_manager) + +# Find dependencies +find_package(ament_cmake REQUIRED) +find_package(rclcpp REQUIRED) +find_package(std_msgs REQUIRED) + +# Create executable +add_executable(${PROJECT_NAME}_node src/rove_manager_node.cpp) + +# Link libraries +ament_target_dependencies(${PROJECT_NAME}_node + rclcpp + std_msgs +) + +# Install executable +install(TARGETS + ${PROJECT_NAME}_node + DESTINATION lib/${PROJECT_NAME} +) + +ament_package() diff --git a/src/rove_manager/package.xml b/src/rove_manager/package.xml new file mode 100644 index 0000000..834d751 --- /dev/null +++ b/src/rove_manager/package.xml @@ -0,0 +1,22 @@ + + + rove_manager + 0.0.0 + The rove_manager package + Capra + GPLv3 + + ament_cmake + rclcpp + std_msgs + + rclcpp + std_msgs + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/rove_manager/src/rove_manager_node.cpp b/src/rove_manager/src/rove_manager_node.cpp new file mode 100644 index 0000000..af57af9 --- /dev/null +++ b/src/rove_manager/src/rove_manager_node.cpp @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +class RoveManagerNode : public rclcpp::Node +{ +public: + RoveManagerNode() : Node("rove_manager_node") + { + launch_subscriber_ = this->create_subscription( + "/manager/launch", 10, std::bind(&RoveManagerNode::launch_callback, this, std::placeholders::_1)); + + kill_subscriber_ = this->create_subscription( + "/manager/kill", 10, std::bind(&RoveManagerNode::kill_callback, this, std::placeholders::_1)); + + status_publisher_ = this->create_publisher("/manager/status", 10); + } + +private: + void launch_callback(const std_msgs::msg::String::SharedPtr msg) + { + std::string package, file; + if (!parse_launch_message(msg->data, package, file)) + { + RCLCPP_ERROR(this->get_logger(), "Failed to parse launch message: %s", msg->data.c_str()); + return; + } + + pid_t pid = fork(); + if (pid == 0) // Child process + { + // Create a new process group for the child process + setpgid(0, 0); + + std::vector args; + args.push_back(strdup("ros2")); + args.push_back(strdup("launch")); + args.push_back(strdup(package.c_str())); + args.push_back(strdup(file.c_str())); + args.push_back(nullptr); + + execvp("ros2", args.data()); + perror("execvp failed"); // Only reached if execvp fails + _exit(1); + } + else if (pid > 0) // Parent process + { + processes_[package + "_" + file].push_back(pid); + RCLCPP_INFO(this->get_logger(), "Launched: %s %s", package.c_str(), file.c_str()); + + // Publish status + std_msgs::msg::String status_msg; + status_msg.data = "Running: " + package + " " + file; + status_publisher_->publish(status_msg); + } + else + { + RCLCPP_ERROR(this->get_logger(), "Failed to fork"); + } + } + + void kill_callback(const std_msgs::msg::String::SharedPtr msg) + { + std::string package, file; + if (!parse_kill_message(msg->data, package, file)) + { + RCLCPP_ERROR(this->get_logger(), "Failed to parse kill message: %s", msg->data.c_str()); + return; + } + + std::string key = package + "_" + file; + auto it = processes_.find(key); + if (it != processes_.end()) + { + for (pid_t pid : it->second) + { + kill(pid, SIGKILL); + waitpid(pid, nullptr, 0); + } + processes_.erase(it); + RCLCPP_INFO(this->get_logger(), "Killed processes for: %s %s", package.c_str(), file.c_str()); + + // Publish status + std_msgs::msg::String status_msg; + status_msg.data = "Not running: " + package + " " + file; + status_publisher_->publish(status_msg); + } + else + { + RCLCPP_WARN(this->get_logger(), "No process found for: %s %s", package.c_str(), file.c_str()); + } + } + + bool parse_launch_message(const std::string &data, std::string &package, std::string &file) + { + std::istringstream stream(data); + std::getline(stream, package, ' '); + std::getline(stream, file, ' '); + + return !package.empty() && !file.empty(); + } + + bool parse_kill_message(const std::string &data, std::string &package, std::string &file) + { + std::istringstream stream(data); + std::getline(stream, package, ' '); + std::getline(stream, file, ' '); + + return !package.empty() && !file.empty(); + } + + rclcpp::Subscription::SharedPtr launch_subscriber_; + rclcpp::Subscription::SharedPtr kill_subscriber_; + rclcpp::Publisher::SharedPtr status_publisher_; + + std::unordered_map> processes_; +}; + +int main(int argc, char *argv[]) +{ + rclcpp::init(argc, argv); + rclcpp::spin(std::make_shared()); + rclcpp::shutdown(); + return 0; +} From 905437f8a7a7c1e9e96a536da31377975bd92abd Mon Sep 17 00:00:00 2001 From: patates-cipsi418 Date: Sat, 22 Jun 2024 00:27:10 -0400 Subject: [PATCH 2/9] add example to ui --- utils/ui/capra_ui.json | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/utils/ui/capra_ui.json b/utils/ui/capra_ui.json index 2105a1f..ef57536 100644 --- a/utils/ui/capra_ui.json +++ b/utils/ui/capra_ui.json @@ -222,6 +222,24 @@ "calibrationTopic": "/zed/zed_node/depth/camera_info" } }, + "Publish!qnfojc": { + "buttonText": "Publish", + "buttonTooltip": "", + "advancedView": true, + "value": "{\n \"data\": \"rove_bringup sim.launch.py\"\n}", + "foxglovePanelTitle": "Launch", + "topicName": "/manager/launch", + "datatype": "std_msgs/msg/String" + }, + "Publish!2cg1exi": { + "buttonText": "Publish", + "buttonTooltip": "", + "advancedView": true, + "value": "{\n \"data\": \"rove_bringup sim.launch.py\"\n}", + "foxglovePanelTitle": "Kill", + "topicName": "/manager/kill", + "datatype": "std_msgs/msg/String" + }, "3D!wd5ayb": { "cameraState": { "distance": 15.475618749968437, @@ -400,7 +418,7 @@ "map!60yjuv": { "center": { "lat": 38.16148014673053, - "lon": -122.45464324951172 + "lon": -122.45462179183961 }, "customTileUrl": "", "disabledTopics": [], @@ -419,7 +437,7 @@ "nameFilter": {} }, "Tab!2iobm2s": { - "activeTabIdx": 0, + "activeTabIdx": 2, "tabs": [ { "title": "Status", @@ -486,6 +504,14 @@ "second": "Image!3593v6f", "direction": "row" } + }, + { + "title": "example", + "layout": { + "first": "Publish!qnfojc", + "second": "Publish!2cg1exi", + "direction": "row" + } } ] }, From 1875de9af970e4889c4f3af33cf8d097bafd9e2e Mon Sep 17 00:00:00 2001 From: patates-cipsi418 Date: Sun, 23 Jun 2024 01:41:46 -0400 Subject: [PATCH 3/9] removing rove_manager --- src/rove_manager/CMakeLists.txt | 24 ---- src/rove_manager/package.xml | 22 ---- src/rove_manager/src/rove_manager_node.cpp | 134 --------------------- 3 files changed, 180 deletions(-) delete mode 100644 src/rove_manager/CMakeLists.txt delete mode 100644 src/rove_manager/package.xml delete mode 100644 src/rove_manager/src/rove_manager_node.cpp diff --git a/src/rove_manager/CMakeLists.txt b/src/rove_manager/CMakeLists.txt deleted file mode 100644 index 826cf63..0000000 --- a/src/rove_manager/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(rove_manager) - -# Find dependencies -find_package(ament_cmake REQUIRED) -find_package(rclcpp REQUIRED) -find_package(std_msgs REQUIRED) - -# Create executable -add_executable(${PROJECT_NAME}_node src/rove_manager_node.cpp) - -# Link libraries -ament_target_dependencies(${PROJECT_NAME}_node - rclcpp - std_msgs -) - -# Install executable -install(TARGETS - ${PROJECT_NAME}_node - DESTINATION lib/${PROJECT_NAME} -) - -ament_package() diff --git a/src/rove_manager/package.xml b/src/rove_manager/package.xml deleted file mode 100644 index 834d751..0000000 --- a/src/rove_manager/package.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - rove_manager - 0.0.0 - The rove_manager package - Capra - GPLv3 - - ament_cmake - rclcpp - std_msgs - - rclcpp - std_msgs - - ament_lint_auto - ament_lint_common - - - ament_cmake - - diff --git a/src/rove_manager/src/rove_manager_node.cpp b/src/rove_manager/src/rove_manager_node.cpp deleted file mode 100644 index af57af9..0000000 --- a/src/rove_manager/src/rove_manager_node.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::chrono_literals; - -class RoveManagerNode : public rclcpp::Node -{ -public: - RoveManagerNode() : Node("rove_manager_node") - { - launch_subscriber_ = this->create_subscription( - "/manager/launch", 10, std::bind(&RoveManagerNode::launch_callback, this, std::placeholders::_1)); - - kill_subscriber_ = this->create_subscription( - "/manager/kill", 10, std::bind(&RoveManagerNode::kill_callback, this, std::placeholders::_1)); - - status_publisher_ = this->create_publisher("/manager/status", 10); - } - -private: - void launch_callback(const std_msgs::msg::String::SharedPtr msg) - { - std::string package, file; - if (!parse_launch_message(msg->data, package, file)) - { - RCLCPP_ERROR(this->get_logger(), "Failed to parse launch message: %s", msg->data.c_str()); - return; - } - - pid_t pid = fork(); - if (pid == 0) // Child process - { - // Create a new process group for the child process - setpgid(0, 0); - - std::vector args; - args.push_back(strdup("ros2")); - args.push_back(strdup("launch")); - args.push_back(strdup(package.c_str())); - args.push_back(strdup(file.c_str())); - args.push_back(nullptr); - - execvp("ros2", args.data()); - perror("execvp failed"); // Only reached if execvp fails - _exit(1); - } - else if (pid > 0) // Parent process - { - processes_[package + "_" + file].push_back(pid); - RCLCPP_INFO(this->get_logger(), "Launched: %s %s", package.c_str(), file.c_str()); - - // Publish status - std_msgs::msg::String status_msg; - status_msg.data = "Running: " + package + " " + file; - status_publisher_->publish(status_msg); - } - else - { - RCLCPP_ERROR(this->get_logger(), "Failed to fork"); - } - } - - void kill_callback(const std_msgs::msg::String::SharedPtr msg) - { - std::string package, file; - if (!parse_kill_message(msg->data, package, file)) - { - RCLCPP_ERROR(this->get_logger(), "Failed to parse kill message: %s", msg->data.c_str()); - return; - } - - std::string key = package + "_" + file; - auto it = processes_.find(key); - if (it != processes_.end()) - { - for (pid_t pid : it->second) - { - kill(pid, SIGKILL); - waitpid(pid, nullptr, 0); - } - processes_.erase(it); - RCLCPP_INFO(this->get_logger(), "Killed processes for: %s %s", package.c_str(), file.c_str()); - - // Publish status - std_msgs::msg::String status_msg; - status_msg.data = "Not running: " + package + " " + file; - status_publisher_->publish(status_msg); - } - else - { - RCLCPP_WARN(this->get_logger(), "No process found for: %s %s", package.c_str(), file.c_str()); - } - } - - bool parse_launch_message(const std::string &data, std::string &package, std::string &file) - { - std::istringstream stream(data); - std::getline(stream, package, ' '); - std::getline(stream, file, ' '); - - return !package.empty() && !file.empty(); - } - - bool parse_kill_message(const std::string &data, std::string &package, std::string &file) - { - std::istringstream stream(data); - std::getline(stream, package, ' '); - std::getline(stream, file, ' '); - - return !package.empty() && !file.empty(); - } - - rclcpp::Subscription::SharedPtr launch_subscriber_; - rclcpp::Subscription::SharedPtr kill_subscriber_; - rclcpp::Publisher::SharedPtr status_publisher_; - - std::unordered_map> processes_; -}; - -int main(int argc, char *argv[]) -{ - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} From 1a81b2400e16f4c46acf2c2f8eedeab0d6909d26 Mon Sep 17 00:00:00 2001 From: patates-cipsi418 Date: Sun, 23 Jun 2024 01:43:38 -0400 Subject: [PATCH 4/9] Add rove_launch_handler from capra_launch_handler, error on service import --- src/rove_launch_handler/CMakeLists.txt | 22 ++++ src/rove_launch_handler/package.xml | 26 +++++ .../resource/rove_launch_handler | 0 .../rove_launch_handler/__init__.py | 0 .../rove_launch_handler/launch_handler.py | 100 ++++++++++++++++++ src/rove_launch_handler/setup.cfg | 4 + src/rove_launch_handler/setup.py | 27 +++++ .../srv/LaunchListRequest.srv | 3 + src/rove_launch_handler/srv/LaunchRequest.srv | 6 ++ .../test/test_copyright.py | 25 +++++ src/rove_launch_handler/test/test_flake8.py | 25 +++++ src/rove_launch_handler/test/test_pep257.py | 23 ++++ 12 files changed, 261 insertions(+) create mode 100644 src/rove_launch_handler/CMakeLists.txt create mode 100644 src/rove_launch_handler/package.xml create mode 100644 src/rove_launch_handler/resource/rove_launch_handler create mode 100644 src/rove_launch_handler/rove_launch_handler/__init__.py create mode 100644 src/rove_launch_handler/rove_launch_handler/launch_handler.py create mode 100644 src/rove_launch_handler/setup.cfg create mode 100644 src/rove_launch_handler/setup.py create mode 100644 src/rove_launch_handler/srv/LaunchListRequest.srv create mode 100644 src/rove_launch_handler/srv/LaunchRequest.srv create mode 100644 src/rove_launch_handler/test/test_copyright.py create mode 100644 src/rove_launch_handler/test/test_flake8.py create mode 100644 src/rove_launch_handler/test/test_pep257.py diff --git a/src/rove_launch_handler/CMakeLists.txt b/src/rove_launch_handler/CMakeLists.txt new file mode 100644 index 0000000..55d602f --- /dev/null +++ b/src/rove_launch_handler/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.5) +project(rove_launch_handler) + +find_package(ament_cmake REQUIRED) +find_package(rclpy REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "srv/LaunchRequest.srv" + "srv/LaunchListRequest.srv" +) + +ament_python_install_package(${PROJECT_NAME}) + +install( + DIRECTORY launch config + DESTINATION share/${PROJECT_NAME} +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/src/rove_launch_handler/package.xml b/src/rove_launch_handler/package.xml new file mode 100644 index 0000000..30d0915 --- /dev/null +++ b/src/rove_launch_handler/package.xml @@ -0,0 +1,26 @@ + + + rove_launch_handler + 0.0.0 + The rove_launch_handler package + Capra + GPLv3 + + ament_cmake + ament_python + + rclpy + rosidl_default_generators + + rclpy + rosidl_default_runtime + + ament_lint_auto + ament_lint_common + + rosidl_interface_packages + + + ament_python + + 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/rove_launch_handler/__init__.py b/src/rove_launch_handler/rove_launch_handler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/rove_launch_handler/rove_launch_handler/launch_handler.py b/src/rove_launch_handler/rove_launch_handler/launch_handler.py new file mode 100644 index 0000000..e144d68 --- /dev/null +++ b/src/rove_launch_handler/rove_launch_handler/launch_handler.py @@ -0,0 +1,100 @@ +#!/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 #TODO fix import, cmake does not generate the services files or need to create seperate package for interfaces + +launchedFiles = dict() + +class LaunchFile: + def __init__(self, package, fileName, pid): + self.package = package + self.fileName = fileName + self.pid = pid + +class LaunchMsg: + def __init__(self): + self.message = "" + self.isLaunched = False + self.fileName = "" + +def launchFile(package, fileName): + command = "ros2 launch {0} {1}".format(package, fileName) + + p = subprocess.Popen(command, shell=True, preexec_fn=os.setsid) + + launchMsg = LaunchMsg() + # Sleep to make sure the launch command has time to fail if there's an error + time.sleep(1) + state = p.poll() + launchMsg.fileName = fileName + if state is None: + launchMsg.message = fileName + " was launched" + launchedFiles[fileName] = LaunchFile(package, fileName, p.pid) + launchMsg.isLaunched = True + else: + launchMsg.message = fileName + " was not launched" + launchMsg.isLaunched = False + return launchMsg + +def killLaunchFile(fileName): + launchMsg = LaunchMsg() + launchMsg.fileName = fileName + if fileName in launchedFiles: + pid = launchedFiles[fileName].pid + os.killpg(os.getpgid(pid), signal.SIGINT) + del launchedFiles[fileName] + launchMsg.message = fileName + " was killed" + launchMsg.isLaunched = False + else: + launchMsg.message = fileName + " was not launched" + launchMsg.isLaunched = False + return launchMsg + +def killAll(): + for launchFile in launchedFiles.values(): + killLaunchFile(launchFile.fileName) + +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 + fileName = request.file_name + # Check if the launch file is already running + if fileName not in launchedFiles: + launchMsg = launchFile(package, fileName) + else: + launchMsg = killLaunchFile(fileName) + response.message = launchMsg.message + response.is_launched = launchMsg.isLaunched + response.file_name = launchMsg.fileName + return response + + def get_launched_files(self, request, response): + # Get array of package names + packageNames = [] + for launchedFile in launchedFiles.values(): + packageNames.append(launchedFile.package) + + response.packages = packageNames + response.files = list(launchedFiles.keys()) + return response + +def main(args=None): + rclpy.init(args=args) + node = LaunchHandlerService() + rclpy.get_default_context().on_shutdown(killAll) + rclpy.spin(node) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/src/rove_launch_handler/setup.cfg b/src/rove_launch_handler/setup.cfg new file mode 100644 index 0000000..8b95d10 --- /dev/null +++ b/src/rove_launch_handler/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/rove_launch_handler +[install] +install_scripts=$base/lib/rove_launch_handler diff --git a/src/rove_launch_handler/setup.py b/src/rove_launch_handler/setup.py new file mode 100644 index 0000000..e6ed7b9 --- /dev/null +++ b/src/rove_launch_handler/setup.py @@ -0,0 +1,27 @@ +from setuptools import setup + +package_name = 'rove_launch_handler' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + py_modules=[], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Capra', + maintainer_email='capra@ens.etsmtl.ca', + description='The rove_launch_handler package', + license='Apache License 2.0', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'launch_handler = rove_launch_handler.launch_handler:main' + ], + }, + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], +) 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' From 0be72a13d782b63101cf7dd593bb66a7464024ac Mon Sep 17 00:00:00 2001 From: SimonR99 Date: Sun, 23 Jun 2024 11:55:51 +0200 Subject: [PATCH 5/9] fix message error --- src/rove_launch_handler/CMakeLists.txt | 13 ++++++--- src/rove_launch_handler/package.xml | 4 +-- .../rove_launch_handler/__init__.py | 0 .../launch_handler.py | 2 +- src/rove_launch_handler/setup.cfg | 4 --- src/rove_launch_handler/setup.py | 27 ------------------- 6 files changed, 13 insertions(+), 37 deletions(-) delete mode 100644 src/rove_launch_handler/rove_launch_handler/__init__.py rename src/rove_launch_handler/{rove_launch_handler => scripts}/launch_handler.py (96%) mode change 100644 => 100755 delete mode 100644 src/rove_launch_handler/setup.cfg delete mode 100644 src/rove_launch_handler/setup.py diff --git a/src/rove_launch_handler/CMakeLists.txt b/src/rove_launch_handler/CMakeLists.txt index 55d602f..47ac841 100644 --- a/src/rove_launch_handler/CMakeLists.txt +++ b/src/rove_launch_handler/CMakeLists.txt @@ -2,18 +2,25 @@ cmake_minimum_required(VERSION 3.5) project(rove_launch_handler) find_package(ament_cmake REQUIRED) -find_package(rclpy 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" ) -ament_python_install_package(${PROJECT_NAME}) +# Install Python executables +install(PROGRAMS + scripts/launch_handler.py + DESTINATION lib/${PROJECT_NAME} +) install( - DIRECTORY launch config + DIRECTORY srv DESTINATION share/${PROJECT_NAME} ) diff --git a/src/rove_launch_handler/package.xml b/src/rove_launch_handler/package.xml index 30d0915..d2ac48e 100644 --- a/src/rove_launch_handler/package.xml +++ b/src/rove_launch_handler/package.xml @@ -4,7 +4,7 @@ 0.0.0 The rove_launch_handler package Capra - GPLv3 + MIT ament_cmake ament_python @@ -21,6 +21,6 @@ rosidl_interface_packages - ament_python + ament_cmake diff --git a/src/rove_launch_handler/rove_launch_handler/__init__.py b/src/rove_launch_handler/rove_launch_handler/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/rove_launch_handler/rove_launch_handler/launch_handler.py b/src/rove_launch_handler/scripts/launch_handler.py old mode 100644 new mode 100755 similarity index 96% rename from src/rove_launch_handler/rove_launch_handler/launch_handler.py rename to src/rove_launch_handler/scripts/launch_handler.py index e144d68..2b25821 --- a/src/rove_launch_handler/rove_launch_handler/launch_handler.py +++ b/src/rove_launch_handler/scripts/launch_handler.py @@ -5,7 +5,7 @@ import signal import subprocess import os -from rove_launch_handler.srv import LaunchRequest, LaunchListRequest #TODO fix import, cmake does not generate the services files or need to create seperate package for interfaces +from rove_launch_handler.srv import LaunchRequest, LaunchListRequest launchedFiles = dict() diff --git a/src/rove_launch_handler/setup.cfg b/src/rove_launch_handler/setup.cfg deleted file mode 100644 index 8b95d10..0000000 --- a/src/rove_launch_handler/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script_dir=$base/lib/rove_launch_handler -[install] -install_scripts=$base/lib/rove_launch_handler diff --git a/src/rove_launch_handler/setup.py b/src/rove_launch_handler/setup.py deleted file mode 100644 index e6ed7b9..0000000 --- a/src/rove_launch_handler/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -from setuptools import setup - -package_name = 'rove_launch_handler' - -setup( - name=package_name, - version='0.0.0', - packages=[package_name], - py_modules=[], - install_requires=['setuptools'], - zip_safe=True, - maintainer='Capra', - maintainer_email='capra@ens.etsmtl.ca', - description='The rove_launch_handler package', - license='Apache License 2.0', - tests_require=['pytest'], - entry_points={ - 'console_scripts': [ - 'launch_handler = rove_launch_handler.launch_handler:main' - ], - }, - data_files=[ - ('share/ament_index/resource_index/packages', - ['resource/' + package_name]), - ('share/' + package_name, ['package.xml']), - ], -) From 02ad394ef3b24250b1e58006987a0155e490d287 Mon Sep 17 00:00:00 2001 From: SimonR99 Date: Sun, 23 Jun 2024 13:59:43 +0200 Subject: [PATCH 6/9] add service handling --- README.md | 18 ++++ src/rove_launch_handler/CMakeLists.txt | 2 +- .../launch/launch_handler.launch.py | 25 +++++ .../scripts/launch_handler.py | 91 +++++++++---------- .../scripts/launch_script.service | 8 ++ .../scripts/launch_script.sh | 7 ++ utils/install.sh | 5 + 7 files changed, 109 insertions(+), 47 deletions(-) create mode 100644 src/rove_launch_handler/launch/launch_handler.launch.py create mode 100755 src/rove_launch_handler/scripts/launch_script.service create mode 100755 src/rove_launch_handler/scripts/launch_script.sh create mode 100755 utils/install.sh 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_launch_handler/CMakeLists.txt b/src/rove_launch_handler/CMakeLists.txt index 47ac841..06f6299 100644 --- a/src/rove_launch_handler/CMakeLists.txt +++ b/src/rove_launch_handler/CMakeLists.txt @@ -20,7 +20,7 @@ install(PROGRAMS ) install( - DIRECTORY srv + DIRECTORY launch srv DESTINATION share/${PROJECT_NAME} ) 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..2996f19 --- /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('rosbridge_server'), + 'launch', + 'rosbridge_websocket_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/scripts/launch_handler.py b/src/rove_launch_handler/scripts/launch_handler.py index 2b25821..333a5d3 100755 --- a/src/rove_launch_handler/scripts/launch_handler.py +++ b/src/rove_launch_handler/scripts/launch_handler.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import time import rclpy from rclpy.node import Node @@ -7,56 +8,60 @@ import os from rove_launch_handler.srv import LaunchRequest, LaunchListRequest -launchedFiles = dict() +launched_files = {} class LaunchFile: - def __init__(self, package, fileName, pid): + def __init__(self, package, file_name, pid): self.package = package - self.fileName = fileName + self.file_name = file_name self.pid = pid class LaunchMsg: def __init__(self): self.message = "" - self.isLaunched = False - self.fileName = "" + self.is_launched = False + self.file_name = "" -def launchFile(package, fileName): - command = "ros2 launch {0} {1}".format(package, fileName) +def launch_file(package, file_name): + command = f"ros2 launch {package} {file_name}" p = subprocess.Popen(command, shell=True, preexec_fn=os.setsid) - launchMsg = LaunchMsg() + 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() - launchMsg.fileName = fileName + launch_msg.file_name = file_name if state is None: - launchMsg.message = fileName + " was launched" - launchedFiles[fileName] = LaunchFile(package, fileName, p.pid) - launchMsg.isLaunched = True + launch_msg.message = f"{file_name} was launched" + launched_files[file_name] = LaunchFile(package, file_name, p.pid) + launch_msg.is_launched = True else: - launchMsg.message = fileName + " was not launched" - launchMsg.isLaunched = False - return launchMsg + launch_msg.message = f"{file_name} was not launched" + launch_msg.is_launched = False + return launch_msg -def killLaunchFile(fileName): - launchMsg = LaunchMsg() - launchMsg.fileName = fileName - if fileName in launchedFiles: - pid = launchedFiles[fileName].pid - os.killpg(os.getpgid(pid), signal.SIGINT) - del launchedFiles[fileName] - launchMsg.message = fileName + " was killed" - launchMsg.isLaunched = False +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: - launchMsg.message = fileName + " was not launched" - launchMsg.isLaunched = False - return launchMsg + launch_msg.message = f"{file_name} was not launched" + launch_msg.is_launched = False + return launch_msg -def killAll(): - for launchFile in launchedFiles.values(): - killLaunchFile(launchFile.fileName) +def kill_all(): + for file_name in list(launched_files.keys()): + kill_launch_file(file_name) class LaunchHandlerService(Node): def __init__(self): @@ -67,31 +72,25 @@ def __init__(self): def launch_callback(self, request, response): package = request.package - fileName = request.file_name - # Check if the launch file is already running - if fileName not in launchedFiles: - launchMsg = launchFile(package, fileName) + file_name = request.file_name + if file_name not in launched_files: + launch_msg = launch_file(package, file_name) else: - launchMsg = killLaunchFile(fileName) - response.message = launchMsg.message - response.is_launched = launchMsg.isLaunched - response.file_name = launchMsg.fileName + 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): - # Get array of package names - packageNames = [] - for launchedFile in launchedFiles.values(): - packageNames.append(launchedFile.package) - - response.packages = packageNames - response.files = list(launchedFiles.keys()) + 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(killAll) + rclpy.get_default_context().on_shutdown(kill_all) rclpy.spin(node) node.destroy_node() rclpy.shutdown() 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..0d31ca9 --- /dev/null +++ b/src/rove_launch_handler/scripts/launch_script.service @@ -0,0 +1,8 @@ +[Unit] +Descript=Robot launch script + +[Service] +ExecStart=/usr/bin/launch_script.sh + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/src/rove_launch_handler/scripts/launch_script.sh b/src/rove_launch_handler/scripts/launch_script.sh new file mode 100755 index 0000000..3b9075b --- /dev/null +++ b/src/rove_launch_handler/scripts/launch_script.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# To be placed in /usr/bin/ +# Launch the robot +#source /media/SSD/stable/rove/src/rove_launch_handler/install/setup.bash +source /home/simon/Workspace/capra/rove/install/setup.bash + +ros2 launch rove_launch_handler launch_handler.launch \ No newline at end of file diff --git a/utils/install.sh b/utils/install.sh new file mode 100755 index 0000000..52d4e2c --- /dev/null +++ b/utils/install.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +sudo cp ./src/rove_launch_handler/scripts/launch_script.sh /usr/bin/launch_script.sh +sudo cp ./src/rove_launch_handler/scripts/launch_script.service /lib/systemd/system/launch_script.service +sudo systemctl enable launch_script.service \ No newline at end of file From f656387f3643a756155e46d8a813ec82b86e13d0 Mon Sep 17 00:00:00 2001 From: SimonR99 Date: Sun, 23 Jun 2024 15:45:27 +0200 Subject: [PATCH 7/9] add install script --- src/rove_launch_handler/scripts/launch_script.service | 7 ++++++- src/rove_launch_handler/scripts/launch_script.sh | 7 ------- utils/install.sh | 8 +++++--- 3 files changed, 11 insertions(+), 11 deletions(-) delete mode 100755 src/rove_launch_handler/scripts/launch_script.sh diff --git a/src/rove_launch_handler/scripts/launch_script.service b/src/rove_launch_handler/scripts/launch_script.service index 0d31ca9..6cd0e14 100755 --- a/src/rove_launch_handler/scripts/launch_script.service +++ b/src/rove_launch_handler/scripts/launch_script.service @@ -1,8 +1,13 @@ [Unit] Descript=Robot launch script +After=network.target [Service] -ExecStart=/usr/bin/launch_script.sh +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/scripts/launch_script.sh b/src/rove_launch_handler/scripts/launch_script.sh deleted file mode 100755 index 3b9075b..0000000 --- a/src/rove_launch_handler/scripts/launch_script.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -# To be placed in /usr/bin/ -# Launch the robot -#source /media/SSD/stable/rove/src/rove_launch_handler/install/setup.bash -source /home/simon/Workspace/capra/rove/install/setup.bash - -ros2 launch rove_launch_handler launch_handler.launch \ No newline at end of file diff --git a/utils/install.sh b/utils/install.sh index 52d4e2c..afd033a 100755 --- a/utils/install.sh +++ b/utils/install.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash - -sudo cp ./src/rove_launch_handler/scripts/launch_script.sh /usr/bin/launch_script.sh +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 enable launch_script.service \ No newline at end of file +sudo systemctl daemon-reload +sudo systemctl enable launch_script.service +sudo systemctl start launch_script.service \ No newline at end of file From 8ea79e355bef182e702379a2e5c994a13ec7b114 Mon Sep 17 00:00:00 2001 From: SimonR99 Date: Sun, 23 Jun 2024 17:52:27 +0200 Subject: [PATCH 8/9] good server + better ui --- .../launch/launch_handler.launch.py | 4 +- utils/ui/capra_ui.json | 292 ++++++++++++++---- 2 files changed, 233 insertions(+), 63 deletions(-) diff --git a/src/rove_launch_handler/launch/launch_handler.launch.py b/src/rove_launch_handler/launch/launch_handler.launch.py index 2996f19..e0f6178 100644 --- a/src/rove_launch_handler/launch/launch_handler.launch.py +++ b/src/rove_launch_handler/launch/launch_handler.launch.py @@ -7,9 +7,9 @@ def generate_launch_description(): rosbridge_launch_file = os.path.join( - get_package_share_directory('rosbridge_server'), + get_package_share_directory('foxglove_bridge'), 'launch', - 'rosbridge_websocket_launch.xml' + 'foxglove_bridge_launch.xml' ) return LaunchDescription([ diff --git a/utils/ui/capra_ui.json b/utils/ui/capra_ui.json index ef57536..d7758fd 100644 --- a/utils/ui/capra_ui.json +++ b/utils/ui/capra_ui.json @@ -4,22 +4,31 @@ "buttonText": "Front LED ON", "buttonTooltip": "", "advancedView": false, - "value": "{}", - "foxglovePanelTitle": "Front LED ON" + "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" }, "Indicator!360e2e8": { - "path": "", + "path": "/odom.twist.twist.linear.x", "style": "bulb", - "fallbackColor": "#a0a0a0", - "fallbackLabel": "False", + "fallbackColor": "#e0e2df", + "fallbackLabel": "Speed good", "rules": [ { - "operator": "=", - "rawValue": "true", + "operator": "<=", + "rawValue": "1", "color": "#68e24a", - "label": "True" + "label": "Speed good" + }, + { + "operator": ">", + "rawValue": "1", + "color": "#ede466", + "label": "Slower" } - ] + ], + "foxglovePanelTitle": "lidar state" }, "Publish!gkhilm": { "buttonText": "Front LED OFF", @@ -218,50 +227,33 @@ "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" } }, - "Publish!qnfojc": { - "buttonText": "Publish", - "buttonTooltip": "", - "advancedView": true, - "value": "{\n \"data\": \"rove_bringup sim.launch.py\"\n}", - "foxglovePanelTitle": "Launch", - "topicName": "/manager/launch", - "datatype": "std_msgs/msg/String" - }, - "Publish!2cg1exi": { - "buttonText": "Publish", - "buttonTooltip": "", - "advancedView": true, - "value": "{\n \"data\": \"rove_bringup sim.launch.py\"\n}", - "foxglovePanelTitle": "Kill", - "topicName": "/manager/kill", - "datatype": "std_msgs/msg/String" - }, + "Joystick Panel.Joystick!f5fjj6": {}, "3D!wd5ayb": { "cameraState": { - "distance": 15.475618749968437, - "perspective": true, - "phi": 53.72454709424579, + "perspective": false, + "distance": 25.847108697940985, + "phi": 33.02243748196572, + "thetaOffset": -106.2487931391679, + "targetOffset": [ + 1.4574957054508668, + -1.872533894914948, + 5.047356121098524e-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 @@ -415,29 +407,167 @@ "imageMode": {}, "followTf": "base_link" }, + "3D!2euzghd": { + "cameraState": { + "perspective": true, + "distance": 25.847108697995846, + "phi": 59.99999999999988, + "thetaOffset": 44.99999999999998, + "targetOffset": [ + -0.6765570540972538, + 1.1691389716638279, + -5.075832289577129e-17 + ], + "target": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "fovy": 45, + "near": 0.5, + "far": 5000 + }, + "followMode": "follow-pose", + "followTf": "map", + "scene": {}, + "transforms": { + "frame:map": { + "visible": true + } + }, + "topics": { + "/marker": { + "visible": true + } + }, + "layers": {}, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + }, + "imageMode": {} + }, "map!60yjuv": { "center": { - "lat": 38.16148014673053, - "lon": -122.45462179183961 + "lat": 38.16148858251846, + "lon": -122.45468616485597 }, "customTileUrl": "", "disabledTopics": [], "followTopic": "/gps", "layer": "map", "topicColors": {}, - "zoomLevel": 16, + "zoomLevel": 14, "maxNativeZoom": 18 }, - "Table!1xg0s4v": { - "topicPath": "" + "3D!ac8om2": {}, + "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" + }, + "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" }, - "RosOut!14blizg": { - "searchTerms": [], - "minLogLevel": 1, - "nameFilter": {} + "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": 2, + "activeTabIdx": 0, "tabs": [ { "title": "Status", @@ -447,7 +577,7 @@ "first": "Publish!1b7sy1a", "second": "Indicator!360e2e8", "direction": "column", - "splitPercentage": 55.757575757575765 + "splitPercentage": 55.6420233463035 }, "second": { "first": "Publish!gkhilm", @@ -506,12 +636,8 @@ } }, { - "title": "example", - "layout": { - "first": "Publish!qnfojc", - "second": "Publish!2cg1exi", - "direction": "row" - } + "title": "Joy", + "layout": "Joystick Panel.Joystick!f5fjj6" } ] }, @@ -522,18 +648,62 @@ "title": "Nav", "layout": { "first": "3D!wd5ayb", + "second": { + "first": "3D!2euzghd", + "second": "map!60yjuv", + "direction": "column", + "splitPercentage": 45.103857566765576 + }, + "direction": "row", + "splitPercentage": 61.47652076855616 + } + }, + { + "title": "Arm", + "layout": "3D!ac8om2" + }, + { + "title": "launch", + "layout": { + "first": { + "first": { + "first": "CallService!2b4k70w", + "second": "CallService!3utg1bx", + "direction": "column" + }, + "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": "map!60yjuv", - "second": "Table!1xg0s4v", - "direction": "row" + "first": "CallService!43dz0yr", + "second": "CallService!2qnnpsv", + "direction": "column" }, - "second": "RosOut!14blizg", + "second": "CallService!6ywrf4", "direction": "column", - "splitPercentage": 48.263254113345525 + "splitPercentage": 64.83679525222553 }, "direction": "row", - "splitPercentage": 50.911458333333336 + "splitPercentage": 85.62162162162163 } } ] @@ -548,6 +718,6 @@ "first": "Tab!2iobm2s", "second": "Tab!1dud6cr", "direction": "column", - "splitPercentage": 25.259067357512954 + "splitPercentage": 30.22794846382557 } } \ No newline at end of file From cf95adc2d2bb07eed18ffcff2136959b7a433547 Mon Sep 17 00:00:00 2001 From: SimonR99 Date: Sun, 23 Jun 2024 17:56:21 +0200 Subject: [PATCH 9/9] remove ament python --- src/rove_launch_handler/package.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rove_launch_handler/package.xml b/src/rove_launch_handler/package.xml index d2ac48e..ec61d5b 100644 --- a/src/rove_launch_handler/package.xml +++ b/src/rove_launch_handler/package.xml @@ -7,7 +7,6 @@ MIT ament_cmake - ament_python rclpy rosidl_default_generators