From f8fe9ebab644891bd0fe7e59d9b8d19221583ebf Mon Sep 17 00:00:00 2001 From: bondada-a Date: Fri, 19 Sep 2025 13:45:19 -0400 Subject: [PATCH 1/7] Add end_effectors directory with new drivers and updated robotiq_hande drivers - Remove legacy robotiq-hande/gripper_service - Add end_effectors/ with VCS-managed repositories - Include EPick configuration overlay" --- src/end_effectors/README.md | 31 +++++ src/end_effectors/end_effectors.repos | 17 +++ src/end_effectors/epick_config/CMakeLists.txt | 14 +++ .../launch/epick_bringup.launch.py | 31 +++++ src/end_effectors/epick_config/package.xml | 22 ++++ .../epick_config/urdf/epick_overlay.xacro | 21 ++++ .../gripper_service/CMakeLists.txt | 64 ----------- .../gripper_service/gripper_service.hpp | 46 -------- src/robotiq-hande/gripper_service/package.xml | 22 ---- .../gripper_service/src/gripper_close.cpp | 47 -------- .../gripper_service/src/gripper_open.cpp | 46 -------- .../gripper_service/src/gripper_service.cpp | 106 ------------------ src/ros2.repos | 12 -- 13 files changed, 136 insertions(+), 343 deletions(-) create mode 100644 src/end_effectors/README.md create mode 100644 src/end_effectors/end_effectors.repos create mode 100644 src/end_effectors/epick_config/CMakeLists.txt create mode 100644 src/end_effectors/epick_config/launch/epick_bringup.launch.py create mode 100644 src/end_effectors/epick_config/package.xml create mode 100644 src/end_effectors/epick_config/urdf/epick_overlay.xacro delete mode 100644 src/robotiq-hande/gripper_service/CMakeLists.txt delete mode 100644 src/robotiq-hande/gripper_service/include/gripper_service/gripper_service.hpp delete mode 100644 src/robotiq-hande/gripper_service/package.xml delete mode 100644 src/robotiq-hande/gripper_service/src/gripper_close.cpp delete mode 100644 src/robotiq-hande/gripper_service/src/gripper_open.cpp delete mode 100644 src/robotiq-hande/gripper_service/src/gripper_service.cpp diff --git a/src/end_effectors/README.md b/src/end_effectors/README.md new file mode 100644 index 000000000..551b787bb --- /dev/null +++ b/src/end_effectors/README.md @@ -0,0 +1,31 @@ +# End Effectors + +This directory contains drivers and configuration for robot end effectors like grippers and vacuum systems. + +## Getting the Drivers + +The actual driver code lives in separate repositories. To download them: + +```bash +vcs import src/end_effectors < src/end_effectors/end_effectors.repos +``` + +This pulls in: +- `serial` - ROS2 serial communication +- `robotiq_hande_driver` - Robotiq HandE gripper driver +- `robotiq_hande_description` - Robotiq HandE URDF models +- `ros2_epick_gripper` - EPick vacuum gripper driver + +**Note:** The EPick driver uses a fork from https://github.com/bondada-a/ros2_epick_gripper.git instead of the upstream PickNikRobotics version. This fork includes updated headers and removes the epick_moveit_studio package (requires Moveit Pro). + +## EPick Configuration + +The `epick_config` package provides an overlay configuration (over ros2_epick_driver) for our specific setup: + +- Serial port: `/tmp/ttyUR` +- Custom positioning offsets +- Hardware vs simulation mode + +## Future Work + +For simpler single-robot setups, we could skip the overlay package and put EPick parameters directly in the robot URDF files? \ No newline at end of file diff --git a/src/end_effectors/end_effectors.repos b/src/end_effectors/end_effectors.repos new file mode 100644 index 000000000..608efb2cb --- /dev/null +++ b/src/end_effectors/end_effectors.repos @@ -0,0 +1,17 @@ +repositories: + serial: + type: git + url: https://github.com/tylerjw/serial.git + version: ros2 + robotiq_hande_driver: + type: git + url: https://github.com/AGH-CEAI/robotiq_hande_driver.git + version: humble-devel + robotiq_hande_description: + type: git + url: https://github.com/macmacal/robotiq_hande_description.git + version: humble-devel + ros2_epick_gripper: + type: git + url: https://github.com/bondada-a/ros2_epick_gripper.git + version: main \ No newline at end of file diff --git a/src/end_effectors/epick_config/CMakeLists.txt b/src/end_effectors/epick_config/CMakeLists.txt new file mode 100644 index 000000000..f88771b1e --- /dev/null +++ b/src/end_effectors/epick_config/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.8) +project(epick_config) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +find_package(ament_cmake REQUIRED) + +install(DIRECTORY urdf launch + DESTINATION share/${PROJECT_NAME} +) + +ament_package() \ No newline at end of file diff --git a/src/end_effectors/epick_config/launch/epick_bringup.launch.py b/src/end_effectors/epick_config/launch/epick_bringup.launch.py new file mode 100644 index 000000000..76ec4c4a6 --- /dev/null +++ b/src/end_effectors/epick_config/launch/epick_bringup.launch.py @@ -0,0 +1,31 @@ +from launch import LaunchDescription +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration + + +def generate_launch_description(): + parent_arg = DeclareLaunchArgument("parent", default_value="tool0") + port_arg = DeclareLaunchArgument("usb_port", default_value="/tmp/ttyUR") + fake_arg = DeclareLaunchArgument("use_fake_hardware", default_value="false") + + usb_port = LaunchConfiguration("usb_port") + use_fake_hardware = LaunchConfiguration("use_fake_hardware") + + controller = Node( + package="controller_manager", + executable="ros2_control_node", + parameters=[ + { + "usb_port": usb_port, + "use_fake_hardware": use_fake_hardware, + } + ], + ) + + return LaunchDescription([ + parent_arg, + port_arg, + fake_arg, + controller, + ]) \ No newline at end of file diff --git a/src/end_effectors/epick_config/package.xml b/src/end_effectors/epick_config/package.xml new file mode 100644 index 000000000..4e509e254 --- /dev/null +++ b/src/end_effectors/epick_config/package.xml @@ -0,0 +1,22 @@ + + + + epick_config + 0.1.0 + Overlay configuration for ros2_epick_gripper (pose and serial port). + Aditya Bondada + Apache-2.0 + + ament_cmake + ros2_control + xacro + ros2launch + ros2run + ros2param + rclcpp + epick_description + + + ament_cmake + + \ No newline at end of file diff --git a/src/end_effectors/epick_config/urdf/epick_overlay.xacro b/src/end_effectors/epick_config/urdf/epick_overlay.xacro new file mode 100644 index 000000000..c37b05af8 --- /dev/null +++ b/src/end_effectors/epick_config/urdf/epick_overlay.xacro @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/robotiq-hande/gripper_service/CMakeLists.txt b/src/robotiq-hande/gripper_service/CMakeLists.txt deleted file mode 100644 index 35311c0e3..000000000 --- a/src/robotiq-hande/gripper_service/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -cmake_minimum_required(VERSION 3.8) -project(gripper_service) - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wall -Wextra -Wpedantic) -endif() - -# find dependencies -find_package(ament_cmake REQUIRED) -find_package(rclcpp REQUIRED) -find_package(rclcpp_components REQUIRED) -find_package(pdf_beamtime_interfaces REQUIRED) -find_package(robotiq_driver REQUIRED) -# uncomment the following section in order to fill in -# further dependencies manually. -# find_package( REQUIRED) - -set(dependencies - rclcpp - rclcpp_components - pdf_beamtime_interfaces - robotiq_driver -) - -include_directories(include) # This makes sure the libraries are visible - -add_executable(gripper_service src/gripper_service.cpp) -ament_target_dependencies(gripper_service ${dependencies}) - -add_executable(gripper_close src/gripper_close.cpp) -ament_target_dependencies(gripper_close ${dependencies}) - -add_executable(gripper_open src/gripper_open.cpp) -ament_target_dependencies(gripper_open ${dependencies}) - -install(TARGETS - gripper_service - gripper_close - gripper_open - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib/${PROJECT_NAME} -) - -install(DIRECTORY DESTINATION share/${PROJECT_NAME}) - -install( - DIRECTORY include/ - DESTINATION include -) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - # the following line skips the linter which checks for copyrights - # comment the line when a copyright and license is added to all source files - set(ament_cmake_copyright_FOUND TRUE) - # the following line skips cpplint (only works in a git repo) - # comment the line when this package is in a git repo and when - # a copyright and license is added to all source files - set(ament_cmake_cpplint_FOUND TRUE) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package() diff --git a/src/robotiq-hande/gripper_service/include/gripper_service/gripper_service.hpp b/src/robotiq-hande/gripper_service/include/gripper_service/gripper_service.hpp deleted file mode 100644 index 0ab662b47..000000000 --- a/src/robotiq-hande/gripper_service/include/gripper_service/gripper_service.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/*Copyright 2023 Brookhaven National Laboratory -BSD 3 Clause License. See LICENSE.txt for details.*/ -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include "pdf_beamtime_interfaces/srv/gripper_control_msg.hpp" - -#include - -class GripperService : public rclcpp::Node -{ -private: - /// @brief your serial port goes here - const char * kComPort = "/tmp/ttyUR"; - const int kSlaveID = 0x09; - - rclcpp::Service::SharedPtr service; - // rclcpp::Node::SharedPtr node_; - RobotiqGripperInterface gripper_; - -/// @brief Gripper commands as enums for ease of use - enum class Gripper_Command {OPEN, CLOSE, PARTIAL, ACTIVE, DEACTIVE}; - - std::map gripper_command_map_ = { - {"ACTIVE", Gripper_Command::ACTIVE}, - {"DEACTIVE", Gripper_Command::DEACTIVE}, - {"OPEN", Gripper_Command::OPEN}, - {"CLOSE", Gripper_Command::CLOSE}, - {"PARTIAL", Gripper_Command::PARTIAL} - }; - - /// @brief callback function for the gripper service - void gripper_controller( - const std::shared_ptr request, - std::shared_ptr response); - -public: - GripperService(); -}; diff --git a/src/robotiq-hande/gripper_service/package.xml b/src/robotiq-hande/gripper_service/package.xml deleted file mode 100644 index 8e79e3ebc..000000000 --- a/src/robotiq-hande/gripper_service/package.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - gripper_service - 0.0.0 - TODO: Package description - wfernando1 - Apache-2.0 - - ament_cmake - rclcpp - rclcpp_components - pdf_beamtime_interfaces - robotiq_driver - - ament_lint_auto - ament_lint_common - - - ament_cmake - - diff --git a/src/robotiq-hande/gripper_service/src/gripper_close.cpp b/src/robotiq-hande/gripper_service/src/gripper_close.cpp deleted file mode 100644 index 6de803e21..000000000 --- a/src/robotiq-hande/gripper_service/src/gripper_close.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*Copyright 2024 Brookhaven National Laboratory -BSD 3 Clause License. See LICENSE.txt for details.*/ -#include -#include -#include - -#include "rclcpp/rclcpp.hpp" -#include "pdf_beamtime_interfaces/srv/gripper_control_msg.hpp" - -using namespace std::chrono_literals; - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - - - std::shared_ptr node = rclcpp::Node::make_shared("gripper_close"); - rclcpp::Client::SharedPtr client = - node->create_client("gripper_service"); - - auto request = std::make_shared(); - request->command = "CLOSE"; - request->grip = 50; - - while (!client->wait_for_service(1s)) { - if (!rclcpp::ok()) { - RCLCPP_ERROR( - rclcpp::get_logger( - "rclcpp"), "Interrupted while waiting for the service. Exiting."); - return 0; - } - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..."); - } - - auto result = client->async_send_request(request); - // Wait for the result. - if (rclcpp::spin_until_future_complete(node, result) == - rclcpp::FutureReturnCode::SUCCESS) - { - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Results: %d", result.get()->results); - } else { - RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service"); - } - - rclcpp::shutdown(); - return 0; -} diff --git a/src/robotiq-hande/gripper_service/src/gripper_open.cpp b/src/robotiq-hande/gripper_service/src/gripper_open.cpp deleted file mode 100644 index a1584bd10..000000000 --- a/src/robotiq-hande/gripper_service/src/gripper_open.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*Copyright 2024 Brookhaven National Laboratory -BSD 3 Clause License. See LICENSE.txt for details.*/ -#include -#include -#include - -#include "rclcpp/rclcpp.hpp" -#include "pdf_beamtime_interfaces/srv/gripper_control_msg.hpp" - -using namespace std::chrono_literals; - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - - std::shared_ptr node = rclcpp::Node::make_shared("gripper_open"); - rclcpp::Client::SharedPtr client = - node->create_client("gripper_service"); - - auto request = std::make_shared(); - request->command = "OPEN"; - request->grip = 50; - - while (!client->wait_for_service(1s)) { - if (!rclcpp::ok()) { - RCLCPP_ERROR( - rclcpp::get_logger( - "rclcpp"), "Interrupted while waiting for the service. Exiting."); - return 0; - } - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..."); - } - - auto result = client->async_send_request(request); - // Wait for the result. - if (rclcpp::spin_until_future_complete(node, result) == - rclcpp::FutureReturnCode::SUCCESS) - { - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Results: %d", result.get()->results); - } else { - RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service"); - } - - rclcpp::shutdown(); - return 0; -} diff --git a/src/robotiq-hande/gripper_service/src/gripper_service.cpp b/src/robotiq-hande/gripper_service/src/gripper_service.cpp deleted file mode 100644 index 1922a6b4a..000000000 --- a/src/robotiq-hande/gripper_service/src/gripper_service.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/*Copyright 2024 Brookhaven National Laboratory -BSD 3 Clause License. See LICENSE.txt for details.*/ -#include - -using namespace std::placeholders; - -GripperService::GripperService() -: Node("gripper_server_node"), - gripper_(kComPort, kSlaveID) -{ - RCLCPP_INFO(this->get_logger(), "Activate the gripper ..."); - // Clear the registers - gripper_.deactivateGripper(); - - // Activate the gripper - gripper_.activateGripper(); - gripper_.setSpeed(0x0F); - - RCLCPP_INFO(this->get_logger(), "Activation is successful"); - - service = - this->create_service( - "gripper_service", - std::bind( - &GripperService::gripper_controller, this, _1, _2)); - - // Check if the service was created successfully - if (service == nullptr) { - RCLCPP_ERROR(this->get_logger(), "Failed to create service"); - rclcpp::shutdown(); - } else { - RCLCPP_INFO(this->get_logger(), "Service %s created successfully", service->get_service_name()); - RCLCPP_INFO(this->get_logger(), "Ready to receive gripper commands."); - } -} - -void GripperService::gripper_controller( - const std::shared_ptr request, - std::shared_ptr response) -{ - int status = 0; - try { - // conver the request command string to the mapping enum - Gripper_Command gripper_command_enum = gripper_command_map_[request->command]; - - switch (gripper_command_enum) { - case Gripper_Command::ACTIVE: - // Activate the gripper - gripper_.deactivateGripper(); - gripper_.activateGripper(); - RCLCPP_INFO(this->get_logger(), "Activation is successful"); - - break; - - case Gripper_Command::DEACTIVE: - // Deactivate the gripper - gripper_.deactivateGripper(); - RCLCPP_INFO(this->get_logger(), "Gripper is Deactivated"); - - break; - - case Gripper_Command::PARTIAL: - { - // Closes the gripper to the percentage set by request->grip - uint8_t val = request->grip * 2.55; // convert the scales from 01-100 to 0-255 - gripper_.setGripperPosition(val); - RCLCPP_INFO(this->get_logger(), "Gripper is Open"); - } - break; - - case Gripper_Command::OPEN: - // Open the gripper fully - gripper_.setGripperPosition(0x00); - RCLCPP_INFO(this->get_logger(), "Gripper is Open"); - break; - - case Gripper_Command::CLOSE: - // Close the gripper fully - gripper_.setGripperPosition(0xFF); - RCLCPP_INFO(this->get_logger(), "Gripper is Close"); - break; - - default: - break; - } - status = 1; - } catch (const std::exception & e) { - RCLCPP_ERROR(this->get_logger(), e.what()); - status = 0; - } - - // Send the response back - response->results = status; -} - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - - auto gripper_server_node = std::make_shared(); - - rclcpp::spin(gripper_server_node); - rclcpp::shutdown(); - - return 0; -} diff --git a/src/ros2.repos b/src/ros2.repos index 6b7124b1f..d8b959cea 100644 --- a/src/ros2.repos +++ b/src/ros2.repos @@ -4,15 +4,3 @@ # Example: ############ repositories: - robotiq-hande/gripper: - type: git - url: https://github.com/PickNikRobotics/ros2_robotiq_gripper.git - version: cmake-external-project-serial - robotiq-hande/serial: - type: git - url: https://github.com/PickNikRobotics/serial-release.git - version: release/humble/serial - custom-ur-descriptions/ur_description: - type: git - url: https://github.com/UniversalRobots/Universal_Robots_ROS2_Description.git - version: 21d5bfc277cffc7eb97c6a515deb8fc2001cc871 From 1b3c36b01908c89887bce34fbb33527139d85ccb Mon Sep 17 00:00:00 2001 From: bondada-a Date: Fri, 19 Sep 2025 14:16:11 -0400 Subject: [PATCH 2/7] updated README.md with end_effectors changes --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 122e9b00d..b311f702f 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Each manifest in the [docker](./docker) directory is a container image that can ### Source Contents - [ros2.repos](./src/ros2.repos): ROS2 workspace file for downloading the required external ROS2 dependencies. -- [robotiq-hande](./src/robotiq-hande): Source directory for the HandE gripper. - - [gripper_service](./src/robotiq-hande/gripper_service): ROS2 package for controlling the HandE gripper. - - Other packages are pulled in through rosdep. +- [end_effectors](./src/end_effectors): End effector drivers and configuration for grippers and vacuum systems. + - [end_effectors.repos](./src/end_effectors/end_effectors.repos): VCS file for downloading robotiq_hande_driver, robotiq_hande_description, ros2_epick_gripper, and serial packages. + - [epick_config](./src/end_effectors/epick_config): Site-specific configuration overlay for EPick vacuum gripper. - [custom-ur-descriptions](./src/custom-ur-descriptions): Source directory for custom UR robot arm descriptions (e.g., attaching grippers or other end effectors). - [ur3e_hande_robot_description](./src/custom-ur-descriptions/ur3e_hande_robot_description): ROS2 package for defining the UR3e robot arm with the HandE gripper. - [ur3e_hande_moveit_config](./src/custom-ur-descriptions/ur3e_hande_moveit_config): ROS2 package for configuring MoveIt for the UR3e robot arm with the HandE gripper. From 7ac1aee0e74305999205620ef3c3af743f23db81 Mon Sep 17 00:00:00 2001 From: sixym3 Date: Tue, 23 Sep 2025 10:00:35 -0400 Subject: [PATCH 3/7] Added pipettor packages and COLCON_IGNORE in packages currently not in use --- .gitignore | 6 ++++++ README.md | 12 ++++++++---- build.sh | 12 ++++++------ setup.sh | 1 + src/aruco_pose/COLCON_IGNORE | 0 src/custom-ur-descriptions/COLCON_IGNORE | 0 src/end_effectors/README.md | 6 +++--- src/end_effectors/end_effectors.repos | 8 ++++++-- src/end_effectors/pipettor | 1 + .../robotiq_hande/robotiq_hande_description | 1 + src/end_effectors/robotiq_hande/robotiq_hande_driver | 1 + src/end_effectors/ros2_epick_gripper | 1 + src/end_effectors/serial | 1 + src/pdf/COLCON_IGNORE | 0 14 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 src/aruco_pose/COLCON_IGNORE create mode 100644 src/custom-ur-descriptions/COLCON_IGNORE create mode 160000 src/end_effectors/pipettor create mode 160000 src/end_effectors/robotiq_hande/robotiq_hande_description create mode 160000 src/end_effectors/robotiq_hande/robotiq_hande_driver create mode 160000 src/end_effectors/ros2_epick_gripper create mode 160000 src/end_effectors/serial create mode 100644 src/pdf/COLCON_IGNORE diff --git a/.gitignore b/.gitignore index eb27649f0..921966acd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,12 @@ log site erobs.code-workspace +# Packages being handled by vcs +pipettor/* +robotiq_hande/* +ros2_epick_gripper/* +serial/* + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/README.md b/README.md index b311f702f..b2a00196d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Each manifest in the [docker](./docker) directory is a container image that can - [hello_moveit_interfaces](./src/demos/hello_moveit_interfaces): ROS2 package for defining the interfaces used in the hello_moveit package. -### Docker Contents +### Docker Contents We use Podman throughout this work, but have named the container images with Docker in mind. @@ -43,17 +43,18 @@ We use Podman throughout this work, but have named the container images with Doc - [ur-example](./docker/ur-example): Container image for running a simple action with the UR3e robot arm. - [erobs-hello-moveit](./docker/erobs-hello-moveit): Container image for running a simple action with the UR3e robot arm. +**⚠️ Deprecation Warning:** +The container images currently in the `docker` directory are being deprecated, as they will soon depend on different source code. Please be aware that these images may not reflect the latest application structure or codebase. ### Hello Moveit -Demonstrations using a combination of the MoveIt tutorials and some UR specific tools, to show how to make simple actions -that can deploy MoveIt using the MoveGroupInterface. +Demonstrations using a combination of the MoveIt tutorials and some UR specific tools, to show how to make simple actions that can deploy MoveIt using the MoveGroupInterface. ### Bluesky ROS Ongoing developments of integrating ROS2 and Bluesky. Currently targeted towards integrating Ophyd Objects as ROS2 Action Clients. -## Using Containers to Run the Full Applicaiton Suite +## Using Containers to Run the Full Application Suite The complete application uses a 1-node-per-container model. The containers are currently orchestrated by bash scripts detailed in the READMEs of each container image. Specifically, the full application is detailed in [erobs-common-img](./docker/erobs-common-img/README.md). @@ -99,6 +100,9 @@ Now, go back to the VNC client. In the `Program` tab, start the program. The in `Program/Graphics` tab, the robot should be moving between four poses every 6 seconds. +**⚠️ Deprecation Warning:** +With the current move towards using MoveIt Task Constructor, we will be only spinning up one container. Theses examples and instructions demonstrate how to send basic commands directly using using ur-driver and should be placed in an tutorial/testing folder. + ## Notes on VSCode Workspace VSCode ROS2 Workspace Template Borrowed from @althack. diff --git a/build.sh b/build.sh index d3b967326..135bd6117 100755 --- a/build.sh +++ b/build.sh @@ -4,12 +4,12 @@ set -e # Set the default build type BUILD_TYPE=RelWithDebInfo -source /opt/ros/${ROS_DISTRO}/setup.bash && colcon build \ - --merge-install \ - --symlink-install \ - --packages-select ur3e_hande_robot_description serial robotiq_driver pdf_beamtime_interfaces \ - --cmake-args "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" "-DCMAKE_EXPORT_COMPILE_COMMANDS=On" \ - --cmake-args "-DCMAKE_CXX_FLAGS=-Wall -Wextra -Wpedantic" +# source /opt/ros/${ROS_DISTRO}/setup.bash && colcon build +# --merge-install \ +# --symlink-install \ +# --packages-select ur3e_hande_robot_description serial robotiq_driver pdf_beamtime_interfaces \ +# --cmake-args "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" "-DCMAKE_EXPORT_COMPILE_COMMANDS=On" \ +# --cmake-args "-DCMAKE_CXX_FLAGS=-Wall -Wextra -Wpedantic" colcon build \ --merge-install \ diff --git a/setup.sh b/setup.sh index bb31f70c4..c1b0d3d28 100755 --- a/setup.sh +++ b/setup.sh @@ -2,6 +2,7 @@ set -e vcs import < src/ros2.repos src +vcs import < src/end_effectors/end_effectors.repos src/end_effectors sudo apt-get update rosdep update rosdep install --from-paths src --ignore-src -y diff --git a/src/aruco_pose/COLCON_IGNORE b/src/aruco_pose/COLCON_IGNORE new file mode 100644 index 000000000..e69de29bb diff --git a/src/custom-ur-descriptions/COLCON_IGNORE b/src/custom-ur-descriptions/COLCON_IGNORE new file mode 100644 index 000000000..e69de29bb diff --git a/src/end_effectors/README.md b/src/end_effectors/README.md index 551b787bb..feb308c54 100644 --- a/src/end_effectors/README.md +++ b/src/end_effectors/README.md @@ -12,9 +12,9 @@ vcs import src/end_effectors < src/end_effectors/end_effectors.repos This pulls in: - `serial` - ROS2 serial communication -- `robotiq_hande_driver` - Robotiq HandE gripper driver -- `robotiq_hande_description` - Robotiq HandE URDF models -- `ros2_epick_gripper` - EPick vacuum gripper driver +- `robotiq_hande` - Robotiq HandE gripper driver and URDF models +- `ros2_epick_gripper` - EPick vacuum gripper driver +- `pipettor` - Custom pipettor developed at CMS NSLS-2 **Note:** The EPick driver uses a fork from https://github.com/bondada-a/ros2_epick_gripper.git instead of the upstream PickNikRobotics version. This fork includes updated headers and removes the epick_moveit_studio package (requires Moveit Pro). diff --git a/src/end_effectors/end_effectors.repos b/src/end_effectors/end_effectors.repos index 608efb2cb..a7b2a440b 100644 --- a/src/end_effectors/end_effectors.repos +++ b/src/end_effectors/end_effectors.repos @@ -3,15 +3,19 @@ repositories: type: git url: https://github.com/tylerjw/serial.git version: ros2 - robotiq_hande_driver: + robotiq_hande/robotiq_hande_driver: type: git url: https://github.com/AGH-CEAI/robotiq_hande_driver.git version: humble-devel - robotiq_hande_description: + robotiq_hande/robotiq_hande_description: type: git url: https://github.com/macmacal/robotiq_hande_description.git version: humble-devel ros2_epick_gripper: type: git url: https://github.com/bondada-a/ros2_epick_gripper.git + version: main + pipettor: + type: git + url: https://github.com/sixym3/pipettor.git version: main \ No newline at end of file diff --git a/src/end_effectors/pipettor b/src/end_effectors/pipettor new file mode 160000 index 000000000..0d0a1576a --- /dev/null +++ b/src/end_effectors/pipettor @@ -0,0 +1 @@ +Subproject commit 0d0a1576a8b00fd53b19b0f0ee2dfd9935d38bec diff --git a/src/end_effectors/robotiq_hande/robotiq_hande_description b/src/end_effectors/robotiq_hande/robotiq_hande_description new file mode 160000 index 000000000..5ae8b9706 --- /dev/null +++ b/src/end_effectors/robotiq_hande/robotiq_hande_description @@ -0,0 +1 @@ +Subproject commit 5ae8b97068f8a1136d37dd476b72bafc2b1cdfb0 diff --git a/src/end_effectors/robotiq_hande/robotiq_hande_driver b/src/end_effectors/robotiq_hande/robotiq_hande_driver new file mode 160000 index 000000000..e270ead18 --- /dev/null +++ b/src/end_effectors/robotiq_hande/robotiq_hande_driver @@ -0,0 +1 @@ +Subproject commit e270ead1882825f10a04f895f6c3877ad7143158 diff --git a/src/end_effectors/ros2_epick_gripper b/src/end_effectors/ros2_epick_gripper new file mode 160000 index 000000000..69e8a8317 --- /dev/null +++ b/src/end_effectors/ros2_epick_gripper @@ -0,0 +1 @@ +Subproject commit 69e8a8317ae2a8493925879580ac6bf7e7f879ca diff --git a/src/end_effectors/serial b/src/end_effectors/serial new file mode 160000 index 000000000..d8d160678 --- /dev/null +++ b/src/end_effectors/serial @@ -0,0 +1 @@ +Subproject commit d8d160678aa0b31cdf467c052b954fa287cc6cdf diff --git a/src/pdf/COLCON_IGNORE b/src/pdf/COLCON_IGNORE new file mode 100644 index 000000000..e69de29bb From 118f18aa6b268197ebbfc5ab15949f7e41d12bc8 Mon Sep 17 00:00:00 2001 From: sixym3 Date: Fri, 3 Oct 2025 13:13:30 -0400 Subject: [PATCH 4/7] Removed empty git submodules, added workflow to automate container builds on version tags, marked docker folder and artifacts as being Depricated, and updated README.md to reflect what is actively being developed --- .devcontainer/Dockerfile | 46 +++++++---- .github/workflows/docker-build.yaml | 49 ++++++++++++ .gitignore | 8 +- README.md | 79 ++++++++++++++----- docker/DEPRECATED.md | 26 ++++++ docker/README.md | 8 +- scripts/pdf-launch-scripts/DEPRECATED.md | 41 ++++++++++ scripts/pdf-launch-scripts/README.md | 6 ++ src/end_effectors/README.md | 2 +- src/end_effectors/pipettor | 1 - .../robotiq_hande/robotiq_hande_description | 1 - .../robotiq_hande/robotiq_hande_driver | 1 - src/end_effectors/ros2_epick_gripper | 1 - src/end_effectors/serial | 1 - 14 files changed, 222 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/docker-build.yaml create mode 100644 docker/DEPRECATED.md create mode 100644 scripts/pdf-launch-scripts/DEPRECATED.md delete mode 160000 src/end_effectors/pipettor delete mode 160000 src/end_effectors/robotiq_hande/robotiq_hande_description delete mode 160000 src/end_effectors/robotiq_hande/robotiq_hande_driver delete mode 160000 src/end_effectors/ros2_epick_gripper delete mode 160000 src/end_effectors/serial diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index bb4b01844..f3aeec6a3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,23 +1,21 @@ FROM --platform=linux/amd64 althack/ros2:humble-full - # ** [Optional] Uncomment this section to install additional packages. ** ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ - && apt-get -y install --no-install-recommends \ - python3-pip \ - python3.10-venv \ - ros-${ROS_DISTRO}-rclpy \ - ros-${ROS_DISTRO}-ur \ - ros-${ROS_DISTRO}-moveit\ - build-essential \ - python3-colcon-common-extensions \ - libopencv-dev \ - python3-opencv \ - # Clean up - && apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - + && apt-get -y install --no-install-recommends \ + python3-pip \ + python3.10-venv \ + ros-${ROS_DISTRO}-rclpy \ + ros-${ROS_DISTRO}-ur \ + ros-${ROS_DISTRO}-moveit\ + build-essential \ + python3-colcon-common-extensions \ + libopencv-dev \ + python3-opencv \ +# Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* ENV DEBIAN_FRONTEND=dialog # Set up auto-source of workspace for ros user @@ -30,5 +28,19 @@ RUN curl -fsSL https://pixi.sh/install.sh | sh RUN echo 'export PATH="/home/ros/.pixi/bin:$PATH"' >> /home/ros/.bashrc RUN echo 'eval "$(pixi completion --shell bash)"' >> /home/ros/.bashrc -# Bring the default user back to root for unit test or other admin tasks +# Copy entire repo and run setup script USER root +WORKDIR ${WORKSPACE} +COPY . . + +# Run setup script to install dependencies +RUN chmod +x setup.sh && \ + sed -i 's/sudo //g' setup.sh && \ + ./setup.sh && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* + +# Bring the default user back to root for unit test or other admin tasks +WORKDIR ${WORKSPACE} +USER root \ No newline at end of file diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml new file mode 100644 index 000000000..0b292b6b6 --- /dev/null +++ b/.github/workflows/docker-build.yaml @@ -0,0 +1,49 @@ +name: Build and Push Docker Image to GHCR +on: + push: + tags: + - 'v*' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./.devcontainer/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 921966acd..7bd78a897 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,10 @@ site erobs.code-workspace # Packages being handled by vcs -pipettor/* -robotiq_hande/* -ros2_epick_gripper/* -serial/* +src/end_effectors/pipettor +src/end_effectors/robotiq_hande +src/end_effectors/ros2_epick_gripper +src/end_effectors/serial # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/README.md b/README.md index b2a00196d..df2c9c64a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Extensible Robotic Beamline Scientist -Project repository for building extensible robotic beamline scientists at NSLS-II. +Project repository for building extensible robotic beamline scientists at NSLS-II. ROS 2 Humble with Ubuntu 22.04 LTS ## Contents @@ -29,22 +29,29 @@ Each manifest in the [docker](./docker) directory is a container image that can - [hello_moveit_interfaces](./src/demos/hello_moveit_interfaces): ROS2 package for defining the interfaces used in the hello_moveit package. -### Docker Contents +### Docker Contents -We use Podman throughout this work, but have named the container images with Docker in mind. +**⚠️ The `docker/` directory and `scripts/pdf-launch-scripts/` are DEPRECATED. See below for the active deployment workflow.** -- [erobs-common-img](./docker/erobs-common-img): Common container image for running the majority of applications herein, including: UR robot driver, gripper service, MoveIt service, and the pdf_beamtime_server (primary `Action` server). -- [bsui](./docker/bsui): Container image for running the Bluesky User Interface with mounts at NSLS-II. -- [azure-kinect](./docker/azure-kinect): Container image for running the Azure Kinect ROS2 driver. -- Other auxiliary container images that are not used in the main application, but are useful for development and testing: - - [ursim](./docker/ursim): Container image for running a simulated UR3e robot arm with a teach pendant. - - [ur-driver](./docker/ur-driver): Container image for running the UR3e robot arm ROS2 driver. - - [ur-moveit](./docker/ur-moveit): Container image for running MoveIt with the UR3e robot arm. - - [ur-example](./docker/ur-example): Container image for running a simple action with the UR3e robot arm. - - [erobs-hello-moveit](./docker/erobs-hello-moveit): Container image for running a simple action with the UR3e robot arm. +#### Active Deployment Workflow -**⚠️ Deprecation Warning:** -The container images currently in the `docker` directory are being deprecated, as they will soon depend on different source code. Please be aware that these images may not reflect the latest application structure or codebase. +For development and deployment + +- **Development**: Use [.devcontainer/Dockerfile](./.devcontainer/Dockerfile) with VSCode devcontainer for local development +- **CI/CD**: Automated builds via [.github/workflows/docker-build.yaml](./.github/workflows/docker-build.yaml) + - Push a version tag to trigger automatic build and publish to GitHub Container Registry (GHCR) +- **Deployment**: Pull the unified container image from GHCR at `ghcr.io//:latest` + - All dependencies are pre-installed (no apt install required at deployment) + - Launch ROS2 nodes using `ros2 launch` commands directly from the container + +#### Deprecated Docker Contents (For Reference Only) + +The following directories contain legacy container configurations and are **no longer maintained**: + +- [docker/](./docker/): Legacy multi-container Dockerfiles - See [docker/DEPRECATED.md](./docker/DEPRECATED.md) +- [scripts/pdf-launch-scripts/](./scripts/pdf-launch-scripts/): Legacy deployment scripts referencing gatekept GHCR images - See [scripts/pdf-launch-scripts/DEPRECATED.md](./scripts/pdf-launch-scripts/DEPRECATED.md) + +These can be used for learning purposes but should not be used for active development or deployment. ### Hello Moveit @@ -54,11 +61,46 @@ Demonstrations using a combination of the MoveIt tutorials and some UR specific Ongoing developments of integrating ROS2 and Bluesky. Currently targeted towards integrating Ophyd Objects as ROS2 Action Clients. -## Using Containers to Run the Full Application Suite +## Development Setup + +### Local Development with VSCode + +1. Install VSCode with the Remote-Containers extension +2. Open this repository in VSCode +3. VSCode will prompt to "Reopen in Container" - accept this +4. The devcontainer will automatically build using `.devcontainer/Dockerfile` +5. Once inside the container, build the workspace: + ```bash + colcon build --symlink-install + source install/setup.bash + ``` -The complete application uses a 1-node-per-container model. The containers are currently orchestrated by bash scripts detailed in the READMEs of each container image. Specifically, the full application is detailed in [erobs-common-img](./docker/erobs-common-img/README.md). +### Deployment -## Running some example applications +For production deployment: + +1. **Automated Build**: Push a version tag to trigger GitHub Actions + ```bash + git tag v1.0.0 + git push origin v1.0.0 + ``` + +2. **Pull from GHCR**: On your deployment machine + ```bash + podman pull ghcr.io//:latest + ``` + +3. **Run containers**: Launch ROS2 nodes with appropriate environment variables + ```bash + podman run -it --network host --ipc=host \ + --env ROS_DOMAIN_ID=10 \ + ghcr.io//:latest \ + ros2 launch + ``` + +## Running Example Applications (Legacy - For Learning Only) + +**⚠️ The following examples use deprecated docker configurations. See above for current deployment workflow.** In order to run the `ur-example` with Docker, follow this procedure: @@ -100,9 +142,6 @@ Now, go back to the VNC client. In the `Program` tab, start the program. The in `Program/Graphics` tab, the robot should be moving between four poses every 6 seconds. -**⚠️ Deprecation Warning:** -With the current move towards using MoveIt Task Constructor, we will be only spinning up one container. Theses examples and instructions demonstrate how to send basic commands directly using using ur-driver and should be placed in an tutorial/testing folder. - ## Notes on VSCode Workspace VSCode ROS2 Workspace Template Borrowed from @althack. diff --git a/docker/DEPRECATED.md b/docker/DEPRECATED.md new file mode 100644 index 000000000..e996a2011 --- /dev/null +++ b/docker/DEPRECATED.md @@ -0,0 +1,26 @@ +# ⚠️ DEPRECATED + +**This directory is deprecated and should not be used for new development.** + +## Why is this deprecated? + +The container images in this directory are being deprecated because: + +1. **CI/CD uses devcontainer**: The GitHub Actions workflows use `.devcontainer/Dockerfile` for testing and building +2. **Different source dependencies**: These images will soon depend on different source code +3. **Inconsistent with development workflow**: The devcontainer approach provides better integration with modern development tools + +## What should you use instead? + +For development and deployment, use: +- **Development**: `.devcontainer/Dockerfile` for VSCode devcontainer development +- **Deployment**: Container images published to GitHub Container Registry (GHCR) built from the devcontainer +- **CI/CD**: Automated workflows in `.github/workflows/` + +## Timeline + +This directory will be removed or archived in a future release. + +## Questions? + +See the main [README.md](../README.md) for current deployment instructions. diff --git a/docker/README.md b/docker/README.md index 983b0ea83..9c31b85b2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,4 +1,10 @@ -# To run the demo contianers +# ⚠️ DEPRECATED - See [DEPRECATED.md](./DEPRECATED.md) + +**This directory is deprecated. Use `.devcontainer/Dockerfile` and GHCR images instead.** + +--- + +# To run the demo contianers for Learning purposes ```bash cd docker/ursim diff --git a/scripts/pdf-launch-scripts/DEPRECATED.md b/scripts/pdf-launch-scripts/DEPRECATED.md new file mode 100644 index 000000000..bfb7b1e01 --- /dev/null +++ b/scripts/pdf-launch-scripts/DEPRECATED.md @@ -0,0 +1,41 @@ +# ⚠️ DEPRECATED + +**This directory is deprecated and should not be used for new development or deployment.** + +## Why is this deprecated? + +The container launch scripts in this directory are being deprecated because: + +1. **Gatekept container images**: These scripts reference GHCR images behind other accounts that you cannot control: + - `ghcr.io/chandimafernando/erobs-common-img:latest` (personal account) + - `ghcr.io/nsls2/erobs-ur-driver:latest` + - `ghcr.io/nsls2/ur-hande-draft:latest` + - `ghcr.io/nsls2/erobs-bsui:latest` + +2. **Old architecture**: These containers use the deprecated `docker/` directory approach that clones and builds source code inside the container at build time + +3. **Inconsistent with CI/CD**: The GitHub Actions workflows now use `.devcontainer/Dockerfile` for building and publishing to GHCR + +## What should you use instead? + +For deployment, use the new unified container workflow: + +### Development +- Use `.devcontainer/Dockerfile` with VSCode devcontainer for local development + +### Deployment +1. **Pull from GHCR**: The GitHub Actions workflow automatically builds and publishes container images to your repository's GHCR when you push version tags +2. **Run containers**: Launch ROS2 nodes directly from the unified container image using `ros2 launch` commands +3. **See the main README**: Refer to [../../README.md](../../README.md) for current deployment instructions + +### CI/CD +- Automated builds are configured in `.github/workflows/docker-build.yaml` +- Push a version tag (e.g., `v1.0.0`) to trigger automated builds + +## Timeline + +This directory will be removed or archived in a future release. + +## Questions? + +See the main [README.md](../../README.md) for current deployment instructions. diff --git a/scripts/pdf-launch-scripts/README.md b/scripts/pdf-launch-scripts/README.md index 4a2488207..4982f0146 100644 --- a/scripts/pdf-launch-scripts/README.md +++ b/scripts/pdf-launch-scripts/README.md @@ -1,3 +1,9 @@ +# ⚠️ DEPRECATED - See [DEPRECATED.md](./DEPRECATED.md) + +**This directory is deprecated. Use `.devcontainer/Dockerfile` and GHCR images instead.** + +--- + # File Contents Docker launch scripts for ROS2 at the PDF beamline. Detailed documentation on building and deploying containers at NSLS-II can be found in our [documentation](https://docs.nsls2.bnl.gov/docs/how-to/containers.html). diff --git a/src/end_effectors/README.md b/src/end_effectors/README.md index b1d7e82a9..3d442bb35 100644 --- a/src/end_effectors/README.md +++ b/src/end_effectors/README.md @@ -17,7 +17,7 @@ This pulls in: - `pipettor` - Custom pipettor developed at CMS NSLS-2 -**Note:** The EPick driver uses a fork from https://github.com/bondada-a/ros2_epick_gripper.git instead of the upstream PickNikRobotics version. This fork includes updated headers and removes the epick_moveit_studio package (requires Moveit Pro). +**Note:** The EPick driver uses a fork from instead of the upstream PickNikRobotics version. This fork includes updated headers and removes the epick_moveit_studio package (requires Moveit Pro). ## EPick Configuration diff --git a/src/end_effectors/pipettor b/src/end_effectors/pipettor deleted file mode 160000 index 0d0a1576a..000000000 --- a/src/end_effectors/pipettor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0d0a1576a8b00fd53b19b0f0ee2dfd9935d38bec diff --git a/src/end_effectors/robotiq_hande/robotiq_hande_description b/src/end_effectors/robotiq_hande/robotiq_hande_description deleted file mode 160000 index 5ae8b9706..000000000 --- a/src/end_effectors/robotiq_hande/robotiq_hande_description +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ae8b97068f8a1136d37dd476b72bafc2b1cdfb0 diff --git a/src/end_effectors/robotiq_hande/robotiq_hande_driver b/src/end_effectors/robotiq_hande/robotiq_hande_driver deleted file mode 160000 index e270ead18..000000000 --- a/src/end_effectors/robotiq_hande/robotiq_hande_driver +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e270ead1882825f10a04f895f6c3877ad7143158 diff --git a/src/end_effectors/ros2_epick_gripper b/src/end_effectors/ros2_epick_gripper deleted file mode 160000 index 69e8a8317..000000000 --- a/src/end_effectors/ros2_epick_gripper +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 69e8a8317ae2a8493925879580ac6bf7e7f879ca diff --git a/src/end_effectors/serial b/src/end_effectors/serial deleted file mode 160000 index d8d160678..000000000 --- a/src/end_effectors/serial +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d8d160678aa0b31cdf467c052b954fa287cc6cdf From 2e73a69158e981b3558f1dcee04cb78b770a65e4 Mon Sep 17 00:00:00 2001 From: sixym3 Date: Fri, 3 Oct 2025 14:01:10 -0400 Subject: [PATCH 5/7] Updated build.sh and setup.sh --- build.sh | 3 ++- setup.sh | 4 +++- src/end_effectors/README.md | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 135bd6117..45d55bd0c 100755 --- a/build.sh +++ b/build.sh @@ -16,4 +16,5 @@ colcon build \ --symlink-install \ --executor sequential \ --cmake-args "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" "-DCMAKE_EXPORT_COMPILE_COMMANDS=On" \ - -Wall -Wextra -Wpedantic + -Wall -Wextra -Wpedantic \ + --packages-skip epick_moveit_studio diff --git a/setup.sh b/setup.sh index c1b0d3d28..06dec8af3 100755 --- a/setup.sh +++ b/setup.sh @@ -5,4 +5,6 @@ vcs import < src/ros2.repos src vcs import < src/end_effectors/end_effectors.repos src/end_effectors sudo apt-get update rosdep update -rosdep install --from-paths src --ignore-src -y + +# Skip moveit_studio_behavior_interface because we are not using it and is paywalled +rosdep install --from-paths src --ignore-src -y --skip-keys moveit_studio_behavior_interface diff --git a/src/end_effectors/README.md b/src/end_effectors/README.md index 70f51d9f2..9fb34aa1f 100644 --- a/src/end_effectors/README.md +++ b/src/end_effectors/README.md @@ -21,10 +21,10 @@ This pulls in: ```bash # Install dependencies -rosdep install --from-paths src --ignore-src -y --skip-keys moveit_studio_behavior_interface +bash setup.sh # Build workspace (skip epick_moveit_studio) -colcon build --packages-skip epick_moveit_studio +bash build.sh ## EPick Configuration From e7c0053865883ffb1779f50591932eaac9cfb440 Mon Sep 17 00:00:00 2001 From: sixym3 Date: Fri, 3 Oct 2025 14:21:18 -0400 Subject: [PATCH 6/7] Update build.sh with another ignore package --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 45d55bd0c..f2d32cebc 100755 --- a/build.sh +++ b/build.sh @@ -16,5 +16,5 @@ colcon build \ --symlink-install \ --executor sequential \ --cmake-args "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" "-DCMAKE_EXPORT_COMPILE_COMMANDS=On" \ - -Wall -Wextra -Wpedantic \ - --packages-skip epick_moveit_studio + -Wall -Wextra -Wpedantic \ + --packages-skip epick_moveit_studio epick_config \ No newline at end of file From e9f890474695e80fde30a82d2a96902543ad7ea5 Mon Sep 17 00:00:00 2001 From: sixym3 Date: Tue, 7 Oct 2025 14:50:20 -0400 Subject: [PATCH 7/7] Update to add lint fixes --- .github/workflows/ros.yaml | 4 +- .github/workflows/ruff.yml | 4 +- .github/workflows/super-linter.yml | 4 +- scripts/pdf-launch-scripts/simple_listener.py | 11 +- src/aruco_pose/launch/aruco_pose.launch.py | 12 +- src/aruco_pose/src/redis_insert.py | 20 ++- src/bluesky_ros/ophyd_ros.py | 16 ++- src/bluesky_ros/pdf_beamtime.py | 24 +++- src/bluesky_ros/pdf_beamtime_demo.py | 9 +- src/bluesky_ros/re_demo.py | 4 +- .../launch/ur_control.launch.py | 65 +++++++-- .../launch/robot_bringup.launch.py | 115 ++++++++++------ .../launch/robot_bringup.launch.py | 127 +++++++++++------- .../launch/robot_bringup.launch.py | 115 ++++++++++------ .../launch/pick_place_repeat.launch.py | 14 +- .../src/pick_place_repeat_client.py | 4 +- .../launch/epick_bringup.launch.py | 14 +- .../bluesky_interrupt_resume.py | 8 +- .../bluesky_interrupt_stop.py | 8 +- .../launch/pdf_beamtime.launch.py | 8 +- .../pdf_beamtime_fidpose_server.launch.py | 8 +- .../pdf_beamtime/src/pdf_beamtime_client.py | 16 ++- .../src/pdf_beamtime_fidpose_client.py | 32 +++-- .../src/pdf_beamtime_fidpose_redis_client.py | 32 +++-- 24 files changed, 468 insertions(+), 206 deletions(-) diff --git a/.github/workflows/ros.yaml b/.github/workflows/ros.yaml index 026a447d7..7f1e7efcf 100644 --- a/.github/workflows/ros.yaml +++ b/.github/workflows/ros.yaml @@ -2,9 +2,9 @@ name: ROS C++ Testing and Linting on: push: - branches: [main, humble] + branches: [main, humble, feature/*] pull_request: - branches: [main, humble] + branches: [main, humble, feature/*] workflow_dispatch: jobs: diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 2a998d557..f9432e4f8 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -2,9 +2,9 @@ name: Check Code Style - Ruff on: push: - branches: [main, humble] + branches: [main, humble, feature/*] pull_request: - branches: [main, humble] + branches: [main, humble, feature/*] workflow_dispatch: jobs: diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 4db07240e..175a1e06f 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -8,9 +8,9 @@ name: Lint Code Base (Super-Linter) on: push: - branches: [main, humble] + branches: [main, humble, feature/*] pull_request: - branches: [main, humble] + branches: [main, humble, feature/*] jobs: run-lint: runs-on: ubuntu-latest diff --git a/scripts/pdf-launch-scripts/simple_listener.py b/scripts/pdf-launch-scripts/simple_listener.py index 1dd13f7e9..2682a4b01 100644 --- a/scripts/pdf-launch-scripts/simple_listener.py +++ b/scripts/pdf-launch-scripts/simple_listener.py @@ -5,14 +5,11 @@ class MinimalSubscriber(Node): - def __init__(self): - super().__init__('minimal_subscriber') + super().__init__("minimal_subscriber") self.subscription = self.create_subscription( - String, - 'chatter', - self.listener_callback, - 10) + String, "chatter", self.listener_callback, 10 + ) self.subscription # prevent unused variable warning def listener_callback(self, msg): @@ -33,5 +30,5 @@ def main(args=None): rclpy.shutdown() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/aruco_pose/launch/aruco_pose.launch.py b/src/aruco_pose/launch/aruco_pose.launch.py index c941aeae7..71b1a904f 100644 --- a/src/aruco_pose/launch/aruco_pose.launch.py +++ b/src/aruco_pose/launch/aruco_pose.launch.py @@ -14,8 +14,16 @@ def generate_launch_description(): name="aruco_pose", output="screen", parameters=[ - PathJoinSubstitution([FindPackageShare("aruco_pose"), "config", "camera_param.yaml"]), - PathJoinSubstitution([FindPackageShare("aruco_pose"), "config", "fiducial_marker_param.yaml"]), + PathJoinSubstitution( + [FindPackageShare("aruco_pose"), "config", "camera_param.yaml"] + ), + PathJoinSubstitution( + [ + FindPackageShare("aruco_pose"), + "config", + "fiducial_marker_param.yaml", + ] + ), ], ) ] diff --git a/src/aruco_pose/src/redis_insert.py b/src/aruco_pose/src/redis_insert.py index 83c85e747..41fb688b4 100644 --- a/src/aruco_pose/src/redis_insert.py +++ b/src/aruco_pose/src/redis_insert.py @@ -9,9 +9,25 @@ client = redis.Redis(host="192.168.56.1", port=6379, db=0) # Step 1: Store tag data in Redis -client.hset("tag:1", mapping={"id": 0, "family": "DICT_APRILTAG_36h11", "size": 0.02665, "sample_name": "sample_1"}) +client.hset( + "tag:1", + mapping={ + "id": 0, + "family": "DICT_APRILTAG_36h11", + "size": 0.02665, + "sample_name": "sample_1", + }, +) -client.hset("tag:2", mapping={"id": 150, "family": "DICT_APRILTAG_36h12", "size": 0.03000, "sample_name": "sample_2"}) +client.hset( + "tag:2", + mapping={ + "id": 150, + "family": "DICT_APRILTAG_36h12", + "size": 0.03000, + "sample_name": "sample_2", + }, +) # Step 2: Indexing the sample_name to the tag key (e.g., tag:1, tag:2) client.hset("sample_name_index", "sample_1", "tag:1") diff --git a/src/bluesky_ros/ophyd_ros.py b/src/bluesky_ros/ophyd_ros.py index cec7777be..afa969f30 100644 --- a/src/bluesky_ros/ophyd_ros.py +++ b/src/bluesky_ros/ophyd_ros.py @@ -41,7 +41,7 @@ def __init__( start_parameter_services: bool = True, parameter_overrides: List[Parameter] = None, allow_undeclared_parameters: bool = False, - automatically_declare_parameters_from_overrides: bool = False + automatically_declare_parameters_from_overrides: bool = False, ) -> None: """Class init.""" super().__init__( @@ -89,7 +89,9 @@ def get_result_callback(self, future: Future): def _stop_spin_callback(self, future: Future): """Manage the execution of all other done Callabacks. This ensures a sensible ordering.""" if not future.done(): - self.get_logger().error("Somehow the stop spin callback was called before the future was done...") + self.get_logger().error( + "Somehow the stop spin callback was called before the future was done..." + ) self.get_result_callback(future) @@ -140,11 +142,17 @@ def _send_goal(self, goal: Any) -> None: goal_msg = self.construct_goal_mesage(goal) if not isinstance(goal_msg, self.action_type.Goal): - raise TypeError("Goal must be of type {}. Received type {}".format(self.action_type.Goal, type(goal_msg))) + raise TypeError( + "Goal must be of type {}. Received type {}".format( + self.action_type.Goal, type(goal_msg) + ) + ) self._action_client.wait_for_server(timeout_sec=10.0) self.get_logger().info("Sending goal request...") - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) self._send_goal_future.add_done_callback(self._goal_response_callback) """ diff --git a/src/bluesky_ros/pdf_beamtime.py b/src/bluesky_ros/pdf_beamtime.py index d151433b7..b7f191d10 100644 --- a/src/bluesky_ros/pdf_beamtime.py +++ b/src/bluesky_ros/pdf_beamtime.py @@ -45,9 +45,13 @@ def iterative_plan(node, n_iter, motor=OT_stage_3_X, safe_position=0.0): # noqa load_position = list(motor.read().values())[0]["value"] for i in range(n_iter): print(f"Starting iteration {i}") - yield from bps.abs_set(node, ["holder_shaft_storage", "holder_shaft_inbeam", "PICK_UP"], group="A") + yield from bps.abs_set( + node, ["holder_shaft_storage", "holder_shaft_inbeam", "PICK_UP"], group="A" + ) yield from bps.wait("A") - yield from bps.abs_set(node, ["holder_shaft_storage", "holder_shaft_inbeam", "PLACE"], group="A") + yield from bps.abs_set( + node, ["holder_shaft_storage", "holder_shaft_inbeam", "PLACE"], group="A" + ) yield from bps.wait("A") print(f"Moving motor to safe position {safe_position}") yield from bps.mv(motor, safe_position) @@ -56,15 +60,25 @@ def iterative_plan(node, n_iter, motor=OT_stage_3_X, safe_position=0.0): # noqa yield from bps.mv(motor, load_position) yield from bps.wait() print("Returning sample to storage") - yield from bps.abs_set(node, ["holder_shaft_inbeam", "holder_shaft_storage", "RETURN_PICK_UP"], group="A") + yield from bps.abs_set( + node, + ["holder_shaft_inbeam", "holder_shaft_storage", "RETURN_PICK_UP"], + group="A", + ) yield from bps.wait("A") - yield from bps.abs_set(node, ["holder_shaft_inbeam", "holder_shaft_storage", "RETURN_PLACE"], group="A") + yield from bps.abs_set( + node, + ["holder_shaft_inbeam", "holder_shaft_storage", "RETURN_PLACE"], + group="A", + ) yield from bps.wait("A") if __name__ == "main": rclpy.init() - node = PickPlaceDevice(node_name="pick_place_device", action_client_name="erbos_pdf_pick_place_action") + node = PickPlaceDevice( + node_name="pick_place_device", action_client_name="erbos_pdf_pick_place_action" + ) RE = RunEngine({}) RE(iterative_plan(node)) rclpy.shutdown() diff --git a/src/bluesky_ros/pdf_beamtime_demo.py b/src/bluesky_ros/pdf_beamtime_demo.py index 8acf2f8f6..1edbf73f2 100644 --- a/src/bluesky_ros/pdf_beamtime_demo.py +++ b/src/bluesky_ros/pdf_beamtime_demo.py @@ -29,7 +29,9 @@ def construct_goal_mesage(self, *args, **kwargs): def feedback_callback(self, feedback_msg): """Handle regular feedback and print the completion percentage.""" feedback = feedback_msg.feedback - self.get_logger().info("Completion percentage: {0} %".format(math.ceil(feedback.status * 100))) + self.get_logger().info( + "Completion percentage: {0} %".format(math.ceil(feedback.status * 100)) + ) def get_result_callback(self, future: Future): """Handle results at the end of a state transition.""" @@ -43,7 +45,10 @@ def plan(node, joint_goals): rclpy.init() -node = PickPlaceRepeatDevice(node_name="pdf_beamtime_control_device", action_client_name="pdf_beamtime_action_server") +node = PickPlaceRepeatDevice( + node_name="pdf_beamtime_control_device", + action_client_name="pdf_beamtime_action_server", +) joint_goals = { "pickup_approach": [1.466, -2.042, -2.1293, -2.164, -0.105, 0.0], diff --git a/src/bluesky_ros/re_demo.py b/src/bluesky_ros/re_demo.py index 4e84c2b58..baad91440 100644 --- a/src/bluesky_ros/re_demo.py +++ b/src/bluesky_ros/re_demo.py @@ -45,7 +45,9 @@ def plan(node, det, motor): rclpy.init() -node = PickPlaceRepeatDevice(node_name="pick_place_repeat_device", action_client_name="pick_place_repeat") +node = PickPlaceRepeatDevice( + node_name="pick_place_repeat_device", action_client_name="pick_place_repeat" +) RE = RunEngine({}) RE(plan(node, det1, motor1)) diff --git a/src/custom-ur-descriptions/ur3e_hande_robot_description/launch/ur_control.launch.py b/src/custom-ur-descriptions/ur3e_hande_robot_description/launch/ur_control.launch.py index 4d90ef5cd..8dd37b91e 100644 --- a/src/custom-ur-descriptions/ur3e_hande_robot_description/launch/ur_control.launch.py +++ b/src/custom-ur-descriptions/ur3e_hande_robot_description/launch/ur_control.launch.py @@ -85,16 +85,35 @@ def launch_setup(context, *args, **kwargs): trajectory_port = LaunchConfiguration("trajectory_port") joint_limit_params = PathJoinSubstitution( - [FindPackageShare(ur_description_package), "config", ur_type, "joint_limits.yaml"] + [ + FindPackageShare(ur_description_package), + "config", + ur_type, + "joint_limits.yaml", + ] ) physical_params = PathJoinSubstitution( - [FindPackageShare(ur_description_package), "config", ur_type, "physical_parameters.yaml"] + [ + FindPackageShare(ur_description_package), + "config", + ur_type, + "physical_parameters.yaml", + ] ) visual_params = PathJoinSubstitution( - [FindPackageShare(ur_description_package), "config", ur_type, "visual_parameters.yaml"] + [ + FindPackageShare(ur_description_package), + "config", + ur_type, + "visual_parameters.yaml", + ] ) script_filename = PathJoinSubstitution( - [FindPackageShare("ur_client_library"), "resources", "external_control.urscript"] + [ + FindPackageShare("ur_client_library"), + "resources", + "external_control.urscript", + ] ) input_recipe_filename = PathJoinSubstitution( [FindPackageShare("ur_robot_driver"), "resources", "rtde_input_recipe.txt"] @@ -107,7 +126,9 @@ def launch_setup(context, *args, **kwargs): [ PathJoinSubstitution([FindExecutable(name="xacro")]), " ", - PathJoinSubstitution([FindPackageShare(description_package), "urdf", description_file]), + PathJoinSubstitution( + [FindPackageShare(description_package), "urdf", description_file] + ), " ", "robot_ip:=", robot_ip, @@ -201,13 +222,19 @@ def launch_setup(context, *args, **kwargs): " ", ] ) - robot_description = {"robot_description": ParameterValue(value=robot_description_content, value_type=str)} + robot_description = { + "robot_description": ParameterValue( + value=robot_description_content, value_type=str + ) + } initial_joint_controllers = PathJoinSubstitution( [FindPackageShare(runtime_config_package), "config", controllers_file] ) - rviz_config_file = PathJoinSubstitution([FindPackageShare(description_package), "rviz", "view_robot.rviz"]) + rviz_config_file = PathJoinSubstitution( + [FindPackageShare(description_package), "rviz", "view_robot.rviz"] + ) # define update rate update_rate_config_file = PathJoinSubstitution( @@ -244,7 +271,9 @@ def launch_setup(context, *args, **kwargs): dashboard_client_node = Node( package="ur_robot_driver", - condition=IfCondition(AndSubstitution(launch_dashboard_client, NotSubstitution(use_fake_hardware))), + condition=IfCondition( + AndSubstitution(launch_dashboard_client, NotSubstitution(use_fake_hardware)) + ), executable="dashboard_client", name="dashboard_client", output="screen", @@ -410,7 +439,9 @@ def generate_launch_description(): ) ) declared_arguments.append( - DeclareLaunchArgument("robot_ip", description="IP address by which the robot can be reached.") + DeclareLaunchArgument( + "robot_ip", description="IP address by which the robot can be reached." + ) ) declared_arguments.append( DeclareLaunchArgument( @@ -546,9 +577,17 @@ def generate_launch_description(): description="Activate loaded joint controller.", ) ) - declared_arguments.append(DeclareLaunchArgument("launch_rviz", default_value="true", description="Launch RViz?")) declared_arguments.append( - DeclareLaunchArgument("launch_dashboard_client", default_value="true", description="Launch Dashboard Client?") + DeclareLaunchArgument( + "launch_rviz", default_value="true", description="Launch RViz?" + ) + ) + declared_arguments.append( + DeclareLaunchArgument( + "launch_dashboard_client", + default_value="true", + description="Launch Dashboard Client?", + ) ) declared_arguments.append( DeclareLaunchArgument( @@ -656,4 +695,6 @@ def generate_launch_description(): description="Port that will be opened for trajectory control.", ) ) - return LaunchDescription(declared_arguments + [OpaqueFunction(function=launch_setup)]) + return LaunchDescription( + declared_arguments + [OpaqueFunction(function=launch_setup)] + ) diff --git a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_standalone_moveit_config/launch/robot_bringup.launch.py b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_standalone_moveit_config/launch/robot_bringup.launch.py index fc36bb82b..a3d7c8ad0 100644 --- a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_standalone_moveit_config/launch/robot_bringup.launch.py +++ b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_standalone_moveit_config/launch/robot_bringup.launch.py @@ -11,22 +11,49 @@ def generate_launch_description(): - ## Arguments - - ur_type = DeclareLaunchArgument('ur_type', default_value='ur5e') - robot_ip = DeclareLaunchArgument('robot_ip', default_value='192.168.1.10') - description_package = DeclareLaunchArgument('description_package', default_value='ur_description') - description_file = DeclareLaunchArgument('description_file', default_value=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_standalone.xacro")) - controllers_file = DeclareLaunchArgument('controllers_file', default_value=os.path.join(get_package_share_directory("ur_standalone_moveit_config"), "config", "ur_controllers.yaml")) + ## Arguments + ur_type = DeclareLaunchArgument("ur_type", default_value="ur5e") + robot_ip = DeclareLaunchArgument("robot_ip", default_value="192.168.1.10") + description_package = DeclareLaunchArgument( + "description_package", default_value="ur_description" + ) + description_file = DeclareLaunchArgument( + "description_file", + default_value=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_standalone.xacro", + ), + ) + controllers_file = DeclareLaunchArgument( + "controllers_file", + default_value=os.path.join( + get_package_share_directory("ur_standalone_moveit_config"), + "config", + "ur_controllers.yaml", + ), + ) - xacro_args = {"name": LaunchConfiguration("ur_type"), "ur_type": LaunchConfiguration("ur_type"), "tf_prefix": "" } + xacro_args = { + "name": LaunchConfiguration("ur_type"), + "ur_type": LaunchConfiguration("ur_type"), + "tf_prefix": "", + } - ## ur_driver + ## ur_driver ur_control_launch = IncludeLaunchDescription( - PythonLaunchDescriptionSource([ - PathJoinSubstitution([FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"]) - ]), + PythonLaunchDescriptionSource( + [ + PathJoinSubstitution( + [ + FindPackageShare("ur_robot_driver"), + "launch", + "ur_control.launch.py", + ] + ) + ] + ), launch_arguments={ "ur_type": LaunchConfiguration("ur_type"), "robot_ip": LaunchConfiguration("robot_ip"), @@ -35,14 +62,20 @@ def generate_launch_description(): "description_file": LaunchConfiguration("description_file"), "controllers_file": LaunchConfiguration("controllers_file"), "tool_voltage": "24", - }.items() + }.items(), ) - # Load MoveIt! configuration moveit_config = ( - MoveItConfigsBuilder("ur_moveit",package_name="ur_standalone_moveit_config") - .robot_description(file_path=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_standalone.xacro"),mappings=xacro_args) + MoveItConfigsBuilder("ur_moveit", package_name="ur_standalone_moveit_config") + .robot_description( + file_path=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_standalone.xacro", + ), + mappings=xacro_args, + ) .trajectory_execution(file_path="config/moveit_controllers.yaml") .robot_description_kinematics(file_path="config/kinematics.yaml") .planning_scene_monitor( @@ -71,12 +104,16 @@ def generate_launch_description(): rviz_arg = DeclareLaunchArgument( "rviz_config", default_value="view_robot_mtc.rviz", - description="RViz config file" + description="RViz config file", ) - rviz_config = PathJoinSubstitution([ - FindPackageShare("ur_standalone_moveit_config"), "rviz", LaunchConfiguration("rviz_config") - ]) + rviz_config = PathJoinSubstitution( + [ + FindPackageShare("ur_standalone_moveit_config"), + "rviz", + LaunchConfiguration("rviz_config"), + ] + ) rviz_node = Node( package="rviz2", @@ -101,7 +138,6 @@ def generate_launch_description(): # parameters=[{"robot_ip": LaunchConfiguration("robot_ip")}] # ) - # Publish TF robot_state_publisher = Node( package="robot_state_publisher", @@ -111,23 +147,20 @@ def generate_launch_description(): parameters=[moveit_config.robot_description], ) - - return LaunchDescription([ - ## arguments - robot_ip, - ur_type, - description_package, - description_file, - controllers_file, - rviz_arg, - - - ## Nodes - # tool_communication, - ur_control_launch, - run_move_group_node, - rviz_node, - robot_state_publisher, - ]) - - \ No newline at end of file + return LaunchDescription( + [ + ## arguments + robot_ip, + ur_type, + description_package, + description_file, + controllers_file, + rviz_arg, + ## Nodes + # tool_communication, + ur_control_launch, + run_move_group_node, + rviz_node, + robot_state_publisher, + ] + ) diff --git a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_epick_moveit_config/launch/robot_bringup.launch.py b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_epick_moveit_config/launch/robot_bringup.launch.py index e2abfb513..eeae3a304 100644 --- a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_epick_moveit_config/launch/robot_bringup.launch.py +++ b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_epick_moveit_config/launch/robot_bringup.launch.py @@ -9,23 +9,51 @@ from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource -def generate_launch_description(): - ## Arguments - ur_type = DeclareLaunchArgument('ur_type', default_value='ur5e') - robot_ip = DeclareLaunchArgument('robot_ip', default_value='192.168.1.10') - description_package = DeclareLaunchArgument('description_package', default_value='ur_description') - description_file = DeclareLaunchArgument('description_file', default_value=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_with_zivid_epick.xacro")) - controllers_file = DeclareLaunchArgument('controllers_file', default_value=os.path.join(get_package_share_directory("ur_zivid_epick_moveit_config"), "config", "ur_epick_controllers.yaml")) +def generate_launch_description(): + ## Arguments + ur_type = DeclareLaunchArgument("ur_type", default_value="ur5e") + robot_ip = DeclareLaunchArgument("robot_ip", default_value="192.168.1.10") + description_package = DeclareLaunchArgument( + "description_package", default_value="ur_description" + ) + description_file = DeclareLaunchArgument( + "description_file", + default_value=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_with_zivid_epick.xacro", + ), + ) + controllers_file = DeclareLaunchArgument( + "controllers_file", + default_value=os.path.join( + get_package_share_directory("ur_zivid_epick_moveit_config"), + "config", + "ur_epick_controllers.yaml", + ), + ) - xacro_args = {"name": LaunchConfiguration("ur_type"), "ur_type": LaunchConfiguration("ur_type"), "tf_prefix": "" } + xacro_args = { + "name": LaunchConfiguration("ur_type"), + "ur_type": LaunchConfiguration("ur_type"), + "tf_prefix": "", + } - ## ur_driver + ## ur_driver ur_control_launch = IncludeLaunchDescription( - PythonLaunchDescriptionSource([ - PathJoinSubstitution([FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"]) - ]), + PythonLaunchDescriptionSource( + [ + PathJoinSubstitution( + [ + FindPackageShare("ur_robot_driver"), + "launch", + "ur_control.launch.py", + ] + ) + ] + ), launch_arguments={ "ur_type": LaunchConfiguration("ur_type"), "robot_ip": LaunchConfiguration("robot_ip"), @@ -34,14 +62,20 @@ def generate_launch_description(): "description_file": LaunchConfiguration("description_file"), "controllers_file": LaunchConfiguration("controllers_file"), "tool_voltage": "24", - }.items() + }.items(), ) - # Load MoveIt! configuration moveit_config = ( - MoveItConfigsBuilder("ur_moveit",package_name="ur_zivid_epick_moveit_config") - .robot_description(file_path=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_with_zivid_epick.xacro"),mappings=xacro_args) + MoveItConfigsBuilder("ur_moveit", package_name="ur_zivid_epick_moveit_config") + .robot_description( + file_path=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_with_zivid_epick.xacro", + ), + mappings=xacro_args, + ) .trajectory_execution(file_path="config/moveit_controllers.yaml") .robot_description_kinematics(file_path="config/kinematics.yaml") .planning_scene_monitor( @@ -70,12 +104,16 @@ def generate_launch_description(): rviz_arg = DeclareLaunchArgument( "rviz_config", default_value="view_robot_mtc.rviz", - description="RViz config file" + description="RViz config file", ) - rviz_config = PathJoinSubstitution([ - FindPackageShare("ur_zivid_epick_moveit_config"), "rviz", LaunchConfiguration("rviz_config") - ]) + rviz_config = PathJoinSubstitution( + [ + FindPackageShare("ur_zivid_epick_moveit_config"), + "rviz", + LaunchConfiguration("rviz_config"), + ] + ) rviz_node = Node( package="rviz2", @@ -100,7 +138,6 @@ def generate_launch_description(): # parameters=[{"robot_ip": LaunchConfiguration("robot_ip")}] # ) - # Publish TF robot_state_publisher = Node( package="robot_state_publisher", @@ -111,9 +148,9 @@ def generate_launch_description(): ) epick_controller_spawner = Node( - package="controller_manager", - executable="spawner", - arguments=["epick_gripper_action_controller", "-c", "/controller_manager"], + package="controller_manager", + executable="spawner", + arguments=["epick_gripper_action_controller", "-c", "/controller_manager"], ) epick_status_controller_spawner = Node( @@ -122,26 +159,22 @@ def generate_launch_description(): arguments=["epick_status_publisher_controller", "-c", "/controller_manager"], ) - - - return LaunchDescription([ - ## arguments - robot_ip, - ur_type, - description_package, - description_file, - controllers_file, - rviz_arg, - - - ## Nodes - # tool_communication, - ur_control_launch, - run_move_group_node, - rviz_node, - robot_state_publisher, - epick_controller_spawner, - epick_status_controller_spawner, - ]) - - \ No newline at end of file + return LaunchDescription( + [ + ## arguments + robot_ip, + ur_type, + description_package, + description_file, + controllers_file, + rviz_arg, + ## Nodes + # tool_communication, + ur_control_launch, + run_move_group_node, + rviz_node, + robot_state_publisher, + epick_controller_spawner, + epick_status_controller_spawner, + ] + ) diff --git a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_hande_moveit_config/launch/robot_bringup.launch.py b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_hande_moveit_config/launch/robot_bringup.launch.py index 14b38fee9..e6ddf48cc 100644 --- a/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_hande_moveit_config/launch/robot_bringup.launch.py +++ b/src/custom-ur-descriptions/ur5e_moveit_configs/ur_zivid_hande_moveit_config/launch/robot_bringup.launch.py @@ -11,22 +11,49 @@ def generate_launch_description(): - ## Arguments - - ur_type = DeclareLaunchArgument('ur_type', default_value='ur5e') - robot_ip = DeclareLaunchArgument('robot_ip', default_value='192.168.1.10') - description_package = DeclareLaunchArgument('description_package', default_value='ur_description') - description_file = DeclareLaunchArgument('description_file', default_value=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_with_zivid_hande.xacro")) - controllers_file = DeclareLaunchArgument('controllers_file', default_value=os.path.join(get_package_share_directory("ur_zivid_hande_moveit_config"), "config", "ur_hande_controllers.yaml")) + ## Arguments + ur_type = DeclareLaunchArgument("ur_type", default_value="ur5e") + robot_ip = DeclareLaunchArgument("robot_ip", default_value="192.168.1.10") + description_package = DeclareLaunchArgument( + "description_package", default_value="ur_description" + ) + description_file = DeclareLaunchArgument( + "description_file", + default_value=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_with_zivid_hande.xacro", + ), + ) + controllers_file = DeclareLaunchArgument( + "controllers_file", + default_value=os.path.join( + get_package_share_directory("ur_zivid_hande_moveit_config"), + "config", + "ur_hande_controllers.yaml", + ), + ) - xacro_args = {"name": LaunchConfiguration("ur_type"), "ur_type": LaunchConfiguration("ur_type"), "tf_prefix": "" } + xacro_args = { + "name": LaunchConfiguration("ur_type"), + "ur_type": LaunchConfiguration("ur_type"), + "tf_prefix": "", + } - ## ur_driver + ## ur_driver ur_control_launch = IncludeLaunchDescription( - PythonLaunchDescriptionSource([ - PathJoinSubstitution([FindPackageShare("ur_robot_driver"), "launch", "ur_control.launch.py"]) - ]), + PythonLaunchDescriptionSource( + [ + PathJoinSubstitution( + [ + FindPackageShare("ur_robot_driver"), + "launch", + "ur_control.launch.py", + ] + ) + ] + ), launch_arguments={ "ur_type": LaunchConfiguration("ur_type"), "robot_ip": LaunchConfiguration("robot_ip"), @@ -35,14 +62,20 @@ def generate_launch_description(): "description_file": LaunchConfiguration("description_file"), "controllers_file": LaunchConfiguration("controllers_file"), "tool_voltage": "24", - }.items() + }.items(), ) - # Load MoveIt! configuration moveit_config = ( - MoveItConfigsBuilder("ur_moveit",package_name="ur_zivid_hande_moveit_config") - .robot_description(file_path=os.path.join(get_package_share_directory("ur5e_robot_description"), "urdf", "ur_with_zivid_hande.xacro"),mappings=xacro_args) + MoveItConfigsBuilder("ur_moveit", package_name="ur_zivid_hande_moveit_config") + .robot_description( + file_path=os.path.join( + get_package_share_directory("ur5e_robot_description"), + "urdf", + "ur_with_zivid_hande.xacro", + ), + mappings=xacro_args, + ) .trajectory_execution(file_path="config/moveit_controllers.yaml") .robot_description_kinematics(file_path="config/kinematics.yaml") .planning_scene_monitor( @@ -71,12 +104,16 @@ def generate_launch_description(): rviz_arg = DeclareLaunchArgument( "rviz_config", default_value="view_robot_mtc.rviz", - description="RViz config file" + description="RViz config file", ) - rviz_config = PathJoinSubstitution([ - FindPackageShare("ur_zivid_hande_moveit_config"), "rviz", LaunchConfiguration("rviz_config") - ]) + rviz_config = PathJoinSubstitution( + [ + FindPackageShare("ur_zivid_hande_moveit_config"), + "rviz", + LaunchConfiguration("rviz_config"), + ] + ) rviz_node = Node( package="rviz2", @@ -101,7 +138,6 @@ def generate_launch_description(): # parameters=[{"robot_ip": LaunchConfiguration("robot_ip")}] # ) - # Publish TF robot_state_publisher = Node( package="robot_state_publisher", @@ -118,22 +154,21 @@ def generate_launch_description(): arguments=["gripper_action_controller", "-c", "/controller_manager"], ) - - return LaunchDescription([ - ## arguments - robot_ip, - ur_type, - description_package, - description_file, - controllers_file, - rviz_arg, - - - ## Nodes - # tool_communication, - ur_control_launch, - run_move_group_node, - rviz_node, - robot_state_publisher, - hande_controller_spawner, - ]) + return LaunchDescription( + [ + ## arguments + robot_ip, + ur_type, + description_package, + description_file, + controllers_file, + rviz_arg, + ## Nodes + # tool_communication, + ur_control_launch, + run_move_group_node, + rviz_node, + robot_state_publisher, + hande_controller_spawner, + ] + ) diff --git a/src/demos/hello_moveit/launch/pick_place_repeat.launch.py b/src/demos/hello_moveit/launch/pick_place_repeat.launch.py index b140a1753..5e301de2a 100644 --- a/src/demos/hello_moveit/launch/pick_place_repeat.launch.py +++ b/src/demos/hello_moveit/launch/pick_place_repeat.launch.py @@ -9,8 +9,18 @@ def generate_launch_description(): package="hello_moveit", executable="pick_place_repeat_action_server", parameters=[ - PathJoinSubstitution([FindPackageShare("hello_moveit"), "config", "pick_place_repeat_params.yaml"]), - {"waypoints_file": PathJoinSubstitution([FindPackageShare("hello_moveit"), "config", "waypoints.yaml"])}, + PathJoinSubstitution( + [ + FindPackageShare("hello_moveit"), + "config", + "pick_place_repeat_params.yaml", + ] + ), + { + "waypoints_file": PathJoinSubstitution( + [FindPackageShare("hello_moveit"), "config", "waypoints.yaml"] + ) + }, ], output="screen", ) diff --git a/src/demos/hello_moveit/src/pick_place_repeat_client.py b/src/demos/hello_moveit/src/pick_place_repeat_client.py index a52eba2df..b435d7dc5 100644 --- a/src/demos/hello_moveit/src/pick_place_repeat_client.py +++ b/src/demos/hello_moveit/src/pick_place_repeat_client.py @@ -23,7 +23,9 @@ def send_goal(self, repeats: int): self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) self._send_goal_future.add_done_callback(self.goal_response_callback) def goal_response_callback(self, future: Future): diff --git a/src/end_effectors/epick_config/launch/epick_bringup.launch.py b/src/end_effectors/epick_config/launch/epick_bringup.launch.py index 76ec4c4a6..db0130833 100644 --- a/src/end_effectors/epick_config/launch/epick_bringup.launch.py +++ b/src/end_effectors/epick_config/launch/epick_bringup.launch.py @@ -23,9 +23,11 @@ def generate_launch_description(): ], ) - return LaunchDescription([ - parent_arg, - port_arg, - fake_arg, - controller, - ]) \ No newline at end of file + return LaunchDescription( + [ + parent_arg, + port_arg, + fake_arg, + controller, + ] + ) diff --git a/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_resume.py b/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_resume.py index 112f67ff5..70178eb29 100644 --- a/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_resume.py +++ b/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_resume.py @@ -42,12 +42,16 @@ def main(args=None): minimal_client = BlueskyInterrupt() pause_future_results = minimal_client.send_pause_request() - minimal_client.get_logger().info("Pause request results: " + str(pause_future_results)) + minimal_client.get_logger().info( + "Pause request results: " + str(pause_future_results) + ) time.sleep(10.0) resume_future_results = minimal_client.send_resume_request() - minimal_client.get_logger().info("Resume request results: " + str(resume_future_results)) + minimal_client.get_logger().info( + "Resume request results: " + str(resume_future_results) + ) minimal_client.destroy_node() rclpy.shutdown() diff --git a/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_stop.py b/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_stop.py index 34f51c079..af344b8ec 100644 --- a/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_stop.py +++ b/src/pdf/pdf_beamtime/acceptance_tests/bluesky_interrupt_stop.py @@ -66,12 +66,16 @@ def main(args=None): minimal_client = BlueskyInterrupt() pause_future_results = minimal_client.send_pause_request() - minimal_client.get_logger().info("Pause request results: " + str(pause_future_results)) + minimal_client.get_logger().info( + "Pause request results: " + str(pause_future_results) + ) time.sleep(2.0) resume_future_results = minimal_client.send_stop_request() - minimal_client.get_logger().info("Resume request results: " + str(resume_future_results)) + minimal_client.get_logger().info( + "Resume request results: " + str(resume_future_results) + ) minimal_client.destroy_node() rclpy.shutdown() diff --git a/src/pdf/pdf_beamtime/launch/pdf_beamtime.launch.py b/src/pdf/pdf_beamtime/launch/pdf_beamtime.launch.py index ef7609f64..f021a32cc 100644 --- a/src/pdf/pdf_beamtime/launch/pdf_beamtime.launch.py +++ b/src/pdf/pdf_beamtime/launch/pdf_beamtime.launch.py @@ -10,8 +10,12 @@ def generate_launch_description(): package="pdf_beamtime", executable="pdf_beamtime_server", parameters=[ - PathJoinSubstitution([FindPackageShare("pdf_beamtime"), "config", "obstacles.yaml"]), - PathJoinSubstitution([FindPackageShare("pdf_beamtime"), "config", "joint_poses.yaml"]), + PathJoinSubstitution( + [FindPackageShare("pdf_beamtime"), "config", "obstacles.yaml"] + ), + PathJoinSubstitution( + [FindPackageShare("pdf_beamtime"), "config", "joint_poses.yaml"] + ), ], output="screen", ) diff --git a/src/pdf/pdf_beamtime/launch/pdf_beamtime_fidpose_server.launch.py b/src/pdf/pdf_beamtime/launch/pdf_beamtime_fidpose_server.launch.py index 1e7d99fb9..67346e3ec 100644 --- a/src/pdf/pdf_beamtime/launch/pdf_beamtime_fidpose_server.launch.py +++ b/src/pdf/pdf_beamtime/launch/pdf_beamtime_fidpose_server.launch.py @@ -10,8 +10,12 @@ def generate_launch_description(): package="pdf_beamtime", executable="pdf_beamtime_fidpose_server", parameters=[ - PathJoinSubstitution([FindPackageShare("pdf_beamtime"), "config", "obstacles.yaml"]), - PathJoinSubstitution([FindPackageShare("pdf_beamtime"), "config", "joint_poses.yaml"]), + PathJoinSubstitution( + [FindPackageShare("pdf_beamtime"), "config", "obstacles.yaml"] + ), + PathJoinSubstitution( + [FindPackageShare("pdf_beamtime"), "config", "joint_poses.yaml"] + ), ], output="screen", ) diff --git a/src/pdf/pdf_beamtime/src/pdf_beamtime_client.py b/src/pdf/pdf_beamtime/src/pdf_beamtime_client.py index 1c1c0f0fe..9c24b13a1 100644 --- a/src/pdf/pdf_beamtime/src/pdf_beamtime_client.py +++ b/src/pdf/pdf_beamtime/src/pdf_beamtime_client.py @@ -16,7 +16,9 @@ class SimpleClient(Node): def __init__(self): """Python init.""" super().__init__("pdf_beamtime_client") - self._action_client = ActionClient(self, PickPlaceControlMsg, "pdf_beamtime_action_server") + self._action_client = ActionClient( + self, PickPlaceControlMsg, "pdf_beamtime_action_server" + ) self._goal_handle = None def send_pickup_goal(self): @@ -36,12 +38,16 @@ def send_pickup_goal(self): goal_msg.place = [x / 180 * math.pi for x in goal_msg.place] self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def feedback_callback(self, feedback_msg): """Display the feedback.""" feedback = feedback_msg.feedback - self.get_logger().info("Completion percentage: {0} %".format(math.ceil(feedback.status * 100))) + self.get_logger().info( + "Completion percentage: {0} %".format(math.ceil(feedback.status * 100)) + ) def goal_response_callback(self, future): """Send a cancellation after 15 seconds.""" @@ -67,7 +73,9 @@ def send_return_sample_goal(self): goal_msg.place = [x / 180 * math.pi for x in goal_msg.place] self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def main(args=None): diff --git a/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_client.py b/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_client.py index b42f6c7c0..1aeb0c1a3 100644 --- a/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_client.py +++ b/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_client.py @@ -16,41 +16,57 @@ class SimpleClient(Node): def __init__(self): """Python init.""" super().__init__("pdf_beamtime_fidpose_client") - self._action_client = ActionClient(self, FidPoseControlMsg, "pdf_beamtime_fidpose_action_server") + self._action_client = ActionClient( + self, FidPoseControlMsg, "pdf_beamtime_fidpose_action_server" + ) self._goal_handle = None def send_pickup_goal(self): """Send a working goal.""" goal_msg = FidPoseControlMsg.Goal() - goal_msg.inbeam_approach = [x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0]] + goal_msg.inbeam_approach = [ + x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0] + ] - goal_msg.inbeam = [x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0]] + goal_msg.inbeam = [ + x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0] + ] goal_msg.sample_return = False goal_msg.sample_id = 150 self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def send_return_sample_goal(self): """Send a working goal.""" goal_msg = FidPoseControlMsg.Goal() - goal_msg.inbeam_approach = [x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0]] + goal_msg.inbeam_approach = [ + x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0] + ] - goal_msg.inbeam = [x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0]] + goal_msg.inbeam = [ + x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0] + ] goal_msg.sample_return = True goal_msg.sample_id = 150 self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def feedback_callback(self, feedback_msg): """Display the feedback.""" feedback = feedback_msg.feedback - self.get_logger().info("Completion percentage: {0} %".format(math.ceil(feedback.status * 100))) + self.get_logger().info( + "Completion percentage: {0} %".format(math.ceil(feedback.status * 100)) + ) def goal_response_callback(self, future): """Send a cancellation after 15 seconds.""" diff --git a/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_redis_client.py b/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_redis_client.py index f05a8089c..99e6aed0f 100644 --- a/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_redis_client.py +++ b/src/pdf/pdf_beamtime/src/pdf_beamtime_fidpose_redis_client.py @@ -17,40 +17,56 @@ class SimpleClient(Node): def __init__(self): """Python init.""" super().__init__("pdf_beamtime_fidpose_client") - self._action_client = ActionClient(self, FidPoseControlMsg, "pdf_beamtime_fidpose_action_server") + self._action_client = ActionClient( + self, FidPoseControlMsg, "pdf_beamtime_fidpose_action_server" + ) self._goal_handle = None def send_pickup_goal(self, sample_id): """Send a working goal.""" goal_msg = FidPoseControlMsg.Goal() - goal_msg.inbeam_approach = [x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0]] - goal_msg.inbeam = [x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0]] + goal_msg.inbeam_approach = [ + x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0] + ] + goal_msg.inbeam = [ + x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0] + ] goal_msg.sample_return = False goal_msg.sample_id = sample_id self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def send_return_sample_goal(self, sample_id): """Send a working goal.""" goal_msg = FidPoseControlMsg.Goal() - goal_msg.inbeam_approach = [x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0]] - goal_msg.inbeam = [x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0]] + goal_msg.inbeam_approach = [ + x / 180 * math.pi for x in [55.10, -51.78, 124.84, -73.16, 52.24, 180.0] + ] + goal_msg.inbeam = [ + x / 180 * math.pi for x in [63.84, -47.71, 98.22, -50.59, 61.00, 180.0] + ] goal_msg.sample_return = True goal_msg.sample_id = sample_id self._action_client.wait_for_server() - self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) + self._send_goal_future = self._action_client.send_goal_async( + goal_msg, feedback_callback=self.feedback_callback + ) def feedback_callback(self, feedback_msg): """Display the feedback.""" feedback = feedback_msg.feedback - self.get_logger().info("Completion percentage: {0} %".format(math.ceil(feedback.status * 100))) + self.get_logger().info( + "Completion percentage: {0} %".format(math.ceil(feedback.status * 100)) + ) def goal_response_callback(self, future): """Send a cancellation after 15 seconds."""