Joystick.cpp
Go to the documentation of this file.
00001 /*
00002  * Joystick.cpp
00003  *
00004  *  Created on: Oct 25, 2011
00005  *      Author: mriedel
00006  */
00007 
00008 #include <telekyb_joystick/Joystick.hpp>
00009 
00010 #include <linux/joystick.h>
00011 #include <sensor_msgs/Joy.h>
00012 #include <telekyb_base/ROS.hpp>
00013 
00014 #include <geometry_msgs/Vector3Stamped.h>
00015 
00016 // boost
00017 #include <boost/algorithm/string.hpp>
00018 #include <boost/lexical_cast.hpp>
00019 
00020 // plausibility checks
00021 #define MAX_NUMBER_AXES 20
00022 #define MAX_NUMBER_BUTTONS 50
00023 
00024 namespace TELEKYB_NAMESPACE {
00025 
00026 
00027 Joystick::Joystick()
00028         : BaseJoystick("", false)
00029 {
00030 
00031 }
00032 
00033 Joystick::Joystick(const std::string& devPath_, bool autoOpen_)
00034         : BaseJoystick(devPath_, autoOpen_)
00035 {
00036 
00037         options = JoystickOptions::InstancePtr();
00038         nodeHandle = ROSModule::Instance().getNodeNameNodeHandle();
00039         pubJoy = nodeHandle.advertise<sensor_msgs::Joy>(options->tPubName->getValue(), 1 );
00040         if (options->tPublishVector3->getValue()) {
00041                 pubVector3 = nodeHandle.advertise<geometry_msgs::Vector3Stamped>(options->tPubName->getValue() + "_vector3", 1 );
00042         }
00043 
00044 }
00045 
00046 Joystick::~Joystick()
00047 {
00048 
00049 }
00050 
00051 void Joystick::run()
00052 {
00053         if (!isOpen()) {
00054                 ROS_ERROR("Joystick %s not open. Cannot enter runloop. ", devPath.c_str());
00055                 return;
00056         }
00057 
00058         // remapping
00059         std::vector<int> buttonRemapping = options->tButtonRemapping->getValue();
00060         // check validity
00061         for (unsigned int i = 0; i < buttonRemapping.size(); ++i) {
00062                 if (buttonRemapping[i] < 0 || buttonRemapping[i] > MAX_NUMBER_BUTTONS ) {
00063                         ROS_ERROR("Wrong button mapping for button %d, value must be between 0 and %d "
00064                                         ,i, MAX_NUMBER_BUTTONS);
00065                         ROS_ERROR("Setting identity for button %d", i);
00066                         buttonRemapping[i] = i;
00067                 }
00068         }
00069         std::vector<int> axisRemapping = options->tAxesRemapping->getValue();
00070         // check validity
00071         for (unsigned int i = 0; i < axisRemapping.size(); ++i) {
00072                 if (axisRemapping[i] < 0 || axisRemapping[i] > MAX_NUMBER_AXES ) {
00073                         ROS_ERROR("Wrong axes mapping for axis %d, value must be between 0 and %d "
00074                                         ,i, MAX_NUMBER_AXES);
00075                         ROS_ERROR("Setting identity for axis %d", i);
00076                         axisRemapping[i] = i;
00077                 }
00078         }
00079         std::vector<double> axisMultiplier = options->tAxisMultiplier->getValue();
00080 
00081         double autorepeat_rate = options->tAutoRepeatRate->getValue();
00082         double autorepeat_interval = 1.0 / autorepeat_rate;
00083         double coalesce_interval = options->tCoalesceInterval->getValue();
00084         double scale = -1. / (1. - options->tDeadZone->getValue()) / 32767.;
00085         double unscaled_deadzone = 32767. * options->tDeadZone->getValue();
00086 
00087 
00088         js_event event;
00089         struct timeval tv;
00090         tv.tv_sec = 1;
00091         tv.tv_usec = 0;
00092         bool publish_now = false;
00093         bool publish_soon = false;
00094         bool tv_set = false;
00095         bool publication_pending = false;
00096 
00097         fd_set set;
00098         sensor_msgs::Joy joyMsg;
00099 
00100         while (ros::ok()) {
00101 
00102                 publish_now = false;
00103                 publish_soon = false;
00104 
00105                 FD_ZERO(&set);
00106                 FD_SET(joystick_fd, &set);
00107 
00108                 int select_out = select(joystick_fd + 1, &set, NULL, NULL, &tv);
00109                 if (select_out == -1) {
00110                         tv.tv_sec = 0;
00111                         tv.tv_usec = 0;
00112                         //ROS_INFO("Select returned negative. %i", ros::isShuttingDown());
00113                         continue;
00114                         //                              break; // Joystick is probably closed. Not sure if this case is useful.
00115                 }
00116 
00117                 if (FD_ISSET(joystick_fd, &set)) {
00118                         if (read(joystick_fd, &event, sizeof(js_event)) == -1 && errno != EAGAIN)
00119                                 break; // Joystick is probably closed. Definitely occurs.
00120 
00121                         //ROS_INFO("Read data...");
00122                         joyMsg.header.stamp = ros::Time().now();
00123                         switch (event.type) {
00124                         case JS_EVENT_BUTTON:
00125                         case JS_EVENT_BUTTON | JS_EVENT_INIT:
00126                                 // remapping?
00127                                 if (event.number >= buttonRemapping.size()) {
00128                                         // fill
00129                                         int old_size = buttonRemapping.size();
00130                                         buttonRemapping.resize(event.number + 1);
00131                                         for (unsigned int i = old_size; i < buttonRemapping.size(); i++) {
00132                                                 // add identity.
00133                                                 buttonRemapping[i] = i;
00134                                         }
00135                                 }
00136 
00137                                 if (buttonRemapping[event.number] >= joyMsg.buttons.size()) {
00138                                         int old_size = joyMsg.buttons.size();
00139                                         joyMsg.buttons.resize(buttonRemapping[event.number] + 1);
00140                                         for (unsigned int i = old_size; i < joyMsg.buttons.size(); i++) {
00141                                                 joyMsg.buttons[i] = 0.0;
00142                                         }
00143                                 }
00144 
00145                                 // remapping
00146                                 joyMsg.buttons[buttonRemapping[event.number]] = (event.value ? 1 : 0);
00147 
00148 
00149 
00150 
00151                                 // For initial events, wait a bit before sending to try to catch
00152                                 // all the initial events.
00153                                 if (!(event.type & JS_EVENT_INIT))
00154                                         publish_now = true;
00155                                 else
00156                                         publish_soon = true;
00157                                 break;
00158                         case JS_EVENT_AXIS:
00159                         case JS_EVENT_AXIS | JS_EVENT_INIT:
00160                                 // size extension?
00161                                 if (event.number >= axisRemapping.size()) {
00162                                         // fill
00163                                         int old_size = axisRemapping.size();
00164                                         axisRemapping.resize(event.number + 1);
00165                                         for (unsigned int i = old_size; i < axisRemapping.size(); i++) {
00166                                                 // add identity.
00167                                                 axisRemapping[i] = i;
00168                                         }
00169                                 }
00170                                 // multiplier extension?
00171                                 if (axisRemapping[event.number] >= axisMultiplier.size()) {
00172                                         int old_size = axisMultiplier.size();
00173                                         axisMultiplier.resize(axisRemapping[event.number] + 1);
00174                                         for (unsigned int i = old_size; i < axisMultiplier.size(); i++)
00175                                                 axisMultiplier[i] = 1.0;
00176                                 }
00177 
00178                                 if (axisRemapping[event.number] >= joyMsg.axes.size()) {
00179                                         int old_size = joyMsg.axes.size();
00180                                         joyMsg.axes.resize(axisRemapping[event.number] + 1);
00181                                         for (unsigned int i = old_size; i < joyMsg.axes.size(); i++)
00182                                                 joyMsg.axes[i] = 0.0;
00183                                 }
00184                                 if (!(event.type & JS_EVENT_INIT)) // Init event.value is wrong.
00185                                 {
00186                                         double val = event.value;
00187                                         // Allows deadzone to be "smooth"
00188                                         if (val > unscaled_deadzone)
00189                                                 val -= unscaled_deadzone;
00190                                         else if (val < -unscaled_deadzone)
00191                                                 val += unscaled_deadzone;
00192                                         else
00193                                                 val = 0;
00194                                         joyMsg.axes[axisRemapping[event.number]] = val * scale * axisMultiplier[axisRemapping[event.number]];
00195                                 }
00196                                 // Will wait a bit before sending to try to combine events.
00197                                 publish_soon = true;
00198                                 break;
00199                         default:
00200                                 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);
00201                                 break;
00202                         }
00203                 } else if (tv_set) // Assume that the timer has expired.
00204                         publish_now = true;
00205 
00206                 if (publish_now) {
00207                         // Assume that all the JS_EVENT_INIT messages have arrived already.
00208                         // This should be the case as the kernel sends them along as soon as
00209                         // the device opens.
00210                         //ROS_INFO("Publish...");
00211                         if (options->tPublishVector3->getValue() && joyMsg.axes.size() >= 3) {
00212                                 geometry_msgs::Vector3Stamped vec3Msg;
00213                                 vec3Msg.header.stamp = ros::Time::now();
00214                                 vec3Msg.vector.x = joyMsg.axes[0];
00215                                 vec3Msg.vector.y = joyMsg.axes[1];
00216                                 vec3Msg.vector.z = joyMsg.axes[2];
00217                                 pubVector3.publish(vec3Msg);
00218                         }
00219 
00220                         pubJoy.publish(joyMsg);
00221                         publish_now = false;
00222                         tv_set = false;
00223                         publication_pending = false;
00224                         publish_soon = false;
00225                 }
00226 
00227                 // If an axis event occurred, start a timer to combine with other
00228                 // events.
00229                 if (!publication_pending && publish_soon) {
00230                         tv.tv_sec = trunc(coalesce_interval);
00231                         tv.tv_usec = (coalesce_interval - tv.tv_sec) * 1e6;
00232                         publication_pending = true;
00233                         tv_set = true;
00234                         //ROS_INFO("Pub pending...");
00235                 }
00236 
00237                 // If nothing is going on, start a timer to do autorepeat.
00238                 if (!tv_set && autorepeat_rate > 0) {
00239                         tv.tv_sec = trunc(autorepeat_interval);
00240                         tv.tv_usec = (autorepeat_interval - tv.tv_sec) * 1e6;
00241                         tv_set = true;
00242                         //ROS_INFO("Autorepeat pending... %i %i", tv.tv_sec, tv.tv_usec);
00243                 }
00244 
00245                 if (!tv_set) {
00246                         tv.tv_sec = 1;
00247                         tv.tv_usec = 0;
00248                 }
00249 
00250                 //diagnostic_.update();
00251         } // End of joystick open loop.
00252 }
00253 
00254 
00255 
00256 //std::vector<Joystick> Joystick::getJoysticks(const std::string& paths)
00257 //{
00258 //      std::vector<std::string> indiviualPaths;
00259 //      boost::split(indiviualPaths, paths, boost::is_any_of(" \t"));
00260 //
00261 //      std::vector<Joystick> res;
00262 //      res.resize(indiviualPaths.size());
00263 //      for (unsigned int i = 0; i < indiviualPaths.size(); ++i) {
00264 //              // create Joystick
00265 //              res[i] = Joystick(indiviualPaths[i]);
00266 //      }
00267 //
00268 //      return res;
00269 //}
00270 
00271 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Defines


telekyb_joystick
Author(s): Martin Riedel
autogenerated on Mon Nov 11 2013 11:14:39