Skip to content
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

[Servo] Refactoring servo #2224

Merged
merged 55 commits into from Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
8050f38
Add C++ APIs: JointJog, Twist and Pose
ibrahiminfinite Jun 3, 2023
dd33754
Rewrite collision monitor
ibrahiminfinite Jun 8, 2023
57fffac
Improve pose tracking + address review comments
ibrahiminfinite Jun 9, 2023
5d73ad7
Squash updates
ibrahiminfinite Jun 12, 2023
2de4c33
Update pose demo and non planning frame command tests
ibrahiminfinite Jun 26, 2023
1008a0e
Refactor command processing into free functions
ibrahiminfinite Jun 28, 2023
965bc5c
Remove tests for wrong frame
ibrahiminfinite Jun 28, 2023
1992189
Singularity scaling does not need joint model group as arg
ibrahiminfinite Jun 28, 2023
b63d0b6
Readablity renaming
ibrahiminfinite Jun 28, 2023
00081cb
Add ROS API for jointjog, twist and pose
ibrahiminfinite Jul 1, 2023
5e2b211
ROS API updates
ibrahiminfinite Jul 2, 2023
6684095
Stop pose tracking on command switch
ibrahiminfinite Jul 2, 2023
0c1ee22
Remove unused launch file
ibrahiminfinite Jul 7, 2023
e4029d8
Remove test dependency on node
ibrahiminfinite Jul 7, 2023
47f7db5
Make util tests self contained
ibrahiminfinite Jul 7, 2023
c1ec27e
Add integration tests for C++ API
ibrahiminfinite Jul 7, 2023
67e1be3
start/stop collision checking with pause service
ibrahiminfinite Jul 14, 2023
90441e7
Improve dynamic pose tracking + review suggestions.
ibrahiminfinite Jul 14, 2023
9772b38
Increase twist + bug fix
ibrahiminfinite Jul 15, 2023
72a5137
Fix pre-commit edit
ibrahiminfinite Jul 15, 2023
a9d5edc
Review updates 1
ibrahiminfinite Jul 17, 2023
1feb399
Add support for unitless commands
ibrahiminfinite Jul 17, 2023
5abc826
Update tests to include unitless computation
ibrahiminfinite Jul 17, 2023
84511ed
Add support for realtime kernel
ibrahiminfinite Jul 17, 2023
95bdaba
ROS API updates
ibrahiminfinite Jul 17, 2023
345bec0
Disable copy construction and assignment
ibrahiminfinite Jul 17, 2023
6c525ef
Make servo responsive to model group change, remove robot specific da…
ibrahiminfinite Jul 18, 2023
2575b5f
Fix collision checking
ibrahiminfinite Jul 18, 2023
25b99d6
Remove unused keycode
ibrahiminfinite Jul 18, 2023
7358d68
Add ROS API tests
ibrahiminfinite Jul 25, 2023
df619c7
Review updates
ibrahiminfinite Jul 27, 2023
63229e6
Make ServoNode a component
ibrahiminfinite Jul 27, 2023
b43abf8
Review updates
ibrahiminfinite Jul 28, 2023
0673950
Comment fix
ibrahiminfinite Jul 28, 2023
e28d088
Review updates
ibrahiminfinite Jul 28, 2023
e45e963
Fix jointjog command conversion
ibrahiminfinite Jul 31, 2023
5b26b05
Add frame transfrom for twist
ibrahiminfinite Aug 1, 2023
99d9805
Add frame transform for pose
ibrahiminfinite Aug 1, 2023
f0b7fdc
Use active joint models
ibrahiminfinite Aug 2, 2023
e5ccdf2
formatting
ibrahiminfinite Aug 2, 2023
a8fa042
Fix command processing condition
ibrahiminfinite Aug 2, 2023
dc1cb30
Definie linear and angular step outside loop in pose demo
ibrahiminfinite Aug 2, 2023
70c06ea
Latch command + smooth halt
ibrahiminfinite Aug 3, 2023
d524172
Minor updates
ibrahiminfinite Aug 3, 2023
78f5c43
Exception handling for transfrom
ibrahiminfinite Aug 3, 2023
7dfe3de
Fix timeout behaviour
ibrahiminfinite Aug 4, 2023
7d5a9d6
Update ROS API tests
ibrahiminfinite Aug 4, 2023
46a9ead
Fail test if joint_state not available
ibrahiminfinite Aug 4, 2023
a1024a3
Stop publishing after smooth halt
ibrahiminfinite Aug 4, 2023
061fb69
Update tests + clang-tidy
ibrahiminfinite Aug 5, 2023
83a11c4
More clang-tidy
ibrahiminfinite Aug 6, 2023
710eb64
Update moveit_msgs repo
ibrahiminfinite Aug 6, 2023
2ee77d3
Add comment for component interface
ibrahiminfinite Aug 6, 2023
eda3133
Fix NOLINT in header
sea-bass Aug 7, 2023
b40a11d
Log halting only while stopping and with debug level
sea-bass Aug 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions moveit_ros/moveit_servo/include/moveit_servo/servo.hpp
Expand Up @@ -118,6 +118,19 @@ class Servo
*/
servo::Params& getParams();

