What is it? Using YADRO In Detail |
Dealing with Macros for the DROIf you want to write your own macros, modify existing ones or just want to translate the existing macros to a different language, this is the place to read on. This part is not yet in the state it should be. Because it doesn't fully show all commands. It is best to look at an existing yadro.cfg-file.
Translating MacrosMost of all the user-interface that is language-dependant can be found in the macros (in the file yadro.cfg). It is no black art to translate them to a different language. There are only 3 keywords to look for. First, the macro names: Do not translate a macro who's name starts with internal! A typical line in the yadro.cfg that needs translation looks like this: Macro:AA Absolute all (X, Y, Z) The text right behind the "Macro:" is the text to be translated (in green). I'll translate them to German: French: Second user queries: getnext("Move to X/Y = 0.0"); I'll translate it to German: The other function to translate (input) and a longer example: input("Hole Circle", "Center X (Disp1):", HCCenterX, "Center Y (Disp2):", HCCenterY, "Number of holes:", HCHoles, "Diameter:", HCDiam, "Starting angle:", HCAngle); translated to German: input("Lochkreis", "Mittelpunkt X (Disp1):", HCCenterX, "Mittelpunkt Y (Disp2):", HCCenterY, "Lochzahl:", HCHoles, "Durchmesser:", HCDiam, "Startwinkel:", HCAngle);
Writing own MacrosHere, I'll go through a complete config-file and pick out the interesting parts and explain the commands on the fly. As DRO:ddisp is making progress, this example doesn't completely reflect the current YADRO.CFG-file. But it still helps to understand things. The first few lines:
The whole YADRO.CFG consists of a list of instructions. To make your life a bit easier you can have comments between macros or interpreter-commands (you'll see that in a moment). Comments start with a ";" at the leftmost position. But you don't need comments, don't you?
Everything between the symbols Interp: and :EndI (on the leftmost!) is directly sent to the interpreter. It is not stored and can not later be referenced. It is handy for setting things up.
Now axis need names. They are not hard coded into the program. They are defined. Internally, axis are numbered from 1
3 (3 axis for now). Axis number 1 being the topmost. You give names to axis with display("AxName", 1, "X") (naming axis #1 "X"). Theoretically you can give names you want, but currently, only a few characters are supported (will add more, have to design them). The names allowed for now are "X", "Y", "Z" and the diameter-sign. To get the diam.character, you write "/O".
As I said, there is a variable pool. The variables need to be declared and defined. Variables do have no scope, they are always global. You might call this ugly or bad style, but in this case it is OK, because all the code tends to be monolithic and small.
Here is a macro. Macros are bracketed by Macro: and :EndM. Macros also have names. And they need names! The name of the macro goes right behind the Macro:. Macro names can have blanks etc. in their name. All macros can be user-selected within a sorted popup-list. But macros (like this one) that start with an "internal" are filtered out (but still stored) and are not directly user executable. They work as tools/subprograms. The command display("Status", 1, 2, "abs") is just another way of telling YADRO what to display. Behind every axis value on the screen is room for displaying status information, like "mm", "inch", "abs", "rel", The first number is the number of the axis, the second number is the line for that axis. Every axis has 6 lines for status-information. To delete a status information, you send an empty string ("") to it.
Here is another macro, that has about a typical size. It is used to switch between metric and inch units. This macro also is an internal. There is a display with a new argument. display("Precision", count, PrecisionMetric) sets the precision (the decimal places behind the decimal point) for every axis. Yes, you can set different precisions and also have different units for each axis. The units are not limited to mm and inch, you can use whatever unit you want. Also you see that I have used the variable PrecisionMetric and not a number. This is good coding style, because you have to change the number only at one place. Also, you see the while statement. This is a looping statement. And it is the only one. There are no for-loops. For programers, it is important to note that after a while (<condition>) there is always a pair of {}, even for single statements. This makes life for the interpreter a bit easier to find the end of the block.
Here is the code part, that does the mayor setup of the YADRO-engine. The code is sent to the interpreter directly. Again, this means that the code is gone, as soon as it is executed. Also again, the variables and their contents is not lost. There are some things worth noting: Variables can be re-declared as often as you want. If the variable exists, the fvar statement is simply ignored. This means, the variable keeps its contents. You should not declare variables in macros that are used in loops, because it is a waist of time. The statement execmacro("internalMetric") executes (or calls) the macro named "internalMetric". Macros can have blanks in their name. If you should want to call a macro you have to write the name exactly in the same way. Case sensitive and with all blanks or whatever. So this is no good idea to call user macros. Think about what happens if your macro is translated to another language. It is best to wrap (even the smallest) macro into an internal macro if it is used both as internal and a user selectable. The statement display("Source", 1, "Dev0 * Dev0Scaling * SignX + OffsetX") is probably the most important one. And needs some explanation. If you want, you can display something different, by simply changing the statement. If you want to add two axis, the statement would look like "Dev0 * Dev0Scaling + Dev2 * Dev2Scaling". Of course, you can do this for primary ("Source") and secondary ("SecSource") axis. You can change that binding whenever you want by simply executing another display("Source" ...). What you have seen until now is a working (disregarding some left out macros) config file. But YADRO would not be YADRO if this would be all.
Here are three interesting macros. Let's have a look at the first "SM Metric" one. User selectable macros can be displayed in a pop-up list. The are alphabetically sorted. So it is wise to group them in a manner that shows which ones belong together. We do this by using abbreviations like "SM" (for "Set Metric" in this example). Also, when a user presses a key, the maco list pops up and selects the first macro that matches the key. If the user continues typing, the selection continues. If the user types "sm" (the selection is not case sensitive), the macro "SM Metric" is selected. If he presses return, the macro is executed. So the selection of the macro for setting metric units is just 3 key strokes away (s+m+<Return>). This is quite good for macros that are not used frequently, but it is obvious, that you want to use the function keys to execute macros. You can bind macros to F-keys by adding a ":BindKey" after the :EndM. So in the first macro, the :EndM:BindKey:F1 binds the function key F1 to the macro "SM Metric". In the first and second macro, I called the internal macros internalInch and internalMetric. The third macro uses a new command senddevice. Senddevice sends any string to the digital interface. You have to know what to do here and should read here for details. In this case, the "c0C" etc. sets the scale #0 to zero. All commands sent to the digital interface wait for an "OK" of the interface. Looking into the documentation (part 3), you will see that a "c0C" takes about 1 second to answer. So these 3 commands "c0C", "c1C" and "c2C" will take 3 seconds to come back. Have a look in a real cfg-file to see how I shipped around this problem. Hint: look for ShdwOffs.
Here is another macro with new things to learn. The SX-macro adds some more offset to the offset. It is stepping or incrementing/decrementing the offset. Again, let me remind how variable-redeclaration is handled: Only for the first time the interpreter finds a fvar SXoffs, the content is initialized to 0.0. Further declarations of the variable keep their value. Here is an example that shows why this is handy. The first time, the step is zero, the user changes it's value and when calling the macro a second time, the macro remembers the previous user input. That user input is processed by the statement input("Offset rel-X by value", "offset:", SXoffs). Input can have a variable number of arguments. But the number of arguments is always odd. The shortest possible form is with one argument. The first argument is always a string. This string is the title in a pop-up window that displays the other parameters (if given) and an OK-"button". If the user leaves the input-window with a return, input returns a value of 1, and the code following input and in-between the {} is executed. If input has more than one argument, it is a repeating pattern of strings and variables. So <string> <string> <var> is OK, or <string> <string> <var> <string> <var>. The input function arranges the argument in lines. On the left is a string, on the right is the value of the variable passed. These input fields call the interpreter to solve the user input. So it is legal for the user to type a "Disp1" as a value. Or to type "sin(30) + 111.033"
This macro is quite understandable with your current knowledge. It does a hole circle with a given center (in the X-Y-plane) with given number of holes and a starting angle. The macro is invoked by pressing F3 (:Bindkey:F3) Note what I do with the variable HCHoles. It first is set to 4 if it was 0. Later, HCHoles will remember the last input. The same happens to HCCenterX and HCCenterY. The statement input has been explained. Note the <string> <string> <var> <string> <var> <string> <var> <string> <var> <string> <var> pattern. Odd number of parameters! If the user leaves the input with an OK, the following code is executed, if not, just part of the setup was executed. The getnext-statement has the same pattern of arguments like the input-statement. You also noticed the sin() and cos(). YPL has other (trigonometric) functions like sinc, cos, tan, asin, acos, atan, sinh, cosh, tanh, sqrt, sqr, log, ... With what you know now, you will understand most of the other macros you find in the YADRO.CFG-file.
Here is a final example of a macro. It is at the very end of YADRO.CFG. Because of this, it is executed as the last piece of code (note the Interp:). This is the place where setup-code goes. In this case, it has one interesting property: If you have to restart YADRO or disconnect some devices to reset them, you don't want to zero all other axis. So the setup is conditional. If the user responds with a Esc to the question, the setup-code is skipped. Other commandsThere are two other commands without code snippets. They do averaging. You will see, that the readings from the scales are not very stable (depending on their quality). If you look back into part 2, you will also see, that some scales have a high theoretical resolution. display("Average", "GAT", 20, 0.01); is one of them. The "GAT" stands for Gliding Average with Threshold. GAT uses a buffer (the size is the 20 in this example) where the last readings are stored. A new reading replaces the oldest one. All values are summed up and divided by the number of readings in the buffer. Don't make buffers to big. A value of 10
20 is about OK. The bigger the buffer, the better the average value. As it is very unhandy to wait for the buffer to be filled with the actual value, there is a threshold. If the current reading differs from the average in the buffer by a value bigger than threshold (in the example 0.01), the whole averaging buffer is discarded. This way, you get right readings when you move and averaged readings that are stable when you don't move. Experiment with the values, they depend upon your scales and the speed of your PC. |