ioadr.cc
Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2005, 2007, 2009 Austin Robot Technology
00003  *
00004  *  License: Modified BSD Software License Agreement
00005  * 
00006  *  $Id: ioadr.cc 1876 2011-11-26 23:48:08Z jack.oquin $
00007  */
00008 
00009 #include <ros/ros.h>
00010 
00011 #include <art_msgs/ArtHertz.h>
00012 #include <art/conversions.h>
00013 
00014 #include <art_msgs/Shifter.h>
00015 #include <art_msgs/IOadrCommand.h>
00016 #include <art_msgs/IOadrState.h>
00017 
00018 #include "dev8x.h"                      // IOADR8x device interface
00019 
00059 class IOadr
00060 {
00061 public:
00062 
00063   IOadr();
00064 
00065   void Main();
00066   int Setup(ros::NodeHandle node);
00067   int Shutdown();
00068 
00069   // pointer to any of the poll_* methods
00070   typedef int (IOadr::*poll_method_t)(int ch);
00071 
00072   typedef struct
00073   {
00074     const char *name;                   // parameter name
00075     poll_method_t function;             // function method to call
00076     int devnum;                         // IOadr8x device number
00077     int field;                          // analog voltage field index
00078   } poll_parms_t;
00079 
00080   int poll_Analog_8bit(int ch);
00081   int poll_Analog_10bit(int ch);
00082   int poll_Digital(int ch);
00083   int poll_ShifterInd(int ch);
00084 
00085 private:
00086 
00087   void GetSetRelays(void);
00088   void PollDevice(void);
00089   void processOutput(const art_msgs::IOadrCommand::ConstPtr &cmd);
00090   void processShifter(const art_msgs::Shifter::ConstPtr &shifterIn);
00091 
00092   std::vector<poll_parms_t *> poll_list_; // poll list
00093 
00094   // .cfg variables:
00095   std::string node_name_;               // actual node name assigned
00096   int reset_relays_;                    // initial/final relays setting
00097   std::string port_;                    // IOADR8x tty port name
00098   bool do_shifter_;                     // handle Shifter messages
00099 
00100   // ROS topic interfaces
00101   ros::Subscriber ioadr_cmd_;            // ioadr command
00102   ros::Publisher  ioadr_state_;          // ioadr state
00103   ros::Subscriber shifter_cmd_;          // shifter command
00104   ros::Publisher  shifter_state_;        // shifter state
00105   uint8_t shifter_gear_;                 // current gear number
00106 
00107   // requested relay settings
00108   uint8_t relay_mask_;
00109   uint8_t relay_bits_;
00110 
00111   // current device input state
00112   art_msgs::IOadrState ioMsg_;         // controller state message
00113 
00114   // hardware IOADR8x interface
00115   dev8x *dev_;
00116 };
00117 
00118 static IOadr::poll_parms_t poll_parms_table[] =
00119 {
00120   //   name          method                      devnum  field
00121   {"AnalogA",        &IOadr::poll_Analog_8bit,   3,      0},
00122   {"AnalogA(10bit)", &IOadr::poll_Analog_10bit,  3,      0},
00123   {"AnalogB",        &IOadr::poll_Analog_8bit,   4,      1},
00124   {"AnalogB(10bit)", &IOadr::poll_Analog_10bit,  4,      1},
00125   {"AnalogC",        &IOadr::poll_Analog_8bit,   5,      2},
00126   {"AnalogC(10bit)", &IOadr::poll_Analog_10bit,  5,      2},
00127   {"DigitalB",       &IOadr::poll_Digital,       1,     -1},
00128   {"ShifterInd",     &IOadr::poll_ShifterInd,    1,     -1},
00129   {"",               NULL,                      -1,     -1},
00130   {NULL,             NULL,                      -1,     -1},
00131 };
00132 
00133 IOadr::poll_parms_t *LookupInput(const char *name)
00134 {
00135   int i;
00136   for (i = 0; poll_parms_table[i].name; ++i)
00137     {
00138       if (0 == strcmp(poll_parms_table[i].name, name))
00139         break;
00140     }
00141   return &poll_parms_table[i];
00142 }
00143 
00144 // Relays bit values for gear indices: reset, park, rev, neut, drive.
00145 // NOTE: these are NOT the same as the digital B input values.
00146 static const uint8_t relay_value_[5] = {0x00, 0x02, 0x04, 0x08, 0x10};
00147 
00148 // constructor
00149 IOadr::IOadr()
00150 {
00151   node_name_ = ros::this_node::getName();
00152   ROS_INFO_STREAM("initialize node: " << node_name_);
00153 
00154   // use private node handle to get parameters
00155   ros::NodeHandle mynh("~");
00156 
00157   mynh.param("reset_relays", reset_relays_, 0);
00158   if (reset_relays_ >= 0)
00159     ROS_INFO("reset relays to 0x%02x", reset_relays_);
00160 
00161   mynh.param("shifter", do_shifter_, false);
00162   if (do_shifter_)
00163     {
00164       ROS_INFO("providing shifter interface");
00165       shifter_gear_ = art_msgs::Shifter::Park;
00166       port_ = "/dev/shifter";
00167     }
00168   else
00169     {
00170       // default port name for main IOADR8x board
00171       port_ = "/dev/ioadr8x";
00172     }
00173   mynh.getParam("port", port_);
00174   ROS_INFO_STREAM("IOADR8x port = " << port_);
00175 
00176   if (mynh.hasParam("poll_list"))
00177     {
00178       // read list of poll strings
00179     }
00180   else
00181     {
00182       // set default poll list depending on node name
00183       if (do_shifter_)
00184         {
00185           // default shifter poll list
00186           if (port_ != "/dev/null")
00187             poll_list_.push_back(LookupInput("ShifterInd"));
00188         }
00189       else
00190         {
00191           // default ioadr poll list
00192           poll_list_.push_back(LookupInput("AnalogA(10bit)"));
00193           poll_list_.push_back(LookupInput("DigitalB"));
00194         }
00195     }
00196 }
00197 
00198 // Set up the device.  Return 0 if things go well, and -1 otherwise.
00199 int IOadr::Setup(ros::NodeHandle node)
00200 {   
00201   static int qDepth = 1;
00202   ros::TransportHints noDelay = ros::TransportHints().tcpNoDelay(true);
00203 
00204   if (do_shifter_)
00205     {
00206       // initialize shifter command and state topics
00207       shifter_cmd_ = node.subscribe("shifter/cmd", qDepth,
00208                                     &IOadr::processShifter, this, noDelay);
00209       shifter_state_ =
00210         node.advertise<art_msgs::Shifter>("shifter/state", qDepth);
00211     }
00212   else
00213     {
00214       // initialize ioadr command and state topics
00215       ioadr_cmd_ = node.subscribe("ioadr/cmd", qDepth,
00216                                   &IOadr::processOutput, this, noDelay);
00217       ioadr_state_ =
00218         node.advertise<art_msgs::IOadrState>("ioadr/state", qDepth);
00219     }
00220 
00221   // create device interface class
00222   dev_ = new dev8x(port_.c_str());
00223   int rc = dev_->dev8x::setup();
00224   if (rc != 0)
00225     return rc;
00226 
00227   ROS_INFO_STREAM(node_name_ << " device opened");
00228 
00229   if (reset_relays_ >= 0)
00230     {
00231       dev_->set_relays((uint8_t) reset_relays_);
00232       ROS_INFO("set relays to 0x%02x", reset_relays_);
00233     }  
00234 
00235   return 0;
00236 }
00237 
00238 // Shutdown the device
00239 int IOadr::Shutdown()
00240 {
00241   if (reset_relays_ >= 0)
00242     {
00243       // make sure IOADR8x board is not busy before setting relays.
00244       usleep((useconds_t) rint(MIN_RELAY_WAIT*1000000.0));
00245       dev_->set_relays((uint8_t) reset_relays_);
00246       ROS_INFO("set relays to 0x%02x", reset_relays_);
00247     }
00248 
00249   dev_->dev8x::shutdown();
00250   ROS_INFO_STREAM(node_name_ << " device closed");
00251   delete dev_;
00252   return 0;
00253 }
00254 
00255 void IOadr::processOutput(const art_msgs::IOadrCommand::ConstPtr &cmd)
00256 {
00257   relay_mask_ |= (cmd->relays_on | cmd->relays_off);
00258   relay_bits_ |= cmd->relays_on;
00259   ROS_DEBUG("relay bits, mask = 0x%02x, 0x%02x", relay_bits_, relay_mask_);
00260 }
00261 
00262 // Callback when shifter command arrives.
00263 // (only subscribed when do_shifter_ is true)
00264 void IOadr::processShifter(const art_msgs::Shifter::ConstPtr &shifterIn)
00265 {
00266   // save requested gear when doing shifter simulation
00267   if (shifterIn->gear != art_msgs::Shifter::Reset
00268       && port_ == "/dev/null")
00269     shifter_gear_ = shifterIn->gear;
00270   ROS_INFO("Shifter command: gear %u", shifterIn->gear);
00271   relay_bits_ = relay_value_[shifterIn->gear];
00272   relay_mask_ = 0xff;                   // set all relay bits
00273 }
00274 
00275 int IOadr::poll_Analog_8bit(int ch)
00276 {
00277   int data;
00278   int rc = dev_->read_8bit_port(poll_list_[ch]->devnum, &data);
00279   if (rc == 0)
00280     {
00281       // convert A/D input to voltage (8-bit converter with 5-volt range)
00282       int i = poll_list_[ch]->field;
00283       ioMsg_.voltages[i] = analog_volts(data, 5.0, 8);
00284       ROS_DEBUG("%s input = %.3f volts (0x%04x)",
00285                 poll_list_[i]->name, ioMsg_.voltages[ch], data);
00286     }
00287   return rc;
00288 }
00289 
00290 int IOadr::poll_Analog_10bit(int ch)
00291 {
00292   int data;
00293   int rc = dev_->read_10bit_port(poll_list_[ch]->devnum, &data);
00294   if (rc == 0)
00295     {
00296       // convert A/D input to voltage (10-bit converter with 5-volt range)
00297       int i = poll_list_[ch]->field;
00298       ioMsg_.voltages[i] = analog_volts(data, 5.0, 10);
00299       ROS_DEBUG("%s input = %.3f volts (0x%04x)",
00300                 poll_list_[ch]->name, ioMsg_.voltages[i], data);
00301     }
00302   return rc;
00303 }
00304 
00305 int IOadr::poll_Digital(int ch)
00306 {
00307   int data;
00308   int rc = dev_->read_8bit_port(poll_list_[ch]->devnum, &data);
00309   if (rc == 0)
00310     {
00311       ioMsg_.digitalB = data;
00312     }
00313   return rc;
00314 }
00315 
00316 // translate shifter indicator into shift request ID
00317 // (only used when do_shifter_ true and port is a real device)
00318 int IOadr::poll_ShifterInd(int ch)
00319 {
00320   // read shifter feedback from Digital port B
00321   int data;
00322   int rc = dev_->read_8bit_port(1, &data);
00323   if (rc == 0)
00324     {
00325       // ignore the results unless the I/O was successful
00326       uint8_t gear;
00327       uint8_t digitalB_bits = ~data;
00328       if (digitalB_bits & 0x80)
00329         gear = art_msgs::Shifter::Park;
00330       else if (digitalB_bits & 0x40)
00331         gear = art_msgs::Shifter::Reverse;
00332       else if (digitalB_bits & 0x20)
00333         gear = art_msgs::Shifter::Neutral;
00334       else if (digitalB_bits & 0x10)
00335         gear = art_msgs::Shifter::Drive;
00336       else
00337         // there should only be one bit on at a time, so this should
00338         // not occur
00339         gear = art_msgs::Shifter::Reset;
00340 
00341       // save current gear number
00342       shifter_gear_ = gear;
00343     }
00344   return rc;
00345 }
00346 
00347 // poll device for pending input
00348 //
00349 // if an I/O fails, the corresponding voltages[i] remains unchanged
00350 //
00351 void IOadr::PollDevice(void)
00352 {
00353   int rc = 0;
00354 
00355   // First, poll any analog or digital ports that are configured.
00356   for (unsigned i = 0; i < poll_list_.size(); ++i)
00357     {
00358       poll_method_t poll_method = poll_list_[i]->function;
00359       if (poll_method)
00360         {
00361           rc = (this->*poll_method)(i);
00362           if (rc != 0)
00363             ROS_ERROR_THROTTLE(100, "poll method returns %d", rc);
00364         }
00365     }
00366 
00367   // Get relay values, set new ones if requested.  Note: setting the
00368   // relays MUST be the last IOADR8x operation of the cycle.  After
00369   // that, the device seems to stay busy for a while.  It hangs if
00370   // contacted again too soon.
00371   GetSetRelays();
00372 
00373   if (do_shifter_)                      // publishing shifter state?
00374     {
00375       art_msgs::Shifter shifter_msg;
00376       shifter_msg.header.stamp = ros::Time::now();
00377       shifter_msg.gear = shifter_gear_;
00378       shifter_msg.relays = ioMsg_.relays;
00379       shifter_state_.publish(shifter_msg);
00380     }
00381   else
00382     {
00383       // publish ioadr state message
00384       ioMsg_.header.stamp = ros::Time::now();
00385       ioadr_state_.publish(ioMsg_);
00386     }
00387 }
00388 
00389 // Get relay values, set new ones if requested.
00390 //
00391 // Updates: relay_mask_, relay_bits_, ioMsg_.relays
00392 //
00393 // If we failed to set the relays this cycle, leave relay_mask_,
00394 // relay_bits_ alone and try again next time.
00395 //
00396 void IOadr::GetSetRelays(void)
00397 {
00398   // get current relay settings
00399   int rc = dev_->query_relays(&ioMsg_.relays);
00400   if (rc != 0)                          // device busy or not working?
00401     return;
00402 
00403   if (relay_mask_)                      // new setting requested?
00404     {
00405       uint8_t new_relays = (ioMsg_.relays & (~relay_mask_)) | relay_bits_;
00406       rc = dev_->set_relays(new_relays);
00407       if (rc == 0)                      // successful?
00408         {
00409           // The device requires a wait after setting all relays
00410           // before accessing them again.  Since set_relays()
00411           // returns immediately, we must leave them alone until
00412           // our next cycle, which should be long enough for the
00413           // device to finish.  At 10Hz, that should not be a
00414           // problem.
00415 
00416           relay_mask_ = relay_bits_ = 0;
00417           ioMsg_.relays = new_relays;
00418           ROS_DEBUG("set relays to 0x%02x", ioMsg_.relays);
00419         }
00420     }
00421 }
00422 
00423 void IOadr::Main()
00424 {
00425   ros::Rate cycle(art_msgs::ArtHertz::IOADR); // set driver cycle rate
00426 
00427   // Main loop; grab messages off our queue and republish them via ROS
00428   while(ros::ok())
00429     {
00430       // wait for next cycle -- this must come first, because Setup()
00431       // may have initialized the relays.  If we hit the device again
00432       // too soon, it locks up.  Apparently, this is not just limited
00433       // to the relay ports.
00434 
00435       cycle.sleep();
00436 
00437       relay_mask_ = relay_bits_ = 0;
00438 
00439       ros::spinOnce();                  // handle incoming commands
00440 
00441       PollDevice();                     // get & publish device status
00442     }
00443 }
00444   
00445 
00446 int main(int argc, char** argv)
00447 {
00448   ros::init(argc, argv, "ioadr");       // default node name
00449   ros::NodeHandle node;
00450 
00451   IOadr io;
00452 
00453   if (io.Setup(node) != 0)
00454     return 2;
00455 
00456   io.Main();                            // driver main loop
00457 
00458   io.Shutdown();
00459 
00460   return 0;
00461 }


art_servo
Author(s): Austin Robot Technology, Jack O'Quin
autogenerated on Fri Jan 3 2014 11:09:12