37 #include <ethercat/ethercat_xenomai_drv.h>    38 #include <dll/ethercat_dll.h>    39 #include <dll/ethercat_device_addressed_telegram.h>    44 #include <sys/ioctl.h>    45 #include <boost/foreach.hpp>    46 #include <boost/regex.hpp>    53   halt_after_reset_(false),
    54   reset_motors_service_count_(0), 
    55   halt_motors_service_count_(0),
    56   halt_motors_error_count_(0),
    57   motors_halted_(false),
    58   motors_halted_reason_(
"")
    72   hw_(0), node_(
ros::NodeHandle(name)),
    73   ni_(0), this_buffer_(0), prev_buffer_(0), buffer_size_(0), halt_motors_(true), reset_state_(0), 
    75   diagnostics_publisher_(node_), 
    76   motor_publisher_(node_, 
"motors_halted", 1, true), 
    77   device_loader_(
"ethercat_hardware", 
"EthercatDevice")
    85   for (uint32_t i = 0; i < 
slaves_.size(); ++i)
    87     EC_FixedStationAddress fsa(i + 1);
    88     EtherCAT_SlaveHandler *sh = 
em_->get_slave_handler(fsa);
    89     if (sh) sh->to_state(EC_PREOP_STATE);
   104   unsigned product_code = sh->get_product_code();
   105   unsigned serial = sh->get_serial();
   106   uint32_t revision = sh->get_revision();
   107   unsigned slave = sh->get_station_address()-1;
   109   if (!sh->to_state(new_state))
   111     ROS_FATAL(
"Cannot goto state %d for slave #%d, product code: %u (0x%X), serial: %u (0x%X), revision: %d (0x%X)",
   112               new_state, slave, product_code, product_code, serial, serial, revision, revision);
   113     if ((product_code==0xbaddbadd) || (serial==0xbaddbadd) || (revision==0xbaddbadd))
   114       ROS_FATAL(
"Note: 0xBADDBADD indicates that the value was not read correctly from device.");
   122   int sock = socket(PF_INET, SOCK_DGRAM, 0);
   125     ROS_FATAL(
"Couldn't open temp socket : %s", strerror(error));
   131   strncpy(ifr.ifr_name, interface, IFNAMSIZ);
   132   if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
   134     ROS_FATAL(
"Cannot get interface flags for %s: %s", interface, strerror(error));
   142   if (!(ifr.ifr_flags & IFF_UP)) {
   143     ROS_FATAL(
"Interface %s is not UP. Try : ifup %s", interface, interface);
   147   if (!(ifr.ifr_flags & IFF_RUNNING)) {
   148     ROS_FATAL(
"Interface %s is not RUNNING. Is cable plugged in and device powered?", interface);
   156   if ((
ni_ = init_ec(interface)) == NULL)
   158     ROS_FATAL(
"Unable to initialize interface: %s", interface);
   166   EtherCAT_DataLinkLayer::instance()->attach(
ni_);
   167   if ((
al_ = EtherCAT_AL::instance()) == NULL)
   169     ROS_FATAL(
"Unable to initialize Application Layer (AL): %p", 
al_);
   175   if (num_ethercat_devices_ == 0)
   177     ROS_FATAL(
"Unable to locate any slaves");
   183   if ((
em_ = EtherCAT_Master::instance()) == NULL)
   185     ROS_FATAL(
"Unable to initialize EtherCAT_Master: %p", 
em_);
   191   slaves_.resize(num_ethercat_devices_);
   194   std::vector<EtherCAT_SlaveHandler*> slave_handles;
   195   for (
unsigned int slave = 0; slave < 
slaves_.size(); ++slave)
   197     EC_FixedStationAddress fsa(slave + 1);
   198     EtherCAT_SlaveHandler *sh = 
em_->get_slave_handler(fsa);
   201       ROS_FATAL(
"Unable to get slave handler #%d", slave);
   205     slave_handles.push_back(sh);
   209   BOOST_FOREACH(EtherCAT_SlaveHandler *sh, slave_handles)
   211     unsigned slave = sh->get_station_address()-1;
   214       ROS_FATAL(
"Unable to configure slave #%d", slave);
   225   BOOST_FOREACH(EtherCAT_SlaveHandler *sh, slave_handles)
   231   BOOST_FOREACH(EtherCAT_SlaveHandler *sh, slave_handles)
   238   BOOST_FOREACH(EtherCAT_SlaveHandler *sh, slave_handles)
   252     ROS_FATAL(
"No communication with devices");
   267   for (
unsigned int slave = 0; slave < 
slaves_.size(); ++slave)
   271       EtherCAT_SlaveHandler *sh = 
slaves_[slave]->sh_;
   274         ROS_FATAL(
"Unable to initialize slave #%d, product code: %d, revision: %d, serial: %d",
   275                   slave, sh->get_product_code(), sh->get_revision(), sh->get_serial());
   280         ROS_FATAL(
"Unable to initialize slave #%d", slave);
   290     static const int MAX_TIMEOUT = 100000;   
   291     static const int DEFAULT_TIMEOUT = 20000; 
   295       timeout = DEFAULT_TIMEOUT; 
   297     if ((timeout <= 1) || (timeout > MAX_TIMEOUT))
   299       int old_timeout = timeout; 
   300       timeout = std::max(1, 
std::min(MAX_TIMEOUT, timeout));
   301       ROS_WARN(
"Invalid timeout (%d) for socket, using %d", old_timeout, timeout);
   303     if (set_socket_timeout(
ni_, timeout))
   305       ROS_FATAL(
"Error setting socket timeout to %d", timeout);      
   320     int max_pd_retries = MAX_TIMEOUT / timeout;  
   321     static const int MAX_RETRIES=50, MIN_RETRIES=1;
   324     if ((max_pd_retries * timeout) > (MAX_TIMEOUT))
   326       max_pd_retries = MAX_TIMEOUT / timeout;
   327       ROS_WARN(
"Max PD retries is too large for given timeout.  Limiting value to %d", max_pd_retries);
   329     if ((max_pd_retries < MIN_RETRIES) || (max_pd_retries > MAX_RETRIES))
   331       max_pd_retries = std::max(MIN_RETRIES,
std::min(MAX_RETRIES,max_pd_retries));
   332       ROS_WARN(
"Limiting max PD retries to %d", max_pd_retries);
   334     max_pd_retries = std::max(MIN_RETRIES,
std::min(MAX_RETRIES,max_pd_retries));
   344   diagnostics_ready_(false),
   345   publisher_(
node_.advertise<diagnostic_msgs::DiagnosticArray>(
"/diagnostics", 1)),
   346   diagnostics_buffer_(NULL),
   347   last_dropped_packet_count_(0),
   348   last_dropped_packet_time_(0)
   359                                                       unsigned int num_ethercat_devices, 
   360                                                       unsigned timeout, 
unsigned max_pd_retries)
   381          const unsigned char *buffer, 
   384   boost::try_to_lock_t try_lock;
   386   if (lock.owns_lock())
   415   } 
