khi_robot_krnx_driver.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, Kawasaki Heavy Industries, LTD.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include <urdf/model.h>
36 #include <khi_robot_krnx_driver.h>
37 
38 namespace khi_robot_control
39 {
40 #define KHI_ROBOT_WD002N "WD002N"
41 #define KHI_ROBOT_RS007L "RS007L"
42 #define KHI_ROBOT_RS007N "RS007N"
43 #define KHI_ROBOT_RS080N "RS080N"
44 #define KHI_KRNX_BUFFER_SIZE 4
45 #define KHI_KRNX_ACTIVATE_TH 0.02
46 #define KHI_KRNX_M2MM 1000
47 
49 {
50  driver_name = __func__;
51  for ( int cno = 0; cno < KRNX_MAX_CONTROLLER; cno++ )
52  {
53  rtc_data[cno].seq_no = 0;
54  sw_dblrefflt[cno] = 0;
55  }
56 }
57 
59 {
60  int state;
61 
62  for ( int cno = 0; cno < KRNX_MAX_CONTROLLER; cno++ )
63  {
64  state = getState( cno );
65  if ( ( state != INIT ) && ( state != DISCONNECTED ) )
66  {
67  infoPrint("destructor");
68  close( cno );
69  }
70  }
71 }
72 
73 bool KhiRobotKrnxDriver::setState( const int& cont_no, const int& state )
74 {
75  std::lock_guard<std::mutex> lock( mutex_state[cont_no] );
76 
77  KhiRobotDriver::setState( cont_no, state );
78 }
79 
80 int KhiRobotKrnxDriver::execAsMonCmd( const int& cont_no, const char* cmd, char* buffer, int buffer_sz, int* as_err_code )
81 {
82  std::lock_guard<std::mutex> lock( mutex_state[cont_no] );
83 
84  return_code = krnx_ExecMon( cont_no, cmd, buffer, buffer_sz, as_err_code );
85  if ( *as_err_code != 0 )
86  {
87  warnPrint( "AS returned %d by %s", *as_err_code, cmd );
88  }
89  else
90  {
91  retKrnxRes( cont_no, "krnx_ExecMon()", return_code );
92  }
93 
94  return return_code;
95 }
96 
97 bool KhiRobotKrnxDriver::retKrnxRes( const int& cont_no, const std::string& name, const int& ret, const bool error )
98 {
99  if ( ret != KRNX_NOERROR )
100  {
101  errorPrint( "%s returned -0x%X", name.c_str(), -ret );
102  if ( error ) { setState( cont_no, ERROR ); }
103  return false;
104  }
105  else
106  {
107  return true;
108  }
109 }
110 
111 /* This function needs some communication time. Don't use this in control loop */
112 bool KhiRobotKrnxDriver::conditionCheck( const int& cont_no, const KhiRobotData& data )
113 {
114  TKrnxPanelInfo panel_info;
115  bool ret = true;
116 
117  if ( getState( cont_no ) == ERROR )
118  {
119  return false;
120  }
121 
122  if ( in_simulation ) { return true; }
123 
124  for ( int ano = 0; ano < data.arm_num; ano++ )
125  {
126  /* Condition Check */
127  return_code = krnx_GetPanelInfo( cont_no, ano, &panel_info );
128  if ( !retKrnxRes( cont_no, "krnx_GetPanelInfo", return_code ) )
129  {
130  ret = false;
131  }
132 
133  if ( panel_info.repeat_lamp != -1 )
134  {
135  errorPrint( "Please change Robot Controller's TEACH/REPEAT to REPEAT" );
136  ret = false;
137  }
138  if ( panel_info.teach_lock_lamp != 0 )
139  {
140  errorPrint( "Please change Robot Controller's TEACH LOCK to OFF" );
141  ret = false;
142  }
143  else if ( panel_info.run_lamp != -1 )
144  {
145  errorPrint( "Please change Robot Controller's RUN/HOLD to RUN" );
146  ret = false;
147  }
148  else if ( panel_info.emergency != 0 )
149  {
150  errorPrint( "Please change Robot Controller's EMERGENCY to OFF" );
151  ret = false;
152  }
153  }
154 
155  if ( !ret )
156  {
157  setState( cont_no, ERROR );
158  }
159 
160  return ret;
161 }
162 
163 bool KhiRobotKrnxDriver::initialize( const int& cont_no, const double& period, KhiRobotData& data, const bool in_simulation )
164 {
165  char msg[256] = { 0 };
166 
167  // robot info
168  cont_info[cont_no].period = period;
169 
170  return_code = krnx_GetKrnxVersion( msg, sizeof(msg) );
171  infoPrint( msg );
172 
173  this->in_simulation = in_simulation;
174 
175  return true;
176 }
177 
178 bool KhiRobotKrnxDriver::open( const int& cont_no, const std::string& ip_address, KhiRobotData& data )
179 {
180  char c_ip_address[64] = { 0 };
181 
182  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
183 
184  if ( getState( cont_no ) != INIT )
185  {
186  warnPrint( "Cannot open cont_no:%d because it is already opend...", cont_no );
187  return false;
188  }
189 
190  if ( in_simulation )
191  {
192  setState( cont_no, CONNECTING );
193  setState( cont_no, INACTIVE );
194  return true;
195  }
196 
197 
198  setState( cont_no, CONNECTING );
199  strncpy( c_ip_address, ip_address.c_str(), sizeof(c_ip_address) );
200  infoPrint( "Connecting to real controller: %s", c_ip_address );
201  return_code = krnx_Open( cont_no, c_ip_address );
202  if ( return_code == cont_no )
203  {
204  cont_info[cont_no].ip_address = ip_address;
205  if ( !loadDriverParam( cont_no, data ) ) { return false; };
206 
207  setState( cont_no, INACTIVE );
208  return true;
209  }
210  else
211  {
212  retKrnxRes( cont_no, "krnx_Open", return_code, false );
213  setState( cont_no, INIT );
214  return false;
215  }
216 }
217 
218 bool KhiRobotKrnxDriver::close( const int& cont_no )
219 {
220  char msg[1024] = { 0 };
221 
222  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
223 
224  if ( in_simulation )
225  {
226  setState( cont_no, DISCONNECTING );
227  setState( cont_no, DISCONNECTED );
228  return true;
229  }
230 
231  /* Switch Reversion */
232  if ( sw_dblrefflt[cont_no] == -1 )
233  {
234  snprintf( msg, sizeof(msg), "SW ZDBLREFFLT_MODSTABLE=ON" );
235  return_code = execAsMonCmd( cont_no, msg, msg_buf, sizeof(msg_buf), &error_code );
236  }
237 
238  setState( cont_no, DISCONNECTING );
239  return_code = krnx_Close( cont_no );
240  if ( return_code == KRNX_NOERROR )
241  {
242  setState( cont_no, DISCONNECTED );
243  }
244 
245  return retKrnxRes( cont_no, "krnx_Close", return_code, false );
246 }
247 
248 bool KhiRobotKrnxDriver::activate( const int& cont_no, KhiRobotData& data )
249 {
250  const int to_home_vel = 20; /* speed 20 */
251  const double timeout_sec_th = 5.0; /* 5 sec */
252  bool is_ready;
253  TKrnxCurMotionData motion_data = { 0 };
254  double timeout_sec_cnt = 0.0;
255  int conv = 1;
256  float diff = 0;
257  int error_lamp = 0;
258  TKrnxPanelInfo panel_info;
259  TKrnxProgramInfo program_info;
260  int arm_num = data.arm_num;
261 
262  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
263 
264  setState( cont_no, ACTIVATING );
265  if ( !conditionCheck( cont_no, data ) ) { return false; }
266 
267  if ( in_simulation )
268  {
269  setRobotDataHome( cont_no, data );
270  setState( cont_no, ACTIVE );
271  return true;
272  }
273 
274  /* Preparation */
275  bool is_cycle = true;
276  for ( int ano = 0; ano < arm_num; ano++ )
277  {
278  return_code = krnx_GetCurErrorLamp( cont_no, ano, &error_lamp );
279  if ( retKrnxRes( cont_no, "krnx_GetCurErrorLamp", return_code ) && ( error_lamp != 0 ) )
280  {
281  /* Error Reset */
282  return_code = krnx_Ereset( cont_no, ano, &error_code );
283  }
284  return_code = krnx_GetPanelInfo( cont_no, ano, &panel_info );
285  if ( retKrnxRes( cont_no, "krnx_GetPanelInfo", return_code ) )
286  {
287  if ( panel_info.cycle_lamp != -1 )
288  {
289  is_cycle = false;
290  }
291  if ( panel_info.motor_lamp != -1 )
292  {
293  /* Motor Power ON */
294  return_code = execAsMonCmd( cont_no, "ZPOW ON", msg_buf, sizeof(msg_buf), &error_code );
295  /* Error Reset */
296  return_code = krnx_Ereset( cont_no, ano, &error_code );
297  }
298  }
299  /* Clear RTC Comp Data */
300  return_code = krnx_OldCompClear( cont_no, ano );
301  }
302  if ( is_cycle )
303  {
304  for ( int ano = 0; ano < arm_num; ano++ )
305  {
306  return_code = krnx_GetProgramInfo( cont_no, ano, &program_info );
307  if ( retKrnxRes( cont_no, "krnx_GetProgramInfo", return_code ) )
308  {
309  std::stringstream program;
310  program << "rb_rtc" << ano + 1;
311  if ( strcmp( program_info.robot[ano].program_name, program.str().c_str() ) == 0 )
312  {
313  /* Already ROS Control */
314  setState( cont_no, ACTIVE );
315  return true;
316  }
317  else
318  {
319  /* Not ROS Control */
320  return_code = krnx_Hold( cont_no, ano, &error_code );
321  ros::Duration(0.2).sleep();
322  }
323  }
324  }
325  }
326 
327  /* Sync RTC Position */
328  if ( !syncRtcPos( cont_no, data ) )
329  {
330  errorPrint( "Failed to sync position" );
331  setState( cont_no, ERROR );
332  return false;
333  }
334 
335  /* Set HOME position */
336  for ( int ano = 0; ano < arm_num; ano++ )
337  {
338  /* Speed SLOW */
339  return_code = krnx_SetMonSpeed( cont_no, ano, to_home_vel, &error_code );
340  /* Executing base program */
341  std::stringstream program;
342  program << "rb_rtc" << ano + 1;
343  return_code = krnx_Execute( cont_no, ano, program.str().c_str(), 1, 0, &error_code );
344 
345  while ( 1 )
346  {
347  ros::Duration(cont_info[cont_no].period/1e+9).sleep();
348  timeout_sec_cnt += cont_info[cont_no].period/1e+9;
349  if ( timeout_sec_cnt > timeout_sec_th )
350  {
351  errorPrint( "Failed to activate: timeout" );
352  setState( cont_no, ERROR );
353  return false;
354  }
355 
356  return_code = krnx_GetRtcSwitch( cont_no, ano, &rtc_data[cont_no].sw );
357  if ( ( return_code != KRNX_NOERROR ) || ( rtc_data[cont_no].sw == 0 ) ) { continue; }
358 
359  return_code = krnx_GetCurMotionData( cont_no, ano, &motion_data );
360  if ( return_code != KRNX_NOERROR ) { continue; }
361 
362  is_ready = true;
363  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
364  {
365  if ( data.arm[ano].type[jt] == urdf::Joint::PRISMATIC ) { conv = KHI_KRNX_M2MM; }
366  else { conv = 1; }
367 
368  diff = data.arm[ano].home[jt]*conv - motion_data.ang[jt];
369  if ( fabs(diff) > KHI_KRNX_ACTIVATE_TH )
370  {
371  is_ready = false;
372  break;
373  }
374  }
375 
376  if ( is_ready )
377  {
378  /* Speed 100 */
379  return_code = krnx_SetMonSpeed( cont_no, ano, 100, &error_code );
380  break;
381  }
382  }
383  }
384 
385  if ( !conditionCheck( cont_no, data ) ) { return false; }
386 
387  setState( cont_no, ACTIVE );
388 
389  return true;
390 }
391 
392 bool KhiRobotKrnxDriver::hold( const int& cont_no, const KhiRobotData& data )
393 {
394  int state;
395  bool ret = true;
396 
397  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
398 
399  state = getState( cont_no );
400  if ( state == ACTIVE )
401  {
402  ret = setState( cont_no, HOLDED );
403  }
404 
405  return ret;
406 }
407 
408 bool KhiRobotKrnxDriver::deactivate( const int& cont_no, const KhiRobotData& data )
409 {
410  char msg[1024] = { 0 };
411  int error_lamp = 0;
412 
413  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
414 
415  if ( in_simulation )
416  {
417  setState( cont_no, DEACTIVATING );
418  setState( cont_no, INACTIVE );
419  return true;
420  }
421 
422  setState( cont_no, DEACTIVATING );
423 
424  for ( int ano = 0; ano < data.arm_num; ano++ )
425  {
426  /* Hold Program */
427  return_code = krnx_Hold( cont_no, ano, &error_code );
428  ros::Duration(0.2).sleep();
429  /* Kill Program */
430  return_code = krnx_Kill( cont_no, ano, &error_code );
431  /* Motor Power OFF */
432  return_code = execAsMonCmd( cont_no, "ZPOW OFF", msg_buf, sizeof(msg_buf), &error_code );
433  return_code = krnx_GetCurErrorLamp( cont_no, ano, &error_lamp );
434  if ( retKrnxRes( cont_no, "krnx_GetCurErrorLamp", return_code ) && ( error_lamp != 0 ) )
435  {
436  /* Error Reset */
437  return_code = krnx_Ereset( cont_no, ano, &error_code );
438  }
439  }
440 
441  setState( cont_no, INACTIVE );
442 
443  return true;
444 }
445 
446 bool KhiRobotKrnxDriver::loadDriverParam( const int& cont_no, KhiRobotData& data )
447 {
448  char robot_name[64] = { 0 };
449  char msg[256] = { 0 };
450  TKrnxPanelInfo panel_info;
451  int jt_num = 0;
452 
453  int arm_num = data.arm_num;
454 
455  if ( arm_num <= 0 )
456  {
457  errorPrint( "Invalid robot size" );
458  return false;
459  }
460 
461  for ( int ano = 0; ano < arm_num; ano++ )
462  {
463  /* Robot Name */
464  return_code = krnx_GetRobotName( cont_no, ano, robot_name );
465  if ( strncmp( robot_name, data.robot_name.c_str(), 6 ) != 0 )
466  {
467  errorPrint( "ROS Robot:%s does not match AS:%s", data.robot_name.c_str(), robot_name );
468  return false;
469  }
470 
471  /* AS Switch */
472  return_code = execAsMonCmd( cont_no, "TYPE SWITCH(ZDBLREFFLT_MODSTABLE)", msg_buf, sizeof(msg_buf), &error_code );
473  if ( retKrnxRes( cont_no, msg, return_code ) )
474  {
475  sw_dblrefflt[cont_no] = atoi(msg_buf);
476  if ( sw_dblrefflt[cont_no] == -1 )
477  {
478  return_code = execAsMonCmd( cont_no, "SW ZDBLREFFLT_MODSTABLE=OFF", msg_buf, sizeof(msg_buf), &error_code );
479  }
480  }
481 
482  /* Joint num */
483  snprintf( msg, sizeof(msg), "TYPE SYSDATA(ZROB.NOWAXIS,%d)", ano+1 );
484  return_code = execAsMonCmd( cont_no, msg, msg_buf, sizeof(msg_buf), &error_code );
485  if ( retKrnxRes( cont_no, msg, return_code ) )
486  {
487  jt_num = atoi(msg_buf);
488  if ( data.arm[ano].jt_num != jt_num )
489  {
490  warnPrint( "ROS JT:%d does not match AS:%d", data.arm[ano].jt_num, jt_num );
491  }
492  }
493 
494  return_code = krnx_GetPanelInfo( cont_no, ano, &panel_info );
495  if ( retKrnxRes( cont_no, "krnx_GetPanelInfo", return_code ) && ( panel_info.cycle_lamp != 0 ) )
496  {
497  /* Hold Program */
498  return_code = krnx_Hold( cont_no, ano, &error_code );
499  if ( !retKrnxRes( cont_no, "krnx_Hold", return_code ) ) { return false; }
500  }
501 
502  /* KRNX */
503  TKrnxRtcInfo rtcont_info;
504  rtcont_info.cyc = (int)(cont_info[cont_no].period/1e+6);
505  rtcont_info.buf = KHI_KRNX_BUFFER_SIZE;
506  rtcont_info.interpolation = 1;
507  return_code = krnx_SetRtcInfo( cont_no, &rtcont_info );
508  retKrnxRes( cont_no, "krnx_SetRtcInfo", return_code );
509  krnx_SetRtcCompMask( cont_no, ano, pow( 2, data.arm[ano].jt_num ) - 1 );
510 
511  /* Kill Program */
512  return_code = krnx_Kill( cont_no, ano, &error_code );
513  if ( !retKrnxRes( cont_no, "krnx_Kill", return_code ) ) { return false; }
514 
515  /* Load Program */
516  if ( !loadRtcProg( cont_no, data.robot_name.c_str() ) )
517  {
518  errorPrint( "Failed to load RTC program");
519  return false;
520  }
521  }
522 
523  return true;
524 }
525 
529 bool KhiRobotKrnxDriver::readData( const int& cont_no, KhiRobotData& data )
530 {
531  static int sim_cnt[KHI_MAX_CONTROLLER] = { 0 };
532  static KhiRobotData prev_data = data;
533  int arm_num = data.arm_num;
534 
535  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
536 
537  if ( in_simulation )
538  {
539  for ( int ano = 0; ano < arm_num; ano++ )
540  {
541  memcpy( data.arm[ano].pos, data.arm[ano].cmd, sizeof(data.arm[ano].pos) );
542  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
543  {
544  data.arm[ano].vel[jt] = data.arm[ano].pos[jt] - prev_data.arm[ano].pos[jt];
545  }
546  }
547  prev_data = data;
548  if ( ( sim_cnt[cont_no] - 1 ) % KRNX_PRINT_TH == 0 )
549  {
550  jointPrint( std::string("read"), data );
551  }
552  sim_cnt[cont_no]++;
553  return true;
554  }
555 
556  static std::vector<TKrnxCurMotionData> motion_data[KRNX_MAX_CONTROLLER][KRNX_MAX_ROBOT];
558  float ang[KRNX_MAX_ROBOT][KRNX_MAXAXES] = {{ 0 }};
559  float vel[KRNX_MAX_ROBOT][KRNX_MAXAXES] = {{ 0 }};
560 
561  for ( int ano = 0; ano < arm_num; ano++ )
562  {
563  if ( !getCurMotionData( cont_no, ano, &motion_cur[ano] ) ) { return false; }
564 
565  if ( motion_data[cont_no][ano].size() >= KRNX_MOTION_BUF )
566  {
567  motion_data[cont_no][ano].erase( motion_data[cont_no][ano].begin() );
568  }
569  motion_data[cont_no][ano].push_back( motion_cur[ano] );
570 
571  // ang
572  memcpy( ang[ano], &motion_cur[ano].ang, sizeof(motion_cur[ano].ang) );
573  // vel
574  if ( motion_data[cont_no][ano].size() > 1 )
575  {
576  std::vector<TKrnxCurMotionData>::iterator it = motion_data[cont_no][ano].end();
577  it--;
578  for ( int jt=0; jt < KHI_MAX_JOINT; jt++ )
579  {
580  vel[ano][jt] = motion_data[cont_no][ano].back().ang[jt] - it->ang[jt];
581  }
582  }
583 
584  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
585  {
586  data.arm[ano].pos[jt] = (double)ang[ano][jt];
587  data.arm[ano].vel[jt] = (double)vel[ano][jt];
588  data.arm[ano].eff[jt] = (double)0; // tmp
589 
590  /* [ mm ] to [ m ] */
591  if ( data.arm[ano].type[jt] == urdf::Joint::PRISMATIC )
592  {
593  data.arm[ano].pos[jt] /= KHI_KRNX_M2MM;
594  data.arm[ano].vel[jt] /= KHI_KRNX_M2MM;
595  }
596  }
597  }
598 
599  return true;
600 }
601 
602 bool KhiRobotKrnxDriver::getCurMotionData( const int& cont_no, const int& robot_no, TKrnxCurMotionData* p_motion_data )
603 {
604  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
605 
606  return_code = krnx_GetCurMotionData( cont_no, robot_no, p_motion_data );
607 
608  return retKrnxRes( cont_no, "krnx_GetCurMotionData", return_code );
609 }
610 
611 bool KhiRobotKrnxDriver::setRobotDataHome( const int& cont_no, KhiRobotData& data )
612 {
613  KhiRobotData base;
614  int arm_num = data.arm_num;
615 
616  if ( data.robot_name == KHI_ROBOT_WD002N )
617  {
618  data.arm[0].home[0] = -45.0f*M_PI/180;
619  data.arm[0].home[1] = 45.0f*M_PI/180;
620  data.arm[1].home[0] = 45.0f*M_PI/180;
621  data.arm[1].home[1] = -45.0f*M_PI/180;
622  data.arm[0].home[2] = data.arm[1].home[2] = 90.0f/KHI_KRNX_M2MM;
623  data.arm[0].home[3] = data.arm[1].home[3] = 0.0f;
624  }
625  else
626  {
627  for ( int ano = 0; ano < arm_num; ano++ )
628  {
629  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
630  {
631  data.arm[ano].home[jt] = 0.0f;
632  }
633  }
634  }
635 
636  for ( int ano = 0; ano < arm_num; ano++ )
637  {
638  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
639  {
640  data.arm[ano].cmd[jt] = data.arm[ano].pos[jt] = data.arm[ano].home[jt];
641  }
642  }
643 
644  return true;
645 }
646 
650 bool KhiRobotKrnxDriver::writeData( const int& cont_no, const KhiRobotData& data )
651 {
652  static int sim_cnt[KHI_MAX_CONTROLLER] = { 0 };
653  int idx, ano, jt;
654  char msg[1024] = { 0 };
655  char status[128] = { 0 };
656  TKrnxCurMotionData motion_data;
657  float jt_pos = 0.0F;
658  float jt_vel = 0.0F;
659  bool is_primed = true;
660  int arm_num = data.arm_num;
661  KhiRobotKrnxRtcData* p_rtc_data = &rtc_data[cont_no];
662 
663  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
664 
665  if ( getState( cont_no ) != ACTIVE ) { return true; }
666 
667  if ( in_simulation )
668  {
669  if ( ( sim_cnt[cont_no] - 1 ) % KRNX_PRINT_TH == 0 )
670  {
671  jointPrint( std::string("write"), data );
672  }
673  sim_cnt[cont_no]++;
674  return true;
675  }
676 
677  /* convert */
678  for ( int ano = 0; ano < arm_num; ano++ )
679  {
680  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
681  {
682  p_rtc_data->comp[ano][jt] = (float)(data.arm[ano].cmd[jt] - data.arm[ano].home[jt]);
683  if ( data.arm[ano].type[jt] == urdf::Joint::PRISMATIC )
684  {
685  p_rtc_data->comp[ano][jt] *= KHI_KRNX_M2MM;
686  }
687  }
688  }
689 
690  for ( int ano = 0; ano < arm_num; ano++ )
691  {
692  return_code = krnx_PrimeRtcCompData( cont_no, ano, &p_rtc_data->comp[ano][0], &p_rtc_data->status[ano][0] );
693  if ( !retKrnxRes( cont_no, "krnx_PrimeRtcCompData", return_code ) ) { is_primed = false; }
694  }
695  if ( !is_primed )
696  {
697  /* ERROR log */
698  for ( int ano = 0; ano < arm_num; ano++ )
699  {
700  snprintf( msg, sizeof(msg), "[krnx_PrimeRtcCompData] ano:%d [jt]pos:vel:status ", ano+1 );
701  krnx_GetRtcCompData( cont_no, ano, &p_rtc_data->old_comp[ano][0] );
702  getCurMotionData( cont_no, ano, &motion_data );
703  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
704  {
705  jt_pos = motion_data.ang_ref[jt];
706  jt_vel = ( p_rtc_data->comp[ano][jt] - p_rtc_data->old_comp[ano][jt] )*(1e+9/cont_info[cont_no].period);
707  if ( data.arm[ano].type[jt] == urdf::Joint::PRISMATIC )
708  {
709  jt_pos /= KHI_KRNX_M2MM;
710  jt_vel /= KHI_KRNX_M2MM;
711  }
712  snprintf( status, sizeof(status), "[%d]%.4f:%.4f:%d ", jt+1, jt_pos, jt_vel, p_rtc_data->status[ano][jt] );
713  strcat( msg, status );
714  ROS_WARN("JT%d:%f,%f,%f,%f,%f,%f", jt+1, data.arm[ano].cmd[jt], data.arm[ano].home[jt]+p_rtc_data->comp[ano][jt],p_rtc_data->old_comp[ano][jt], p_rtc_data->comp[ano][jt], data.arm[ano].home[jt], motion_data.ang_ref[jt]);
715  ROS_WARN("JT%d:%f,%f,%f,%f,%f,%f", jt+1, data.arm[ano].cmd[jt]*180/M_PI, (data.arm[ano].home[jt]+p_rtc_data->comp[ano][jt])*180/M_PI, p_rtc_data->old_comp[ano][jt]*180/M_PI, p_rtc_data->comp[ano][jt]*180/M_PI, data.arm[ano].home[jt]*180/M_PI, motion_data.ang_ref[jt]*180/M_PI);
716  }
717  errorPrint( msg );
718  }
719  return false;
720  }
721 
722  return_code = krnx_SendRtcCompData( cont_no, p_rtc_data->seq_no );
723  p_rtc_data->seq_no++;
724 
725  return retKrnxRes( cont_no, "krnx_SendRtcCompData", return_code );
726 }
727 
728 bool KhiRobotKrnxDriver::updateState( const int& cont_no, const KhiRobotData& data )
729 {
730  int error_lamp = 0;
731  int error_code = 0;
732  int state;
733  TKrnxPanelInfo panel_info;
734  int arm_num = data.arm_num;
735 
736  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
737 
738  state = getState( cont_no );
739  if ( state == ERROR )
740  {
741  for ( int ano = 0; ano < arm_num; ano++ )
742  {
743  return_code = krnx_GetPanelInfo( cont_no, ano, &panel_info );
744  if ( retKrnxRes( cont_no, "krnx_GetPanelInfo", return_code ) && ( panel_info.cycle_lamp != 0 ) )
745  {
746  /* Hold Program */
747  return_code = krnx_Hold( cont_no, ano, &error_code );
748  if ( !retKrnxRes( cont_no, "krnx_Hold", return_code ) ) { return false; }
749  }
750  }
751  }
752 
753  if ( in_simulation ) { return true; }
754 
755  for ( int ano = 0; ano < arm_num; ano++ )
756  {
757  return_code = krnx_GetCurErrorLamp( cont_no, ano, &error_lamp );
758  if ( ( state != ERROR ) && ( error_lamp != 0 ) )
759  {
760  return_code = krnx_GetCurErrorInfo( cont_no, ano, &error_code );
761  errorPrint( "AS ERROR %d: ano:%d code:%d", cont_no, ano+1, error_code );
762  setState( cont_no, ERROR );
763  return true;
764  }
765  return_code = krnx_GetRtcSwitch( cont_no, ano, &rtc_data[cont_no].sw );
766  if ( ( state != INACTIVE ) && ( rtc_data[cont_no].sw == 0 ) )
767  {
768  errorPrint( "RTC SWITCH turned OFF %d: ano:%d", cont_no, ano+1 );
769  deactivate( cont_no, data );
770  return true;
771  }
772  }
773 
774  return true;
775 }
776 
777 bool KhiRobotKrnxDriver::getPeriodDiff( const int& cont_no, double& diff )
778 {
779  if ( !contLimitCheck( cont_no, KRNX_MAX_CONTROLLER ) ) { return false; }
780  static bool buffer_enabled = false;
781  int ano = 0;
782  int buffer_length = 0;
783 
784  if ( getState( cont_no ) != ACTIVE )
785  {
786  diff = 0;
787  return true;
788  }
789 
790  if ( in_simulation )
791  {
792  diff = 0;
793  return true;
794  }
795 
796  buffer_length = krnx_GetRtcBufferLength( cont_no, ano );
797  // check if KRNX can get buffer length from KHI controller
798  if ( buffer_length > 0 )
799  {
800  buffer_enabled = true;
801  }
802 
803  if ( buffer_enabled )
804  {
805  diff = ( buffer_length - KHI_KRNX_BUFFER_SIZE ) * cont_info[cont_no].period;
806  }
807  else
808  {
809  diff = 0;
810  }
811 
812  return true;
813 }
814 
815 std::vector<std::string> KhiRobotKrnxDriver::splitString( const std::string& str, const char& del )
816 {
817  int first = 0;
818  int last = str.find_first_of( del );
819  std::vector<std::string> list;
820 
821  if ( first < str.size() )
822  {
823  std::string sub_str1( str, first, last - first );
824  list.push_back( sub_str1 );
825  first = last + 1;
826  std::string sub_str2( str, first, std::string::npos );
827  list.push_back( sub_str2 );
828  }
829 
830  return list;
831 }
832 
833 bool KhiRobotKrnxDriver::loadRtcProg( const int& cont_no, const std::string& name )
834 {
835  FILE* fp;
836  int fd;
837  char tmplt[] = "/tmp/khi_robot-rtc_param-XXXXXX";
838  char fd_path[128] = { 0 };
839  char file_path[128] = { 0 };
840  ssize_t rsize;
841 
842  fd = mkstemp(tmplt);
843 
844  if ( ( fp = fdopen( fd, "w" ) ) != NULL)
845  {
846  /* retrieve path */
847  snprintf( fd_path, sizeof(fd_path), "/proc/%d/fd/%d", getpid(), fd );
848  rsize = readlink( fd_path, file_path, sizeof(file_path) );
849  if ( rsize < 0 ) { return false; }
850 
851  /* RTC program */
852  if ( name == KHI_ROBOT_WD002N )
853  {
854  fprintf( fp, ".PROGRAM rb_rtc1()\n" );
855  fprintf( fp, " HERE #rtchome1\n" );
856  fprintf( fp, " FOR .i = 1 TO 8\n" );
857  fprintf( fp, " .acc[.i] = 0\n" );
858  fprintf( fp, " END\n" );
859  fprintf( fp, " L3ACCURACY .acc[1] ALWAYS\n" );
860  fprintf( fp, " RTC_SW 1: ON\n" );
861  fprintf( fp, "1 JMOVE #rtchome1\n" );
862  fprintf( fp, " GOTO 1\n" );
863  fprintf( fp, " RTC_SW 1: OFF\n" );
864  fprintf( fp, ".END\n" );
865  fprintf( fp, ".PROGRAM rb_rtc2()\n" );
866  fprintf( fp, " HERE #rtchome2\n" );
867  fprintf( fp, " FOR .i = 1 TO 8\n" );
868  fprintf( fp, " .acc[.i] = 0\n" );
869  fprintf( fp, " END\n" );
870  fprintf( fp, " L3ACCURACY .acc[1] ALWAYS\n" );
871  fprintf( fp, " RTC_SW 2: ON\n" );
872  fprintf( fp, "1 JMOVE #rtchome2\n" );
873  fprintf( fp, " GOTO 1\n" );
874  fprintf( fp, " RTC_SW 2: OFF\n" );
875  fprintf( fp, ".END\n" );
876  }
877  else
878  {
879  fprintf( fp, ".PROGRAM rb_rtc1()\n" );
880  fprintf( fp, " HERE #rtchome1\n" );;
881  fprintf( fp, " ACCURACY 0 ALWAYS\n" );
882  fprintf( fp, " RTC_SW 1: ON\n" );
883  fprintf( fp, "1 JMOVE #rtchome1\n" );
884  fprintf( fp, " GOTO 1\n" );
885  fprintf( fp, " RTC_SW 1: OFF\n" );
886  fprintf( fp, ".END\n" );
887  }
888  fclose( fp );
889  }
890  else
891  {
892  return false;
893  }
894 
895  return_code = krnx_Load( cont_no, file_path );
896  unlink( file_path );
897  if ( !retKrnxRes( cont_no, "krnx_Load", return_code ) ) { return false; }
898 
899  return true;
900 }
901 
902 bool KhiRobotKrnxDriver::syncRtcPos( const int& cont_no, KhiRobotData& data )
903 {
904  TKrnxCurMotionData motion_data = { 0 };
905 
906  for ( int ano = 0; ano < data.arm_num; ano++ )
907  {
908  /* Driver */
909  if ( !getCurMotionData( cont_no, ano, &motion_data ) ) { return false; }
910  for ( int jt = 0; jt < data.arm[ano].jt_num; jt++ )
911  {
912  data.arm[ano].home[jt] = (double)motion_data.ang[jt];
913  if ( data.arm[ano].type[jt] == urdf::Joint::PRISMATIC )
914  {
915  data.arm[ano].home[jt] /= KHI_KRNX_M2MM;
916  }
917  }
918  }
919 
920  return true;
921 }
922 
923 bool KhiRobotKrnxDriver::commandHandler( khi_robot_msgs::KhiRobotCmd::Request& req, khi_robot_msgs::KhiRobotCmd::Response& res)
924 {
925  int cont_no = 0;
926  char resp[KRNX_MSGSIZE] = { 0 };
927  int acode;
928  int dcode;
929  std::vector<std::string> vlist;
930  std::string api_cmd;
931  const char del = ' ';
932  int arg;
933  int onoff;
934  int state;
935  TKrnxIoInfo io;
936 
937  /* default */
938  res.driver_ret = KRNX_NOERROR;
939  res.as_ret = 0;
940  res.cmd_ret = "";
941  api_cmd = "";
942  arg = 0;
943  onoff = 0;
944 
945  if ( req.type == "as" )
946  {
947  if ( !isTransitionState( cont_no ) )
948  {
949  dcode = execAsMonCmd( cont_no, req.cmd.c_str(), resp, sizeof(resp), &acode );
950  res.driver_ret = dcode;
951  res.as_ret = acode;
952  res.cmd_ret = std::string(resp);
953  }
954  else
955  {
956  res.driver_ret = KRNX_E_BADARGS;
957  res.cmd_ret = "IS TRANSITION STATE";
958  }
959  }
960  else if ( req.type == "driver" )
961  {
962  state = getState( cont_no );
963  if ( req.cmd == "get_status" )
964  {
965  res.cmd_ret = getStateName( cont_no );
966  }
967  else if ( req.cmd == "hold" )
968  {
969  if ( state == ACTIVE )
970  {
971  setStateTrigger( cont_no, HOLD );
972  }
973  else
974  {
975  res.cmd_ret = "NOT ACTIVE STATE";
976  }
977  }
978  else if ( req.cmd == "restart" )
979  {
980  if ( ( state == INACTIVE ) || ( state == HOLDED ) || ( state == ERROR ) )
981  {
982  setStateTrigger( cont_no, RESTART );
983  }
984  else
985  {
986  res.cmd_ret = "NOT INACTIVE/HOLDED/ERROR STATE";
987  }
988  }
989  else if ( req.cmd == "quit" )
990  {
991  setStateTrigger( cont_no, QUIT );
992  }
993  else
994  {
995  vlist = splitString( req.cmd, del );
996  if ( vlist.size() == 2 )
997  {
998  api_cmd = vlist[0];
999  if ( api_cmd == "get_signal" )
1000  {
1001  dcode = krnx_GetCurIoInfo( cont_no, &io );
1002  res.driver_ret = dcode;
1003  arg = std::atoi( vlist[1].c_str() );
1004  if ( arg >= 1 && arg <= KHI_MAX_SIG_SIZE )
1005  {
1006  /* DO */
1007  onoff = io.io_do[(arg-1)/8] & ( 1 << (arg-1)%8 );
1008  }
1009  else if ( arg >= 1000 && arg <= 1000 + KHI_MAX_SIG_SIZE )
1010  {
1011  /* DI */
1012  arg -= 1000;
1013  onoff = io.io_di[(arg-1)/8] & ( 1 << (arg-1)%8 );
1014  }
1015  else if ( arg >= 2001 && arg <= 2000 + KHI_MAX_SIG_SIZE )
1016  {
1017  /* INTERNAL */
1018  arg -= 2000;
1019  onoff = io.internal[(arg-1)/8] & ( 1 << (arg-1)%8 );
1020  }
1021  else
1022  {
1023  res.driver_ret = KRNX_E_BADARGS;
1024  res.cmd_ret = "INVALID ARGS";
1025  }
1026  if ( res.driver_ret == KRNX_NOERROR )
1027  {
1028  if ( onoff ) { res.cmd_ret = "-1"; }
1029  else { res.cmd_ret = "0";}
1030  }
1031  }
1032  else if ( api_cmd == "set_signal" )
1033  {
1034  std::string as_cmd = req.cmd;
1035  as_cmd.replace( 0, strlen("set_signal"), "SIGNAL" );
1036  dcode = execAsMonCmd( cont_no, as_cmd.c_str(), resp, sizeof(resp), &acode );
1037  res.driver_ret = dcode;
1038  res.as_ret = acode;
1039  }
1040  else
1041  {
1042  res.driver_ret = KRNX_E_BADARGS;
1043  res.cmd_ret = "INVALID CMD";
1044  }
1045  }
1046  else
1047  {
1048  res.driver_ret = KRNX_E_BADARGS;
1049  res.cmd_ret = "INVALID ARGS";
1050  }
1051  }
1052  }
1053  else
1054  {
1055  res.driver_ret = KRNX_E_BADARGS;
1056  res.cmd_ret = "INVALID TYPE";
1057  }
1058 
1059  return true;
1060 }
1061 
1062 } // end of khi_robot_control namespace
DECLSPEC_IMPORT int WINAPI krnx_SetRtcInfo(int cont_no, TKrnxRtcInfo *rtc_info)
msg
DECLSPEC_IMPORT int WINAPI krnx_ExecMon(int cont_no, const char *cmd, char *buffer, int buffer_sz, int *as_err_code)
std::vector< std::string > splitString(const std::string &str, const char &del)
DECLSPEC_IMPORT int WINAPI krnx_GetPanelInfo(int cont_no, int robot_no, TKrnxPanelInfo *panelinfo)
void errorPrint(const char *format,...)
DECLSPEC_IMPORT int WINAPI krnx_Open(int cont_no, char *hostname)
#define KRNX_MAX_CONTROLLER
Definition: krnx.h:59
bool initialize(const int &cont_no, const double &period, KhiRobotData &data, const bool in_simulation=false) override
bool setState(const int &cont_no, const int &state)
float comp[KRNX_MAX_ROBOT][KRNX_MAXAXES]
DECLSPEC_IMPORT int WINAPI krnx_GetRtcCompData(int cont_no, int robot_no, float *comp)
short cyc
Definition: krnx.h:238
float old_comp[KRNX_MAX_ROBOT][KRNX_MAXAXES]
#define KHI_KRNX_M2MM
#define KHI_KRNX_ACTIVATE_TH
short emergency
Definition: krnx.h:164
short motor_lamp
Definition: krnx.h:158
bool sleep() const
KhiRobotControllerInfo cont_info[KHI_MAX_CONTROLLER]
DECLSPEC_IMPORT int WINAPI krnx_Load(int cont_no, const char *filename)
#define KRNX_MOTION_BUF
#define KHI_MAX_JOINT
short teach_lock_lamp
Definition: krnx.h:163
char internal[KRNX_MAXSIGNAL/8]
Definition: krnx.h:172
DECLSPEC_IMPORT int WINAPI krnx_OldCompClear(int cont_no, int robot_no)
int status[KRNX_MAX_ROBOT][KRNX_MAXAXES]
char io_di[KRNX_MAXSIGNAL/8]
Definition: krnx.h:171
#define KHI_MAX_CONTROLLER
#define ROS_WARN(...)
bool conditionCheck(const int &cont_no, const KhiRobotData &data)
DECLSPEC_IMPORT int WINAPI krnx_GetRobotName(int cont_no, int robot_no, char *robot_name)
short run_lamp
Definition: krnx.h:161
bool readData(const int &cont_no, KhiRobotData &data) override
KhiRobotKrnxRtcData rtc_data[KRNX_MAX_CONTROLLER]
bool writeData(const int &cont_no, const KhiRobotData &data) override
#define KHI_ROBOT_WD002N
DECLSPEC_IMPORT int WINAPI krnx_GetRtcBufferLength(int cont_no, int robot_no)
bool setRobotDataHome(const int &cont_no, KhiRobotData &data)
KhiRobotArmData arm[KHI_MAX_ARM]
DECLSPEC_IMPORT int WINAPI krnx_GetCurMotionData(int cont_no, int robot_no, TKrnxCurMotionData *md)
DECLSPEC_IMPORT int WINAPI krnx_Execute(int cont_no, int robot_no, const char *program, int exec_num, int step_num, int *as_err_code)
bool isTransitionState(const int &cont_no)
short cycle_lamp
Definition: krnx.h:159
DECLSPEC_IMPORT int WINAPI krnx_GetRtcSwitch(int cont_no, int robot_no, int *rtc_sw)
int getState(const int &cont_no)
char program_name[20]
Definition: krnx.h:192
bool setStateTrigger(const int &cont_no, const int &state_trigger)
std::string getStateName(const int &cont_no)
bool syncRtcPos(const int &cont_no, KhiRobotData &data)
bool getCurMotionData(const int &cont_no, const int &robot_no, TKrnxCurMotionData *p_motion_data)
DECLSPEC_IMPORT int WINAPI krnx_GetCurIoInfo(int cont_no, TKrnxIoInfo *ioinfo)
DECLSPEC_IMPORT int WINAPI krnx_Ereset(int cont_no, int robot_no, int *as_err_code)
DECLSPEC_IMPORT int WINAPI krnx_GetKrnxVersion(char *ver_text, int ver_len)
void jointPrint(std::string name, const KhiRobotData &data)
bool commandHandler(khi_robot_msgs::KhiRobotCmd::Request &req, khi_robot_msgs::KhiRobotCmd::Response &res) override
#define KRNX_E_BADARGS
Definition: krnx.h:98
DECLSPEC_IMPORT int WINAPI krnx_SetRtcCompMask(int cont_no, int robot_no, int mask)
std::mutex mutex_state[KRNX_MAX_CONTROLLER]
#define KRNX_NOERROR
Definition: krnx.h:97
bool updateState(const int &cont_no, const KhiRobotData &data) override
short interpolation
Definition: krnx.h:240
DECLSPEC_IMPORT int WINAPI krnx_SendRtcCompData(int cont_no, unsigned short seq_no)
DECLSPEC_IMPORT int WINAPI krnx_GetCurErrorLamp(int cont_no, int robot_no, int *error_lamp)
TKrnxStepperInfo robot[KRNX_MAX_ROBOT]
Definition: krnx.h:209
int execAsMonCmd(const int &cont_no, const char *cmd, char *buffer, int buffer_sz, int *as_err_code)
#define KHI_MAX_SIG_SIZE
ROSCPP_DECL bool del(const std::string &key)
bool deactivate(const int &cont_no, const KhiRobotData &data) override
DECLSPEC_IMPORT int WINAPI krnx_GetProgramInfo(int cont_no, int robot_no, TKrnxProgramInfo *proginfo)
DECLSPEC_IMPORT int WINAPI krnx_Close(int sd)
#define KRNX_PRINT_TH
short repeat_lamp
Definition: krnx.h:160
float ang_ref[KRNX_MAXAXES]
Definition: krnx.h:471
#define KHI_KRNX_BUFFER_SIZE
#define KRNX_MSGSIZE
bool activate(const int &cont_no, KhiRobotData &data) override
short buf
Definition: krnx.h:239
bool setState(const int &cont_no, const int &state)
bool open(const int &cont_no, const std::string &ip_address, KhiRobotData &data) override
void infoPrint(const char *format,...)
bool close(const int &cont_no) override
bool loadDriverParam(const int &cont_no, KhiRobotData &data)
DECLSPEC_IMPORT int WINAPI krnx_Kill(int cont_no, int robot_no, int *as_err_code)
bool hold(const int &cont_no, const KhiRobotData &data) override
float ang[KRNX_MAXAXES]
Definition: krnx.h:470
DECLSPEC_IMPORT int WINAPI krnx_GetCurErrorInfo(int cont_no, int robot_no, int *error_code)
#define KRNX_MAXAXES
Definition: krnx.h:66
bool getPeriodDiff(const int &cont_no, double &diff) override
bool retKrnxRes(const int &cont_no, const std::string &name, const int &ret, const bool error=true)
#define KRNX_MAX_ROBOT
Definition: krnx.h:61
void warnPrint(const char *format,...)
DECLSPEC_IMPORT int WINAPI krnx_SetMonSpeed(int cont_no, int robot_no, float speed, int *as_err_code)
DECLSPEC_IMPORT int WINAPI krnx_Hold(int cont_no, int robot_no, int *as_err_code)
DECLSPEC_IMPORT int WINAPI krnx_PrimeRtcCompData(int cont_no, int robot_no, const float *comp, int *status)
bool loadRtcProg(const int &cont_no, const std::string &name)
char io_do[KRNX_MAXSIGNAL/8]
Definition: krnx.h:170
bool contLimitCheck(const int &cont_no, const int &limit)


khi_robot_control
Author(s): nakamichi_d
autogenerated on Fri Mar 26 2021 02:34:21