Create your own test tools and jigs

I used to work at Ushio (industrial halogen lamps) and our lamps were built in a rather keen way in 4 - 6 process steps. After each step, a length check on the coil (filament) was performed to see if the coils would still be within specification. In order to do this, (expensive) aluminium rulers were engraved and painted.
This engraving and painting was a serious problem. It was expensive, time consuming and not too accurate. So I made a small program that would print a test tool on A4 sized stickers. With some cutting and glueing, I could now make rulers within an hour for a fraction of the cost. This turned out to be escpecially handy when production managed to loose a hardcoded ruler.

Ruler: the source

MODULE Rulers;

FROM    ASCII               IMPORT  ESC, FF;
FROM    InOut               IMPORT  CloseInput, CloseOutput, RedirectInput, RedirectOutput, Done, ReadCard,
                                    ReadString, Write, WriteCard, WriteLn, WriteLine, WriteString;
FROM    RealConversions     IMPORT  StringToReal;
FROM    SYSTEM              IMPORT  ASSEMBLER;
FROM    System              IMPORT  GetArg, Terminate;
FROM    Strings             IMPORT  Append, CompareStr;
FROM    Xchar               IMPORT  ReadName, SkipUntil, UpperString;


TYPE    PrinterStatus   = (Ready, Offline);
        LineStyle       = (Solid, Dashed);
        PenState        = (Up, Down);


CONST   X0          =   100;
        Y0          =   100;    (*  Plot the first frame at X0, Y0          *)
        MaxFrame    = 10400;    (*  Total height of a frame                 *)


VAR     TopMargin,              (*  Printer does not print above this line  *)
        BottomMargin,           (*  Printer does not print below this line  *)
        LeftMargin,             (*  Printer cannot print left of this line  *)
        RightMargin,            (*  Printer cannot print right of this line *)
        Frame, Xpos, Ypos,
        FrameX, FrameY,
        NsuppsDone, distance    : CARDINAL;
        ch                      : CHAR;
        string                  : ARRAY [0..59] OF CHAR;
        FileName                : ARRAY [0..19] OF CHAR;
        PrinterName             : ARRAY [0..31] OF CHAR;
        StepSize                : REAL;                     (*  Length of 1 step in �m  *)


PROCEDURE UserMessage (n : CARDINAL);       (*  Show varous messages to instruct the user   *)

BEGIN
    WriteLn;
    CASE n OF
     0 :    WriteLine ("Thank you for using this GNU GPL software. Please study the guidelines of the");
            WriteLine ("GNU General Public License. This is FREE software!");
            |
     1 :    WriteLine ("The syntax is  Ruler coilnr [Enter].");
            WriteLine ("The coilnumber is in the specification.");
            |
     2 :    WriteLine ("Cannot find file 'Printer.Def' and hence cannot start up. Create a new");
            WriteLine ("file, or retrieve it from a backup. Program halted.");
            UserMessage (0);
            |
     3 :    WriteLine ("The printer is not online. It would be convenient if you could fix this.");
            |
     4 :    WriteLine ("There is no file to read data from. I cannot work like this.");
            |
     5 :    WriteLine ("An error occurred while reading a floating point number.");
            WriteLine ("By the time you read this, the program will be aborted.");
    END;
    WriteLn
END UserMessage;


PROCEDURE Pen (state : PenState);       (*  Control the "plotter pen"   *)

BEGIN
    IF state = Up THEN
        WriteString ("pu; ")
    ELSE
        WriteString ("pd; ")
    END
END Pen;


PROCEDURE CheckPrinter () : PrinterStatus;

VAR     Status      : CARDINAL;

BEGIN
    ASM
        MOV     AH, 1
        MOV     DX, 0
        INT     17H
        MOV     AL, AH
        MOV     AH, 0
        MOV     [Status], AX
    END;
    IF Status = 90H THEN
        RETURN Ready
    ELSE
        RETURN Offline
    END
END CheckPrinter;


PROCEDURE MakeOutline (x, y   : CARDINAL);

(*  Plot frames on sheet of paper. The output must have been redirected to PRN
    and the printer must be in plotter-mode.
    *)