catch (boost::thread_interrupted 
const&) {
   423         const accumulator_set<
double, stats<tag::max, tag::mean> > &acc,
   426   status.
addf(key + 
" Avg (us)",       
"%5.4f", extract_result<tag::mean>(acc) * 1e6); 
   427   status.
addf(key + 
" 1 Sec Max (us)", 
"%5.4f", extract_result<tag::max>(acc) * 1e6);  
   428   status.
addf(key + 
" Max (us)",       
"%5.4f", max * 1e6);                            
   439   status_.name = 
"EtherCAT Master";
   442     std::ostringstream desc;
   443     desc << 
"Motors halted";
   446       desc << 
" soon after reset";
   490     status_.
addf(
"Sent Packets",        
"%llu", (
unsigned long long)c->sent);
   491     status_.
addf(
"Received Packets",    
"%llu", (
unsigned long long)c->received);
   492     status_.
addf(
"Collected Packets",   
"%llu", (
unsigned long long)c->collected);
   493     status_.
addf(
"Dropped Packets",     
"%llu", (
unsigned long long)c->dropped);
   494     status_.
addf(
"TX Errors",           
"%llu", (
unsigned long long)c->tx_error);
   495     status_.
addf(
"TX Network Down",     
"%llu", (
unsigned long long)c->tx_net_down);
   496     status_.
addf(
"TX Would Block",      
"%llu", (
unsigned long long)c->tx_would_block);
   497     status_.
addf(
"TX No Buffers",       
"%llu", (
unsigned long long)c->tx_no_bufs);
   498     status_.
addf(
"TX Queue Full",       
"%llu", (
unsigned long long)c->tx_full);
   499     status_.
addf(
"RX Runt Packet",      
"%llu", (
unsigned long long)c->rx_runt_pkt);
   500     status_.
addf(
"RX Not EtherCAT",     
"%llu", (
unsigned long long)c->rx_not_ecat);
   501     status_.
addf(
"RX Other EML",        
"%llu", (
unsigned long long)c->rx_other_eml);
   502     status_.
addf(
"RX Bad Index",        
"%llu", (
unsigned long long)c->rx_bad_index);
   503     status_.
addf(
"RX Bad Sequence",     
"%llu", (
unsigned long long)c->rx_bad_seqnum);
   504     status_.
addf(
"RX Duplicate Sequence", 
"%llu", (
unsigned long long)c->rx_dup_seqnum);    
   505     status_.
addf(
"RX Duplicate Packet", 
"%llu", (
unsigned long long)c->rx_dup_pkt);    
   506     status_.
addf(
"RX Bad Order",        
"%llu", (
unsigned long long)c->rx_bad_order);    
   507     status_.
addf(
"RX Late Packet",      
"%llu", (
unsigned long long)c->rx_late_pkt);
   508     status_.
addf(
"RX Late Packet RTT",  
"%llu", (
unsigned long long)c->rx_late_pkt_rtt_us);
   510     double rx_late_pkt_rtt_us_avg = 0.0;
   511     if (c->rx_late_pkt > 0) {
   512       rx_late_pkt_rtt_us_avg = ((double)c->rx_late_pkt_rtt_us_sum)/((double)c->rx_late_pkt);
   514     status_.
addf(
"RX Late Packet Avg RTT", 
"%f", rx_late_pkt_rtt_us_avg);
   535   for (
unsigned int s = 0; 
s < 
slaves_.size(); ++
s)
   551   unsigned char *this_buffer, *prev_buffer;
   554   this_buffer = this_buffer_;
   559     haltMotors(
false , 
"service request");
   564   const unsigned CYCLES_PER_HALT_RELEASE = 2; 
   568     reset_state_ = CYCLES_PER_HALT_RELEASE * 
slaves_.size() + 5;
   569     last_reset_ = update_start_time;
   572   bool reset_devices = reset_state_ == CYCLES_PER_HALT_RELEASE * 
slaves_.size() + 3;
   575     halt_motors_ = 
false;
   582   for (
unsigned int s = 0; 
s < 
slaves_.size(); ++
s)
   586     bool halt_device = halt_motors_ || ((
s*CYCLES_PER_HALT_RELEASE+1) < reset_state_);
   587     slaves_[
s]->packCommand(this_buffer, halt_device, reset_devices);
   601   hw_->current_time_ = txandrx_end_time;
   606     haltMotors(
true , 
"communication error");
   612     this_buffer = this_buffer_;
   613     prev_buffer = prev_buffer_;
   614     for (
unsigned int s = 0; 
s < 
slaves_.size(); ++
s)
   616       if (!
slaves_[
s]->unpackState(this_buffer, prev_buffer) && !reset_devices)
   618         haltMotors(
true , 
"device error");
   627     unsigned char *tmp = this_buffer_;
   628     this_buffer_ = prev_buffer_;
   639   if ((update_start_time - last_published_) > 
ros::Duration(1.0))
   641     last_published_ = update_start_time;
   643     motor_publisher_.lock();
   644     motor_publisher_.msg_.data = halt_motors_;
   645     motor_publisher_.unlockAndPublish();
   661     motor_publisher_.lock();
   662     motor_publisher_.msg_.data = halt_motors_;
   663     motor_publisher_.unlockAndPublish();
   684   max = std::max(max, extract_result<tag::max>(acc));
   702   diagnostics_publisher_.publish(this_buffer_, 
diagnostics_);
   705   static accumulator_set<double, stats<tag::max, tag::mean> > blank;
   716   static int start_address = 0x00010000;
   718   unsigned product_code = sh->get_product_code();
   719   unsigned serial = sh->get_serial();
   720   uint32_t revision = sh->get_revision();
   721   unsigned slave = sh->get_station_address()-1;
   753   stringstream class_name_regex_str;
   754   class_name_regex_str << 
"(.*/)?" << product_code;
   755   boost::regex class_name_regex(class_name_regex_str.str(), boost::regex::extended);
   757   std::vector<std::string> classes = device_loader_.getDeclaredClasses();
   758   std::string matching_class_name;
   760   BOOST_FOREACH(
const std::string &class_name, classes)
   762     if (regex_match(class_name, class_name_regex))
   764       if (matching_class_name.size() != 0)
   766         ROS_ERROR(
"Found more than 1 EtherCAT driver for device with product code : %d", product_code);
   767         ROS_ERROR(
"First class name = '%s'.  Second class name = '%s'",
   768                   class_name.c_str(), matching_class_name.c_str());
   770       matching_class_name = class_name;
   774   if (matching_class_name.size() != 0)
   779       p = device_loader_.createInstance(matching_class_name);
   784       ROS_FATAL(
"Unable to load plugin for slave #%d, product code: %u (0x%X), serial: %u (0x%X), revision: %d (0x%X)",
   785                 slave, product_code, product_code, serial, serial, revision, revision);
   791     if ((product_code==0xbaddbadd) || (serial==0xbaddbadd) || (revision==0xbaddbadd))
   793       ROS_FATAL(
"Note: 0xBADDBADD indicates that the value was not read correctly from device.");
   794       ROS_FATAL(
"Perhaps you should power-cycle the MCBs");
   798       ROS_ERROR(
"Unable to load plugin for slave #%d, product code: %u (0x%X), serial: %u (0x%X), revision: %d (0x%X)",
   799                 slave, product_code, product_code, serial, serial, revision, revision);
   801       BOOST_FOREACH(
const std::string &class_name, classes)
   813     p->construct(sh, start_address);
   825     p = device_loader_.createInstance(type);
   830     ROS_FATAL(
"Unable to load plugin for non-EtherCAT device '%s' with type: %s : %s"   831               , name.c_str(), type.c_str(), e.what());
   834     ROS_INFO(
"Creating non-EtherCAT device '%s' of type '%s'", name.c_str(), type.c_str());
   847   XmlRpcValue::ValueStruct &
getMap() {
return *_value.asStruct;}
   883     ROS_ERROR(
"Rosparam 'non_ethercat_devices' is not a struct type");
   888   typedef XmlRpc::XmlRpcValue::ValueStruct::value_type map_item_t ;
   889   BOOST_FOREACH(map_item_t &item, my_devices.
getMap())
   891     const std::string &name(item.first);
   896       ROS_ERROR(
"non_ethercat_devices/%s is not a struct type", name.c_str());
   902       ROS_ERROR(
"non_ethercat_devices/%s 'type' element", name.c_str());
   906     std::string type(static_cast<std::string>(device_info[
"type"])); 
   909       configNonEthercatDevice(name,type);
   910     if (new_device != NULL)
   920   if (NULL == oob_com_)
   924     EC_Logic *logic = EC_Logic::instance();
   926     EC_UINT 
length = 
sizeof(p);
   929     APRD_Telegram 
status(logic->get_idx(), 
   937     EC_Ethernet_Frame frame(&
status);    
   938     oob_com_->txandrx(&frame);
   944   for (
unsigned i = 0; i < 
slaves_.size(); ++i)
   947     d->collectDiagnostics(oob_com_);
   955   const struct netif_counters &c(ni_->counters);      
   956   os << 
"netif counters :" << endl
   957      << 
" sent          = " << c.sent << endl
   958      << 
" received      = " << c.received << endl
   959      << 
" collected     = " << c.collected << endl
   960      << 
" dropped       = " << c.dropped << endl
   961      << 
" tx_error      = " << c.tx_error << endl
   962      << 
" tx_net_down   = " << c.tx_net_down << endl
   963      << 
" tx_would_block= " << c.tx_would_block << endl
   964      << 
" tx_no_bufs    = " << c.tx_no_bufs << endl
   965      << 
" tx_full       = " << c.tx_full << endl
   966      << 
" rx_runt_pkt   = " << c.rx_runt_pkt << endl
   967      << 
" rx_not_ecat   = " << c.rx_not_ecat << endl
   968      << 
" rx_other_eml  = " << c.rx_other_eml << endl
   969      << 
" rx_bad_index  = " << c.rx_bad_index << endl
   970      << 
" rx_bad_seqnum = " << c.rx_bad_seqnum << endl
   971      << 
" rx_dup_seqnum = " << c.rx_dup_seqnum << endl
   972      << 
" rx_dup_pkt    = " << c.rx_dup_pkt << endl
   973      << 
" rx_bad_order  = " << c.rx_bad_order << endl
   974      << 
" rx_late_pkt   = " << c.rx_late_pkt << endl;
   981   bool success = 
false;
   982   for (
unsigned i=0; i<tries && !success; ++i) {
   997   if (position >= (
int)
slaves_.size())
   999     ROS_WARN(
"Invalid device position %d.  Use 0-%d, or -1.", position, 
int(
slaves_.size())-1);
  1005     ROS_WARN(
"Invalid level : %d.  Using level=2 (ERROR).", level);
  1009   string new_reason(
"Manually triggered : " + reason);
  1011   bool retval = 
false;
  1014     for (
unsigned i=0; i<
slaves_.size(); ++i)
  1016       if (
slaves_[i]->publishTrace(new_reason,level,delay))
  1024     retval = 
slaves_[position]->publishTrace(new_reason,level,delay);
  1027       ROS_WARN(
"Device %d does not support publishing trace", position);
 vector< diagnostic_msgs::KeyValue > values_
 
unsigned reset_motors_service_count_
Number of times reset_motor service has been used. 
 
static void timingInformation(diagnostic_updater::DiagnosticStatusWrapper &status, const string &key, const accumulator_set< double, stats< tag::max, tag::mean > > &acc, double max)
Helper function for converting timing for diagnostics. 
 
static const unsigned dropped_packet_warning_hold_time_
Number of seconds since late dropped packet to keep warning. 
 
EthercatHardwareDiagnostics diagnostics_
Diagnostics information use by publish function. 
 
void publish(const boost::shared_ptr< M > &message) const 
 
EthercatHardwareDiagnostics()
 
void diagnosticsThreadFunc()
Publishing thread main loop. 
 
void haltMotors(bool error, const char *reason)
 
void wait(unique_lock< mutex > &m)
 
void summary(unsigned char lvl, const std::string s)
 
ROSCONSOLE_DECL void initialize()
 
pr2_hardware_interface::HardwareInterface * hw_
 
void initialize(const std::string &interface)
 
void init(char *interface, bool allow_unprogrammed)
Initialize the EtherCAT Master Library. 
 
ros::Publisher publisher_
 
MyXmlRpcValue(XmlRpc::XmlRpcValue &value)
 
std::vector< boost::shared_ptr< EthercatDevice > > slaves_
 
accumulator_set< double, stats< tag::max, tag::mean > > pack_command_acc_
time taken by all devices packCommand functions 
 
unsigned halt_motors_service_count_
Number of time halt_motor service call is used. 
 
unsigned halt_motors_error_count_
Number of transitions into halt state due to device error. 
 
void stop()
Stops publishing thread. May block. 
 
bool motors_halted_
True if motors are halted. 
 
bool publishTrace(int position, const string &reason, unsigned level, unsigned delay)
Ask one or all EtherCAT devices to publish (motor) traces. 
 
unsigned char * prev_buffer_
 
Type const & getType() const 
 
EthernetInterfaceInfo ethernet_interface_info_
Information about Ethernet interface used for EtherCAT communication. 
 
unsigned char * diagnostics_buffer_
 
void addf(const std::string &key, const char *format,...)
 
unsigned int num_ethercat_devices_
 
accumulator_set< double, stats< tag::max, tag::mean > > txandrx_acc_
time taken by to transmit and recieve process data 
 
~EthercatHardwareDiagnosticsPublisher()
 
const char * motors_halted_reason_
reason that motors first halted 
 
void publishDiagnostics()
Collects raw diagnostics data and passes it to diagnostics_publisher. 
 
void publishDiagnostics()
Publishes diagnostics. 
 
unsigned timeout_
Timeout (in microseconds) to used for sending/recieving packets once in realtime mode. 
 
vector< EthercatDevice * > devices
 
void collectDiagnostics()
Collects diagnotics from all devices. 
 
unsigned int buffer_size_
 
bool txandrx_PD(unsigned buffer_size, unsigned char *buffer, unsigned tries)
Send process data. 
 
void update(bool reset, bool halt)
Send most recent motor commands and retrieve updates. This command must be run at a sufficient rate o...
 
boost::shared_ptr< EthercatDevice > configSlave(EtherCAT_SlaveHandler *sh)
 
std::vector< boost::shared_ptr< EthercatDevice > > slaves_
 
boost::thread diagnostics_thread_
 
bool input_thread_is_stopped_
 
uint64_t last_dropped_packet_count_
Count of dropped packets last diagnostics cycle. 
 
diagnostic_updater::DiagnosticStatusWrapper status_
 
unsigned int num_ethercat_devices_
 
EthercatHardwareDiagnosticsPublisher(ros::NodeHandle &node)
 
boost::shared_ptr< EthercatDevice > configNonEthercatDevice(const std::string &product_id, const std::string &data)
 
realtime_tools::RealtimePublisher< std_msgs::Bool > motor_publisher_
 
boost::condition_variable diagnostics_cond_
 
void initialize(const string &interface, unsigned int buffer_size, const std::vector< boost::shared_ptr< EthercatDevice > > &slaves, unsigned int num_ethercat_devices_, unsigned timeout, unsigned max_pd_retries)
Initializes hardware publish. 
 
static void changeState(EtherCAT_SlaveHandler *sh, EC_State new_state)
 
EthercatOobCom * oob_com_
 
void mergeSummary(unsigned char lvl, const std::string s)
 
unsigned char * this_buffer_
 
bool hasMember(const std::string &name) const 
 
struct netif_counters counters_
 
diagnostic_msgs::DiagnosticArray diagnostic_array_
 
static void updateAccMax(double &max, const accumulator_set< double, stats< tag::max, tag::mean > > &acc)
 
EthercatHardwareDiagnosticsPublisher diagnostics_publisher_
 
void publish(const unsigned char *buffer, const EthercatHardwareDiagnostics &diagnostics)
Triggers publishing of new diagnostics data. 
 
unsigned int buffer_size_
 
~EthercatHardware()
Destructor. 
 
unsigned timeout_
Timeout controls how long EtherCAT driver waits for packet before declaring it as dropped...
 
EthercatHardware(const std::string &name)
Constructor. 
 
bool getParam(const std::string &key, std::string &s) const 
 
unsigned max_pd_retries_
Number of times (in a row) to retry sending process data (realtime data) before halting motors...
 
void loadNonEthercatDevices()
 
void mergeSummaryf(unsigned char lvl, const char *format,...)
 
void add(const std::string &key, const T &val)
 
boost::mutex diagnostics_mutex_
mutex protects all class data and cond variable 
 
bool hasParam(const std::string &key) const 
 
void publishDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &d)
Collect and append ethernet interface diagnostics. 
 
accumulator_set< double, stats< tag::max, tag::mean > > unpack_state_acc_
time taken by all devices updateState functions 
 
ROSCPP_DECL int close_socket(socket_fd_t &socket)
 
void notify_one() BOOST_NOEXCEPT
 
void printCounters(std::ostream &os=std::cout)
 
static double min(double a, double b)
 
unsigned max_pd_retries_
Max number of times to retry sending process data before halting motors. 
 
bool halt_after_reset_
True if motor halt soon after motor reset. 
 
ros::Time last_dropped_packet_time_
Time last packet was dropped 0 otherwise. Used for warning about dropped packets. ...
 
static const bool collect_extra_timing_
 
XmlRpcValue::ValueStruct & getMap()
 
ros::Time last_published_
 
accumulator_set< double, stats< tag::max, tag::mean > > publish_acc_
time taken by any publishing step in main loop