spacenav_teleop.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  * \file
00003  *
00004  * $Id: cob_interactive_teleop.cpp 674 2012-04-19 13:59:19Z spanel $
00005  *
00006  * Copyright (C) Brno University of Technology
00007  *
00008  * This file is part of software developed by Robo@FIT group.
00009  *
00010  * Author: Zdenek Materna (imaterna@fit.vutbr.cz)
00011  * Supervised by: Michal Spanel (spanel@fit.vutbr.cz)
00012  * Date: 1/12/2012
00013  *
00014  * This file is free software: you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as published by
00016  * the Free Software Foundation, either version 3 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * This file is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU Lesser General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
00026  */
00027 
00028 #include "cob_spacenav_teleop/spacenav_teleop.h"
00029 
00030 using namespace cob_spacenav_teleop;
00031 
00032 SpaceNavTeleop::SpaceNavTeleop() {
00033 
00034         enabled_ = true;
00035 
00036         tfl_ = new tf::TransformListener();
00037 
00038         ros::param::param<double>("~max_vel_x",params_.max_vel_x,0.3);
00039         ros::param::param<double>("~max_vel_y",params_.max_vel_y,0.2);
00040         ros::param::param<double>("~max_vel_th",params_.max_vel_th,0.3);
00041         ros::param::param<double>("~scale_linear",params_.scale_linear,0.5);
00042         ros::param::param<double>("~scale_angular",params_.scale_angular,0.25);
00043 
00044         ros::param::param<double>("~spacenav/max_val",params_.sn_max_val,350.0);
00045         ros::param::param<double>("~spacenav/min_val_th",params_.sn_min_val_th,0.05);
00046 
00047         ros::param::param<double>("~spacenav/ignore_th_high",params_.ignore_th_high,0.9);
00048         ros::param::param<double>("~spacenav/ignore_th_low",params_.ignore_th_low,0.1);
00049 
00050         ros::param::param<bool>("~spacenav/instant_stop_enabled",params_.instant_stop_enabled,false);
00051 
00052         ros::param::param<bool>("~unsafe_limiter",params_.unsafe_limiter,false);
00053 
00054         ros::param::param<bool>("~use_rviz_cam",params_.use_rviz_cam,false);
00055         ros::param::param<std::string>("~rviz_cam_link",params_.rviz_cam_link,"/rviz_cam");
00056 
00057         params_.robot_base_link = "/base_link";
00058 
00059         if (params_.sn_min_val_th > 0.5) params_.sn_min_val_th = 0.5;
00060         if (params_.sn_min_val_th < 0.0) params_.sn_min_val_th = 0.0;
00061 
00062         // make sure that all values are positive
00063         if (params_.sn_max_val < 0.0) params_.sn_max_val *= -1.0;
00064         if (params_.max_vel_x < 0.0) params_.max_vel_x *= -1;
00065         if (params_.max_vel_y < 0.0) params_.max_vel_y *= -1;
00066         if (params_.max_vel_th < 0.0) params_.max_vel_th *= -1;
00067 
00068         // and limit maximal values
00069 
00070   btns_.left = false;
00071   btns_.right = false;
00072   btns_.right_last = false;
00073   btns_.right_trigger = false;
00074 
00075         stop_detected_ = false;
00076         //some_dir_limited_ = false;
00077         x_pref_ = false;
00078         y_pref_ = false;
00079         z_pref_ = false;
00080 
00081         pref_time_ = ros::Time(0);
00082 
00083         bp_.header.frame_id = params_.rviz_cam_link;
00084         bp_.header.stamp = ros::Time(0);
00085         bp_.pose.position.x = 0;
00086         bp_.pose.position.y = 0;
00087         bp_.pose.position.z = 0;
00088         bp_.pose.orientation.x = 0.0;
00089         bp_.pose.orientation.y = 0.0;
00090         bp_.pose.orientation.z = 0.0;
00091         bp_.pose.orientation.w = 1.0;
00092 
00093         sn_data_.last_data = ros::Time(0);
00094         sn_data_.last_nonzero_data = ros::Time(0);
00095 
00096         ros::NodeHandle nh("~");
00097 
00098         offset_sub_ = nh.subscribe("/spacenav/offset",3,&SpaceNavTeleop::spacenavOffsetCallback,this);
00099         rot_offset_sub_ = nh.subscribe("/spacenav/rot_offset",3,&SpaceNavTeleop::spacenavRotOffsetCallback,this);
00100         joy_sub_ = nh.subscribe<sensor_msgs::Joy>("/spacenav/joy",3,&SpaceNavTeleop::joyCallback,this);
00101 
00102         twist_publisher_safe_ = nh.advertise<geometry_msgs::Twist>("/cmd_vel_safe",3);
00103         twist_publisher_unsafe_ = nh.advertise<geometry_msgs::Twist>("/cmd_vel_unsafe",3);
00104 
00105         publishing_to_unsafe_ = false;
00106         robot_centric_mode_ = false;
00107 
00108         // 50 Hz
00109         timer_ = nh.createTimer(ros::Duration(0.02),&SpaceNavTeleop::timerCallback,this);
00110 
00111         service_en_ = nh.advertiseService("enable", &SpaceNavTeleop::Enable,this);
00112         service_dis_ = nh.advertiseService("disable", &SpaceNavTeleop::Disable,this);
00113 
00114         if (params_.instant_stop_enabled) ROS_INFO("Instant stop feature enabled.");
00115         else ROS_INFO("Instant stop feature disabled.");
00116 
00117         if (params_.unsafe_limiter) ROS_INFO("Unsafe limiter activated.");
00118         else ROS_INFO("Unsafe limiter NOT activated.");
00119 
00120         ROS_INFO("Initiated...");
00121 
00122 
00123 }
00124 
00125 SpaceNavTeleop::~SpaceNavTeleop() {
00126 
00127         delete tfl_;
00128 
00129 
00130 }
00131 
00132 void SpaceNavTeleop::joyCallback(const sensor_msgs::Joy::ConstPtr& joy) {
00133 
00134         if ((int)(joy->buttons.size()) != 2) return;
00135 
00136         btns_.mutex.lock();
00137 
00138         btns_.right_last = btns_.right;
00139 
00140         btns_.left = joy->buttons[0];
00141         btns_.right = joy->buttons[1];
00142 
00143         // activate "triger" only if teleop is enabled
00144         if (enabled_ && (!btns_.right_last) && btns_.right) btns_.right_trigger = true;
00145 
00146         btns_.mutex.unlock();
00147 
00148 }
00149 
00150 bool SpaceNavTeleop::Enable(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) {
00151 
00152         ROS_INFO("Spacenav teleop enabled.");
00153         enabled_ = true;
00154         return true;
00155 
00156 }
00157 
00158 bool SpaceNavTeleop::Disable(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) {
00159 
00160         ROS_INFO("Spacenav teleop disabled.");
00161         enabled_ = false;
00162         return true;
00163 
00164 }
00165 
00166 void SpaceNavTeleop::normAngle(double& a) {
00167 
00168         if (a > 2*M_PI) {
00169 
00170                 a -= 2*M_PI;
00171                 return;
00172 
00173         }
00174 
00175         if (a < 0) {
00176 
00177                 a = 2*M_PI + a;
00178 
00179         }
00180 
00181         return;
00182 
00183 }
00184 
00185 // Return the rotation in Euler angles
00186 geometry_msgs::Vector3 SpaceNavTeleop::GetAsEuler(geometry_msgs::Quaternion quat)
00187 {
00188   geometry_msgs::Vector3 vec;
00189 
00190   btQuaternion q;
00191 
00192   btScalar roll, pitch, yaw;
00193 
00194   tf::quaternionMsgToTF(quat, q);
00195   btMatrix3x3(q).getRPY(roll,pitch,yaw);
00196 
00197   vec.x = (double)roll;
00198   vec.y = (double)pitch;
00199   vec.z = (double)yaw;
00200 
00201   normAngle(vec.x);
00202   normAngle(vec.y);
00203   normAngle(vec.z);
00204 
00205   return vec;
00206 
00207 }
00208 
00209 
00210 void SpaceNavTeleop::timerCallback(const ros::TimerEvent& ev) {
00211 
00212         ROS_INFO_ONCE("Timer triggered.");
00213 
00214         if (sn_data_.offset_received && sn_data_.rot_offset_received) ROS_INFO_ONCE("COB SpaceNav Teleop is running.");
00215         else return;
00216 
00217         if ( params_.use_rviz_cam && (!tfl_->frameExists(params_.rviz_cam_link)) ) {
00218 
00219                 ROS_ERROR_ONCE("We are going to use RVIZ camera position but it's TF frame (%s) doesn't exist! This message will apper only once.",params_.rviz_cam_link.c_str());
00220                 return;
00221 
00222         }
00223 
00224         if (!enabled_) return;
00225 
00226         if (twist_publisher_safe_.getNumSubscribers() == 0) {
00227 
00228                 ROS_WARN_ONCE("We have no subscriber on main (safe) topic.");
00229 
00230                 return;
00231 
00232         } else {
00233 
00234                 ROS_INFO_ONCE("Someone is subscribed. Starting publishing...");
00235 
00236         }
00237 
00238         geometry_msgs::Twist tw;
00239 
00240         tw.linear.x = 0.0;
00241         tw.linear.y = 0.0;
00242         tw.linear.z = 0.0;
00243 
00244         tw.angular.x = 0.0;
00245         tw.angular.y = 0.0;
00246         tw.angular.z = 0.0;
00247 
00248         geometry_msgs::Vector3 offset;
00249         geometry_msgs::Vector3 rot_offset;
00250 
00251         ros::Time last_data;
00252 
00253         sn_data_.mutex.lock();
00254 
00255         offset = sn_data_.offset;
00256         rot_offset = sn_data_.rot_offset;
00257         last_data = sn_data_.last_data;
00258 
00259         sn_data_.mutex.unlock();
00260 
00261         // instant STOP
00262         if ( ((ros::Time::now() - last_data) > ros::Duration(0.5)) && (last_data != ros::Time(0)) ) {
00263 
00264                 // spacenav node probably crashed ?
00265                 ROS_WARN("Old data");
00266                 twist_publisher_safe_.publish(tw);
00267 
00268                 return;
00269 
00270         }
00271 
00272 
00273         if (!stop_detected_) {
00274 
00275                 if ( (offset.z < -0.85) && params_.instant_stop_enabled) {
00276 
00277                         stop_detected_ = true;
00278                         ROS_WARN("Instant stop!");
00279                         time_of_stop_ = ros::Time::now();
00280 
00281                         twist_publisher_safe_.publish(tw);
00282                         return;
00283 
00284                 }
00285 
00286 
00287         } else {
00288 
00289                 if ((ros::Time::now() - time_of_stop_) > ros::Duration(5.0)) {
00290 
00291                         stop_detected_ = false;
00292                         ROS_INFO("Releasing instant stop.");
00293 
00294                 } else {
00295 
00296                         twist_publisher_safe_.publish(tw);
00297                         return;
00298 
00299                 }
00300 
00301         }
00302 
00303         if ( (ros::Time::now() - sn_data_.last_nonzero_data ) > ros::Duration(1.0)) {
00304 
00305                 // we have nothing to publish
00306                 return;
00307 
00308         }
00309 
00310         // allow different ways of control
00311         if (fabs(rot_offset.y) > fabs(offset.x)) offset.x = rot_offset.y;
00312         if (fabs(rot_offset.x) > fabs(offset.y)) offset.y = -rot_offset.x;
00313 
00314 
00315         // filter out too small values
00316         if (fabs(offset.x) < params_.sn_min_val_th ) offset.x = 0;
00317         if (fabs(offset.y) < params_.sn_min_val_th ) offset.y = 0;
00318         if (fabs(rot_offset.z) < params_.sn_min_val_th ) rot_offset.z = 0;
00319 
00320         bool unsafe = false;
00321         bool mode_trigger = false;
00322 
00323         btns_.mutex.lock();
00324         unsafe = btns_.left;
00325         mode_trigger = btns_.right_trigger;
00326         btns_.right_trigger = false;
00327 
00328         btns_.mutex.unlock();
00329 
00330         if (!params_.use_rviz_cam) {
00331 
00332                 ROS_INFO_ONCE("Started in mode without using RVIZ camera position.");
00333                 robot_centric_mode_ = true;
00334 
00335         } else {
00336 
00337                 if (robot_centric_mode_) {
00338 
00339                         if (mode_trigger) {
00340 
00341                                 ROS_INFO("Switching back to user centric mode.");
00342                                 robot_centric_mode_ = false;
00343 
00344                         }
00345 
00346                 } else {
00347 
00348                         if (mode_trigger) {
00349 
00350                                 robot_centric_mode_ = true;
00351                                 ROS_INFO("Switching to robot centric mode.");
00352 
00353                         }
00354 
00355                 }
00356 
00357         }
00358 
00359         if (!robot_centric_mode_) {
00360 
00361         // transformation of velocities vector is not needed for turning in place
00362         //if (!rot) {
00363 
00364                 ROS_INFO_ONCE("Started in mode with using RVIZ camera position.");
00365 
00366                 // this is necessary only if we don't want to rotate
00367 
00368                 geometry_msgs::PoseStamped bp = bp_;
00369 
00370                 if (!transf(params_.robot_base_link,bp)) return;
00371 
00372                 geometry_msgs::Vector3 rpy = GetAsEuler(bp.pose.orientation);
00373 
00374                 // this is angle between robot base_link and RVIZ camera
00375                 ROS_DEBUG("YAW: %f",(rpy.z/(2*M_PI))*360);
00376 
00377                 Eigen::Vector3f vec((float)offset.x,(float)offset.y,(float)offset.z);
00378 
00379                 Eigen::AngleAxisf tr((float)rpy.z, Eigen::Vector3f::UnitZ());
00380 
00381                 // we are rotating velocities vector around Z axis
00382                 vec = tr * vec;
00383 
00384                 offset.x = (double)vec(0);
00385                 offset.y = (double)vec(1);
00386                 offset.z = (double)vec(2);
00387 
00388         }
00389 
00390 
00391         // will we prefer some direction?
00392         if ( (fabs(offset.x) > params_.ignore_th_high) && (fabs(offset.y) < params_.ignore_th_low) && (fabs(rot_offset.z) < params_.ignore_th_low)) {
00393 
00394                 if (!x_pref_) {
00395 
00396                         x_pref_ = true;
00397                         y_pref_ = false;
00398                         z_pref_ = false;
00399                         pref_time_ = ros::Time::now();
00400                         ROS_INFO("Preferring x dir");
00401 
00402                 }
00403 
00404         } else
00405 
00406         if ( (fabs(offset.y) > params_.ignore_th_high) && (fabs(offset.x) < params_.ignore_th_low) && (fabs(rot_offset.z) < params_.ignore_th_low) ) {
00407 
00408                 if (!y_pref_) {
00409 
00410                         x_pref_ = false;
00411                         y_pref_ = true;
00412                         z_pref_ = false;
00413                         pref_time_ = ros::Time::now();
00414                         ROS_INFO("Preferring y dir");
00415 
00416                 }
00417 
00418         } else
00419 
00420         if ( (fabs(offset.z) > params_.ignore_th_high) && (fabs(offset.x) < params_.ignore_th_low) && (fabs(rot_offset.y) < params_.ignore_th_low) ) {
00421 
00422                 if (!z_pref_) {
00423 
00424                         x_pref_ = false;
00425                         y_pref_ = false;
00426                         z_pref_ = true;
00427                         pref_time_ = ros::Time::now();
00428                         ROS_INFO("Preferring z rot");
00429 
00430                 }
00431 
00432         } else {
00433 
00434 
00435                 if (x_pref_ || y_pref_ || z_pref_) {
00436 
00437                         if ( (ros::Time::now() - pref_time_) > ros::Duration(0.5) ) {
00438 
00439                                 x_pref_ = false;
00440                                 y_pref_ = false;
00441                                 z_pref_ = false;
00442 
00443                                 ROS_INFO("No dir preferred.");
00444 
00445                         }
00446 
00447                 }
00448 
00449         }
00450 
00451         if (x_pref_) {
00452 
00453                 offset.y = 0.0;
00454                 rot_offset.z = 0.0;
00455 
00456         }
00457 
00458 
00459         if (y_pref_) {
00460 
00461                 offset.x = 0.0;
00462                 rot_offset.z = 0.0;
00463 
00464         }
00465 
00466         if (z_pref_) {
00467 
00468                 offset.x = 0.0;
00469                 rot_offset.y = 0.0;
00470 
00471         }
00472 
00473 
00474         // scale to velocities for COB
00475         offset.x *= params_.max_vel_x;
00476         offset.y *= params_.max_vel_y;
00477 
00478         rot_offset.z *= params_.max_vel_th;
00479 
00480 
00481         tw.linear = offset;
00482         tw.angular = rot_offset;
00483 
00484 
00485         if (unsafe) {
00486 
00487                 if (!publishing_to_unsafe_) {
00488 
00489                         publishing_to_unsafe_ = true;
00490                         ROS_WARN("Publishing to unsafe topic!");
00491 
00492                 }
00493 
00494                 if (params_.unsafe_limiter) {
00495 
00496                         tw.angular.z = 0.0;
00497                         tw.linear.x = 0.0;
00498                         tw.linear.y /= 3.0;
00499 
00500                 }
00501 
00502                 twist_publisher_unsafe_.publish(tw);
00503 
00504         } else {
00505 
00506                 if (publishing_to_unsafe_) {
00507 
00508                         ROS_INFO("Publishing to safe topic again.");
00509                         publishing_to_unsafe_ = false;
00510 
00511                 }
00512 
00513                 twist_publisher_safe_.publish(tw);
00514 
00515         }
00516 
00517 
00518         return;
00519 
00520 }
00521 
00522 bool SpaceNavTeleop::transf(std::string target_frame,geometry_msgs::PoseStamped& pose) {
00523 
00524         // transform pose of camera into world
00525         try {
00526 
00527                         if (tfl_->waitForTransform(target_frame, pose.header.frame_id, pose.header.stamp, ros::Duration(2.0))) {
00528 
00529                           tfl_->transformPose(target_frame,pose,pose);
00530 
00531                         } else {
00532 
00533                           ROS_ERROR("Could not get TF transf. from %s into %s.",pose.header.frame_id.c_str(),target_frame.c_str());
00534                           return false;
00535 
00536                         }
00537 
00538         } catch(tf::TransformException& ex){
00539            std::cerr << "Transform error: " << ex.what() << std::endl;
00540 
00541            return false;
00542         }
00543 
00544         return true;
00545 
00546 }
00547 
00548 void SpaceNavTeleop::spacenavOffsetCallback(const geometry_msgs::Vector3ConstPtr& offset) {
00549 
00550         sn_data_.mutex.lock();
00551 
00552         sn_data_.offset = *offset;
00553 
00554         // limit max. value
00555         if (sn_data_.offset.x > params_.sn_max_val) sn_data_.offset.x = params_.sn_max_val;
00556         if (sn_data_.offset.x < -params_.sn_max_val) sn_data_.offset.x = -params_.sn_max_val;
00557 
00558         if (sn_data_.offset.y > params_.sn_max_val) sn_data_.offset.y = params_.sn_max_val;
00559         if (sn_data_.offset.y < -params_.sn_max_val) sn_data_.offset.y = -params_.sn_max_val;
00560 
00561         if (sn_data_.offset.z > params_.sn_max_val) sn_data_.offset.z = params_.sn_max_val;
00562         if (sn_data_.offset.z < -params_.sn_max_val) sn_data_.offset.z = -params_.sn_max_val;
00563 
00564 
00565         // normalize
00566         sn_data_.offset.x /= params_.sn_max_val;
00567         sn_data_.offset.y /= params_.sn_max_val;
00568         sn_data_.offset.z /= params_.sn_max_val;
00569 
00570         sn_data_.last_data = ros::Time::now();
00571 
00572         if (sn_data_.offset.x != 0.0 || sn_data_.offset.y != 0.0) sn_data_.last_nonzero_data = ros::Time::now();
00573 
00574         sn_data_.mutex.unlock();
00575 
00576         if (!sn_data_.offset_received) {
00577 
00578                 sn_data_.offset_received = true;
00579                 ROS_INFO("Offset received.");
00580 
00581         }
00582 
00583 }
00584 
00585 
00586 void SpaceNavTeleop::spacenavRotOffsetCallback(const geometry_msgs::Vector3ConstPtr& rot_offset) {
00587 
00588         sn_data_.mutex.lock();
00589 
00590         sn_data_.rot_offset = *rot_offset;
00591 
00592         if (sn_data_.rot_offset.x > params_.sn_max_val) sn_data_.rot_offset.x = params_.sn_max_val;
00593         if (sn_data_.rot_offset.x < -params_.sn_max_val) sn_data_.rot_offset.x = -params_.sn_max_val;
00594 
00595 
00596         if (sn_data_.rot_offset.y > params_.sn_max_val) sn_data_.rot_offset.y = params_.sn_max_val;
00597         if (sn_data_.rot_offset.y < -params_.sn_max_val) sn_data_.rot_offset.y = -params_.sn_max_val;
00598 
00599         if (sn_data_.rot_offset.z > params_.sn_max_val) sn_data_.rot_offset.z = params_.sn_max_val;
00600         if (sn_data_.rot_offset.z < -params_.sn_max_val) sn_data_.rot_offset.z = -params_.sn_max_val;
00601 
00602         sn_data_.rot_offset.x /= params_.sn_max_val;
00603         sn_data_.rot_offset.y /= params_.sn_max_val;
00604         sn_data_.rot_offset.z /= params_.sn_max_val;
00605 
00606         if (sn_data_.rot_offset.z != 0.0) sn_data_.last_nonzero_data = ros::Time::now();
00607 
00608         sn_data_.mutex.unlock();
00609 
00610         if (!sn_data_.rot_offset_received) {
00611 
00612                 sn_data_.rot_offset_received = true;
00613                 ROS_INFO("Rot. offset received.");
00614 
00615         }
00616 
00617 }
00618 
00619 
00620 int main(int argc, char** argv)
00621 {
00622   ros::init(argc, argv, "cob_spacenav_teleop");
00623 
00624   ROS_INFO("Starting COB SpaceNav Teleop...");
00625   SpaceNavTeleop sp;
00626 
00627   /*ros::AsyncSpinner spinner(3);
00628   spinner.start();
00629   ros::waitForShutdown();*/
00630 
00631   ros::spin();
00632 
00633 }


cob_spacenav_teleop
Author(s): Zdenek Materna
autogenerated on Sun Jan 5 2014 11:56:24