42 static const std::string
LOGNAME =
"jog_calcs";
48 : parameters_(parameters), default_sleep_rate_(1000)
54 while (
ros::ok() && !model_loader_ptr)
59 const moveit::core::RobotModelPtr& kinematic_model = model_loader_ptr->getModel();
60 kinematic_state_ = std::make_shared<moveit::core::RobotState>(kinematic_model);
99 shared_variables.lock();
101 shared_variables.unlock();
109 int zero_velocity_count = 0;
114 bool wait_for_jog_commands =
true;
117 geometry_msgs::TwistStamped cartesian_deltas;
118 control_msgs::JointJog joint_deltas;
137 shared_variables.lock();
139 shared_variables.unlock();
143 if (wait_for_jog_commands || shared_variables.
paused)
148 shared_variables.lock();
152 shared_variables.unlock();
159 shared_variables.lock();
163 shared_variables.unlock();
165 bool valid_nonzero_command =
false;
169 if (have_nonzero_cartesian_cmd)
171 shared_variables.lock();
173 shared_variables.unlock();
178 else if (have_nonzero_joint_cmd)
180 shared_variables.lock();
182 shared_variables.unlock();
188 valid_nonzero_command = have_nonzero_cartesian_cmd || have_nonzero_joint_cmd;
192 if (!valid_nonzero_command)
199 have_nonzero_cartesian_cmd =
false;
200 have_nonzero_joint_cmd =
false;
202 shared_variables.lock();
205 shared_variables.unlock();
209 shared_variables.lock();
211 if (valid_nonzero_command)
229 shared_variables.unlock();
233 if (!have_nonzero_cartesian_cmd && !have_nonzero_joint_cmd)
236 if (zero_velocity_count < std::numeric_limits<int>::max())
237 ++zero_velocity_count;
240 zero_velocity_count = 0;
256 if (std::isnan(cmd.twist.linear.x) || std::isnan(cmd.twist.linear.y) || std::isnan(cmd.twist.linear.z) ||
257 std::isnan(cmd.twist.angular.x) || std::isnan(cmd.twist.angular.y) || std::isnan(cmd.twist.angular.z))
266 if ((fabs(cmd.twist.linear.x) > 1) || (fabs(cmd.twist.linear.y) > 1) || (fabs(cmd.twist.linear.z) > 1) ||
267 (fabs(cmd.twist.angular.x) > 1) || (fabs(cmd.twist.angular.y) > 1) || (fabs(cmd.twist.angular.z) > 1))
276 cmd.twist.linear.x = 0;
278 cmd.twist.linear.y = 0;
280 cmd.twist.linear.z = 0;
282 cmd.twist.angular.x = 0;
284 cmd.twist.angular.y = 0;
286 cmd.twist.angular.z = 0;
291 Eigen::Vector3d translation_vector(cmd.twist.linear.x, cmd.twist.linear.y, cmd.twist.linear.z);
292 Eigen::Vector3d angular_vector(cmd.twist.angular.x, cmd.twist.angular.y, cmd.twist.angular.z);
296 const auto tf_planning_to_cmd_frame =
300 translation_vector = tf_planning_to_cmd_frame.linear() * translation_vector;
301 angular_vector = tf_planning_to_cmd_frame.linear() * angular_vector;
305 cmd.twist.linear.x = translation_vector(0);
306 cmd.twist.linear.y = translation_vector(1);
307 cmd.twist.linear.z = translation_vector(2);
308 cmd.twist.angular.x = angular_vector(0);
309 cmd.twist.angular.y = angular_vector(1);
310 cmd.twist.angular.z = angular_vector(2);
322 for (
auto dimension = jacobian.rows(); dimension >= 0; --dimension)
330 Eigen::JacobiSVD<Eigen::MatrixXd> svd =
331 Eigen::JacobiSVD<Eigen::MatrixXd>(jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV);
332 Eigen::MatrixXd matrix_s = svd.singularValues().asDiagonal();
333 Eigen::MatrixXd pseudo_inverse = svd.matrixV() * matrix_s.inverse() * svd.matrixU().transpose();
360 for (
double velocity : cmd.velocities)
362 if (std::isnan(velocity))
424 auto point = trajectory.points[0];
426 for (
int i = 2; i < count + 1; ++i)
429 trajectory.points.push_back(point);
443 for (
int i = 0; i < delta_theta.size(); ++i)
451 trajectory_msgs::JointTrajectory new_joint_traj;
454 new_joint_traj.joint_names = joint_state.name;
456 trajectory_msgs::JointTrajectoryPoint point;
459 point.positions = joint_state.position;
461 point.velocities = joint_state.velocity;
468 point.accelerations = acceleration;
470 new_joint_traj.points.push_back(point);
472 return new_joint_traj;
478 double singularity_scale)
480 shared_variables.lock();
482 shared_variables.unlock();
484 if (collision_scale > 0 && collision_scale < 1)
489 else if (collision_scale == 0)
494 delta_theta = collision_scale * singularity_scale * delta_theta;
499 const Eigen::JacobiSVD<Eigen::MatrixXd>& svd,
500 const Eigen::MatrixXd& jacobian,
501 const Eigen::MatrixXd& pseudo_inverse)
503 double velocity_scale = 1;
504 std::size_t num_dimensions = jacobian.rows();
510 Eigen::VectorXd vector_toward_singularity = svd.matrixU().col(num_dimensions - 1);
512 double ini_condition = svd.singularValues()(0) / svd.singularValues()(svd.singularValues().size() - 1);
518 Eigen::VectorXd delta_x(num_dimensions);
520 delta_x = vector_toward_singularity / scale;
523 Eigen::VectorXd new_theta;
525 new_theta += pseudo_inverse * delta_x;
528 Eigen::JacobiSVD<Eigen::MatrixXd> new_svd(jacobian);
529 double new_condition = new_svd.singularValues()(0) / new_svd.singularValues()(new_svd.singularValues().size() - 1);
532 if (ini_condition >= new_condition)
534 vector_toward_singularity *= -1;
538 double dot = vector_toward_singularity.dot(commanded_velocity);
546 velocity_scale = 1. -
562 return velocity_scale;
570 std::size_t joint_delta_index = 0;
574 const auto bounds = joint->getVariableBounds(joint->getName());
575 if (bounds.acceleration_bounded_)
577 bool clip_acceleration =
false;
578 double acceleration_limit = 0.0;
579 if (acceleration(joint_delta_index) < bounds.min_acceleration_)
581 clip_acceleration =
true;
582 acceleration_limit = bounds.min_acceleration_;
584 else if (acceleration(joint_delta_index) > bounds.max_acceleration_)
586 clip_acceleration =
true;
587 acceleration_limit = bounds.max_acceleration_;
591 if (clip_acceleration)
595 const double relative_change =
598 delta_theta(joint_delta_index);
600 if (fabs(relative_change) < 1)
601 delta_theta(joint_delta_index) = relative_change * delta_theta(joint_delta_index);
605 if (bounds.velocity_bounded_)
609 bool clip_velocity =
false;
610 double velocity_limit = 0.0;
611 if (velocity(joint_delta_index) < bounds.min_velocity_)
613 clip_velocity =
true;
614 velocity_limit = bounds.min_velocity_;
616 else if (velocity(joint_delta_index) > bounds.max_velocity_)
618 clip_velocity =
true;
619 velocity_limit = bounds.max_velocity_;
628 if (fabs(relative_change) < 1)
630 delta_theta(joint_delta_index) = relative_change * delta_theta(joint_delta_index);
631 velocity(joint_delta_index) = relative_change * velocity(joint_delta_index);
641 bool halting =
false;
646 double joint_angle = 0;
657 const std::vector<moveit_msgs::JointLimits> limits = joint->getVariableBoundsMsg();
669 " position limit. Halting.");
680 std_msgs::Int8 status_msg;
689 delta_theta = Eigen::ArrayXd::Zero(delta_theta.rows());
696 if (joint_traj.points.empty())
698 joint_traj.points.push_back(trajectory_msgs::JointTrajectoryPoint());
699 joint_traj.points[0].positions.resize(
num_joints_);
700 joint_traj.points[0].velocities.resize(
num_joints_);
711 joint_traj.points[0].velocities[i] = 0;
718 shared_variables.lock();
720 shared_variables.unlock();
734 catch (
const std::out_of_range& e)
752 Eigen::VectorXd result(6);
790 for (std::size_t m = 0; m < command.joint_names.size(); ++m)
796 catch (
const std::out_of_range& e)
817 for (std::size_t i = 0,
size = static_cast<std::size_t>(increments.size()); i <
size; ++i)
821 output.position[i] += increments[
static_cast<long>(i)];
823 catch (
const std::out_of_range& e)
826 "increments do not match.");
836 unsigned int num_rows = jacobian.rows() - 1;
837 unsigned int num_cols = jacobian.cols();
839 if (row_to_remove < num_rows)
841 jacobian.block(row_to_remove, 0, num_rows - row_to_remove, num_cols) =
842 jacobian.block(row_to_remove + 1, 0, num_rows - row_to_remove, num_cols);
843 delta_x.segment(row_to_remove, num_rows - row_to_remove) =
844 delta_x.segment(row_to_remove + 1, num_rows - row_to_remove);
846 jacobian.conservativeResize(num_rows, num_cols);
847 delta_x.conservativeResize(num_rows);
void enforceSRDFAccelVelLimits(Eigen::ArrayXd &delta_theta)
Scale the delta theta to match joint velocity/acceleration limits.
Eigen::ArrayXd prev_joint_velocity_
bool publish_joint_accelerations
std::atomic< bool > stop_requested
ros::Publisher status_pub_
moveit::core::RobotStatePtr kinematic_state_
bool have_nonzero_joint_cmd
#define ROS_INFO_NAMED(name,...)
static const std::string LOGNAME
#define ROS_WARN_THROTTLE_NAMED(period, name,...)
#define ROS_ERROR_STREAM_NAMED(name, args)
void lowPassFilterPositions(sensor_msgs::JointState &joint_state)
Smooth position commands with a lowpass filter.
std::vector< LowPassFilter > position_filters_
double hard_stop_singularity_threshold
trajectory_msgs::JointTrajectory composeJointTrajMessage(sensor_msgs::JointState &joint_state) const
Compose the outgoing JointTrajectory message.
bool publish_joint_positions
double velocityScalingFactorForSingularity(const Eigen::VectorXd &commanded_velocity, const Eigen::JacobiSVD< Eigen::MatrixXd > &svd, const Eigen::MatrixXd &jacobian, const Eigen::MatrixXd &pseudo_inverse)
Possibly calculate a velocity scaling factor, due to proximity of singularity and direction of motion...
void insertRedundantPointsIntoTrajectory(trajectory_msgs::JointTrajectory &trajectory, int count) const
Gazebo simulations have very strict message timestamp requirements. Satisfy Gazebo by stuffing multip...
std::size_t size(custom_string const &s)
void updateCachedStatus(JogArmShared &shared_variables)
Update the stashed status so it can be retrieved asynchronously.
std::atomic< bool > paused
ROSCPP_DECL const std::string & getName()
Eigen::Isometry3d tf_moveit_to_cmd_frame
bool addJointIncrements(sensor_msgs::JointState &output, const Eigen::VectorXd &increments) const
JogCalcs(const JogArmParameters ¶meters, const robot_model_loader::RobotModelLoaderPtr &model_loader_ptr)
#define ROS_ERROR_STREAM_THROTTLE_NAMED(period, name, args)
doubleAcc dot(const VectorAcc &lhs, const VectorAcc &rhs)
sensor_msgs::JointState joints
std::string planning_frame
bool enforceSRDFPositionLimits(trajectory_msgs::JointTrajectory &new_joint_traj)
Avoid overshooting joint limits.
double low_pass_filter_coeff
bool jointJogCalcs(const control_msgs::JointJog &cmd, JogArmShared &shared_variables)
Do jogging calculations for direct commands to a joint.
double joint_limit_margin
bool convertDeltasToOutgoingCmd()
Convert joint deltas to an outgoing JointTrajectory command. This happens for joint commands and Cart...
std::atomic_bool drift_dimensions[6]
ros::Rate default_sleep_rate_
trajectory_msgs::JointTrajectory outgoing_command
bool isInitialized()
Check if the robot state is being updated and the end effector transform is known.
geometry_msgs::TwistStamped command_deltas
void publish(const boost::shared_ptr< M > &message) const
bool cartesianJogCalcs(geometry_msgs::TwistStamped &cmd, JogArmShared &shared_variables)
Do jogging calculations for Cartesian twist commands.
bool publish_joint_velocities
std::atomic_bool control_dimensions[6]
void applyVelocityScaling(JogArmShared &shared_variables, Eigen::ArrayXd &delta_theta, double singularity_scale)
double lower_singularity_threshold
#define ROS_WARN_STREAM_THROTTLE_NAMED(period, name, args)
JogArmParameters parameters_
sensor_msgs::JointState incoming_joint_state_
std::string robot_link_command_frame
Eigen::VectorXd scaleJointCommand(const control_msgs::JointJog &command) const
If incoming velocity commands are from a unitless joystick, scale them to physical units...
const std::unordered_map< uint, std::string > JOG_ARM_STATUS_CODE_MAP({ { NO_WARNING, "No warnings" }, { DECELERATE_FOR_SINGULARITY, "Close to a singularity, decelerating" }, { HALT_FOR_SINGULARITY, "Very close to a singularity, emergency stop" }, { DECELERATE_FOR_COLLISION, "Close to a collision, decelerating" }, { HALT_FOR_COLLISION, "Collision detected, emergency stop" }, { JOINT_BOUND, "Close to a joint bound (position or velocity), halting" } })
std::map< std::string, std::size_t > joint_state_name_map_
int num_outgoing_halt_msgs_to_publish
sensor_msgs::JointState internal_joint_state_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void calculateJointVelocities(sensor_msgs::JointState &joint_state, const Eigen::ArrayXd &delta_theta)
Convert an incremental position command to joint velocity message.
const std::vector< std::string > & getActiveJointModelNames() const
void publishStatus() const
Publish the status of the jogger to a ROS topic.
std::atomic< bool > is_initialized_
control_msgs::JointJog joint_command_deltas
double collision_velocity_scale
void suddenHalt(trajectory_msgs::JointTrajectory &joint_traj)
Suddenly halt for a joint limit or other critical issue. Is handled differently for position vs...
const std::vector< const JointModel *> & getActiveJointModels() const
std::string move_group_name
const int gazebo_redundant_message_count_
bool updateJoints(JogArmShared &shared_variables)
Parse the incoming joint msg for the joints of our MoveGroup.
const moveit::core::JointModelGroup * joint_model_group_
Eigen::VectorXd scaleCartesianCommand(const geometry_msgs::TwistStamped &command) const
If incoming velocity commands are from a unitless joystick, scale them to physical units...
bool have_nonzero_cartesian_cmd
std::string command_in_type
sensor_msgs::JointState original_joint_state_
#define ROS_DEBUG_STREAM_THROTTLE_NAMED(period, name, args)
Eigen::Isometry3d tf_moveit_to_cmd_frame_
void removeDimension(Eigen::MatrixXd &matrix, Eigen::VectorXd &delta_x, unsigned int row_to_remove)
std::atomic< StatusCode > status
Eigen::ArrayXd delta_theta_
void startMainLoop(JogArmShared &shared_variables)
trajectory_msgs::JointTrajectory outgoing_command_