00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
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
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
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
00262 if ( ((ros::Time::now() - last_data) > ros::Duration(0.5)) && (last_data != ros::Time(0)) ) {
00263
00264
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
00306 return;
00307
00308 }
00309
00310
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
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
00362
00363
00364 ROS_INFO_ONCE("Started in mode with using RVIZ camera position.");
00365
00366
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
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
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
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
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
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
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
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
00628
00629
00630
00631 ros::spin();
00632
00633 }