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
00029
00030
00031
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_;
00052 double coalesce_interval_;
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
00078
00079
00080
00081
00082
00083
00084
00085 public:
00086 Joystick() : nh_() {}
00087
00089 int main(int argc, char **argv)
00090 {
00091
00092
00093
00094
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
00109 velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>("/joy_cmd_vel", 100, false);
00110
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
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
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
00171 while (nh_.ok())
00172 {
00173 open_ = false;
00174
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
00185
00186
00187
00188
00189
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
00202 }
00203
00204 ROS_INFO("Opened joystick: %s. deadzone_: %f.", joy_dev_.c_str(), deadzone_);
00205 open_ = true;
00206
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;
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
00223 int select_out = select(joy_fd+1, &set, NULL, NULL, &tv);
00224
00225 if (select_out == -1)
00226 {
00227 tv.tv_sec = 0;
00228 tv.tv_usec = 0;
00229
00230 continue;
00231
00232 }
00233
00234 if (FD_ISSET(joy_fd, &set))
00235 {
00236 if (read(joy_fd, &event, sizeof(js_event)) == -1 && errno != EAGAIN)
00237 break;
00238
00239
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
00255
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))
00271 {
00272 double val = event.value;
00273
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
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)
00291 publish_now = true;
00292
00293 if (publish_now)
00294 {
00295
00296
00297
00298
00299
00300
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
00310
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
00318 }
00319
00320
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
00327 }
00328
00329 if (!tv_set)
00330 {
00331 tv.tv_sec = 1;
00332 tv.tv_usec = 0;
00333 }
00334
00335
00336 }
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 }