/* $FabBSD$ */ /* * Copyright (c) 2009 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Block processing routines. * * [1] Thomas R. Kramer, Frederick M. Proctor, and Elena Messina, The NIST * RS274NGC Interpreter - Version 3, National Institute of Standards and * Technology, NISTIR 6556, August 2000. */ #include #include #include #include #include #include #include #include #include "ngc.h" /* * XXX * A: Inserer blocks G0, G1, G2, ... artificiellement * en preprocessing. * * B: Garder flags pour G0, G1, G2, ... dans la state. * XXX */ /* Delay execution for a specified amount of time */ static int dwell(struct ngc_block *blk, struct ngc_word *w) { struct ngc_word *P; if ((P = ngc_getparam(blk,'P')) != NULL) { if (P->data.i < 0) { cnc_set_error("G4: P cannot be negative"); return (-1); } sleep(P->data.i); } else { cnc_set_error("G4: missing P argument"); return (-1); } return (0); } /* * Set spindle speed */ static int spindle_set_speed(struct ngc_block *blk, struct ngc_word *w) { if (w->data.i < 0) { cnc_set_error("S cannot be negative"); return (-1); } ngc_spinspeed = w->data.i; /* TODO spindle(4) */ return (0); } /* * Select a tool */ static int tool_set(struct ngc_block *blk, struct ngc_word *w) { if (w->data.i < 0) { cnc_set_error("T cannot be negative"); return (-1); } /* XXX TODO: validate tool# with atc(4) */ ngc_tool = w->data.i; /* TODO issue atc(4) prepare */ return (0); } /* Initiate a tool change */ static int tool_change(struct ngc_block *blk, struct ngc_word *w) { /* TODO issue atc(4) change */ return (0); } /* Set the cutter radius offset. */ static int set_cutter_radius_offs(struct ngc_block *blk, struct ngc_word *w) { struct ngc_word *D; if (w->data.i == 40) { /* G40 */ ngc_cromode = NGC_CUTTER_OFFS_OFF; return (0); } if (ngc_cromode != NGC_CUTTER_OFFS_OFF) { cnc_set_error("G%d: Cutter radius offset is already on", w->data.i); return (-1); } if (ngc_planesel != NGC_PLANE_XY) { cnc_set_error("G%d: the XY plane is not active", w->data.i); return (-1); } ngc_cromode = (w->data.i == 41) ? NGC_CUTTER_OFFS_LEFT : NGC_CUTTER_OFFS_RIGHT; if ((D = ngc_getparam(blk,'D')) != NULL) { if (D->data.i < 0) { cnc_set_error("G%d: D cannot be negative", w->data.i); return (-1); } /* XXX TODO: validate tool# with atc(4) */ } return (0); } /* Set the tool length offset. */ static int set_tool_length_offs(struct ngc_block *blk, struct ngc_word *w) { struct ngc_word *H; switch (w->data.i) { case 43: if ((H = ngc_getparam(blk,'H')) == NULL) { cnc_set_error("G43: missing H parameter"); return (-1); } if (H->data.i < 0) { cnc_set_error("G43: H cannot be negative"); return (-1); } /* XXX TODO: validate tool# with atc(4) */ ngc_tlo = H->data.i; return (0); case 49: ngc_tlo = 0; return (0); } return (0); } /* Rapid motion to given position */ static int fastmove(ngc_vec_t *nPos) { struct cnc_velocity Vp; cnc_vec_t kPos; int i; for (i = 0; i < NGC_NAXES; i++) { kPos.v[i] = (ngc_axis_types[i] == NGC_LINEAR) ? nPos->v[i]*ngc_linscale : nPos->v[i]*ngc_rotscale; } Vp.v0 = 100; /* XXX use machine default! */ Vp.F = (cnc_vel_t)(ngc_feedfast*ngc_feedscale); Vp.Amax = (cnc_vel_t)10; /* XXX use machine default! */ Vp.Jmax = (cnc_vel_t)10; /* XXX use machine default! */ if (!ngc_simulate) { return cncmove(&Vp, &kPos); } else { return (0); } } /* Return to home (through an optional intermediate point). */ static int gohome(struct ngc_block *blk, struct ngc_word *w) { ngc_vec_t T, Tint; int i, j; /* Move to intermediate position if specified */ T = ngc_pos; if (ngc_axiswords_to_vec(blk, &Tint) > 0) { if (fastmove(&Tint) == -1) { cnc_set_error("G%d: moving to intermediate point: %s", w->data.i, cnc_get_error()); return (-1); } } /* Move to home position (#5161 or #5181) */ for (i = 0, j = ((w->data.i == 28) ? 5161 : 5181); i < NGC_NAXES; i++) { T.v[i] = ngc_params[j]; } return fastmove(&T); } /* Set coordinate system (or "work offset") origin */ static int setcsysorigin(struct ngc_block *blk, struct ngc_word *w) { struct ngc_word *P, *a; int i, b; if ((P = ngc_getparam(blk, 'P')) == NULL) { cnc_set_error("G10 L2: missing P number"); return (-1); } if (P->data.i < 1 || P->data.i > 9) { cnc_set_error("G10 L2: invalid P number %d", P->data.i); return (-1); } b = ngc_csys_bases[P->data.i]; for (i = 0; i < NGC_NAXES; i++) { if ((a = ngc_getparam(blk, ngc_axis_words[i]))) ngc_params[b+i] = a->data.f; } return (0); } /* Set coordinate system axis offsets. */ static int setcsysoffset(struct ngc_block *blk, struct ngc_word *w) { struct ngc_word *a; int i; for (i = 0; i < NGC_NAXES; i++) { if (ngc_getparam(blk, ngc_axis_words[i]) != NULL) break; } if (i == NGC_NAXES) { cnc_set_error("G%d: missing axis words", w->data.i); return (-1); } switch (w->data.i) { case 92: /* Set/save axis offsets */ for (i = 0; i < NGC_NAXES; i++) { if ((a = ngc_getparam(blk, ngc_axis_words[i])) != NULL) { ngc_csys_offset[i] += ngc_pos.v[i] - a->data.f; ngc_params[5211+i] = ngc_csys_offset[i]; } } break; case 92001: /* Reset/save axis offsets */ for (i = 0; i < NGC_NAXES; i++) { ngc_csys_offset[i] = 0.0; ngc_params[5211+i] = 0.0; } break; case 92002: /* Reset axis offsets */ for (i = 0; i < NGC_NAXES; i++) { ngc_csys_offset[i] = 0.0; } break; case 92003: /* Load axis offsets */ for (i = 0; i < NGC_NAXES; i++) { ngc_csys_offset[i] = ngc_params[5211+i]; } break; } return (0); } /* Perform rapid linear motion (G0) */ static int movelinear_fast(struct ngc_block *blk) { ngc_vec_t nPos; /* Compute the target vector */ nPos = ngc_pos; if (ngc_axiswords_to_vec(blk, &nPos) < 1) { cnc_set_error("G0: All axis words are omitted"); return (-1); } return fastmove(&nPos); } /* Perform linear motion at feedrate (G1) */ static int movelinear_feed(struct ngc_block *blk) { struct cnc_velocity Vp; ngc_vec_t nPos; cnc_vec_t kPos; ngc_real_t F; int i; /* Compute the target vector. */ nPos = ngc_pos; if (ngc_axiswords_to_vec(blk, &nPos) < 1) { cnc_set_error("G1: All axis words are omitted"); return (-1); } /* Compute the velocity profile from the desired feedrate. */ switch (ngc_feedmode) { case NGC_UNITS_PER_MIN: Vp.v0 = 100; /* XXX use machine default! */ Vp.F = (cnc_vel_t)(ngc_feedrate*ngc_feedscale); Vp.Amax = (cnc_vel_t)10; /* XXX use machine default! */ Vp.Jmax = (cnc_vel_t)10; /* XXX use machine default! */ F = ngc_feedrate*ngc_feedscale; break; case NGC_ONE_OVER_MIN: /* XXX TODO */ cnc_set_error("G93 mode not yet implemented"); return (-1); } for (i = 0; i < NGC_NAXES; i++) { kPos.v[i] = (ngc_axis_types[i] == NGC_LINEAR) ? nPos.v[i]*ngc_linscale : nPos.v[i]*ngc_rotscale; } if (!ngc_simulate) { return cncmove(&Vp, &kPos); } else { return (0); } } /* Perform circular or helical arc motion at feedrate (G2/G3) */ static int movearc_feed(struct ngc_block *blk, struct ngc_word *w) { #if 0 ngc_vec_t T; int dir = (w->data.i == 2) ? NGC_CW : NGC_CCW; T = ngc_pos; if (ngc_axiswords_to_vec(blk,&T) < 1) { cnc_set_error("G1: All axis words are omitted"); return (-1); } if (ngc_move_arc(&T, ngc_feedrate) == -1) { return (-1); } return (0); cnc_set_error("unimplemented arcs"); return (-1); #endif return (0); } /* * Execute an instruction block. The order of processing is described on * p.41 of [1]. At this point, we assume that previously enabled modal * commands have been inserted into the block in preprocessing. */ int ngc_block_exec(struct ngc_prog *prog, int iBlk) { struct ngc_block *blk = &prog->blks[iBlk]; struct ngc_word *w; int case18 = 0, rv; /* 1. Set feed rate mode */ if (ngc_getcmd(blk,'G',94)) { ngc_feedmode = NGC_UNITS_PER_MIN; } else if (ngc_getcmd(blk,'G',93)) { ngc_feedmode = NGC_ONE_OVER_MIN; } /* 2. Set feed rate */ if ((w = ngc_getparam(blk,'F')) != NULL) { ngc_feedrate = (ngc_feedmode == NGC_UNITS_PER_MIN) ? ngc_units_to_mm(w->data.f) : w->data.f; } else if (ngc_feedmode == NGC_ONE_OVER_MIN) { if (ngc_getcmd(blk,'G',1) || ngc_getcmd(blk,'G',2) || ngc_getcmd(blk,'G',3)) { cnc_set_error("G93: missing F-word"); return (-1); } } /* 3. Set spindle speed */ if ((w = ngc_getparam(blk,'S')) != NULL && spindle_set_speed(blk, w)) { return (-1); } /* 4. Select tool */ if ((w = ngc_getparam(blk,'T')) != NULL && tool_set(blk, w) == -1) { return (-1); } /* 5. Apply tool changes */ if ((w = ngc_getcmd(blk,'M',6)) != NULL && tool_change(blk, w) == -1) { return (-1); } /* 6. Apply spindle commands */ if (ngc_getcmd(blk,'M',3)) { /* TODO spindle(4) start CW */ } if (ngc_getcmd(blk,'M',4)) { /* TODO spindle(4) start CCW */ } if (ngc_getcmd(blk,'M',5)) { /* TODO spindle(4) stop */ } /* 7. Apply coolant commands */ if (ngc_getcmd(blk,'M',7)) { /* TODO coolant(4) mist on */ } if (ngc_getcmd(blk,'M',8)) { /* TODO coolant(4) flood on */ } if (ngc_getcmd(blk,'M',9)) { /* TODO coolant(4) all off */ } /* 8. Control speed/feed override switches. */ if (ngc_getcmd(blk,'M',48)) { /* TODO cncpanel speed/feed override switch enable */ } if (ngc_getcmd(blk,'M',49)) { /* TODO cncpanel speed/feed override switch disable */ } /* 9. Dwell */ if ((w = ngc_getcmd(blk,'G',4)) != NULL) { if (dwell(blk, w) == -1) return (-1); } /* 10. Plane selection */ if (ngc_getcmd(blk,'G',17)) { ngc_planesel = NGC_PLANE_XY; } else if (ngc_getcmd(blk,'G',18)) { ngc_planesel = NGC_PLANE_ZX; } else if (ngc_getcmd(blk,'G',19)) { ngc_planesel = NGC_PLANE_YZ; } /* 11. Unit selection */ if (ngc_getcmd(blk,'G',20)) { ngc_units = NGC_INCH; } else if (ngc_getcmd(blk,'G',21)) { ngc_units = NGC_METRIC; } /* 12. Set cutter radius offset */ if ((w = ngc_getcmd(blk,'G',40)) != NULL || (w = ngc_getcmd(blk,'G',41)) != NULL || (w = ngc_getcmd(blk,'G',42)) != NULL) { if (set_cutter_radius_offs(blk, w) == -1) return (-1); } /* 13. Set tool length offset */ if ((w = ngc_getcmd(blk,'G',43)) != NULL || (w = ngc_getcmd(blk,'G',49)) != NULL) { if (set_tool_length_offs(blk, w) == -1) return (-1); } /* 14. Select coordinate system (or "work offset") */ if (ngc_getcmd(blk,'G',54)) { ngc_csys = 1; } else if (ngc_getcmd(blk,'G',55)) { ngc_csys = 2; } else if (ngc_getcmd(blk,'G',56)) { ngc_csys = 3; } else if (ngc_getcmd(blk,'G',57)) { ngc_csys = 4; } else if (ngc_getcmd(blk,'G',58)) { ngc_csys = 5; } else if (ngc_getcmd(blk,'G',59)) { ngc_csys = 6; } else if (ngc_getcmd(blk,'G',59001)) { ngc_csys = 7; } else if (ngc_getcmd(blk,'G',59002)) { ngc_csys = 8; } else if (ngc_getcmd(blk,'G',59003)) { ngc_csys = 9; } /* 15. Set path control mode */ if (ngc_getcmd(blk,'G',61)) { ngc_pathctl = NGC_EXACT_PATH; } else if (ngc_getcmd(blk,'G',61001)) { ngc_pathctl = NGC_EXACT_STOP; } else if (ngc_getcmd(blk,'G',64)) { ngc_pathctl = NGC_CONT_PATH; } /* 16. Set distance mode */ if (ngc_getcmd(blk,'G',90)) { ngc_distmode = NGC_ABSOLUTE; } else if (ngc_getcmd(blk,'G',91)) { ngc_distmode = NGC_INCREMENTAL; } /* 17. Set retract mode */ if (ngc_getcmd(blk,'G',99)) { ngc_distmode = NGC_RETRACT_PREVIOUS; } else if (ngc_getcmd(blk,'G',98)) { ngc_distmode = NGC_RETRACT_POSITION; } /* 18 (case A). Return to home (G28/G30) */ case18 = 0; if ((w = ngc_getcmd(blk,'G',28)) != NULL || (w = ngc_getcmd(blk,'G',30)) != NULL) { case18 = 1; if (gohome(blk, w) == -1) return (-1); } /* 18 (case B). Set coordinate system origin (G10 L2) */ if ((w = ngc_getcmd(blk,'G',10)) != NULL) { struct ngc_word *L; if (((L = ngc_getparam(blk,'L'))) && L->data.i == 2) { if (case18 != 0) { cnc_set_error("G10 L2: conflicts with G28/G30"); return (-1); } case18 = 2; if (setcsysorigin(blk, w) == -1) return (-1); } } /* * 18 (case C). Set coordinate system offset (also known as "position * register" with Fanuc controllers). */ if ((w = ngc_getcmd(blk,'G',92)) != NULL || (w = ngc_getcmd(blk,'G',92001)) != NULL || (w = ngc_getcmd(blk,'G',92002)) != NULL || (w = ngc_getcmd(blk,'G',94)) != NULL) { if (case18 != 0) { cnc_set_error("G%d: conflicts with %s", w->data.i, (case18 == 1) ? "G28/G30" : "G10 L2"); return (-1); } if (setcsysoffset(blk, w) == -1) return (-1); } /* * 19. Perform motion. */ rv = 0; if (ngc_getcmd(blk,'G',0)) { rv = movelinear_fast(blk); } else if (ngc_getcmd(blk,'G',1)) { rv = movelinear_feed(blk); } else if ((w = ngc_getcmd(blk,'G',2)) || (w = ngc_getcmd(blk,'G',3))) { rv = movearc_feed(blk, w); } if (rv == -1) return (-1); return (0); }