Joystick.cpp
Go to the documentation of this file.
00001 /*
00002  * teleop_pr2
00003  * Copyright (c) 2009, Willow Garage, Inc.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the <ORGANIZATION> nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 //\author: Blaise Gassend
00032 
00033 #include <unistd.h>
00034 #include <math.h>
00035 #include <linux/joystick.h>
00036 #include <fcntl.h>
00037 #include <ros/ros.h>
00038 #include <sensor_msgs/Joy.h>
00039 #include <geometry_msgs/Twist.h>
00040 #include <boost/thread.hpp>
00041 
00042 
00044 class Joystick
00045 {
00046 private:
00047   ros::NodeHandle nh_;
00048   bool open_;
00049   std::string joy_dev_;
00050   double deadzone_;
00051   double autorepeat_rate_;  // in Hz.  0 for no repeat.
00052   double coalesce_interval_; // Defaults to 100 Hz rate limit.
00053   int event_count_;
00054   int pub_count_;
00055   double lastDiagTime_;
00056 
00057   double a_scale_;
00058   double l_scale_;
00059   ros::Publisher velocity_publisher_;
00060   ros::Timer velocity_publish_timer_;
00061   sensor_msgs::Joy current_joy_message_;
00062 
00063   void publish_velocity() {
00064     ROS_INFO("Publishing...");
00065 
00066     while (ros::ok()) {
00067       geometry_msgs::Twist vel;
00068       vel.angular.z = a_scale_ * current_joy_message_.axes[3];
00069       vel.linear.x = l_scale_ * current_joy_message_.axes[4];
00070       velocity_publisher_.publish(vel);
00071 
00072       boost::this_thread::sleep(boost::posix_time::milliseconds(1000.0 / 30.0));
00073     }
00074 
00075   }
00076 
00077   // void publish_velocity(const ros::TimerEvent& event) {
00078   //   ROS_INFO("Publishing...");
00079          //  geometry_msgs::Twist vel;
00080          //  vel.angular.z = a_scale_ * current_joy_message_.axes[3];
00081          //  vel.linear.x = l_scale_ * current_joy_message_.axes[4];
00082          //  velocity_publisher_.publish(vel);
00083   // }
00084 
00085 public:
00086   Joystick() : nh_() {}
00087 
00089   int main(int argc, char **argv)
00090   {
00091 //    diagnostic_.add("Joystick Driver Status", this, &Joystick::diagnostics);
00092 //    diagnostic_.setHardwareID("none");
00093 
00094     // Parameters
00095     ros::NodeHandle nh_param("~");
00096 
00097     current_joy_message_.axes.push_back(0);
00098     current_joy_message_.axes.push_back(0);
00099     current_joy_message_.axes.push_back(0);
00100     current_joy_message_.axes.push_back(0);
00101     current_joy_message_.axes.push_back(0);
00102 
00103     std::string pub_topic;
00104     nh_param.param<std::string>("topic", pub_topic, "joy");
00105 
00106     ROS_INFO("Starting joystick publisher...");
00107 
00108     // pub_ = nh_.advertise<sensor_msgs::Joy>(pub_topic, 1);
00109     velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>("/joy_cmd_vel", 100, false);
00110     // velocity_publish_timer_ = nh_.createTimer(ros::Duration(0.1), boost::bind(&Joystick::publish_velocity, this, _1));
00111 
00112     nh_param.param<std::string>("dev", joy_dev_, "/dev/input/js0");
00113     nh_param.param<double>("deadzone", deadzone_, 0.05);
00114     nh_param.param<double>("autorepeat_rate", autorepeat_rate_, 0);
00115     nh_param.param<double>("coalesce_interval", coalesce_interval_, 0.001);
00116 
00117     nh_param.param("scale_angular", a_scale_, 0.9);
00118     nh_param.param("scale_linear" , l_scale_, 2.0);
00119 
00120     // Checks on parameters
00121     if (autorepeat_rate_ > 1 / coalesce_interval_)
00122       ROS_WARN("joy_node: autorepeat_rate (%f Hz) > 1/coalesce_interval (%f Hz) does not make sense. Timing behavior is not well defined.", autorepeat_rate_, 1/coalesce_interval_);
00123 
00124     if (deadzone_ >= 1)
00125     {
00126       ROS_WARN("joy_node: deadzone greater than 1 was requested. The semantics of deadzone have changed. It is now related to the range [-1:1] instead of [-32767:32767]. For now I am dividing your deadzone by 32767, but this behavior is deprecated so you need to update your launch file.");
00127       deadzone_ /= 32767;
00128     }
00129 
00130     if (deadzone_ > 0.9)
00131     {
00132       ROS_WARN("joy_node: deadzone (%f) greater than 0.9, setting it to 0.9", deadzone_);
00133       deadzone_ = 0.9;
00134     }
00135 
00136     if (deadzone_ < 0)
00137     {
00138       ROS_WARN("joy_node: deadzone_ (%f) less than 0, setting to 0.", deadzone_);
00139       deadzone_ = 0;
00140     }
00141 
00142     if (autorepeat_rate_ < 0)
00143     {
00144       ROS_WARN("joy_node: autorepeat_rate (%f) less than 0, setting to 0.", autorepeat_rate_);
00145       autorepeat_rate_ = 0;
00146     }
00147 
00148     if (coalesce_interval_ < 0)
00149     {
00150       ROS_WARN("joy_node: coalesce_interval (%f) less than 0, setting to 0.", coalesce_interval_);
00151       coalesce_interval_ = 0;
00152     }
00153 
00154     // Parameter conversions
00155     double autorepeat_interval = 1 / autorepeat_rate_;
00156     double scale = -1. / (1. - deadzone_) / 32767.;
00157     double unscaled_deadzone = 32767. * deadzone_;
00158 
00159     js_event event;
00160     struct timeval tv;
00161     fd_set set;
00162     int joy_fd;
00163     event_count_ = 0;
00164     pub_count_ = 0;
00165     lastDiagTime_ = ros::Time::now().toSec();
00166 
00167 
00168     boost::thread th(boost::bind(&Joystick::publish_velocity, this));
00169 
00170     // Big while loop opens, publishes
00171     while (nh_.ok())
00172     {
00173       open_ = false;
00174 //      diagnostic_.force_update();
00175       bool first_fault = true;
00176       while (true)
00177       {
00178         ros::spinOnce();
00179         if (!nh_.ok())
00180           goto cleanup;
00181         joy_fd = open(joy_dev_.c_str(), O_RDONLY);
00182         if (joy_fd != -1)
00183         {
00184           // There seems to be a bug in the driver or something where the
00185           // initial events that are to define the initial state of the
00186           // joystick are not the values of the joystick when it was opened
00187           // but rather the values of the joystick when it was last closed.
00188           // Opening then closing and opening again is a hack to get more
00189           // accurate initial state data.
00190           close(joy_fd);
00191           joy_fd = open(joy_dev_.c_str(), O_RDONLY);
00192         }
00193         if (joy_fd != -1)
00194           break;
00195         if (first_fault)
00196         {
00197           ROS_ERROR("Couldn't open joystick %s. Will retry every second.", joy_dev_.c_str());
00198           first_fault = false;
00199         }
00200         sleep(1.0);
00201 //        diagnostic_.update();
00202       }
00203 
00204       ROS_INFO("Opened joystick: %s. deadzone_: %f.", joy_dev_.c_str(), deadzone_);
00205       open_ = true;
00206 //      diagnostic_.force_update();
00207 
00208       bool tv_set = false;
00209       bool publication_pending = false;
00210       tv.tv_sec = 1;
00211       tv.tv_usec = 0;
00212       sensor_msgs::Joy joy_msg; // Here because we want to reset it on device close.
00213       while (nh_.ok())
00214       {
00215         ros::spinOnce();
00216 
00217         bool publish_now = false;
00218         bool publish_soon = false;
00219         FD_ZERO(&set);
00220         FD_SET(joy_fd, &set);
00221 
00222         //ROS_INFO("Select...");
00223         int select_out = select(joy_fd+1, &set, NULL, NULL, &tv);
00224         //ROS_INFO("Tick...");
00225         if (select_out == -1)
00226         {
00227           tv.tv_sec = 0;
00228           tv.tv_usec = 0;
00229           //ROS_INFO("Select returned negative. %i", ros::isShuttingDown());
00230           continue;
00231           //                            break; // Joystick is probably closed. Not sure if this case is useful.
00232         }
00233 
00234         if (FD_ISSET(joy_fd, &set))
00235         {
00236           if (read(joy_fd, &event, sizeof(js_event)) == -1 && errno != EAGAIN)
00237             break; // Joystick is probably closed. Definitely occurs.
00238 
00239           //ROS_INFO("Read data...");
00240           joy_msg.header.stamp = ros::Time().now();
00241           event_count_++;
00242           switch(event.type)
00243           {
00244           case JS_EVENT_BUTTON:
00245           case JS_EVENT_BUTTON | JS_EVENT_INIT:
00246             if(event.number >= joy_msg.buttons.size())
00247             {
00248               int old_size = joy_msg.buttons.size();
00249               joy_msg.buttons.resize(event.number+1);
00250               for(unsigned int i=old_size;i<joy_msg.buttons.size();i++)
00251                 joy_msg.buttons[i] = 0.0;
00252             }
00253             joy_msg.buttons[event.number] = (event.value ? 1 : 0);
00254             // For initial events, wait a bit before sending to try to catch
00255             // all the initial events.
00256             if (!(event.type & JS_EVENT_INIT))
00257               publish_now = true;
00258             else
00259               publish_soon = true;
00260             break;
00261           case JS_EVENT_AXIS:
00262           case JS_EVENT_AXIS | JS_EVENT_INIT:
00263             if(event.number >= joy_msg.axes.size())
00264             {
00265               int old_size = joy_msg.axes.size();
00266               joy_msg.axes.resize(event.number+1);
00267               for(unsigned int i=old_size;i<joy_msg.axes.size();i++)
00268                 joy_msg.axes[i] = 0.0;
00269             }
00270             if (!(event.type & JS_EVENT_INIT)) // Init event.value is wrong.
00271             {
00272               double val = event.value;
00273               // Allows deadzone to be "smooth"
00274               if (val > unscaled_deadzone)
00275                 val -= unscaled_deadzone;
00276               else if (val < -unscaled_deadzone)
00277                 val += unscaled_deadzone;
00278               else
00279                 val = 0;
00280               joy_msg.axes[event.number] = val * scale;
00281             }
00282             // Will wait a bit before sending to try to combine events.
00283             publish_soon = true;
00284             break;
00285           default:
00286             ROS_WARN("joy_node: Unknown event type. Please file a ticket. time=%u, value=%d, type=%Xh, number=%d", event.time, event.value, event.type, event.number);
00287             break;
00288           }
00289         }
00290         else if (tv_set) // Assume that the timer has expired.
00291           publish_now = true;
00292 
00293         if (publish_now)
00294         {
00295           // Assume that all the JS_EVENT_INIT messages have arrived already.
00296           // This should be the case as the kernel sends them along as soon as
00297           // the device opens.
00298           //ROS_INFO("Publish...");
00299 
00300           // pub_.publish(joy_msg);
00301                 current_joy_message_ = joy_msg;
00302           publish_now = false;
00303           tv_set = false;
00304           publication_pending = false;
00305           publish_soon = false;
00306           pub_count_++;
00307         }
00308 
00309         // If an axis event occurred, start a timer to combine with other
00310         // events.
00311         if (!publication_pending && publish_soon)
00312         {
00313           tv.tv_sec = trunc(coalesce_interval_);
00314           tv.tv_usec = (coalesce_interval_ - tv.tv_sec) * 1e6;
00315           publication_pending = true;
00316           tv_set = true;
00317           //ROS_INFO("Pub pending...");
00318         }
00319 
00320         // If nothing is going on, start a timer to do autorepeat.
00321         if (!tv_set && autorepeat_rate_ > 0)
00322         {
00323           tv.tv_sec = trunc(autorepeat_interval);
00324           tv.tv_usec = (autorepeat_interval - tv.tv_sec) * 1e6;
00325           tv_set = true;
00326           //ROS_INFO("Autorepeat pending... %i %i", tv.tv_sec, tv.tv_usec);
00327         }
00328 
00329         if (!tv_set)
00330         {
00331           tv.tv_sec = 1;
00332           tv.tv_usec = 0;
00333         }
00334 
00335 //        diagnostic_.update();
00336       } // End of joystick open loop.
00337 
00338       close(joy_fd);
00339       ros::spinOnce();
00340       if (nh_.ok())
00341         ROS_ERROR("Connection to joystick device lost unexpectedly. Will reopen.");
00342     }
00343 
00344   cleanup:
00345     ROS_INFO("joy_node shut down.");
00346 
00347     return 0;
00348   }
00349 };
00350 
00351 int main(int argc, char **argv)
00352 {
00353   ros::init(argc, argv, "joy_node");
00354   Joystick j;
00355   return j.main(argc, argv);
00356 }


mr_tools
Author(s): Igor Makhtes
autogenerated on Fri Aug 28 2015 11:35:35