ethercat_manager.cpp
Go to the documentation of this file.
2 
3 #include <string.h>
4 
5 #include <unistd.h>
6 
7 #include <boost/ref.hpp>
8 #include <boost/interprocess/sync/scoped_lock.hpp>
9 
10 #include <soem/ethercattype.h>
11 #include <soem/nicdrv.h>
12 #include <soem/ethercatbase.h>
13 #include <soem/ethercatmain.h>
14 #include <soem/ethercatdc.h>
15 #include <soem/ethercatcoe.h>
16 #include <soem/ethercatfoe.h>
17 #include <soem/ethercatconfig.h>
18 #include <soem/ethercatprint.h>
19 
20 #include <ros/ros.h>
21 
22 namespace
23 {
24  static const unsigned THREAD_SLEEP_TIME = 10000; // 10 ms
25  static const unsigned EC_TIMEOUTMON = 500;
26 
27  void handleErrors()
28  {
29  /* one ore more slaves are not responding */
31  ec_readstate();
32  for (int slave = 1; slave <= ec_slavecount; slave++)
33  {
34  if ((ec_slave[slave].group == 0) && (ec_slave[slave].state != EC_STATE_OPERATIONAL))
35  {
37  if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
38  {
39  ROS_ERROR("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);
41  ec_writestate(slave);
42  }
43  else if(ec_slave[slave].state == EC_STATE_SAFE_OP)
44  {
45  ROS_WARN("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);
47  ec_writestate(slave);
48  }
49  else if(ec_slave[slave].state > 0)
50  {
51  if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
52  {
54  ROS_INFO("MESSAGE : slave %d reconfigured\n",slave);
55  }
56  }
57  else if(!ec_slave[slave].islost)
58  {
59  /* re-check state */
60  ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);
61  if (!ec_slave[slave].state)
62  {
64  ROS_ERROR("ERROR : slave %d lost\n",slave);
65  }
66  }
67  }
68  if (ec_slave[slave].islost)
69  {
70  if(!ec_slave[slave].state)
71  {
72  if (ec_recover_slave(slave, EC_TIMEOUTMON))
73  {
75  ROS_INFO("MESSAGE : slave %d recovered\n",slave);
76  }
77  }
78  else
79  {
81  ROS_INFO("MESSAGE : slave %d found\n",slave);
82  }
83  }
84  }
85  }
86 
87  void cycleWorker(boost::mutex& mutex, bool& stop_flag)
88  {
89  while (!stop_flag)
90  {
91  int expected_wkc = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
92  int sent, wkc;
93  {
94  boost::mutex::scoped_lock lock(mutex);
95  sent = ec_send_processdata();
96  wkc = ec_receive_processdata(EC_TIMEOUTRET);
97  }
98 
99  if (wkc < expected_wkc)
100  {
101  handleErrors();
102  }
103 
104  usleep(THREAD_SLEEP_TIME);
105  }
106  }
107 
108 } // end of anonymous namespace
109 
110 
112  : ifname_(ifname)
113  , stop_flag_(false)
114 {
115  if (initSoem(ifname))
116  {
117  cycle_thread_ = boost::thread(cycleWorker,
118  boost::ref(iomap_mutex_),
119  boost::ref(stop_flag_));
120  }
121  else
122  {
123  // construction failed
124  throw EtherCatError("Could not initialize SOEM");
125  }
126 }
127 
129 {
130  stop_flag_ = true;
131  ec_close();
132  cycle_thread_.join();
133 }
134 
135 void robotiq_ethercat::EtherCatManager::write(int slave_no, uint8_t channel, uint8_t value)
136 {
137  boost::mutex::scoped_lock lock(iomap_mutex_);
138  ec_slave[slave_no].outputs[channel] = value;
139 }
140 
142 {
143  boost::mutex::scoped_lock lock(iomap_mutex_);
144  return ec_slave[slave_no].inputs[channel];
145 }
146 
148 {
149  boost::mutex::scoped_lock lock(iomap_mutex_);
150  return ec_slave[slave_no].outputs[channel];
151 }
152 
153 bool robotiq_ethercat::EtherCatManager::initSoem(const std::string& ifname)
154 {
155  // Copy string contents because SOEM library doesn't
156  // practice const correctness
157  const static unsigned MAX_BUFF_SIZE = 1024;
158  char buffer[MAX_BUFF_SIZE];
159  size_t name_size = ifname_.size();
160  if (name_size > sizeof(buffer) - 1)
161  {
162  ROS_ERROR("Ifname %s exceeds maximum size of %u bytes", ifname.c_str(), MAX_BUFF_SIZE);
163  return false;
164  }
165  std::strncpy(buffer, ifname_.c_str(), MAX_BUFF_SIZE);
166 
167  ROS_INFO("Initializing etherCAT master");
168 
169  if (!ec_init(buffer))
170  {
171  ROS_ERROR("Could not initialize ethercat driver");
172  return false;
173  }
174 
175  /* find and auto-config slaves */
176  if (ec_config_init(FALSE) <= 0)
177  {
178  ROS_WARN("No slaves found on %s", ifname_.c_str());
179  return false;
180  }
181 
182  ROS_INFO("SOEM found and configured %d slaves", ec_slavecount);
183 
184  unsigned map_size = ec_slave[0].Obytes + ec_slave[0].Ibytes;
185  iomap_.reset(new uint8_t[map_size]);
186 
187  int iomap_size = ec_config_map(iomap_.get());
188  ROS_INFO("SOEM IOMap size: %d", iomap_size);
189 
190  // locates dc slaves - ???
191  ec_configdc();
192 
193  // '0' here addresses all slaves
195  {
196  ROS_ERROR("Could not set EC_STATE_SAFE_OP");
197  return false;
198  }
199 
200  /*
201  This section attempts to bring all slaves to operational status. It does so
202  by attempting to set the status of all slaves (ec_slave[0]) to operational,
203  then proceeding through 40 send/recieve cycles each waiting up to 50 ms for a
204  response about the status.
205  */
209 
210  ec_writestate(0);
211  int chk = 40;
212  do {
215  ec_statecheck(0, EC_STATE_OPERATIONAL, 50000); // 50 ms wait for state check
216  } while (chk-- && (ec_slave[0].state != EC_STATE_OPERATIONAL));
217 
219  {
220  ROS_ERROR_STREAM("OPERATIONAL state not set, exiting");
221  return false;
222  }
223 
224  ROS_INFO("Finished configuration successfully");
225  return true;
226 }
int ec_reconfig_slave(uint16 slave, int timeout)
bool initSoem(const std::string &ifname)
boolean islost
EtherCAT exception. Currently this is only thrown in the event of a failure to construct an EtherCat ...
int ec_readstate(void)
int ec_send_processdata(void)
uint16 outputsWKC
#define EC_TIMEOUTSTATE
uint32 Ibytes
int ec_slavecount
uint8 * outputs
int ec_recover_slave(uint16 slave, int timeout)
uint32 Obytes
int ec_receive_processdata(int timeout)
uint16 state
int ec_init(const char *ifname)
EtherCatManager(const std::string &ifname)
Constructs and initializes the ethercat slaves on a given network interface.
unsigned char uint8_t
#define ROS_WARN(...)
#define EC_TIMEOUTMON
#define TRUE
int ec_config_map(void *pIOmap)
uint8_t readOutput(int slave_no, uint8_t channel) const
Reads the "channel-th" output-register of the given slave no.
EC_STATE_OPERATIONAL
#define ROS_INFO(...)
int slave
#define FALSE
EC_STATE_ACK
EC_STATE_SAFE_OP
boost::scoped_array< uint8_t > iomap_
#define EC_TIMEOUTRET
boolean docheckstate
int ec_writestate(uint16 slave)
int wkc
void write(int slave_no, uint8_t channel, uint8_t value)
writes &#39;value&#39; to the &#39;channel-th&#39; output-register of the given &#39;slave&#39;
boolean ec_configdc(void)
uint8_t readInput(int slave_no, uint8_t channel) const
Reads the "channel-th" input-register of the given slave no.
#define ROS_ERROR_STREAM(args)
void ec_close(void)
uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout)
#define ROS_ERROR(...)
int ec_config_init(uint8 usetable)
uint8 * inputs


robotiq_ethercat
Author(s): Jonathan Meyer
autogenerated on Tue Jun 1 2021 02:29:53