/**
* \brief Get the current state of the robot as given by planning scene monitor.
* @return The current state of the robot.
*/
KinematicState getCurrentRobotState();

/**
* \brief Smoothly halt at a commanded state when command goes stale.
* @param The last commanded joint states.
* @return The next state stepping towards the required halting state.
*/
KinematicState smoothHalt(KinematicState halt_state);

private:
/**
* \brief Convert a give twist command to planning frame
Expand Down
7 changes: 4 additions & 3 deletions moveit_ros/moveit_servo/include/moveit_servo/servo_node.hpp
Expand Up @@ -96,9 +96,9 @@ class ServoNode
void twistCallback(const geometry_msgs::msg::TwistStamped::SharedPtr msg);
void poseCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg);

std::optional<KinematicState> processJointJogCommand();
std::optional<KinematicState> processTwistCommand();
std::optional<KinematicState> processPoseCommand();
KinematicState processJointJogCommand();
KinematicState processTwistCommand();
KinematicState processPoseCommand();

// Variables

Expand All @@ -107,6 +107,7 @@ class ServoNode
servo::Params servo_params_;
planning_scene_monitor::PlanningSceneMonitorPtr planning_scene_monitor_;

KinematicState last_commanded_state_; // Used when commands go stale;
control_msgs::msg::JointJog latest_joint_jog_;
geometry_msgs::msg::TwistStamped latest_twist_;
geometry_msgs::msg::PoseStamped latest_pose_;
Expand Down
39 changes: 39 additions & 0 deletions moveit_ros/moveit_servo/src/servo.cpp
Expand Up @@ -46,6 +46,7 @@ namespace
{
const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_servo.servo");
constexpr double ROBOT_STATE_WAIT_TIME = 5.0; // seconds
constexpr double STOPPED_VELOCITY_EPS = 1e-4;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should really be a parameter (we found issues with that on Kinova robots), but definitely not for this PR!

} // namespace

namespace moveit_servo
Expand Down Expand Up @@ -460,4 +461,42 @@ const PoseCommand Servo::toPlanningFrame(const PoseCommand& command)
return PoseCommand{ servo_params_.planning_frame, tf2::transformToEigen(target_pose_msg) };
}

KinematicState Servo::getCurrentRobotState()
{
moveit::core::RobotStatePtr robot_state = planning_scene_monitor_->getStateMonitor()->getCurrentState();
const moveit::core::JointModelGroup* joint_model_group =
robot_state->getJointModelGroup(servo_params_.move_group_name);
const auto joint_names = joint_model_group->getActiveJointModelNames();

KinematicState current_state(joint_names.size());
current_state.joint_names = joint_names;
robot_state->copyJointGroupPositions(joint_model_group, current_state.positions);
robot_state->copyJointGroupVelocities(joint_model_group, current_state.velocities);
robot_state->copyJointGroupAccelerations(joint_model_group, current_state.accelerations);

return current_state;
}

KinematicState Servo::smoothHalt(KinematicState halt_state)
{
const auto current_state = getCurrentRobotState();

const size_t num_joints = current_state.joint_names.size();
for (size_t i = 0; i < num_joints; i++)
{
const double vel = (halt_state.positions[i] - current_state.positions[i]) / servo_params_.publish_period;
halt_state.velocities[i] = (vel > STOPPED_VELOCITY_EPS) ? vel : 0.0;
halt_state.accelerations[i] =
(halt_state.velocities[i] - current_state.velocities[i]) / servo_params_.publish_period;
}

if (smoother_)
{
smoother_->reset(current_state.positions);
smoother_->doSmoothing(halt_state.positions);
}

return halt_state;
}

} // namespace moveit_servo
49 changes: 27 additions & 22 deletions moveit_ros/moveit_servo/src/servo_node.cpp
Expand Up @@ -185,37 +185,34 @@ void ServoNode::poseCallback(const geometry_msgs::msg::PoseStamped::SharedPtr ms
new_pose_msg_ = true;
}

std::optional<KinematicState> ServoNode::processJointJogCommand()
KinematicState ServoNode::processJointJogCommand()
{
std::optional<KinematicState> next_joint_state = std::nullopt;

// Mark latest jointjog command as processed.
KinematicState next_joint_state;
// Reject any other command types that had arrived simultaneously.
new_joint_jog_msg_ = new_twist_msg_ = new_pose_msg_ = false;
new_twist_msg_ = new_pose_msg_ = false;

const bool command_stale = (node_->now() - latest_joint_jog_.header.stamp) >=
rclcpp::Duration::from_seconds(servo_params_.incoming_command_timeout);
if (!command_stale)
{
// JointJogCommand is an alias for VectorXd, so we can directly make a map and pass it.
JointJogCommand command{ latest_joint_jog_.joint_names, latest_joint_jog_.velocities };
next_joint_state = servo_->getNextJointState(command);
}
else
{
RCLCPP_WARN(LOGGER, "JointJog command is stale, will not process.");
next_joint_state = servo_->smoothHalt(last_commanded_state_);
}

return next_joint_state;
}

std::optional<KinematicState> ServoNode::processTwistCommand()
KinematicState ServoNode::processTwistCommand()
{
std::optional<KinematicState> next_joint_state = std::nullopt;
KinematicState next_joint_state;

// Mark latest twist command as processed.
// Reject any other command types that had arrived simultaneously.
new_joint_jog_msg_ = new_twist_msg_ = new_pose_msg_ = false;
new_joint_jog_msg_ = new_pose_msg_ = false;

const bool command_stale = (node_->now() - latest_twist_.header.stamp) >=
rclcpp::Duration::from_seconds(servo_params_.incoming_command_timeout);
Expand All @@ -229,19 +226,19 @@ std::optional<KinematicState> ServoNode::processTwistCommand()
}
else
{
RCLCPP_WARN(LOGGER, "Twist command is stale, will not process.");
next_joint_state = servo_->smoothHalt(last_commanded_state_);
}

return next_joint_state;
}

std::optional<KinematicState> ServoNode::processPoseCommand()
KinematicState ServoNode::processPoseCommand()
{
std::optional<KinematicState> next_joint_state = std::nullopt;
KinematicState next_joint_state;

// Mark latest pose command as processed.
// Reject any other command types that had arrived simultaneously.
new_joint_jog_msg_ = new_twist_msg_ = new_pose_msg_ = false;
new_joint_jog_msg_ = new_twist_msg_ = false;

const bool command_stale = (node_->now() - latest_pose_.header.stamp) >=
rclcpp::Duration::from_seconds(servo_params_.incoming_command_timeout);
Expand All @@ -252,7 +249,7 @@ std::optional<KinematicState> ServoNode::processPoseCommand()
}
else
{
RCLCPP_WARN(LOGGER, "Pose command is stale, will not process.");
next_joint_state = servo_->smoothHalt(last_commanded_state_);
}

return next_joint_state;
Expand All @@ -261,16 +258,23 @@ std::optional<KinematicState> ServoNode::processPoseCommand()
void ServoNode::servoLoop()
{
moveit_msgs::msg::ServoStatus status_msg;
std::optional<KinematicState> next_joint_state;
KinematicState next_joint_state;
rclcpp::WallRate servo_frequency(1 / servo_params_.publish_period);

// Initialize the kinematicState
{
auto state = servo_->getCurrentRobotState();
std::fill(state.velocities.begin(), state.velocities.end(), 0.0);
std::fill(state.accelerations.begin(), state.accelerations.end(), 0.0);
next_joint_state = state;
}

while (rclcpp::ok() && !stop_servo_)
{
// Skip processing if servoing is disabled.
if (servo_paused_)
continue;

next_joint_state = std::nullopt;
const CommandType expectedType = servo_->getCommandType();

if (expectedType == CommandType::JOINT_JOG && new_joint_jog_msg_)
Expand All @@ -291,20 +295,21 @@ void ServoNode::servoLoop()
RCLCPP_WARN_STREAM(LOGGER, "Command type has not been set, cannot accept input");
}

if (next_joint_state && (servo_->getStatus() != StatusCode::INVALID))
if ((servo_->getStatus() != StatusCode::INVALID))
{
if (servo_params_.command_out_type == "trajectory_msgs/JointTrajectory")
trajectory_publisher_->publish(composeTrajectoryMessage(servo_->getParams(), next_joint_state.value()));
trajectory_publisher_->publish(composeTrajectoryMessage(servo_->getParams(), next_joint_state));
else if (servo_params_.command_out_type == "std_msgs/Float64MultiArray")
multi_array_publisher_->publish(composeMultiArrayMessage(servo_->getParams(), next_joint_state.value()));
multi_array_publisher_->publish(composeMultiArrayMessage(servo_->getParams(), next_joint_state));
last_commanded_state_ = next_joint_state;
}

status_msg.code = static_cast<int8_t>(servo_->getStatus());
status_msg.message = servo_->getStatusMessage();
status_publisher_->publish(status_msg);
}

servo_frequency.sleep();
servo_frequency.sleep();
}
}

} // namespace moveit_servo
Expand Down