From ed1bcabad168c6ea414520a0a8f9d050c5bcc518 Mon Sep 17 00:00:00 2001
From: Daniel Rogge <drogge@tormach.com>
Date: Fri, 21 Sep 2012 09:59:08 -0500
Subject: [PATCH] Fanuc-style tool change for Lathes.  On Fanuc-controlled lathes (as well Fanuc-like lathes like Haas, Okuma, and likely others). tool changes are not commanded with an M6, and offsets are not applied with G43. Rather the T word both commands a tool change and applies offsets. The offsets on Fanuc lathe controls are stored in two separate registers: geometry and wear. The wear offset register has IDs in the 1-99 range, the geometry offset register has IDs in the 10001 - 10099 range.
  A T word followed by one or two digits causes a tool change and applies only the geometry offsets. A T word with three or four digits also applies the wear offsets.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Example:

“T01xx – selects the tool mounted in position one and activates geometry offset number one.
Txx01 – selects the wear offset register number one.
Examples:
T0101 for turret station one, applies geometry offset one, applies wear offset one.
T0111 for turret station one, applies geometry offset one, applies wear offset eleven.
The first pair of numbers is always the tool station number and geometry offset, the second pair is the wear offset register. For gang tooling, the tool station is irrelevant. For ATC, the T call must also perform a tool change request.”

The Fanuc language with respect to tool changes, geometry and wear offsets for industrial lathes is described in detail by Peter Smid in his book CNC Fundamentals. Offsets can be stored with G10 L1, where a P value less than 100 will store wear offsets and a P value between 10001 and 10099 will store geometery offsets.

The attached patch enables this method of changing tools when the correct feature is enabled in the RS274NGC section of the INI file. Default functionality is not affected by this patch.

