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 on 28 October 2006 and
Page equipped with FroogleBuster technology