VAR     n       : CARDINAL;

BEGIN
    WriteString ("pa ");    WriteCard (x, 1);   Write (",");    WriteCard (y, 1);   Write (";");
    FOR n := 0 TO 5 DO
        Pen (Down);     WriteString ("pr 0, 10400, 1200, 0, 0, -10400, -1200, 0;");     Pen (Up);
        IF n < 5 THEN
            WriteString ("pr 1320, 0;")
        ELSE
            WriteString ("pa ");
            WriteCard (x, 1);       Write (",");
            WriteCard (y, 1);       Write (";")
        END
    END
END MakeOutline;


PROCEDURE SkipFrame;

BEGIN
    Ypos := 0;
    INC (Frame);
    INC (FrameX, 1320);
    IF Frame = 6 THEN
        Write (ESC);    WriteString ("%1A");    Write (FF);
        Write (ESC);    WriteString ("%1B");
        MakeOutline (X0, Y0);
        Frame := 0;
        FrameX := X0;
    END;
    Xpos := 600;
    Pen (Up);
    WriteString ("pa ");    WriteCard (Xpos + FrameX, 1);    WriteString (", 100;")
END SkipFrame;


PROCEDURE Bar (x  : CARDINAL; type :  LineStyle);

(*  Produce a bar, perpendicular to the ruler, with a total height of <x> mm,
    make the linestyle as defined in <type>.
    *)

BEGIN
    Pen (Up);   WriteString ("pr ");    WriteCard (20 * x, 1);  WriteString (", 0;");   Pen (Down);
    IF type = Dashed THEN
        WriteString ("lt 2,1; ")
    END;
    WriteString ("pr -");   WriteCard (40 * x, 1);  WriteString (", 0; ");
    IF type = Dashed THEN
        WriteString ("lt; ")
    END;
    Pen (Up);   WriteString ("pr ");    WriteCard (20 * x, 1);  WriteLine (", 0;")
END Bar;


PROCEDURE Line (x  : CARDINAL);

(*  Produce a horizontal line of length  steps. Increment Ypos counter.  *)

VAR     dist        : CARDINAL;

BEGIN
    WriteString ("pr 0, ");
    IF Ypos + x > MaxFrame THEN
        x := x + Ypos - MaxFrame;
        dist := MaxFrame - Ypos;
        WriteCard (dist, 1);
        Write (";");
        SkipFrame;
        Pen (Down);
        WriteString ("pr 0, ")
    END;
    WriteCard (x, 1);   Write (";");    Pen (Up);
    INC (Ypos, x)
END Line;


PROCEDURE GetNumber (VAR value  : CARDINAL);

VAR     Number      : ARRAY [0..9] OF CHAR;
        x           : REAL;
        ok          : BOOLEAN;

BEGIN
    ReadString (Number);
    StringToReal (Number, x, ok);
    IF NOT ok THEN
        CloseOutput;
        UserMessage (5);
        WriteString ("De fout was : ");   WriteLine (Number);
        Terminate (5)
    END;
    value := TRUNC (1000.0 * x / StepSize)
END GetNumber;


PROCEDURE StartLine;

BEGIN
    Pen (Down);
    GetNumber (distance);       Line (distance);        Bar (20, Solid);
    Pen (Up)
END StartLine;


PROCEDURE MakeTail;

BEGIN
    GetNumber (distance);
    Pen (Down);     Line (distance);        INC (Ypos, distance);       Pen (Up)
END MakeTail;


PROCEDURE Move (distance  : CARDINAL);

BEGIN
    Line (distance);
END Move;


PROCEDURE MakeWhite;

BEGIN
    GetNumber (distance);
    Move (distance)
END MakeWhite;


PROCEDURE MakeTarget;       (*  Syntax  : Target distance, tolerance <EOL>  *)

VAR     tolerance   : CARDINAL;

BEGIN
    GetNumber (distance);
    GetNumber (tolerance);
    DEC (distance, tolerance);
    Pen (Down);         Line (distance);        Pen (Up);
    Bar (20, Solid);
    Line (tolerance);
    Bar (20, Dashed);
    Line (tolerance);
    Bar (20, Solid);
    Ypos := Ypos + 2 * tolerance