To try it out, add the line FEATURES = 64 to the RS274NGC section of your INI file (or modify your FEATURES mask if you’re already using RS274NGC features, documented here: http://www.linuxcnc.org/docs/devel/html/remap/structure.html#_optional_interpreter_features_ini_file_configuration_a_id_sub_ini_features_a)
Also create a tool.tbl file that contains tools 1-27 and 10000-10027, with corresponding pocket numbers.

To answer the question of why you would want to use this feature:

1.	It’s a more standard way of calling out tool changes in lathe g code – programs that ran on a FANUC-controlled lathe require fewer modifications to be compatible with LCNC.
2.	It makes correcting for wear easier (no math on the part of the operator)
3.	 To hit tight tolerance with the same tool on more than one diameter - a different wear offset can be used for each diameter
a.	Example – diameter A is 2.000 -0. +0.003, diameter B is 3.000 -0.003 +0. Very hard to hit with the same tool AND wear offset.
4.	So that the program can use a nominal dimension
a.	Example: the drawing uses unilateral tolerance of 3.000 +0.002 - 0.000. Instead of programming 3.001, you can program 3.0 and use a wear offset of 0.001.

Drawbacks:
Because of the limitations of NML message size, the tool table cannot have more than 56 pockets. When wear offsets are stored in separate registers, the number of tools available to the user when using this feature is half of that 56 (28) because both wear and geometry offsets must have pocket assignments to be accessed by G10 L1 and by status.tool_table[]. Even with the NML message size changed (if this happens in the future) the Smid/Fanuc syntax limits the number of tools to 99.
---
 src/emc/rs274ngc/interp_convert.cc  |   33 ++++++++++++++++++++++++++++++---
 src/emc/rs274ngc/interp_find.cc     |    5 +++++
 src/emc/rs274ngc/interp_internal.hh |    1 +
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/emc/rs274ngc/interp_convert.cc b/src/emc/rs274ngc/interp_convert.cc
index d21a373..b8bc7c8 100644
--- a/src/emc/rs274ngc/interp_convert.cc
+++ b/src/emc/rs274ngc/interp_convert.cc
@@ -2473,6 +2473,11 @@ int Interp::convert_home(int move,       //!< G code, must be G_28 or G_30
       w_end = w_end_home;  
   }
 
+  // check for unset g28 position (Tormach only)
+  if ((end_x == 9999) || (end_z == 9999)){
+	  ERS("Cannot use G28 until G28 position has been set");
+  }
+
   // move indexers first, one at a time
   if (AA_end != settings->AA_current && settings->a_indexer)
       issue_straight_index(3, AA_end, block->line_number, settings);
@@ -3511,8 +3516,7 @@ int Interp::convert_setup_tool(block_pointer block, setup_pointer settings) {
     CHKS(!(block->x_flag || block->y_flag || block->z_flag ||
 	   block->a_flag || block->b_flag || block->c_flag ||
 	   block->u_flag || block->v_flag || block->w_flag ||
-	   block->r_flag || block->q_flag || block->i_flag ||
-           block->j_flag),
+	   block->r_flag || block->q_flag || block->i_flag),
 	 _("G10 L1 without offsets has no effect"));
 
     if(direct) {
@@ -5097,6 +5101,8 @@ int Interp::convert_tool_length_offset(int g_code,       //!< g_code being execu
                                       setup_pointer settings)   //!< pointer to machine settings                 
 {
   int index;
+  int geo_offset_register = 0;
+  int wear_offset_register = 0;
   EmcPose tool_offset;
   ZERO_EMC_POSE(tool_offset);
 
@@ -5128,6 +5134,23 @@ int Interp::convert_tool_length_offset(int g_code,       //!< g_code being execu
     tool_offset.u = USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.u);
     tool_offset.v = USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.v);
     tool_offset.w = USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.w);
+    if (FEATURE(LATHE_TOOLCHANGE)) {
+		if (block->t_number > 99 && block->t_number<10000) {
+			geo_offset_register = floor(block->t_number/100) + 10000;	// geometery offset is first two digits of T call, plus 10000 offset
+			wear_offset_register = block->t_number % 100;	// wear offset is second two digits
+		} else if (block->t_number < 100) {
+			geo_offset_register = block->t_number + 10000;	// per Smit (p.404 CNC Fundamentals) geo offsets are offset by 10000
+		}
+		CHP((find_tool_pocket(settings, geo_offset_register, &index)));
+		tool_offset.tran.x = USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.tran.x);
+		tool_offset.tran.z = USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.tran.z);
+		if (block->t_number > 99) {
+			CHP((find_tool_pocket(settings, wear_offset_register, &index)));
+			// wear offsets are stored in the actual tool value register (e.g. T1 X Z stores wear, T10001 X Z stores geo offsets)
+			tool_offset.tran.x += USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.tran.x);
+			tool_offset.tran.z += USER_TO_PROGRAM_LEN(settings->tool_table[index].offset.tran.z);
+		}
+	 }
   } else if (g_code == G_43_1) {
     tool_offset = settings->tool_offset;
     index = -1;
@@ -5140,7 +5163,7 @@ int Interp::convert_tool_length_offset(int g_code,       //!< g_code being execu
     if(block->u_flag) tool_offset.u = block->u_number;
     if(block->v_flag) tool_offset.v = block->v_number;
     if(block->w_flag) tool_offset.w = block->w_number;
-  } else {
+	} else {
     ERS("BUG: Code not G43, G43.1, or G49");
   }
   USE_TOOL_LENGTH_OFFSET(tool_offset);
@@ -5202,6 +5225,10 @@ int Interp::convert_tool_select(block_pointer block,     //!< pointer to a block
   SELECT_POCKET(pocket, block->t_number);
   settings->selected_pocket = pocket;
   settings->selected_tool = block->t_number;
+  if (FEATURE(LATHE_TOOLCHANGE)) {
+	CHP(convert_tool_change(settings));
+	CHP(convert_tool_length_offset(G_43, block, settings));
+	} 
   return INTERP_OK;
 }
 
diff --git a/src/emc/rs274ngc/interp_find.cc b/src/emc/rs274ngc/interp_find.cc
index a28d099..323db6b 100644
--- a/src/emc/rs274ngc/interp_find.cc
+++ b/src/emc/rs274ngc/interp_find.cc
@@ -707,6 +707,11 @@ double Interp::find_turn(double x1,      //!< X-coordinate of start point
 
 int Interp::find_tool_pocket(setup_pointer settings, int toolno, int *pocket)
 {
+    if (FEATURE(LATHE_TOOLCHANGE)) {
+		if (toolno > 99 && toolno < 10000) {
+			toolno = floor(toolno / 100);
+		}
+	}
     if(!settings->random_toolchanger && toolno == 0) {
         *pocket = 0;
         return INTERP_OK;
diff --git a/src/emc/rs274ngc/interp_internal.hh b/src/emc/rs274ngc/interp_internal.hh
index 66a8924..b0b0e19 100644
--- a/src/emc/rs274ngc/interp_internal.hh
+++ b/src/emc/rs274ngc/interp_internal.hh
@@ -723,6 +723,7 @@ typedef struct setup_struct
     // do not lowercase named params inside comments - for #<_hal[PinName]>
 #define FEATURE_NO_DOWNCASE_OWORD    0x00000010
 #define FEATURE_OWORD_WARNONLY       0x00000020
+#define FEATURE_LATHE_TOOLCHANGE     0x00000040
 
     boost::python::object pythis;  // boost::cref to 'this'
     const char *on_abort_command;
-- 
1.7.0.4

