post_processor.cpp
Go to the documentation of this file.
2 
3 namespace fanuc_post_processor
4 {
5 
7  program_name_("ros"),
8  program_comment_(""),
9  permissions_(READ_WRITE),
10  applicative_(""),
11  line_numbers_(true),
12  for_count_(0)
13 {
14 }
15 
17 {
18 }
19 
20 unsigned FanucPostProcessor::generatePrograms(std::vector<std::pair<ProgramName, Program>> &output_programs,
21  const unsigned lines_per_program)
22 {
23  output_programs.clear();
24 
25  if (lines_per_program == 1)
26  {
27  ROS_ERROR_STREAM("Need at least 2 instructions per program");
28  return 0;
29  }
30 
31  const unsigned number_of_programs(
32  lines_per_program == 0 ? 1 : std::ceil((double)commands_.size() / lines_per_program));
33 
34  if (number_of_programs > 999)
35  {
36  ROS_ERROR_STREAM("More than 999 programs would be generated: " << number_of_programs);
37  return 0;
38  }
39 
40  std::string program;
41  unsigned program_id(0);
42  unsigned line_count(0);
43 
44  std::map<unsigned, FanucPose> poses_in_program; // key is the original pose ID, FanucPose contains the 'new' pose ID
45  ProgramName program_name;
46  for (unsigned cmd_id(0); cmd_id < commands_.size(); ++cmd_id)
47  {
48  // Initialize program
49  if (program.empty())
50  {
51  // PROG
52  program.append("/PROG ");
53  program_name = program_name_;
54  if (!tweakProgramName(program_name, program_id))
55  return 0;
56  program.append(program_name);
57  program.append("\n");
58 
59  // ATTR
60  program.append("/ATTR");
61  program.append("\n");
62  program.append("COMMENT = \"" + program_comment_ + "\";");
63  program.append("\n");
64  program.append("PROTECT = " + permissionsToString(permissions_) + ";");
65  program.append("\n");
66 
67  // Default group
68  if (!poses_.empty() && poses_.front().groups_.size() > 4)
69  {
70  ROS_ERROR_STREAM("Poses have more than 4 groups");
71  return 0;
72  }
73 
74  std::string default_group("1,*,*,*,*");
75 
76  if (!poses_.empty())
77  {
78  default_group = "";
79  const unsigned number_of_groups(poses_.front().groups_.size());
80 
81  // Add group
82  for (unsigned i(0); i < number_of_groups; ++i)
83  {
84  if (default_group.size() == 8) // Last group case
85  default_group.append("1");
86  else
87  default_group.append("1,");
88  }
89 
90  // Add empty
91  for (unsigned i(0); i < 5 - number_of_groups; ++i)
92  {
93  if (default_group.size() == 8) // Last group case
94  default_group.append("*");
95  else
96  default_group.append("*,");
97  }
98  }
99 
100  program.append("DEFAULT_GROUP = " + default_group + ";");
101  program.append("\n");
102 
103  // APPL
104  if (!applicative_.empty())
105  {
106  program.append("/APPL\n");
107  program.append(" " + applicative_ + ";");
108  program.append("\n");
109  }
110 
111  // MN
112  program.append("/MN");
113  program.append("\n");
114  }
115 
116  if (std::shared_ptr<FanucPoseCommand> pose_cmd = std::dynamic_pointer_cast<FanucPoseCommand>(commands_.at(cmd_id)))
117  {
118  // Check if pose is in the map
119  if (poses_in_program.find(pose_cmd->pose_.pose_id_) == poses_in_program.end())
120  {
121  // Pose is not in the map, we assign it a new ID and add it to the map
122  FanucPose modified_pose(pose_cmd->pose_);
123  modified_pose.pose_id_ = poses_in_program.size() + 1; // Pose ID starts at 1 (not zero)
124  poses_in_program.insert(std::pair<unsigned, FanucPose>(pose_cmd->pose_.pose_id_, modified_pose));
125  }
126  // If pose is in the map we don't need to do anything
127 
128  std::string line(poses_in_program.find(pose_cmd->pose_.pose_id_)->second.getMainLineString());
129  prependLineNumber(line, line_count++);
130  program.append(line);
131  }
132  else if (std::shared_ptr<FanucStringCommand> str_cmd = std::dynamic_pointer_cast<FanucStringCommand>(
133  commands_.at(cmd_id)))
134  {
135  std::string line(str_cmd->cmd_);
136  prependLineNumber(line, line_count++);
137  program.append(line);
138  }
139  else
140  {
141  ROS_ERROR_STREAM("Un-recognized FanucCommand!");
142  return 0;
143  }
144  program.append("\n");
145 
146  // Program limit hit
147  if (lines_per_program != 0 && line_count == lines_per_program - 1)
148  {
149  // Don't add a CALL if this is also the last command of the program
150  if (cmd_id == commands_.size() - 1)
151  break;
152 
153  ProgramName next_program_name(program_name_);
154  if (!tweakProgramName(next_program_name, program_id + 1))
155  return 0;
156 
157  std::string call_line("CALL " + next_program_name + " ;\n");
158  prependLineNumber(call_line, line_count++);
159  program.append(call_line);
160 
161  // POS
162  program.append("/POS");
163  program.append("\n");
164 
165  for (auto pose_map : poses_in_program)
166  program.append(pose_map.second.getPoseLinesString());
167 
168  // END
169  program.append("/END\n\n");
170 
171  output_programs.push_back(std::pair<ProgramName, Program>(program_name, program));
172  ++program_id;
173  line_count = 0;
174  program.clear();
175  poses_in_program.clear();
176  }
177  }
178 
179  // End of commands, finish last program generated
180  // POS
181  program.append("/POS");
182  program.append("\n");
183 
184  for (auto pose_map : poses_in_program)
185  program.append(pose_map.second.getPoseLinesString());
186 
187  // END
188  program.append("/END\n\n");
189  output_programs.push_back(std::pair<ProgramName, Program>(program_name, program));
190  return output_programs.size();
191 }
192 
194 {
195  commands_.clear();
196  poses_.clear();
197  labels_id_.clear();
198 }
199 
200 void FanucPostProcessor::useLineNumbers(bool line_numbers)
201 {
202  line_numbers_ = line_numbers;
203 }
204 
205 void FanucPostProcessor::uploadToFtp(const std::vector<std::pair<ProgramName, Program>> programs,
206  const std::string ip_address,
207  const std::string port_number,
208  const std::string username,
209  const std::string password)
210 {
211  // Write programs on disk
212  for (auto &program : programs)
213  {
214  std::ofstream ls_program;
215  ls_program.open("/tmp/" + program.first + ".ls");
216  if (!ls_program.is_open())
217  throw std::runtime_error("Could not open /tmp/" + program.first + ".ls for writing");
218 
219  ls_program << program.second;
220  ls_program.close();
221 
222  // Upload to the robot
223  ROS_INFO_STREAM("Trying to upload " + program.first + ".ls at " + ip_address);
224  try
225  {
227  curlite.set(CURLOPT_URL, "ftp://@" + ip_address + ":" + port_number + "/\\" + program.first + ".ls");
228  curlite.set(CURLOPT_USERNAME, username);
229  curlite.set(CURLOPT_PASSWORD, password);
230  curlite.set(CURLOPT_UPLOAD, true);
231 
232  // Open input file stream
233  std::ifstream ifs("/tmp/" + program.first + ".ls", std::ios::binary);
234  ifs >> curlite;
235 
236  double total_secs = curlite.getInfo<double>(CURLINFO_TOTAL_TIME);
237  ROS_INFO_STREAM("Upload time: " << total_secs << " s");
238  }
239  catch (std::exception &e)
240  {
241  throw std::runtime_error(e.what());
242  }
243  }
244 }
245 
247 {
248  if (name.empty())
249  throw std::runtime_error("Program name cannot be empty");
250  if (name.find(' ') != std::string::npos)
251  throw std::runtime_error("Program name cannot contain a space");
252  if (name.size() > program_name_max_size_)
253  name.resize(program_name_max_size_);
254 
255  program_name_ = name;
256  std::transform(program_name_.begin(), program_name_.end(), program_name_.begin(), ::toupper);
257 }
258 
259 void FanucPostProcessor::setProgramComment(const std::string comment)
260 {
261  program_comment_ = comment;
262 }
263 
265 {
266  permissions_ = perms;
267 }
268 
269 void FanucPostProcessor::setApplicative(const std::string appl)
270 {
271  applicative_ = appl;
272 }
273 
275 {
276  if (!pose.isValid())
277  throw std::runtime_error("Pose is not valid");
278 
279  if (!poses_.empty() && !pose.hasSameGroupsAxes(poses_.front()))
280  throw std::runtime_error("Pose does not have the same groups/axes of the first pose in the program");
281 
282  if (poses_.empty())
283  pose.pose_id_ = 1;
284  else
285  pose.pose_id_ = poses_.back().pose_id_ + 1;
286 
287  poses_.push_back(pose);
288  std::shared_ptr<FanucPoseCommand> cmd = std::make_shared<FanucPoseCommand>(pose);
289  commands_.push_back(cmd);
290 }
291 
292 void
294 {
295  if (pose.pose_id_ == 0)
296  throw std::runtime_error("Invalid pose id (0)");
297 
298  for (auto pose_tmp : poses_)
299  {
300  if (pose_tmp.pose_id_ == pose.pose_id_)
301  {
302  pose.groups_.clear(); // Remove these fields to avoid confusion
303  std::shared_ptr<FanucPoseCommand> cmd = std::make_shared<FanucPoseCommand>(pose);
304  cmd->pose_.groups_ = pose_tmp.groups_; // Copy robot pose
305 
306  if (!cmd->pose_.isValid())
307  throw std::runtime_error("Pose is not valid");
308 
309  commands_.push_back(cmd);
310  return;
311  }
312  }
313 
314  throw std::runtime_error("Pose ID " + std::to_string(pose.pose_id_) + " was not found");
315 }
316 
317 void FanucPostProcessor::appendComment(const std::string comment)
318 {
319  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("!" + comment + ";");
320  commands_.push_back(cmd);
321 }
322 
324 {
325  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(";");
326  commands_.push_back(cmd);
327 }
328 
329 void FanucPostProcessor::appendDigitalOutput(const unsigned digital_out_id,
330  const bool state)
331 {
332  const std::string DO_id(std::to_string(digital_out_id));
333  const std::string on_off(state == true ? "ON" : "OFF");
334  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("DO[" + DO_id + "]=" + on_off + ";");
335  commands_.push_back(cmd);
336 }
337 
338 void FanucPostProcessor::appendDigitalOutput(const unsigned digital_out_id,
339  const double pulse_time)
340 {
341  if (pulse_time <= 0)
342  throw std::runtime_error("Pulse time must be > 0");
343 
344  const std::string digital_output_id(std::to_string(digital_out_id));
345  std::ostringstream ss;
346  ss.imbue(std::locale("C")); // To ensure dot as a decimal separator
347  ss << std::fixed << std::setprecision(2);
348  ss << pulse_time;
349  const std::string time = ss.str();
350  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(
351  "DO[" + digital_output_id + "]=PULSE," + time + "sec;");
352  commands_.push_back(cmd);
353 }
354 
355 void FanucPostProcessor::appendWait(const double time)
356 {
357  if (time <= 0)
358  throw std::runtime_error("Time must be >= 0");
359 
360  std::ostringstream ss;
361  ss.imbue(std::locale("C")); // To ensure dot as a decimal separator
362  ss << std::fixed << std::setprecision(2);
363  ss << time;
364  const std::string duration = ss.str();
365  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("WAIT " + duration + "(sec);");
366  commands_.push_back(cmd);
367 }
368 
369 void FanucPostProcessor::appendWait(const unsigned digital_in_id,
370  bool state)
371 {
372  const std::string DI_id(std::to_string(digital_in_id));
373  const std::string DI_state(state ? "ON" : "OFF");
374  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(
375  "WAIT DI[" + DI_id + "]=" + DI_state + ";");
376  commands_.push_back(cmd);
377 }
378 
379 void FanucPostProcessor::appendUFrame(const unsigned uf_id)
380 {
381  if (uf_id > 9)
382  throw std::runtime_error("UFrame number exceeds maximum of 9, UFrame ID given = " + std::to_string(uf_id));
383 
384  const std::string uframe(std::to_string(uf_id));
385  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("UFRAME_NUM=" + uframe + ";");
386  commands_.push_back(cmd);
387 }
388 
389 void FanucPostProcessor::appendUTool(const unsigned ut_id)
390 {
391  if (ut_id == 0 || ut_id > 9)
392  throw std::runtime_error("UTool ID must be between 1 and 9. UTool ID given = " + std::to_string(ut_id));
393 
394  const std::string utool(std::to_string(ut_id));
395  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("UTOOL_NUM=" + utool + ";");
396  commands_.push_back(cmd);
397 }
398 
400  const unsigned value)
401 {
402  const std::string group_id(std::to_string(id));
403  const std::string group_value(std::to_string(value));
404  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(
405  "GO[" + group_id + "]=" + group_value + ";");
406  commands_.push_back(cmd);
407 }
408 
409 void FanucPostProcessor::appendSetRegister(const unsigned r_id,
410  const double value)
411 {
412  if (r_id == 0)
413  throw std::runtime_error("Register ID starts at 1. 0 Given register ID = 0");
414 
415  const std::string id(std::to_string(r_id));
416  std::ostringstream ss;
417  ss.imbue(std::locale("C")); // To ensure dot as a decimal separator
418  ss << std::fixed << std::setprecision(2);
419  ss << value;
420  const std::string r_value = ss.str();
421  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("R[" + id + "]=" + r_value + ";");
422  commands_.push_back(cmd);
423 }
424 
425 void FanucPostProcessor::appendCall(const std::string program_name)
426 {
427  std::string name(program_name);
428  std::transform(name.begin(), name.end(), name.begin(), ::toupper);
429  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("CALL " + name + ";");
430  commands_.push_back(cmd);
431 }
432 
433 void FanucPostProcessor::appendRun(const std::string program_name)
434 {
435  std::string name(program_name);
436  std::transform(name.begin(), name.end(), name.begin(), ::toupper);
437  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("RUN " + name + ";");
438  commands_.push_back(cmd);
439 }
440 
441 void FanucPostProcessor::appendLabel(const unsigned id)
442 {
443  // Search if label is used, if not return false
444  for (std::vector<unsigned>::iterator iter(labels_id_.begin()); iter != labels_id_.end(); ++iter)
445  if (*iter == id)
446  throw std::runtime_error("Label ID does not exist. Given label ID = " + std::to_string(id));
447  labels_id_.push_back(id); // Label "id" is now available in appendJumpLabel
448 
449  const std::string lbl_id(std::to_string(id));
450  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("LBL[" + lbl_id + "];");
451  commands_.push_back(cmd);
452 }
453 
454 void FanucPostProcessor::appendJumpLabel(const unsigned id)
455 {
456  // Do not check if label is available, it might be declared after the JUMP
457  const std::string lbl_id(std::to_string(id));
458  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("JMP LBL[" + lbl_id + "];");
459  commands_.push_back(cmd);
460 }
461 
463 {
464  const std::string datamon_id(std::to_string(id));
465  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("Sample Start[" + datamon_id + "];");
466  commands_.push_back(cmd);
467 }
468 
470 {
471  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("Sample End;");
472  commands_.push_back(cmd);
473 }
474 
475 void FanucPostProcessor::appendFor(const unsigned reg_id,
476  const std::string start,
477  const std::string stop)
478 {
479  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(
480  "FOR R[" + std::to_string(reg_id) + "]=" + start + " TO " + stop + ";");
481  commands_.push_back(cmd);
482  ++for_count_;
483 }
484 
485 void FanucPostProcessor::appendFor(const unsigned reg_id,
486  const unsigned start,
487  const unsigned stop)
488 {
489  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(
490  "FOR R[" + std::to_string(reg_id) + "]=" + std::to_string(start)
491  + " TO " + std::to_string(stop) + ";");
492  ++for_count_;
493 }
494 
496 {
497  if (for_count_ == 0)
498  throw std::runtime_error("Cannot append ENDFOR without appending a FOR first.");
499 
500  --for_count_;
501  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>("ENDFOR;");
502  commands_.push_back(cmd);
503 }
504 
505 void FanucPostProcessor::appendCustomCommand(const std::string command)
506 {
507  std::shared_ptr<FanucStringCommand> cmd = std::make_shared<FanucStringCommand>(command + ";");
508  commands_.push_back(cmd);
509 }
510 
511 bool FanucPostProcessor::getPoseFromId(const unsigned pose_id,
512  FanucPose &pose)
513 {
514  bool found = false;
515  for (auto pose_tmp : poses_)
516  {
517  if (pose_tmp.pose_id_ == pose_id)
518  {
519  pose = pose_tmp;
520  found = true;
521  break;
522  }
523  }
524 
525  return found;
526 }
527 
529  const unsigned number)
530 {
531  if (!line_numbers_)
532  {
533  line.insert(0, ":");
534  return;
535  }
536 
537  if (number > 99999)
538  throw std::runtime_error("Line number exceeds 99999! Line number = " + std::to_string(number));
539 
540  std::string line_header(std::to_string(number));
541  line_header.append(":");
542 
543  int characters_to_be_added(6 - line_header.size());
544  if (characters_to_be_added < 0)
545  throw std::runtime_error("Error computing line number characters");
546 
547  for (unsigned i(0); i < (unsigned)characters_to_be_added; ++i)
548  line_header.insert(0, " ");
549 
550  line.insert(0, line_header);
551 }
552 
554  const unsigned number)
555 {
556  std::string twk_name(name);
557  unsigned digit_count(std::to_string(number).size());
558  if (digit_count > program_name_max_size_)
559  return false;
560 
561  int offset(0);
562  while (twk_name.size() + digit_count + offset > program_name_max_size_)
563  --offset;
564 
565  if (offset < 0)
566  twk_name.erase(twk_name.size() + offset, -offset);
567  twk_name.append(std::to_string(number));
568 
569  name = twk_name;
570  return true;
571 }
572 
573 }
Fanuc post-processor.
Definition: axis.hpp:6
void appendGroupOutput(const unsigned id, const unsigned value)
void appendCall(const std::string program_name)
bool line_numbers_
void appendComment(const std::string comment)
void setPermissions(const FanucPostProcessor::Permissions perms)
Definition: pose.hpp:12
FanucPostProcessor()
Default Constructor.
void appendCustomCommand(const std::string command)
std::string ProgramName
bool isValid() const
Definition: pose.cpp:113
void appendSetRegister(const unsigned r_id, const double value)
void prependLineNumber(std::string &line, const unsigned number)
~FanucPostProcessor()
std::string program_name_
unsigned generatePrograms(std::vector< std::pair< ProgramName, Program >> &output_programs, const unsigned lines_per_program=0)
void appendPose(FanucPose &pose)
std::string program_comment_
void appendPoseId(FanucPose &pose)
void appendJumpLabel(const unsigned id)
unsigned pose_id_
Definition: pose.hpp:119
void appendLabel(const unsigned id)
std::vector< FanucGroup > groups_
Definition: pose.hpp:129
void appendDigitalOutput(const unsigned digital_out_id, const bool state)
bool tweakProgramName(ProgramName &name, const unsigned number)
void appendEndFor()
std::vector< unsigned > labels_id_
Permissions
void setProgramName(std::string name)
std::string applicative_
ValueType getInfo(CURLINFO key, ValueType const &defaultValue=ValueType())
Definition: curlite.hpp:343
void appendEmptyLine()
void useLineNumbers(bool line_numbers)
const unsigned program_name_max_size_
std::vector< FanucPose > poses_
bool getPoseFromId(const unsigned pose_id, FanucPose &pose)
std::vector< std::shared_ptr< FanucCommand > > commands_
void appendDataMonitorStart(const unsigned id)
void setProgramComment(const std::string comment)
bool set(CURLoption opt, ValueType value)
Definition: curlite.hpp:297
#define ROS_INFO_STREAM(args)
bool hasSameGroupsAxes(const FanucPose &other) const
Definition: pose.cpp:91
void setApplicative(const std::string appl)
void appendWait(const double time)
void appendUFrame(const unsigned uf_id)
unsigned for_count_
void clearProgram()
void uploadToFtp(const std::vector< std::pair< ProgramName, Program >> programs, const std::string ip_address, const std::string port_number="21", const std::string username="", const std::string password="")
#define ROS_ERROR_STREAM(args)
void appendUTool(const unsigned ut_id)
std::string permissionsToString(Permissions perm)
void appendFor(const unsigned reg_id, const std::string start, const std::string stop)
void appendRun(const std::string program_name)
FanucPostProcessor::Permissions permissions_
void appendDataMonitorStop()


fanuc_post_processor
Author(s): Victor Lamoine - Institut Maupertuis
autogenerated on Mon Jun 10 2019 13:16:56