END MakeTarget;


PROCEDURE GetText;

VAR     Xt, Yt      : CARDINAL;

BEGIN
    GetNumber (Xt);
    GetNumber (Yt);
    ReadName (string);
    INC (Xt, FrameX);
    INC (Yt, FrameY);
    WriteString ("pa ");        WriteCard (Xt, 1);      Write (",");    WriteCard (Yt, 1);      Write (";");
    Pen (Down);
        WriteString ("di 0,1; lb"); WriteString (string);   Write ("#");
    Pen (Up);
    WriteString ("pa ");
        WriteCard (Xpos + FrameX, 1);   Write (",");
        WriteCard (Ypos + FrameY, 1);   Write (";")
END GetText;


PROCEDURE MakeNsupp;

VAR     h1, h2      : CARDINAL;

BEGIN
    IF (NsuppsDone MOD 2) = 0 THEN
        h1 := 15;
        h2 := 20
    ELSE
        h1 := 20;
        h2 := 15
    END;
    Pen (Down);
    GetNumber (distance);       Line (distance);        Bar (h1, Solid);
    GetNumber (distance);       Move (distance);        Bar (h2, Solid);
    INC (NsuppsDone);
    Pen (Up)
END MakeNsupp;


PROCEDURE MakeSegment;

BEGIN
    GetNumber (distance);
    Pen (Down);
    Line (distance);        Bar (20, Solid);        Pen (Up)
END MakeSegment;


PROCEDURE SetPenwidth;

VAR     Number      : ARRAY [0..5] OF CHAR;

BEGIN
    ReadString (Number);
    WriteString ("pw ");        WriteLine (Number);     Write (";")
END SetPenwidth;


PROCEDURE PlotRuler;     (*  Output the rulers  *)

VAR     Word        : ARRAY [0..15] OF CHAR;

