diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..1bc4b3f8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Alliander N. V. +# +# SPDX-License-Identifier: Apache-2.0 +Language: Cpp +BasedOnStyle: Google + +InsertNewlineAtEOF: true +SeparateDefinitionBlocks: Always +SortIncludes: true +IncludeBlocks: Regroup +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: false diff --git a/.clangd b/.clangd new file mode 100644 index 00000000..e56e106f --- /dev/null +++ b/.clangd @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: Alliander N. V. +# +# SPDX-License-Identifier: Apache-2.0 +Documentation: + CommentFormat: Doxygen diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 4c5ce3b1..cb31342f 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Alliander N. V. -# +# # SPDX-License-Identifier: Apache-2.0 services: @@ -17,13 +17,16 @@ services: - "/tmp/.X11-unix:/tmp/.X11-unix" - "${HOME}/.vscode-server:/home/rcdt/.vscode-server" - "../:/home/rcdt/rcdt_robotics/" - - ../.cache/zed/resources:/usr/local/zed/resources - - ../.cache/zed/settings:/usr/local/zed/settings - "../.personal.bashrc:/home/rcdt/.personal.bashrc" - "../.env:/home/rcdt/.env" - "../pyproject.toml:/home/rcdt/pyproject.toml" - "../.config:/home/rcdt/.config" + - "../clangd:/home/rcdt/clangd" # Allows to mount a newer clangd version, can be used in VSCode. - "/dev:/dev" + - "${HOME}/.nix-profile/bin/nvim:/usr/bin/nvim" + - "/nix/store:/nix/store" + - "../.cache/zed/resources:/usr/local/zed/resources" + - "../.cache/zed/settings:/usr/local/zed/settings" environment: - "DISPLAY" - "RCUTILS_COLORIZED_OUTPUT=1" diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 8bf16ec1..52c58367 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -37,12 +37,19 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: sudo apt install -y clang-format - - run: find ros2_ws/src -iname '*.h' -o -iname '*.hpp' -o -iname '*.cpp' | xargs clang-format --dry-run --Werror + - run: python3 -m pip install clang-format + - run: find ros2_ws/src -iname '*.h' -o -iname '*.hpp' -o -iname '*.cpp' | xargs clang-format --dry-run --Werror --style=file + + doxygen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: sudo apt update && sudo apt install -y doxygen + - run: ./doxygen-lint.sh reuse: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: REUSE Compliance Check - uses: fsfe/reuse-action@v4 \ No newline at end of file + uses: fsfe/reuse-action@v4 diff --git a/.gitignore b/.gitignore index 093c8cba..626f48a2 100644 --- a/.gitignore +++ b/.gitignore @@ -20,8 +20,13 @@ ignore/ .vscode-server build/ +clangd/ .env !.devcontainer/.env .cache .venv + +# for LSP in neovim +.clangd-build/ +**/compile_commands.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4bffa62c..2a2075c3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,6 +51,13 @@ repos: hooks: - id: clang-format types_or: [c++, c, cuda] + - repo: local + hooks: + - id: doxygen + name: doxygen linting + entry: ./doxygen-lint.sh + language: system + pass_filenames: false - repo: https://github.com/fsfe/reuse-tool rev: v5.0.2 hooks: diff --git a/dockerfiles/install_scripts/dev_packages.sh b/dockerfiles/install_scripts/dev_packages.sh index 588f642f..7d203a35 100755 --- a/dockerfiles/install_scripts/dev_packages.sh +++ b/dockerfiles/install_scripts/dev_packages.sh @@ -9,4 +9,6 @@ source /home/$UNAME/.bashrc apt update apt install -y \ - ros-$ROS_DISTRO-nmea-navsat-driver \ No newline at end of file + clang \ + doxygen \ + ros-$ROS_DISTRO-nmea-navsat-driver diff --git a/docs/content/workflows.md b/docs/content/workflows.md index 0d172aed..246976a8 100644 --- a/docs/content/workflows.md +++ b/docs/content/workflows.md @@ -27,6 +27,9 @@ Checks all files in this repository on usage of copyright terms. - **Ty**:\ Runs static type checks on our Python code using [Ty](https://github.com/astral-sh/ty). +- **doxygen**:\ +Runs code documentation checks for .cpp, .hpp, and .h files, using the rules specified in *doxyfile.lint*. In the future, other filetypes may be added as well. + ### Local Development You can run these checks locally before committing by using the [`pre-commit`](https://pre-commit.com/) framework: diff --git a/doxyfile.lint b/doxyfile.lint new file mode 100644 index 00000000..8ad026f9 --- /dev/null +++ b/doxyfile.lint @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: Alliander N. V. +# +# SPDX-License-Identifier: Apache-2.0 +PROJECT_NAME = "RCDT Robotics" + +INPUT = ros2_ws/src +RECURSIVE = YES +QUIET = YES + +WARNINGS = YES +WARN_NO_PARAMDOC = YES +WARN_IF_UNDOC_ENUM_VAL = YES + +EXTRACT_PRIVATE = YES +EXTRACT_PRIV_VIRTUAL = YES +EXTRACT_PACKAGE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES + +# If no output is generated, Doxygen seems to not fully parse documentation. +# This can lead to erroneous warnings that are not present if any type of output is generated. +GENERATE_LATEX = NO +GENERATE_HTML = NO +GENERATE_RTF = YES + +FILE_PATTERNS = *.cpp \ + *.h \ + *.hpp diff --git a/doxygen-lint.sh b/doxygen-lint.sh new file mode 100755 index 00000000..0e735fe3 --- /dev/null +++ b/doxygen-lint.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: Alliander N. V. +# +# SPDX-License-Identifier: Apache-2.0 +FILENAME=doxyfile.lint + +if ! command -v doxygen > /dev/null 2>&1 ; then + echo "Doxygen not found, exiting." + exit 1 +fi + +if [ ! -f $FILENAME ]; then + echo "Doxyfile '$FILENAME' not found, exiting." + exit 1 +fi + +OUTPUT=$(doxygen $FILENAME /dev/null 2>&1) +NUM_WARNINGS=$(echo "$OUTPUT" | grep -i "warning:" | wc -l) + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +rm -rf $SCRIPT_DIR/rtf/ + +if [ "$NUM_WARNINGS" -gt 0 ]; then + echo "$OUTPUT" + echo "Doxygen found $NUM_WARNINGS documentation warnings." + exit 1 +fi diff --git a/ros2_ws/src/rcdt_moveit/include/moveit_manager.hpp b/ros2_ws/src/rcdt_moveit/include/moveit_manager.hpp index b8bcac42..d3a45a48 100644 --- a/ros2_ws/src/rcdt_moveit/include/moveit_manager.hpp +++ b/ros2_ws/src/rcdt_moveit/include/moveit_manager.hpp @@ -2,12 +2,13 @@ // // # SPDX-License-Identifier: Apache-2.0 +#include + #include #include #include #include #include -#include #include #include #include @@ -29,71 +30,170 @@ typedef std_srvs::srv::Trigger Trigger; typedef geometry_msgs::msg::PoseStamped PoseStamped; typedef rcdt_messages::srv::ExpressPoseInOtherFrame ExpressPoseInOtherFrame; -struct Action { - std::string name; - std::string argument = ""; - float value = 0.0; -}; - +/** + * Class to interact with the Moveit framework. + */ class MoveitManager { -public: + public: + /** + * @brief constructor for the MoveitManager class. + * @param node The ROS2 node to attach to. + */ MoveitManager(rclcpp::Node::SharedPtr node); -private: - rclcpp::Node::SharedPtr node; - rclcpp::Node::SharedPtr client_node; - moveit::planning_interface::MoveGroupInterface move_group; - moveit::planning_interface::PlanningSceneInterface planning_scene_interface; - const moveit::core::JointModelGroup *joint_model_group; - moveit_visual_tools::MoveItVisualTools moveit_visual_tools; - PoseStamped goal_pose; + private: + rclcpp::Node::SharedPtr node; /**< ROS2 node with MoveIt Services */ + rclcpp::Node::SharedPtr + client_node; /**< ROS2 node with ExpressPoseInOtherFrame Client */ + moveit::planning_interface::MoveGroupInterface + move_group; /**< Interface for setting joint/pose goals */ + moveit::planning_interface::PlanningSceneInterface + planning_scene_interface; /**< Interface for adding collision objects */ + const moveit::core::JointModelGroup* + joint_model_group; /**< Joint models for planning trajectories */ + moveit_visual_tools::MoveItVisualTools + moveit_visual_tools; /**< Visualization tools */ + PoseStamped goal_pose; /**< Goal pose to move end-effector to */ // Definitions: std::map shapes = { - {"BOX", 1}, {"SPHERE", 2}, {"CYLINDER", 3}, {"CONE", 4}}; - std::set pilz_types = {"PTP", "LIN", "CIRC"}; + {"BOX", 1}, + {"SPHERE", 2}, + {"CYLINDER", 3}, + {"CONE", 4}}; /**< Basic shape types for MoveIt */ + std::set pilz_types = { + "PTP", "LIN", + "CIRC"}; /**< Motion planning types (point-to-point, linear, circular) */ // Clients: rclcpp::Client::SharedPtr - express_pose_in_other_frame_client; + express_pose_in_other_frame_client; /**< Client to transform a Pose in + another coordinate frame */ // Services: - rclcpp::Service::SharedPtr add_object_service; + rclcpp::Service::SharedPtr + add_object_service; /**< Service to add collision object */ + + /** + * @brief Callback to add a collision object. + * @param request The AddObject request indicating object pose and shape. + * @param response Response indicating whether the service call succeeded. + */ void add_object(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr clear_objects_service; + rclcpp::Service::SharedPtr + clear_objects_service; /**< Service to remove all collision objects */ + + /** + * @brief Callback to clear collision objects. + * @param request The Trigger request. + * @param response Response indicating whether the service call succeeded. + */ void clear_objects(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr define_goal_pose_service; + rclcpp::Service::SharedPtr + define_goal_pose_service; /**< Service to define goal + pose for arm to move to */ + + /** + * @brief Callback to define goal pose for arm to move to. + * @param request The DefineGoalPose request containing the goal pose. + * @param response Response indicating whether the service call succeeded. + */ void define_goal_pose(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr transform_goal_pose_service; - void - transform_goal_pose(const std::shared_ptr request, - std::shared_ptr response); - - rclcpp::Service::SharedPtr move_to_configuration_service; + rclcpp::Service::SharedPtr + transform_goal_pose_service; /**< Service to offset the goal_pose by a + specified translation */ + + /** + * @brief Callback to offset goal_pose by a specified translation around a + * specified axis. + * @param request The TransformGoalPose request containing relevant axis and + * translation. + * @param response Response indicating whether the service call succeeded. + */ + void transform_goal_pose( + const std::shared_ptr request, + std::shared_ptr response); + + rclcpp::Service::SharedPtr + move_to_configuration_service; /**< Service to move to a specified + configuration */ + + /** + * @brief Callback to move arm to a specified configuration (e.g. home). + * @param request The MoveToConf request containing the configuration. + * @param response Response indicating whether the service call succeeded. + */ void move_to_configuration(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr move_hand_to_pose_service; + rclcpp::Service::SharedPtr + move_hand_to_pose_service; /**< Service to move hand to + a specified goal Pose */ + + /** + * @brief Callback to move arm to a specified goal Pose. + * @param request The MoveHandToPose request containing the goal Pose and Pilz + * planning type. + * @param response Response indicating whether the service call succeeded. + */ void move_hand_to_pose(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr add_marker_service; + rclcpp::Service::SharedPtr + add_marker_service; /**< Service to add a visual marker at a + specified Pose */ + + /** + * @brief Callback to add a visual marker at a specified location. + * @param request The AddMarker request containing the Pose to add the visual + * marker. + * @param response Response indicating whether the service call succeeded. + */ void add_marker(const std::shared_ptr request, std::shared_ptr response); - rclcpp::Service::SharedPtr clear_markers_service; + rclcpp::Service::SharedPtr + clear_markers_service; /**< Service to clear all visual markers. */ + + /** + * @brief Callback to clear all visual markers. + * @param request The Trigger request to remove all visual markers. + * @param response Response indicating whether the service call succeeded. + */ void clear_markers(const std::shared_ptr request, std::shared_ptr response); // Methods: + /** + * @brief Initializes the ExpressPoseInOtherFrame service client Node and + * Client. + */ void initialize_clients(); + + /** + * @brief Initializes all MoveIt Services + */ void initialize_services(); + + /** + * @brief Method to change a specified Pose to a world-fixed frame. + * @param pose PoseStamped object to transform into world-fixed-frame. + * @return PoseStamped object transformed to world-fixed frame. + */ PoseStamped change_frame_to_world(PoseStamped pose); + + /** + * @brief Method that engages the move_group to plan a trajectory to the + * goal_pose. + * @param planning_type String containing the Pilz planning type + * (point-to-point, linear, circular). + * @return boolean indicating whether the planning succeeded or not. + */ bool plan_and_execute(std::string planning_type = ""); -}; \ No newline at end of file +}; diff --git a/ros2_ws/src/rcdt_moveit/src/moveit_manager.cpp b/ros2_ws/src/rcdt_moveit/src/moveit_manager.cpp index 1da19280..82cfe7f4 100644 --- a/ros2_ws/src/rcdt_moveit/src/moveit_manager.cpp +++ b/ros2_ws/src/rcdt_moveit/src/moveit_manager.cpp @@ -3,6 +3,7 @@ // # SPDX-License-Identifier: Apache-2.0 #include "moveit_manager.hpp" + #include #include #include @@ -21,7 +22,6 @@ MoveitManager::MoveitManager(rclcpp::Node::SharedPtr node_) moveit::planning_interface::MoveGroupInterface::ROBOT_DESCRIPTION, node->get_namespace())), moveit_visual_tools(node, "base", "/rviz_markers") { - moveit_visual_tools.loadMarkerPub(false); move_group.setEndEffectorLink("fr3_hand"); joint_model_group = move_group.getRobotModel()->getJointModelGroup("fr3_arm"); @@ -193,7 +193,7 @@ void MoveitManager::clear_markers( response->success = true; } -int main(int argc, char **argv) { +int main(int argc, char** argv) { rclcpp::init(argc, argv); rclcpp::NodeOptions node_options; node_options.automatically_declare_parameters_from_overrides(true); @@ -203,4 +203,4 @@ int main(int argc, char **argv) { executor.add_node(node); executor.spin(); rclcpp::shutdown(); -} \ No newline at end of file +}