xarm_driver_node.cpp
Go to the documentation of this file.
1 /* Copyright 2018 UFACTORY Inc. All Rights Reserved.
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Author: Jason Peng <jason@ufactory.cc>
6  ============================================================================*/
7 #include <xarm_driver.h>
8 #include <signal.h>
9 #include <thread>
10 #include "xarm/core/connect.h"
11 #include "xarm/core/report_data.h"
13 
14 #define DEBUG_MODE 0
15 #define DEBUG_DETAIL 0
16 #define PRINT_HEX_DATA(hex, len, ...) \
17 { \
18  if (DEBUG_MODE && DEBUG_DETAIL) { \
19  printf(__VA_ARGS__); \
20  for (int i = 0; i < len; ++i) { \
21  printf("%02x ", hex[i]); \
22  } \
23  printf("\n"); \
24  } \
25 }
26 
27 void exit_sig_handler(int signum)
28 {
29  fprintf(stderr, "[xarm_driver] Ctrl-C caught, exit process...\n");
30  exit(-1);
31 }
32 
34 {
35  public:
36  XarmRTConnection(ros::NodeHandle& root_nh, char *server_ip, xarm_api::XARMDriver &drv)
37  {
38  root_nh.getParam("DOF", joint_num_);
39  root_nh.getParam("joint_names", joint_name_);
40  root_nh.getParam("xarm_report_type", report_type);
41  ip = server_ip;
42  xarm_driver = drv;
43  xarm_driver.XARMDriverInit(root_nh, server_ip);
44  ros::Duration(0.5).sleep();
45  std::thread th(thread_proc, (void *)this);
46  th.detach();
47  }
48 
49  bool reConnect(void)
50  {
52  int retryCnt = 0;
53  ROS_INFO("try to reconnect to report socket");
54  while (retryCnt < 5)
55  {
56  retryCnt++;
58  ROS_INFO("reconnect to report socket success");
59  return true;
60  }
61  ros::Duration(2).sleep();
62  }
63  ROS_ERROR("reconnect to report socket failed");
64  return false;
65  }
66 
67  void thread_run(void)
68  {
69  int ret;
70  int err_num = 0;
71  int rxcnt;
72  int i;
73  int first_cycle = 1;
74  double d;
75  double * prev_angle = new double [joint_num_];
76 
78 
79  int size = 0;
80  int num = 0;
81  int offset = 0;
82  unsigned char rx_data[1024];
83  unsigned char prev_data[1280];
84  unsigned char ret_data[1024 * 2];
85 
86  int db_read_cnt = 0;
87  int db_packet_cnt = 0;
88  int db_success_pkt_cnt = 0;
89  int db_discard_pkt_cnt = 0;
90  int db_failed_pkt_cnt = 0;
91  bool prev_pkt_is_not_empty = false;
92 
93  ROS_INFO("start to handle the tcp report");
94 
96 
98  {
99  r.sleep();
100  ret = xarm_driver.get_frame(rx_data);
101  if (ret != 0) continue;
102  db_read_cnt += 1;
103 
104  num = bin8_to_32(rx_data);
105  if (num < 4 && size <= 0) continue;
106  if (size <= 0) {
107  size = bin8_to_32(rx_data + 4);
108  bin32_to_8(size, &ret_data[0]);
109  }
110  if (num + offset < size) {
111  if (DEBUG_MODE)
112  ROS_INFO("[READ:%d][PACKET:%d][SUCCESS:%d][DISCARD:%d][FAILED:%d] The data packet length is insufficient, waiting for the next packet splicing. num=%d, offset=%d, length=%d\n",
113  db_read_cnt, db_packet_cnt, db_success_pkt_cnt, db_discard_pkt_cnt, db_failed_pkt_cnt, num, offset, num + offset);
114  memcpy(ret_data + offset + 4, rx_data + 4, num);
115  offset += num;
116  continue;
117  }
118  else {
119  memcpy(ret_data + offset + 4, rx_data + 4, size - offset);
120  db_packet_cnt += 1;
121  int offset2 = size - offset;
122  while (num - offset2 >= size) {
123  db_discard_pkt_cnt += 1;
124  db_packet_cnt += 1;
125  if (DEBUG_MODE)
126  ROS_INFO("[READ:%d][PACKET:%d][SUCCESS:%d][DISCARD:%d][FAILED:%d] Data packet stick to packets, the previous data packet will be discarded. num=%d, offset=%d\n",
127  db_read_cnt, db_packet_cnt, db_success_pkt_cnt, db_discard_pkt_cnt, db_failed_pkt_cnt, num, offset);
128  PRINT_HEX_DATA(ret_data, size + 4, "[%d] Discard Packet: ", db_packet_cnt);
129  memcpy(ret_data + 4, rx_data + 4 + offset2, size);
130  offset2 += size;
131  }
132 
133  int size_of_data = bin8_to_32(ret_data + 4);
134  if (size_of_data != size) {
135  db_failed_pkt_cnt += 2;
136  ROS_WARN("[READ:%d][PACKET:%d][SUCCESS:%d][DISCARD:%d][FAILED:%d] Packet abnormal. num=%d, offset=%d, size=%d, length=%d\n",
137  db_read_cnt, db_packet_cnt, db_success_pkt_cnt, db_discard_pkt_cnt, db_failed_pkt_cnt, num, offset, size, size_of_data);
138  PRINT_HEX_DATA(ret_data, size + 4, "[%d] Abnormal Packet: ", db_packet_cnt);
139  if (reConnect()) {
140  size = 0;
141  offset = 0;
142  prev_pkt_is_not_empty = false;
143  first_cycle = 1;
144  continue;
145  };
146  ROS_ERROR("packet abnormal, reconnect failed\n");
147  break;
148  }
149  else {
150  if (prev_pkt_is_not_empty) {
151  PRINT_HEX_DATA(prev_data, size + 4, "[%d] Normal Packet: ", db_packet_cnt);
152  // xarm_driver.update_rich_data(prev_data, size + 4);
153  }
154  memcpy(prev_data, ret_data, size + 4);
155  }
156  // xarm_driver.update_rich_data(ret_data, size + 4);
157  offset = num - offset2;
158  if (offset > 0) {
159  if (DEBUG_MODE)
160  ROS_INFO("[READ:%d][PACKET:%d][SUCCESS:%d][DISCARD:%d][FAILED:%d] Data packets are redundant and will be left for the next packet splicing process. num=%d, offset=%d\n",
161  db_read_cnt, db_packet_cnt, db_success_pkt_cnt, db_discard_pkt_cnt, db_failed_pkt_cnt, num, offset);
162  memcpy(ret_data + 4, rx_data + 4 + offset2, offset);
163  }
164  if (!prev_pkt_is_not_empty) {
165  prev_pkt_is_not_empty = true;
166  continue;
167  }
168  }
169 
170  ret = report_data_ptr->flush_data(prev_data);
171 
172  // ret = xarm_driver.flush_report_data(report_data);
173  if (ret == 0) {
174  db_success_pkt_cnt++;
175  }
176  else {
177  db_failed_pkt_cnt++;
178  }
179  if (DEBUG_MODE && db_packet_cnt % 900 == 2) {
180  // report_data_ptr->print_data();
181  ROS_INFO("[READ:%d][PACKET:%d][SUCCESS:%d][DISCARD:%d][FAILED:%d]", db_read_cnt, db_packet_cnt, db_success_pkt_cnt, db_discard_pkt_cnt, db_failed_pkt_cnt);
182  }
183 
184  if (ret == 0)
185  {
186  rxcnt++;
187  last_now = now;
188  now = ros::Time::now();
189  elapsed = now - last_now;
190  js_msg.header.stamp = now;
191  js_msg.header.frame_id = "real-time data";
192  js_msg.name.resize(joint_num_);
193  js_msg.position.resize(joint_num_);
194  js_msg.velocity.resize(joint_num_);
195  js_msg.effort.resize(joint_num_);
196  for(i = 0; i < joint_num_; i++)
197  {
198  d = (double)report_data_ptr->angle[i];
199  js_msg.name[i] = joint_name_[i];
200  js_msg.position[i] = d;
201 
202  if (first_cycle)
203  {
204  js_msg.velocity[i] = 0;
205  first_cycle = 0;
206  }
207  else
208  {
209  js_msg.velocity[i] = (js_msg.position[i] - prev_angle[i]) / elapsed.toSec();
210  }
211 
212  js_msg.effort[i] = (double)report_data_ptr->tau[i];
213 
214  prev_angle[i] = d;
215  }
216 
218 
219  rm_msg.state = report_data_ptr->state;
220  rm_msg.mode = report_data_ptr->mode;
221  rm_msg.cmdnum = report_data_ptr->cmdnum;
222  rm_msg.err = report_data_ptr->err;
223  rm_msg.warn = report_data_ptr->war;
224  rm_msg.mt_brake = report_data_ptr->mt_brake;
225  rm_msg.mt_able = report_data_ptr->mt_able;
226  rm_msg.angle.resize(joint_num_);
227 
228  for(i = 0; i < joint_num_; i++)
229  {
230  /* set the float precision*/
231  double d = report_data_ptr->angle[i];
232  double r;
233  char str[8];
234  sprintf(str, "%0.3f", d);
235  sscanf(str, "%lf", &r);
236  rm_msg.angle[i] = r;
237  }
238  for(i = 0; i < 6; i++)
239  {
240  rm_msg.pose[i] = report_data_ptr->pose[i];
241  rm_msg.offset[i] = report_data_ptr->tcp_offset[i];
242  }
244 
245  // publish io state: This line may interfere with servoj execution
246  // xarm_driver.pub_io_state();
247 
248  if (report_type == "rich" && report_data_ptr->total_num >= 417) {
251  cio_msg.input_digitals[0] = report_data_ptr->cgpio_input_digitals[0];
252  cio_msg.input_digitals[1] = report_data_ptr->cgpio_input_digitals[1];
253  cio_msg.output_digitals[0] = report_data_ptr->cgpio_output_digitals[0];
254  cio_msg.output_digitals[1] = report_data_ptr->cgpio_output_digitals[1];
255 
256  cio_msg.input_analogs[0] = report_data_ptr->cgpio_input_analogs[0];
257  cio_msg.input_analogs[1] = report_data_ptr->cgpio_input_analogs[1];
258  cio_msg.output_analogs[0] = report_data_ptr->cgpio_output_analogs[0];
259  cio_msg.output_analogs[1] = report_data_ptr->cgpio_output_analogs[1];
260 
261  for (int i = 0; i < 16; ++i) {
262  cio_msg.input_conf[i] = report_data_ptr->cgpio_input_conf[i];
263  cio_msg.output_conf[i] = report_data_ptr->cgpio_output_conf[i];
264  }
266  }
267  }
268  else
269  {
270  ROS_WARN("[DEBUG] real_data.flush_data failed, ret = %d\n", ret);
271  // printf("Error: real_data.flush_data failed, ret = %d\n", ret);
272  err_num++;
273  break;
274  }
275 
276  }
277  delete report_data_ptr;
278  delete [] prev_angle;
279  ROS_ERROR("xArm Report Connection Failed! Please Shut Down (Ctrl-C) and Retry ...");
280  }
281 
282  static void* thread_proc(void *arg)
283  {
284  XarmRTConnection* threadTest=(XarmRTConnection*)arg;
285  threadTest->thread_run();
286  return (void*)0;
287  }
288 
289  public:
290  char *ip;
291  std::string report_type;
295  // ReportDataNorm norm_data;
297  sensor_msgs::JointState js_msg;
299  xarm_msgs::RobotMsg rm_msg;
300  xarm_msgs::CIOState cio_msg;
301 
303  std::vector<std::string> joint_name_;
304  constexpr static const double GET_FRAME_RATE_HZ = 1000;
305 };
306 
307 int main(int argc, char **argv)
308 {
309  ros::init(argc, argv, "xarm_driver_node");
310 
311  // with namespace (ns) specified in the calling launch file (xarm by default)
312  ros::NodeHandle n;
313 
314  xarm_api::XARMDriver driver;
315  ROS_INFO("start xarm driver");
316 
317  std::string robot_ip = "192.168.1.121";
318  if (!n.hasParam("xarm_robot_ip"))
319  {
320  ROS_ERROR("No param named 'xarm_robot_ip'");
321  ROS_ERROR("Use default robot ip = 192.168.1.121");
322  }
323  else
324  {
325  n.getParam("xarm_robot_ip", robot_ip);
326  }
327 
328  char server_ip[20]={0};
329  strcpy(server_ip,robot_ip.c_str());
330  XarmRTConnection rt_connect(n, server_ip, driver);
331 
332  signal(SIGINT, exit_sig_handler);
334 
335  printf("end");
336 
337  return 0;
338 }
d
void closeReportSocket(void)
Definition: xarm_driver.cpp:33
int main(int argc, char **argv)
unsigned char cgpio_input_conf[16]
Definition: report_data.h:195
unsigned char cgpio_output_conf[16]
Definition: report_data.h:196
float angle[7]
Definition: report_data.h:140
bool sleep() const
std::vector< std::string > joint_name_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
float tau[7]
Definition: report_data.h:142
int flush_data(unsigned char *rx_data)
Definition: report_data.cc:554
void XARMDriverInit(ros::NodeHandle &root_nh, char *server_ip)
Definition: xarm_driver.cpp:44
#define DEBUG_MODE
static void * thread_proc(void *arg)
int get_frame(unsigned char *data)
int bin8_to_32(unsigned char *a)
Definition: data_type.h:38
#define ROS_WARN(...)
float cgpio_output_analogs[2]
Definition: report_data.h:194
void pub_joint_state(sensor_msgs::JointState &js_msg)
int cgpio_output_digitals[2]
Definition: report_data.h:192
void exit_sig_handler(int signum)
#define PRINT_HEX_DATA(hex, len,...)
float tcp_offset[6]
Definition: report_data.h:149
SocketPort * arm_report
XarmRTConnection(ros::NodeHandle &root_nh, char *server_ip, xarm_api::XARMDriver &drv)
#define ROS_INFO(...)
xarm_msgs::CIOState cio_msg
void pub_cgpio_state(xarm_msgs::CIOState &cio_msg)
int cgpio_input_digitals[2]
Definition: report_data.h:191
sensor_msgs::JointState js_msg
ros::Duration elapsed
static constexpr const double GET_FRAME_RATE_HZ
bool sleep()
bool isConnectionOK(void)
XArmReportData * report_data_ptr
bool getParam(const std::string &key, std::string &s) const
static Time now()
void pub_robot_msg(xarm_msgs::RobotMsg &rm_msg)
float cgpio_input_analogs[2]
Definition: report_data.h:193
bool hasParam(const std::string &key) const
xarm_msgs::RobotMsg rm_msg
xarm_api::XARMDriver xarm_driver
#define ROS_ERROR(...)
float pose[6]
Definition: report_data.h:141
ROSCPP_DECL void waitForShutdown()
void bin32_to_8(int a, unsigned char *b)
Definition: data_type.h:25
bool reConnectReportSocket(char *server_ip)
Definition: xarm_driver.cpp:38


xarm_api
Author(s):
autogenerated on Sat May 8 2021 02:51:23