BEGIN
    IF CheckPrinter () = Offline THEN
        UserMessage (3);
        Terminate (3)
    ELSE
        RedirectOutput ("PRN")
    END;
    Xpos := 600;     Ypos := 0;

    Write (ESC);    WriteString ("%1B");            (*  Make printer think it's a plotter   *)
    WriteString ("df; ct 1; pw 0.1; sp 1; dt#; ");
    Pen (Up);
    MakeOutline (X0, Y0);
    RedirectInput (FileName);
    IF  NOT Done  THEN
        UserMessage (4);
        Terminate (4)
    END;
    REPEAT
        ReadString (Word)
    UNTIL CompareStr (Word, 'BEGIN') = 0;
    LOOP
        ReadString (Word);
        UpperString (Word);
        IF    CompareStr (Word, "END")      = 0   THEN  EXIT
        ELSIF CompareStr (Word, "NAME")     = 0   THEN  GetText
        ELSIF CompareStr (Word, "NBAR")     = 0   THEN  MakeNsupp
        ELSIF CompareStr (Word, "PENWIDTH") = 0   THEN  SetPenwidth
        ELSIF CompareStr (Word, "SEGMENT")  = 0   THEN  MakeSegment
        ELSIF CompareStr (Word, "SKIP")     = 0   THEN  SkipFrame
        ELSIF CompareStr (Word, "START")    = 0   THEN  StartLine
        ELSIF CompareStr (Word, "TAIL")     = 0   THEN  MakeTail
        ELSIF CompareStr (Word, "TARGET")   = 0   THEN  MakeTarget
        ELSIF CompareStr (Word, "WHITE")    = 0   THEN  MakeWhite
        END
    END;
    Write (ESC);    WriteString ("%1A");        (*  Tell printer she's a printer    *)
    Write (FF);                                 (*  Eject ready page                *)
    CloseInput;
    CloseOutput
END PlotRuler;


PROCEDURE Initialize;           (*  Read and interpret the Printer.Def file     *)

VAR     Word            : ARRAY [0..15] OF CHAR;
        count, Value    : CARDINAL;

BEGIN
    RedirectInput ("Printer.Def");
    IF NOT Done THEN
        UserMessage (3);
        Terminate (3)
    END;
    REPEAT
        ReadString (Word)
    UNTIL CompareStr (Word, 'BEGIN') = 0;
    LOOP
        ReadString (Word);
        IF CompareStr (Word, '')                = 0 THEN    EXIT    END;
        IF CompareStr (Word, 'PrinterName')     = 0 THEN    ReadName (PrinterName)
        ELSIF CompareStr (Word, 'TopMargin')    = 0 THEN    ReadCard (TopMargin)
        ELSIF CompareStr (Word, 'BottomMargin') = 0 THEN    ReadCard (BottomMargin)
        ELSIF CompareStr (Word, 'LeftMargin')   = 0 THEN    ReadCard (LeftMargin)
        ELSIF CompareStr (Word, 'RightMargin')  = 0 THEN    ReadCard (RightMargin)
        ELSIF CompareStr (Word, 'StepSize')     = 0 THEN    ReadCard (Value);
                                                            StepSize := FLOAT (Value) / 1000.0
        ELSIF CompareStr (Word, 'END')          = 0 THEN    EXIT
        ELSE
            WriteString ("Unknown option: ");   WriteString (Word);
            WriteLine (" ignored. Please correct this file later.")
        END
    END;
    CloseInput;
    Frame  :=  0;
    FrameX := X0;
    FrameY := Y0;
    NsuppsDone := 0;
    GetArg (FileName, count);
    IF count = 0 THEN
        WriteString ("The coilnumber for this ruler is : ");
        ReadString (FileName)
    END;
    Append (FileName, '.URF')
END Initialize;


BEGIN
    Initialize;
    PlotRuler;
    UserMessage (0)
END Rulers.
   

Printer.def

Below is the sample content for a Brother HL-4 Ve printer. The names of the variables speak for themselves. StepSize is the calibration constant. You just start with a StepSize of 25000 and do some test prints. Change the StepSize until the printer produces calibrated line lengths. This ought to be possible within three trials.

      
This file contains the margins for the current printer. All values are in 
miilimeters and all numbers must be natural numbers, so NO DECIMAL POINTS are 
allowed. And negative numbers are also forbidden.

BEGIN

PrinterName     "Brother HL-4 Ve"
TopMargin       13
BottomMargin    13
LeftMargin      6
RightMargin     6
StepSize        24592

END

If you foul up this file, it's your own stupid fault.

The file is read from "BEGIN" to "END". So don't mess around with these words. 
They're here to please you, so don't spoil it.

This file is copyleft Jan Verhoeven and is released as part of a GNU GPL style 
FREE program.
   
As you can see, this is my favorite kind of configuration file.

URF: Ushio Ruler File

The ruler was made for one specific coil (filament) that had different coiling segments. Each segment could have different threads and turns and hence different lengths. This was all specified in the specification. One of the parameters was the 'coil number' which was a code for a coiling pattern. Many lamps could have the same coiling number.
In the example below, the lamp had a coil with number '4711'. So the filename was '4711.URF'.

      
BEGIN

Name    28  20  "QIR 230-640 INS        Coiling ruler"
        White   12
        Start   18
        Segment 35
        Segment 135
        Nbar    120     2.5
        Nbar    10      2.5
        Target  20      0.8
        Tail    20
SKIP

Name    28.2  10  "QIR 230-640 INS        After supportering"
        White   5
        Start   12
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Target  20      1.1
        PenWidth 0.5
        Tail    15
        PenWidth 0.2

SKIP

Name    28.2  10  "QIR 230-640 INS        After foilwelding"
        White   5
        Start   12
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Target  20      1.1
        Tail    15
SKIP

Name    28.2  20  "QIR 230-640 INS        After forming"
        White   5
        Start   12
        Nbar    25      1.2
        Nbar    10      1.2
        Nbar    25      1.2
        Nbar    10      1.2
        Target  40      1.1
        Tail    15

SKIP

Name    28.2  100  "QIR 230-640 INS        Before forming"
        White   5
        Start   12
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Nbar    25      1.2
        Target  20      1.1
        Tail    15

END
   

Page created October 28, 2006 and