Skip to content

Refactor the robotic manipulation package #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: development
Choose a base branch
from
18 changes: 18 additions & 0 deletions ros2_ws/src/robotic_manipulation/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Language: Cpp
BasedOnStyle: Google

AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
BraceWrapping:
AfterClass: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterEnum: true
BreakBeforeBraces: Custom
ColumnLimit: 100
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 2
DerivePointerAlignment: false
PointerAlignment: Middle
ReflowComments: false
4 changes: 2 additions & 2 deletions ros2_ws/src/robotic_manipulation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ find_package(vision_msgs REQUIRED)
find_package(rosbag2_cpp REQUIRED)
find_package(rai_interfaces REQUIRED)

add_executable(robotic_manipulation src/robotic_manipulation.cpp src/arm_controller.cpp src/state_controller.cpp)
add_executable(robotic_manipulation src/robotic_manipulation.cpp src/arm_controller.cpp src/rai_manipulation_interface_node.cpp)
target_include_directories(robotic_manipulation PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_features(robotic_manipulation PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17
target_compile_features(robotic_manipulation PUBLIC c_std_99 cxx_std_20) # Require C99 and C++20
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason for c++20?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::numbers::pi is the reason. Before C++20, no standard constant for π was defined.

ament_target_dependencies(
robotic_manipulation
"moveit_ros_planning_interface"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
/* Copyright (C) 2025 Robotec.AI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <moveit/move_group_interface/move_group_interface.h>

class ArmController {
class ArmController
{
public:
ArmController() = default;
~ArmController();

void Initialize();

geometry_msgs::msg::Pose CalculatePose(double x, double y, double z,
double r = 0.0);
geometry_msgs::msg::Pose CalculatePose(double x, double y, double z, double r = 0.0);

bool MoveThroughWaypoints(const std::vector<geometry_msgs::msg::Pose>& waypoints);
bool MoveThroughWaypoints(std::vector<geometry_msgs::msg::Pose> const & waypoints);

void Open();
void Close();
Expand All @@ -21,11 +36,21 @@ class ArmController {
bool GetGripper();

std::vector<double> CaptureJointValues();
bool SetJointValues(std::vector<double> const &jointValues);
bool SetJointValues(std::vector<double> const & jointValues);

void SetReferenceFrame(std::string const &frame);
void SetReferenceFrame(std::string const & frame);

private:
// The joint values for the gripper to be open and closed.
static double constexpr OpenGripperJointValue = 0.038;
static double constexpr ClosedGripperJointValue = 0.002;

// The base orientation of the end effector resulting in the gripper pointing
// straight down.
static double constexpr EndEffectorBaseRoll = 0.0;
static double constexpr EndEffectorBasePitch = std::numbers::pi;
static double constexpr EndEffectorBaseYaw = 45.0 * std::numbers::pi / 180.0;

void WaitForClockMessage();

std::shared_ptr<moveit::planning_interface::MoveGroupInterface> m_pandaArm;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright (C) 2025 Robotec.AI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <std_srvs/srv/trigger.hpp>

#include "rai_interfaces/srv/manipulator_move_to.hpp"
#include "robotic_manipulation/arm_controller.h"

class RaiManipulationInterfaceNode
{
public:
RaiManipulationInterfaceNode();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the destructor? Don't you need to destroy the services anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The services will get destroyed automatically when the shared_ptrs stored in this class get destroyed. Previously the destructor was here to shut down the executor thread, which wasn't even used since we spin the node in the main thread now, so I removed it.


void Initialize(ArmController & arm);
void Spin();

private:
rclcpp::Node::SharedPtr m_node;
rclcpp::Service<rai_interfaces::srv::ManipulatorMoveTo>::SharedPtr m_moveToService;
rclcpp::Service<std_srvs::srv::Trigger>::SharedPtr m_resetService;

rclcpp::executors::SingleThreadedExecutor m_executor;

std::vector<double> m_startingPose;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which configuration of clang-format did you use? It is quite strange the tool did not add a line break here.

Please add the configuration file to the repository to ensure every developer uses the same one. I suggest using the same one as in other projects within this namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a configuration file I found in the RAI repository and reformated the files again.

This file was deleted.

4 changes: 2 additions & 2 deletions ros2_ws/src/robotic_manipulation/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<package format="3">
<name>robotic_manipulation</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<description>A package providing services for robotic manipulation using RAI.</description>
<maintainer email="[email protected]">kdabrowski</maintainer>
<license>TODO: License declaration</license>
<license>Apache 2.0</license>

<buildtool_depend>ament_cmake</buildtool_depend>

Expand Down
103 changes: 65 additions & 38 deletions ros2_ws/src/robotic_manipulation/src/arm_controller.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
/* Copyright (C) 2025 Robotec.AI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "robotic_manipulation/arm_controller.h"

#include <numbers>
#include <rosgraph_msgs/msg/clock.hpp>

void ArmController::Initialize() {
void ArmController::Initialize()
{
m_node = rclcpp::Node::make_shared("arm_controller");
m_node->set_parameter(rclcpp::Parameter("use_sim_time", true));

Expand All @@ -11,31 +28,31 @@ void ArmController::Initialize() {
m_executor.add_node(m_node);
m_spinner = std::thread([this]() { m_executor.spin(); });

m_pandaArm = std::make_shared<moveit::planning_interface::MoveGroupInterface>(
m_node, "panda_arm");
m_hand = std::make_shared<moveit::planning_interface::MoveGroupInterface>(
m_node, "hand");
m_pandaArm =
std::make_shared<moveit::planning_interface::MoveGroupInterface>(m_node, "panda_arm");
m_hand = std::make_shared<moveit::planning_interface::MoveGroupInterface>(m_node, "hand");

m_pandaArm->setMaxVelocityScalingFactor(1.0);
m_pandaArm->setMaxAccelerationScalingFactor(1.0);
}

ArmController::~ArmController() {
ArmController::~ArmController()
{
m_executor.cancel();
if (m_spinner.joinable()) {
m_spinner.join();
}
}

geometry_msgs::msg::Pose ArmController::CalculatePose(double x, double y,
double z, double r) {
geometry_msgs::msg::Pose ArmController::CalculatePose(double x, double y, double z, double r)
{
geometry_msgs::msg::Pose pose;
pose.position.x = x;
pose.position.y = y;
pose.position.z = z;

auto quat = tf2::Quaternion();
quat.setEuler(0.0, M_PI, tf2Radians(45.0) + r);
quat.setEuler(EndEffectorBaseRoll, EndEffectorBasePitch, EndEffectorBaseYaw + r);
pose.orientation.x = quat.x();
pose.orientation.y = quat.y();
pose.orientation.z = quat.z();
Expand All @@ -44,65 +61,75 @@ geometry_msgs::msg::Pose ArmController::CalculatePose(double x, double y,
return pose;
}

bool ArmController::MoveThroughWaypoints(const std::vector<geometry_msgs::msg::Pose>& waypoints) {
bool ArmController::MoveThroughWaypoints(std::vector<geometry_msgs::msg::Pose> const & waypoints)
{
auto logger = m_node->get_logger();

const int NumTries = 10;
int constexpr NumTries = 10;
for (int i = 0; i < NumTries; i++) {
moveit_msgs::msg::RobotTrajectory trajectory;
if (m_pandaArm->computeCartesianPath(waypoints, 0.01, 0.0, trajectory) ==
-1) {
RCLCPP_ERROR(logger,
"MoveThroughWaypoints: Failed to compute Cartesian path");
if (m_pandaArm->computeCartesianPath(waypoints, 0.01, 0.0, trajectory) == -1) {
RCLCPP_ERROR(logger, "MoveThroughWaypoints: Failed to compute Cartesian path");
continue;
}

if (m_pandaArm->execute(trajectory) == moveit::core::MoveItErrorCode::SUCCESS) {
return true;
}
RCLCPP_ERROR(logger, "MoveThroughWaypoints: Failed to execute trajectory, trying again...");
RCLCPP_ERROR(
logger,
"MoveThroughWaypoints: Failed to execute "
"trajectory, trying again...");
}

RCLCPP_ERROR(logger, "MoveThroughWaypoints: Failed to execute trajectory after %d tries", NumTries);
RCLCPP_ERROR(
logger, "MoveThroughWaypoints: Failed to execute trajectory after %d tries", NumTries);
return false;
}

void ArmController::Open() {
void ArmController::Open()
{
gripper.store(true);
// m_hand->setNamedTarget("open");
m_hand->setJointValueTarget("panda_finger_joint1", 0.038);
m_hand->setJointValueTarget("panda_finger_joint1", OpenGripperJointValue);
while (m_hand->move() != moveit::core::MoveItErrorCode::SUCCESS) {
RCLCPP_ERROR(m_node->get_logger(), "Failed to open hand");
}
}

void ArmController::Close() {
void ArmController::Close()
{
gripper.store(false);
m_hand->setJointValueTarget("panda_finger_joint1", 0.002);
// m_hand->setNamedTarget("close");
m_hand->setJointValueTarget("panda_finger_joint1", ClosedGripperJointValue);
while (m_hand->move() != moveit::core::MoveItErrorCode::SUCCESS) {
RCLCPP_ERROR(m_node->get_logger(), "Failed to close hand");
}
}

std::vector<double> ArmController::GetEffectorPose() {
std::vector<double> ArmController::GetEffectorPose()
{
auto pose = m_pandaArm->getCurrentPose().pose;
auto rotation = tf2::Quaternion(pose.orientation.x, pose.orientation.y,
pose.orientation.z, pose.orientation.w);
auto rotation =
tf2::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
tf2::Matrix3x3 m(rotation);
m.getRPY(pose.orientation.x, pose.orientation.y, pose.orientation.z, 0);
return {pose.position.x, pose.position.y,
pose.position.z, pose.orientation.x,
pose.orientation.y - M_PI, pose.orientation.z - tf2Radians(135.0)};
return {
pose.position.x,
pose.position.y,
pose.position.z,
pose.orientation.x,
pose.orientation.y - EndEffectorBasePitch,
pose.orientation.z - (tf2Radians(180.0) - EndEffectorBaseYaw)};
};

bool ArmController::GetGripper() { return gripper.load(); }

std::vector<double> ArmController::CaptureJointValues() {
std::vector<double> ArmController::CaptureJointValues()
{
return m_pandaArm->getCurrentJointValues();
}

bool ArmController::SetJointValues(std::vector<double> const &jointValues) {
bool ArmController::SetJointValues(std::vector<double> const & jointValues)
{
m_pandaArm->setJointValueTarget(jointValues);
if (m_pandaArm->move() != moveit::core::MoveItErrorCode::SUCCESS) {
RCLCPP_ERROR(m_node->get_logger(), "Failed to set joint values");
Expand All @@ -111,19 +138,19 @@ bool ArmController::SetJointValues(std::vector<double> const &jointValues) {
return true;
}

void ArmController::SetReferenceFrame(std::string const &frame) {
void ArmController::SetReferenceFrame(std::string const & frame)
{
m_pandaArm->setPoseReferenceFrame(frame);
}

void ArmController::WaitForClockMessage() {
bool clock_received = false;
void ArmController::WaitForClockMessage()
{
bool clockReceived = false;
auto qos = rclcpp::QoS(rclcpp::KeepLast(1));
qos.best_effort();
auto subscription = m_node->create_subscription<rosgraph_msgs::msg::Clock>(
"/clock", qos, [&] (rosgraph_msgs::msg::Clock::SharedPtr) {
clock_received = true;
});
while (!clock_received) {
"/clock", qos, [&](rosgraph_msgs::msg::Clock::SharedPtr) { clockReceived = true; });
while (!clockReceived) {
rclcpp::spin_some(m_node);
}
subscription.reset();
Expand Down
Loading