Introduction And History
For quite a long time we have wanted additiona features added to the NIST RS274.NGC interpreter. Keith Rumley spoke of some of his modifications at the first fest in Detroit. That fest was named EMC-Monday. In general the issues include
- differing behavior of the g90 commands over time.
- subroutines
- lathe code
- threading and tapping
Several of these issues were addressed in code submitted to the emc branch at
SourceForge about the same time it was decided to move development to the emc2 branch. Further stress was added by forks that produced different code for emc2 interpreter than were used for the emc changes. These two divergent systems require that we now merge these systems by hand.
Once the merge is completed, it is essential that the new interpreter be tested extensively to satisfy all that it is good. The good pronouncement will be made by the EMC board as soon as test procedures have been established and results confirmed.
Summary of Actions
A branch will be setup in the emc2 module that will allow ken, keith, and others to work out source for the new interpreter. The following is a brief discussion on IRC that led up to this.
- <lerman_> I'm going to take a current EMC2 tar file, make some changes to the interpreter, test them, and send the changed file to alex_joni (who seems to know what he is doing). At that time, he can make a branch and check the stuff in (I mean commit a change). See, I told you that I'm an RCS type of guy.
- <rayh> we would just merge back in the changed interpreter files?
- <alex_joni> not merge, first commit..
- <alex_joni> merge back to HEAD after it's proven to work
- <rayh> I guess I was hoping that we could employ several folk to work on this all at the same time.
- <rayh> that is the advantage of CVS.
- <cradek> lerman_: don't you have cvs access?
- <lerman_> How many lines is a small change?
- <alex_joni> lerman_: certainly not more than 200
- <alex_joni> but the basic idea is to keep added functionality in a commit
- <lerman_> I don't have CVS write access (because I'm afraid of it). And I've forgotten most of what I learned about CVS from reading a one page tutorial, but I could relearn it. Yeah, I'll do that.
- <alex_joni> not add more than one feature at a time...
- <alex_joni> lerman_: don't be afraid to ask for commands
- <cradek> lerman_: any screwup can be fixed.
- <lerman_> Is there a requirement that each commit be tested before and work before it is committed?
- <cradek> lerman_: if you are a programmer, especially one who has used another revision control system, you can use cvs successfully with the man page "in hand"
- <lerman_> cradek: yes, I know.
- <cradek> I certainly have to use the man page for anything other than update/commit
- <lerman_> I would be surprised if the entire subroutine functionality took more than 200 lines.
- <alex_joni> yup, same here, especially for working with branches
- <SWPadnos> It's getting the sandbox created that's the hardest. After that, all you need is cvs up or cvs ci
- <alex_joni> lerman_: rumley's latest commit is 25kB
- <rayh> IMO if we call this a Ken branch, you can do any sort of commit you like and that works for your co-conspirators.
- <lerman_> So, if a line is 50 characters, it is 500 lines.
- <lerman_> Would the head poobah in charge of the CVS repository for emc2 kindly make me a developer? [Damn, I didn't want to do that. I had planned on avoiding responsibility for anything.}
Ken Lerman Stuff
Additonal interpreter functions that are needed:
- Subroutines
- Looping construct
- Conditional construct
See: SubroutineSample for some code that uses this. For a fairly complex example see JMKsFusee.
I, Kenneth Lerman, the originator of this page have NO G code experience. I'm a programmer and compiler designer who does have some idea of what I'd like. Feel free to change this stuff so that it makes sense for this environment. Some thoughts:
- The interpreter should continue to run like an interpreter; not a compiler. This means that subroutines should be defined before they are used.
- Let's separate the G code stuff from the control stuff.
- The parameter and expression syntax of the present interpreter should be used for the new control constructs. New binary operators should be added to support comparison: GT, LT, GE, LE, EQ, NE -- representing greater than, less than, greater than or equal to, less than or equal to, equal to, and not equal to, respectively. The equal and not equal operators should indicate equal if the value is within (absolute value strictly less than) a TOLERANCE. For now, assume that TOLERANCE is .0001.
In the examples below, things in italics are my comments.
- Onnnnn sub declare the beginning of a subroutine
- the subroutine body goes here
- Onnnnn endsub end of subroutine declaration - the nnnnn must match the nnnnn in the sub line
- Onnnnn while [expression] begin loop do it while [expression] is true
- the body of the loop goes here
- Onnnnn endwhile end of loop - the nnnnn must match the nnnnn in the while
- Onnnnn if [expression] conditionally execute the body if [expression] is true
- the body of the conditional goes here
- Onnnnn else if the "if" wasn't true, the else part will execute
- the body of the else goes here
- Onnnnn endif end of conditional - the nnnnn must match the nnnnn in the if
- Onnnnn if [expression]
- body
- Onnnnn elseif [expression] acts like an else followed by an if
- body
- Onnnnn endif
- Onnnnn do
- this body is executed at least once
- Onnnnn while [expression]
- Onnnnn call [arg1] [arg2]... call the subroutine with the declaration nnnnn. Optional arg1, arg2,... (up to arg30) will be passed in parameters 1 to 30 in the context of the called subroutine. On return from the subroutine the original values of those parameters will be restored. The args are full expressions that are evaluated in the calling context. Subroutines may call other subroutines (even recursively) with a maximum nesting level of ten.
- The following is not strictly needed, but software programmers find them handy
- Onnnnn return return from the containing subroutine
- Onnnnn break break out of the while with label Onnnnn -- this will skip down until the matchining endwhile, and may break out of multiple nested whiles.
- Onnnnn continue skip down to the end of the while with label Onnnnn. If it was a do...while, the while will be evaluated and the loop repeated if appropriate. If it was a while...endwhile, the endwhile will execute which takes control back to the matching while.
Some notes:
- Each of these control blocks begins with an Onnnnn word. That makes easier for the parser to know what it is doing and isn't a problem for the user. I have to admit, though, that writing "callsub Onnnnn" seems more natural than writing "Onnnnn callsub".
- Subroutine declarations may NOT be nested.
- Subroutines may be called anywhere (but must be declared before they are called. They may be called from other subroutines, and may be called recursively if it makes sense.
- while and if may be nested. They may not overlap without nesting.
- When the interpreter scans a sub block, it remembers the location of the next line in the file and associates it with the "O" number. It continues scanning, skipping lines until it sees the matching Onnnnn endsub.
- When the interpreter scans a callsub, it pushes (saves) the current location in the input file (on a stack). It then goes to the location in the file associated with the Onnnnn and starts interpretation there.
- When the interpreter scans a return, it pops the stack and continues interpretation where it left off. When it interprets an endsub, it treats it like a return.
- When the interpreter scans a while, it remembers the location of the Onnnnn. If the expression is true (values close to zero are treated as zero), it continues execution. If the expression was not true, it skips execution of all of the blocks until it finds the matching Onnnnn.
- When the interpreter scans an endwhile, it restarts interpretation at the location of the remembered Onnnnn. (Assumng it wasn't skipping. If it was skipping, it ignores the endwhile).
- if is treated exactly as while.
- The matching endif is ignored if the interpreter was skipping. Interpretation is turned back on (skipping is ended).
I believe these definitions should provide a lot of functionality at very low implementation cost. Comments, suggestions, etc are always welcome.
Keith Rumley Stuff
The following email describes what Keith is thinking about a migration of their work to the EMC2 branch. Some lines are quoted from an earlier post.
I was typing this out to reply on list, but since I'm not on IRC, and wouldn't be able to make it tomorrow, anyway, perhaps the following would be useful as a starting point.
>> The real problem is that the interpreter that Ken is talking
>> about is in emc not emc2 nor BDI. This is an issue that we
Back in May I did a test compile with the EMC1 interpreter plugged into EMC2.
It took about a few hours, but was easier than I expected. (Wholesale replacement of the EMC2 RS274NGC/ with EMC1 rs274ngc_new/. Replacement of emctask/emctask.cc emctask/emc_canon.cc and emctask/canon_pre.cc, update to emc.cc and emc.hh as below.)
>> will need to resolve in the next few days. Perhaps this
>> weekend, during the IRC on Sunday (hint
>> hint) we can study enough of it out to work out the steps
>> need to make this possible.
For an actual merge, my understanding is that the following would need to be addressed:
- 1. Agreement on what to migrate Then,
- 2. Move features to separate files for given functions/commands and update the related function calls and error messages. The AND/OR/IS/ISNT and /*AA*/ etc stuff would need cleaned out of the EMC1 code. rs274ngc.hh has a fair amount of change, as well.
- 3. Harmonize emc.ini files
- 4. Harmonize the emctask/ files emctask.cc, emccanon.cc, and canon_pre.cc with their EMC2 equivalents. This primarily involves changes to features being migrated. (expanded ini-file variable passing to the interpreter)
- 5. Harmonize the emcnml/ files emc.cc and emc.hh Reference interpreter-determined array sizes to rs274ngc.hh, instead of hard-coding them.
- emc.hh:
- ...
- #include "rs274ngc.hh"
- ...
- #define EMC_TASK_ACTIVE_G_CODES RS274NGC_ACTIVE_G_CODES;
- #define EMC_TASK_ACTIVE_M_CODES RS274NGC_ACTIVE_M_CODES;
- #define EMC_TASK_ACTIVE_SETTINGS RS274NGC_ACTIVE_SETTINGS;
- ...
- emc.cc:
- ...
- void EMC_TASK_STAT::update(CMS *cms)
- ...
- cms->update(activeGCodes,EMC_TASK_ACTIVE_G_CODES);
- cms->update(activeMCodes,EMC_TASK_ACTIVE_M_CODES);
- cms->update(activeSettings,EMC_TASK_ACTIVE_SETTINGS);
- 6. Documenting the features/changes
Having worked a lot with the interpreter, I'm interested in how this issue develops, and would like to help if I can. I'm at my limits for time is the other issue.
If you and the folks on IRC Sunday can come up with a list, I could perhaps incrementally work away at it.
Regards,
Keith
Attached is a review of the EMC1 interpreter changes, between mine and those
KL has made.
1. G92 bugs cleared up (after M02, abort, affected commands G92 aware)
2. G92 P<1-9> modifier (lets the coordinate systems be set directly to value given, vs using G10 L2 and entering desired position in absolute coordinates to get the same thing )
3. G92 is modal, and mode is retained in the active code display. Lets you know it's on/off/stored.
4. G54-G59.3 commands turn off and save G92 offsets. A switch may be set in the ini file to keep them in effect.
5. Subroutines and conditional evaluation commands added.
6. User M code implementation expanded and cleaned up. Two examples are in emc/programs/M101, M102.c
7. Multiple user M codes, and M62-M65's may be on one line. M62-M65 get priority.
8. User m-codes are executed in the order they appear on the line.
(within the groups M62-M65, and then the general user m code group.)
Incidentally general user m-codes execute last of any m-codes on a line.
9. M62-M65 throw an error if they get invalid values. (negative values)
10. Error checking for P/Q values back in place, and user M code handling for them.
11. MS-DOS format files are allowed.
12. Semi-colons may be used for comments
13. An incremental retract peck-drilling cycle added, G83.1.
14. MDI command error checks now displayed.
15. Bug fix for pseudo random motion when a command issued from MDI before previous motion was complete.
16. New files (including same file) may be (re)opened without having to run or 'verify' them first.
17. Ini file control of a number of interpreter options, some previously compile-time only.
17.1 Allow files without '%' and 'M02/M30' file delimiters
17.2 Skip comment reading. Speeds up g-code parsing if you've lots of comments
17.3 Keep current coordinate system in effect after M02/M30
17.4 Coordinate system to use as default after M02/M30
17.5 Keep G92 axis offsets after M02/M30
17.6 Keep G92 axis offsets after G59-G59.3 (old default behavior, obviates P2 modifier)
17.7 G83 rapid down distance above bottom of hole
17.8 G83.1 rapid retract increment
17.9 Tolerance setting for what is considered logically equal in expressions
17.10 Tolerance setting for arc endpoints, inch
17.11 Tolerance setting for arc endpoints, mm
17.12 Tolerance setting for concavity, inside corners, cutter compensation.