program gcodegenerator_v5; uses SysUtils, StrUtils, Math; type TPoint = record X, Y: double; end; type TStatorParams = record StatorName: String; BaseDiameter: Double; BaseRadius: Double; NumberOfRays: Integer; RayShape: string; RayDiameter: Double; RayWidth: Double; RayHeight: Double; RayLength: Double; RayTopShape: string; RayTopDiameter: Double; RayTopWidth: Double; RayTopHeight: Double; RayCenterOffset: Double; WireDiameter: Double; NeedleDiameter: Double; NeedleRigidity: Double; WorkSpeed :integer; end; type TLayer = record Turns: Integer; // Количество витков StartZ: double; // Начальная координата EndZ: double; // Конечная координата end; var StartTime, EndTime, ExecutionTime: TDateTime; InputFileName, OutputFileName, CoilGeometryFileName: string; StatorParams: TStatorParams; InFile, OutFile, CoilGeometryFile: TextFile; Line: string; CoilRadius,CoilWidth,CoilHeight :double; StartX: double; StartY: double; StartZ: double; CurrentX: double; CurrentY: double; CurrentZ: double; coords: TPoint; normalizecoords: TPoint; Layers: array[1..10] of TLayer; i, j, k: Integer; CoilLength :double; CurrentCoilTurns, CoilTurnsSum :Integer; AngleBetweenRays :double; RequiredSpacing: Double; LayerNumber :Integer; MaxLayers :Integer; angle :double; MaxDepth,MaxPath :double; MoveForward:boolean; WindDirection:integer; OperationMode:string; xclearance,yclearance,zclearance: Double; FixtureOffset: Double; FixtureDiameter: Double; FixtureTurns:integer; function ParseLine(Line: string): Boolean; var Parts: array of string; Value: string; TrimmedLine: string; begin TrimmedLine := Trim(Line); // Удаляем пробелы в начале и конце строки if Length(TrimmedLine) = 0 then begin exit(true); // Пустая строка - пропускаем end else if TrimmedLine[1] in [';','#'] then begin exit(true); // Строка комментария - пропускаем end; Parts := SplitString(TrimmedLine, '='); // Используем TrimmedLine Result := Length(Parts) = 2; if Result then begin Value := LowerCase(Trim(Parts[1])); // Приводим к нижнему регистру case Trim(Parts[0]) of 'stator_name': begin StatorParams.StatorName := Value; writeln('StatorName: ', StatorParams.StatorName); writeln(); end; 'Operation_Mode': begin OperationMode := Value; writeln('Operation Mode: ', OperationMode); writeln(); end; 'base_dia': begin StatorParams.BaseDiameter := StrToFloat(Value); writeln('Base Diameter: ', StatorParams.BaseDiameter:8:2); writeln(); StatorParams.BaseRadius := StatorParams.BaseDiameter/2; writeln('Base Radius: ', StatorParams.BaseRadius:8:2); writeln(); end; 'num_rays': begin StatorParams.NumberOfRays := StrToInt(Value); writeln('Number of Rays: ', StatorParams.NumberOfRays); AngleBetweenRays := 360/StatorParams.NumberOfRays; writeln('Angle Between Rays: ', AngleBetweenRays); writeln(); end; 'ray_shape': begin if Pos(Value, 'circle, rect, superellipse') = 0 then raise Exception.Create('Invalid value for ray_shape: ' + Value); StatorParams.RayShape := Value; writeln('Ray Shape: ', StatorParams.RayShape); writeln(); end; 'ray_dia': begin StatorParams.RayDiameter := StrToFloat(Value); writeln('Ray Diameter: ', StatorParams.RayDiameter:8:2); writeln(); end; 'ray_w': begin StatorParams.RayWidth := StrToFloat(Value); writeln('Ray Width: ', StatorParams.RayWidth:8:2); writeln(); end; 'ray_h': begin StatorParams.RayHeight := StrToFloat(Value); writeln('Ray Height: ', StatorParams.RayHeight:8:2); writeln(); end; 'ray_len': begin StatorParams.RayLength := StrToFloat(Value); writeln('Ray Length: ', StatorParams.RayLength:8:2); writeln(); end; 'raytop_shape': begin if Pos(Value, 'circle, rect, superellipse') = 0 then raise Exception.Create('Invalid value for ray_top: ' + Value); StatorParams.RayTopShape := Value; writeln('Ray Top Shape: ', StatorParams.RayTopShape); end; 'raytop_dia': begin StatorParams.RayTopDiameter := StrToFloat(Value); writeln('Ray Top Diameter: ', StatorParams.RayTopDiameter:8:2); writeln(); end; 'raytop_w': begin StatorParams.RayTopWidth := StrToFloat(Value); writeln('Ray Top Width: ', StatorParams.RayTopWidth:8:2); writeln(); end; 'raytop_h': begin StatorParams.RayTopHeight := StrToFloat(Value); writeln('Ray Top Height: ', StatorParams.RayTopHeight:8:2); writeln(); end; 'ray_offset': begin StatorParams.RayCenterOffset := StrToFloat(Value); writeln('Ray Center Offset: ', StatorParams.RayCenterOffset:8:2); writeln(); end; 'wire_diameter': begin StatorParams.WireDiameter := StrToFloat(Value); writeln('Wire Diameter: ', StatorParams.WireDiameter:8:2); writeln(); end; 'needle_diameter': begin StatorParams.NeedleDiameter := StrToFloat(Value); writeln('Needle Diameter: ', StatorParams.NeedleDiameter:8:2); writeln(); end; 'needle_rigidity': begin StatorParams.NeedleRigidity := StrToFloat(Value); StatorParams.NeedleRigidity := StatorParams.NeedleRigidity/100; writeln('Needle Rigidity: ', StatorParams.NeedleRigidity:8:2); writeln(); end; 'x_clearance': begin xclearance := StrToFloat(Value); writeln('X Clearance: ', xclearance:8:2); writeln(); end; 'y_clearance': begin yclearance := StrToFloat(Value); writeln('Y Clearance: ', yclearance:8:2); writeln(); end; 'z_clearance': begin zclearance := StrToFloat(Value); writeln('Z Clearance: ', zclearance:8:2); writeln(); end; 'fixture_offset': begin FixtureOffset := StrToFloat(Value); writeln('Fixture Offset: ', FixtureOffset:8:2); writeln(); end; 'fixture_dia': begin FixtureDiameter := StrToFloat(Value); writeln('Fixture Diameter: ', FixtureDiameter:8:2); writeln(); end; 'fixture_turns': begin FixtureTurns := StrToInt(Value); writeln('Fixture Turns: ', FixtureTurns); writeln(); end; 'work_speed': begin StatorParams.WorkSpeed := StrToInt(Value); writeln('Work Speed: ', StatorParams.WorkSpeed); writeln(); end; else Result := False; end; if not Result then begin writeln('Error: Unknown parameter: ', Parts[0]); exit; end; end; end; procedure ReadInputFile(); Begin // **Opening the input file** AssignFile(InFile, InputFileName); try Reset(InFile); // **This line opens the file for reading** while not EOF(InFile) do begin ReadLn(InFile, Line); if Length(Line) > 0 then if not ParseLine(Line) then writeln('Error: Invalid line: ', Line); end; except on E: Exception do begin writeln('Error opening or reading input file: ', E.Message); Halt(1); end; end; CloseFile(InFile); end; function CircleCoordinates(diameter, angleDegrees: Double): TPoint; var radius: Double; angleRadians: Double; begin radius := diameter / 2; // angleRadians := -1*angleDegrees * PI / 180; // Перевод градусов в радианы angleRadians := -1 * DegToRad(angleDegrees); Result.X := radius * Cos(angleRadians); Result.Y := radius * Sin(angleRadians); end; function CalculateAngle(opposite, adjacent: Double): Double; begin if adjacent = 0 then raise Exception.Create('Adjacent side cannot be zero'); // CalculateAngle := ArcTan(opposite / adjacent) * 180 / PI; CalculateAngle := RadToDeg(ArcTan(opposite / adjacent)); end; function NormalizeZ(radius: Real; thetaDeg: Real): Real; var thetaRad, alphaRad, xKas, yKas, mTang, bTang: Real; begin // 1. Преобразование угла из градусов в радианы. thetaRad := DegToRad(thetaDeg); // 2. Вычисление координат точки касания на окружности (относительно центра 0,0). xKas := radius * Cos(thetaRad); yKas := radius * Sin(thetaRad); // 3. Вычисление угла, перпендикулярного радиус-вектору (касательной). alphaRad := thetaRad + PI / 2; // 4. Вычисление углового коэффициента касательной. mTang := Tan(alphaRad); // 5. Вычисление свободного члена уравнения касательной (y = mTang * x + bTang). bTang := yKas - mTang * xKas; // 6. Вычисление координаты X точки пересечения касательной с осью X (y = 0). // 0 = mTang * x + bTang // x = -bTang / mTang if mTang = 0 then begin // Касательная параллельна оси X - нет точки пересечения. Возвращаем NaN. NormalizeZ := NaN; end else begin NormalizeZ := -bTang / mTang; end; end; function DepthCheck(thickness, lineLength, angleDeg: double): double; var xIntersection, distanceToIntersection, radius: double; begin xIntersection := (thickness/2 + thickness/2 * cos(DegToRad(angleDeg)))/sin(DegToRad(angleDeg)); distanceToIntersection := sqrt(sqr(xIntersection) + sqr(1.2)); radius := lineLength / (2 * tan(DegToRad(angleDeg) / 2)); DepthCheck := distanceToIntersection + radius; end; function CalculateMaxPath(length, width, angleDegrees: double): double; //функция вычисляет максимальное расстояние между лучами. Для этого от центра статора до var topLeftX, topLeftY, rotatedX, rotatedY, angleRadians, distance: double; begin // Вычисляем координаты верхнего левого угла прямоугольника topLeftX := -length; topLeftY := width / 2; // Преобразуем угол в радианы (с учетом вращения по часовой стрелке) angleRadians := degToRad(-angleDegrees); // Вычисляем координаты повернутого нижнего левого угла второго прямоугольника rotatedX := -length * cos(angleRadians) - (-width / 2) * sin(angleRadians); rotatedY := -length * sin(angleRadians) + (-width / 2) * cos(angleRadians); // Вычисляем расстояние между точками distance := sqrt(sqr(rotatedX - topLeftX) + sqr(rotatedY - topLeftY)); // Возвращаем результат MaxPath := distance; end; procedure CalculateCoilGeometry(); var StartZ, EndZ: double; begin writeln('CalculateCoilGeometry'); AssignFile(CoilGeometryFile, CoilGeometryFileName); try Rewrite(CoilGeometryFile); //Считаем, сколько слоёв можем намотать. MaxPath:=CalculateMaxPath((StatorParams.RayLength+StatorParams.BaseRadius), StatorParams.RayWidth, AngleBetweenRays); //writeln(CoilGeometryFile, ';MaxPath:', MaxPath); //MaxLayers :=trunc(((MaxPath-RequiredSpacing)/2/StatorParams.WireDiameter)); MaxLayers :=round((MaxPath-StatorParams.NeedleDiameter)/2/(StatorParams.WireDiameter+RequiredSpacing)); if (MaxLayers mod 2 = 0) then writeln(CoilGeometryFile, ';MaxLayers ', MaxLayers) else begin dec(MaxLayers); writeln(CoilGeometryFile, ';Сalculations resulted in MaxLayers=', MaxLayers+1, ' because it is even, MaxLayers=MaxLayers-1 and equal ',MaxLayers); end; MoveForward:=true; for i := 1 to MaxLayers do begin write(CoilGeometryFile, ';Lair:', i, ' have '); //Считаем длину катушки и количество витков //Для этого считаем необходимое расстояние между лучами. 2 диаметра провода + диаметр иглы + 2 зазора безопасности RequiredSpacing:=yclearance*2+(i-1)*StatorParams.WireDiameter*2+StatorParams.NeedleDiameter; //Используя необходимое расстояние, рассчитываем на какую, максимальную глубину может погрузиться иголка. (расстояние от центра статора) MaxDepth:=DepthCheck(StatorParams.RayWidth, RequiredSpacing, AngleBetweenRays); //writeln(OutFile, ';RayWidth ', StatorParams.RayWidth:0:5); //writeln(OutFile, ';RequiredSpacing ', RequiredSpacing:0:5); //writeln(OutFile, ';AngleBetweenRays ', AngleBetweenRays:0:5); //writeln(CoilGeometryFile, ';MaxDepth ', MaxDepth:0:5); //writeln(OutFile); //Если допустимая глубина меньше, чем диаметр основания, тогда длина катушки равна длине луча. //Если допустимая глубина больше, чем диаметр + длина луча, прекращаем движ. //Иначе длина катушки равна "радиус_основания + длина_луча - глубина) If (MaxDepth < (StatorParams.BaseRadius)) then CoilLength:=StatorParams.RayLength else if (MaxDepth > (StatorParams.RayLength+StatorParams.BaseRadius)) then break else CoilLength:=StatorParams.RayLength+StatorParams.BaseRadius-MaxDepth; //writeln(CoilGeometryFile, '!!!'); write(CoilGeometryFile, CoilLength:0:5, 'mm '); //CurrentCoilTurns := ceil(CoilLength/StatorParams.WireDiameter); //Исходя из длины катушки считаем количество витков. И складываем сколько всего витков на катушке. CurrentCoilTurns := round(CoilLength/StatorParams.WireDiameter); write(CoilGeometryFile, CurrentCoilTurns, ' Turns'); CoilTurnsSum := CoilTurnsSum+CurrentCoilTurns; //Перед каждым слоем нужно пересчитать координату Z //writeln(CoilGeometryFile,' StartZ=',CurrentZ:0:5); // if (MoveForward = false) then CurrentZ:=StatorParams.RayLength+StatorParams.BaseRadius-StatorParams.WireDiameter/2 // else CurrentZ:=StatorParams.RayLength+StatorParams.BaseRadius-StatorParams.WireDiameter*(CurrentCoilTurns-0.5); if (MoveForward = false) then StartZ:=StatorParams.RayLength+StatorParams.BaseRadius-StatorParams.WireDiameter/2 else StartZ:=StatorParams.RayLength+StatorParams.BaseRadius-StatorParams.WireDiameter*(CurrentCoilTurns-0.5); write(CoilGeometryFile,' NewStartZ=',StartZ:0:5); if (MoveForward = true) then EndZ:=StartZ+StatorParams.WireDiameter*CurrentCoilTurns else EndZ:=StartZ-StatorParams.WireDiameter*CurrentCoilTurns; writeln(CoilGeometryFile,' EndZ=',EndZ:0:5); //Inc(LayerNumber); CoilWidth:=CoilWidth+StatorParams.WireDiameter*2; MoveForward:= not MoveForward; //writeln(CoilGeometryFile,';MoveForward: ', MoveForward); //writeln(CoilGeometryFile); writeln(CoilGeometryFile, CurrentCoilTurns, ' ',StartZ:0:5, ' ',EndZ:0:5); Layers[i].Turns := CurrentCoilTurns; Layers[i].StartZ := StartZ; Layers[i].EndZ := EndZ; end; writeln(CoilGeometryFile); writeln(CoilGeometryFile,';CoilTurnsSum: ', CoilTurnsSum); except on E: Exception do begin writeln('Error writing to coil_geometry file: ', E.Message); Halt(1); end; end; CloseFile(CoilGeometryFile); end; procedure ReadCoilGeometry(); var // Parts: array of string; // Value: string; TrimmedLine: string; line: string; count, i, turns: Integer; startZ: float; endZ: float; spacePos: Integer; err: Integer; begin writeln('ReadCoilGeometry'); AssignFile(CoilGeometryFile, CoilGeometryFileName); try Reset(CoilGeometryFile); // **This line opens the file for reading** i := 0; while not EOF(CoilGeometryFile) do begin //writeln('!!!'); ReadLn(CoilGeometryFile, Line); if Length(Line) > 0 then begin TrimmedLine := Trim(Line); // Удаляем пробелы в начале и конце строки if (Length(TrimmedLine) = 0) then continue //exit() // Пустая строка - пропускаем else if TrimmedLine[1] in [';','#'] then continue; // exit(); // Строка комментария - пропускаем StringReplace(TrimmedLine, ',', '.', [rfReplaceAll]); inc(i); spacePos := Pos(' ', TrimmedLine); //writeln(spacePos); //writeln('!', TrimmedLine); Val(Copy(TrimmedLine, 1, spacePos - 1), turns, err); spacePos := 1 + spacePos; //writeln('? ',spacePos); //i:=1; TrimmedLine:=Copy(TrimmedLine, spacePos, Length(TrimmedLine)); spacePos := Pos(' ',TrimmedLine); //writeln(spacePos); //writeln('!!', TrimmedLine); Val(Copy(TrimmedLine, 1, spacePos - 1), startZ, err); TrimmedLine:=Copy(TrimmedLine, spacePos, Length(TrimmedLine)); //writeln('!!!', TrimmedLine); spacePos := Pos(' ',TrimmedLine); //writeln(spacePos); Val(Copy(TrimmedLine, 1, Length(TrimmedLine)), endZ, err); writeln('layer:',i,' turns:', turns,' startX:', startZ:0:3,' endX:', endZ:0:3); Layers[i].Turns := turns; Layers[i].StartZ := StartZ; Layers[i].EndZ := EndZ; //for i := 1 to CurrentCoilTurns do //begin // writeln(Layers[i].Turns,Layers[i].StartZ,Layers[i].EndZ); //end; //MaxLayers //writeln(); end; //if not ParseLine(Line) then // writeln('Error: Invalid line: ', Line); end; MaxLayers:=i; except on E: Exception do begin writeln('Error opening or reading Coil Geometry File: ', E.Message); Halt(1); end; end; CloseFile(CoilGeometryFile); end; procedure StartSequence(); begin writeln(OutFile, ';Generate G-code file for ',StatorParams.StatorName,' stator. At ',FormatDateTime('dd.mm.yyyy hh:nn:ss.zzz', StartTime)); writeln(OutFile, '; G-code for stator winding'); writeln(OutFile, 'G90 ; Absolute coordinate system'); //writeln(OutFile, 'G1 Y-10'); writeln(OutFile, 'G28 X Y Z'); writeln(OutFile, 'G1 X0 Y0'); writeln(OutFile); // Move to center of ray along Y axis and reset coordinate writeln(OutFile, 'G1 X', StatorParams.RayCenterOffset:0:2, ' Y0.0'); writeln(OutFile, 'G92 X0 Y0'); //отводим иглу левее и выше вершины луча CoilRadius:=(StatorParams.RayTopHeight/2+StatorParams.NeedleDiameter/2+yclearance); CoilWidth:=(StatorParams.RayTopWidth+StatorParams.NeedleDiameter+yclearance*2); CoilHeight:=(StatorParams.RayTopHeight+StatorParams.NeedleDiameter+xclearance*2); writeln(OutFile, ';CoilRadius = ', CoilRadius:0:3); writeln(OutFile, ';CoilWidth = ', CoilWidth:0:3); writeln(OutFile, ';CoilHeight = ', CoilHeight:0:3); StartX:=-1*CoilHeight/2; StartY:=-1*AngleBetweenRays/2; writeln(OutFile, 'G1 X', StartX:0:3, ' Y', StartY:0:3); //приближаемся к основанию статора. CurrentZ:=(StatorParams.BaseDiameter/2)+zclearance; writeln(OutFile, 'G1 Z', CurrentZ:0:2, ' F', StatorParams.WorkSpeed); //Встаём на паузу для того, чтобы привязать конец проволоки writeln(OutFile, 'M0'); //Движение "вверх" первой катушки. Делается один раз, чтобы образовать петлю от крючка. writeln(OutFile, 'G1 X', StartX:0:3, ' Y', -1*StartY:0:3); end; procedure MakeCoil(); begin for j := 1 to CurrentCoilTurns do begin writeln(OutFile,';Coil№ = ',j); writeln(OutFile,'M117 L',LayerNumber,'/C',j,'/S',CoilTurnsSum-CurrentCoilTurns+j); //Move from -X,Y to X,Y angle := WindDirection*AngleBetweenRays/2; CurrentX :=CoilHeight/2+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity); writeln(OutFile, 'G1 X', CurrentX:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5,' F',StatorParams.WorkSpeed, ' ;Point 1 CurrentZ= ',CurrentZ:0:5, ' 2x_clear= ',+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity):0:3); // Top Right Corner if MoveForward then CurrentZ:=CurrentZ+StatorParams.WireDiameter/4 else CurrentZ:=CurrentZ-StatorParams.WireDiameter/4; //Divide the path into 100 points //Move from X,Y to X,-Y for k := 1 to 100 do begin angle := AngleBetweenRays/2; angle := WindDirection*(angle-(2*(angle/100*k))); CurrentX :=CoilHeight/2+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity); writeln(OutFile, 'G1 X', CurrentX:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5,' F',round(1.2*StatorParams.WorkSpeed/StatorParams.BaseRadius*CurrentZ), ' ;Point 2 CurrentZ= ',CurrentZ:0:5, ' 3x_clear= ',+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity):0:3); // Bottom Right Corner end; if MoveForward then CurrentZ:=CurrentZ+StatorParams.WireDiameter/4 else CurrentZ:=CurrentZ-StatorParams.WireDiameter/4; //Move from X,-Y to -X,-Y angle := -1*WindDirection*AngleBetweenRays/2; CurrentX :=CoilHeight/2+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity); writeln(OutFile, 'G1 X', -1*CurrentX:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5,' F',StatorParams.WorkSpeed, ' ;Point 3 CurrentZ= ',CurrentZ:0:5, ' 4x_clear= ',+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity):0:3); // Bottom Left Corner if MoveForward then CurrentZ:=CurrentZ+StatorParams.WireDiameter/4 else CurrentZ:=CurrentZ-StatorParams.WireDiameter/4; //Move from -X,-Y to -X,Y //Divide the path into 100 points for k := 1 to 100 do begin angle := AngleBetweenRays/2; angle := -1*WindDirection*(angle-(2*(angle/100*k))); CurrentX :=CoilHeight/2+((CurrentZ-StatorParams.BaseRadius)*xclearance*StatorParams.NeedleRigidity); writeln(OutFile, 'G1 X', -1*CurrentX:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5,' F',round(1.2*StatorParams.WorkSpeed/StatorParams.BaseRadius*CurrentZ) , ' ;Point 4 CurrentZ= ',CurrentZ:0:5, ' 1x_clear= ',+((CurrentZ-StatorParams.BaseRadius*xclearance*StatorParams.NeedleRigidity)):0:3); // Top Left Corner end; if MoveForward then CurrentZ:=CurrentZ+StatorParams.WireDiameter/4 else CurrentZ:=CurrentZ-StatorParams.WireDiameter/4; end; end; procedure PairCoilWind(mode: string); begin if ((mode = 'Aa') or (mode = 'Bb') or (mode = 'Cc')) then begin WindDirection:=1; end else if ((mode = 'aA') or (mode = 'bB') or (mode = 'cC')) then begin WindDirection:=-1; end else begin Writeln('Wrong Pair Coil Pattern. (Aa, aA, Bb, bB, Cc, cC'); Readln; Halt(1); end; for LayerNumber := 1 to MaxLayers do begin writeln(OutFile, ';Layer ', LayerNumber); if (Layers[LayerNumber].StartZ > Layers[LayerNumber].EndZ) then CoilLength:=Layers[LayerNumber].StartZ-Layers[LayerNumber].EndZ else CoilLength:=Layers[LayerNumber].EndZ-Layers[LayerNumber].StartZ; writeln(OutFile, ';CoilLength ', CoilLength:0:5); CurrentCoilTurns:=Layers[LayerNumber].Turns; //writeln(OutFile, ';CurrentCoilTurns ', CurrentCoilTurns); CoilTurnsSum := CoilTurnsSum+CurrentCoilTurns; writeln(OutFile, ';CoilTurnsSum ', CoilTurnsSum); CurrentZ:=Layers[LayerNumber].StartZ; writeln(OutFile,'; NewZ=',CurrentZ:0:5); //Начинаем мотать. writeln(OutFile, ';We make ',CurrentCoilTurns, ' turns on ', LayerNumber, ' layer.' ); writeln(OutFile); WindDirection := 1; MakeCoil(); writeln(OutFile, 'M300 S2500 P100'); CoilWidth:=CoilWidth+StatorParams.WireDiameter*2; MoveForward:= not MoveForward; writeln(OutFile,';MoveForward: ', MoveForward); end; writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, 'G4 P100'); writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, 'G4 P100'); writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, ';Coil Complete.'); writeln(OutFile, ';Changing coords.'); writeln(OutFile, 'G92 Y', -1*angle:0:5); writeln(OutFile, ';Second coil'); for LayerNumber := 1 to MaxLayers do begin writeln(OutFile, ';Layer ', LayerNumber); if (Layers[LayerNumber].StartZ > Layers[LayerNumber].EndZ) then CoilLength:=Layers[LayerNumber].StartZ-Layers[LayerNumber].EndZ else CoilLength:=Layers[LayerNumber].EndZ-Layers[LayerNumber].StartZ; writeln(OutFile, ';CoilLength ', CoilLength:0:5); CurrentCoilTurns:=Layers[LayerNumber].Turns; //writeln(OutFile, ';CurrentCoilTurns ', CurrentCoilTurns); CoilTurnsSum := CoilTurnsSum+CurrentCoilTurns; writeln(OutFile, ';CoilTurnsSum ', CoilTurnsSum); CurrentZ:=Layers[LayerNumber].StartZ; writeln(OutFile,'; NewZ=',CurrentZ:0:5); //Начинаем мотать. writeln(OutFile, ';We make ',CurrentCoilTurns, ' turns on ', LayerNumber, ' layer.' ); writeln(OutFile); WindDirection := -1; MakeCoil(); writeln(OutFile, 'M300 S2500 P100'); CoilWidth:=CoilWidth+StatorParams.WireDiameter*2; MoveForward:= not MoveForward; writeln(OutFile,';MoveForward: ', MoveForward); end; writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, 'G4 P50'); writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, 'G4 P50'); writeln(OutFile, 'M300 S2500 P100'); writeln(OutFile, ';Coil Complete.'); end; procedure MoveToNextPair(); begin writeln(OutFile, ';Move To Next Pair'); writeln(OutFile, 'G92 Y0'); writeln(OutFile, 'G1 Y', 360/(StatorParams.NumberOfRays/3/2):0:5 ); // Top Left Corner writeln(OutFile, ';Turn to next pair with ',360/(StatorParams.NumberOfRays/3/2):0:5,'°.' ); writeln(OutFile, 'G92 Y',StartY:0:5); end; procedure CreateMotorPhase(pattern:string); begin PairCoilWind(pattern); MoveToNextPair(); PairCoilWind(pattern); MoveToNextPair(); PairCoilWind(pattern); MoveToNextPair(); PairCoilWind(pattern); end; procedure MoveToFixture(); begin writeln(OutFile, ';Move To Fixture'); writeln(OutFile, 'G1 X', FixtureOffset:0:3); writeln(OutFile, 'M0'); //Пауза end; procedure AttachToFixture(); begin writeln(OutFile, ';Attach To Fixture'); for j := 0 to FixtureTurns do begin for i := 0 to 360 do begin coords := CircleCoordinates(FixtureDiameter/2+xclearance, i+180); angle := CalculateAngle(coords.Y, CurrentZ); writeln(OutFile, 'G1 X', coords.X:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5); CurrentZ:=CurrentZ+StatorParams.WireDiameter/360; end; end; end; begin //Start Programm // Command line argument handling StartTime := Now; if ParamCount < 3 then begin Writeln('Usage: GCodeGenerator '); Halt(1); end; InputFileName := ParamStr(1); OutputFileName := ParamStr(2); CoilGeometryFileName := ParamStr(3); ReadInputFile(); // G-code generation AssignFile(OutFile, OutputFileName); try Rewrite(OutFile); StartSequence(); // *** Your G-code generation logic here *** if (OperationMode = 'auto') then CalculateCoilGeometry() else if (OperationMode = 'manual') then ReadCoilGeometry() else begin writeln('Error determining operation mode.'); writeln('You should use auto or manual.'); Readln; Halt(1); end; writeln(); writeln(OutFile, ';Information about layers'); writeln(OutFile, ';MaxLayers: ', MaxLayers); for i := 1 to MaxLayers do begin writeln(OutFile, ';', i, ' ',Layers[i].Turns,' ',Layers[i].StartZ:0:5,' ',Layers[i].EndZ:0:5); end; Inc(LayerNumber); //Начинаем мотать катушку. writeln(OutFile); writeln(OutFile, ';Start winding'); //Двигаемся от центра к краю MoveForward:=true; if (StatorParams.RayShape = 'circle') then begin for j := 0 to CurrentCoilTurns do begin for i := 0 to 360 do begin coords := CircleCoordinates(CoilRadius*2, i+180); // writeln(OutFile,'CoilRadius*2= ',CoilRadius*2:0:5,' X=', coords.X:0:3, ' Y=', coords.Y:0:5); angle := CalculateAngle(coords.Y, CurrentZ); // writeln(OutFile, ';G1 X', coords.X:0:3, ' Y', angle:0:5,' Z', CurrentZ:0:5); writeln(OutFile, 'G1 X', coords.X:0:3, ' Y', angle:0:5,' Z', NormalizeZ(CurrentZ, angle):0:5); // writeln(OutFile); CurrentZ:=CurrentZ+StatorParams.WireDiameter/360; end; writeln(OutFile, ';Next coil.'); end; writeln(OutFile, ';Second coil'); Inc(LayerNumber); // RequiredSpacing:=StatorParams.RayWidth+StatorParams.NeedleDiameter+StatorParams.PathClearance*2+LayerNumber*StatorParams.WireDiameter*2; // writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=StatorParams.RayTopWidth; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=RequiredSpacing+StatorParams.NeedleDiameter; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); RequiredSpacing:=RequiredSpacing+yclearance*2+LayerNumber*StatorParams.WireDiameter*2; writeln(OutFile, ';RequiredSpacing = ',RequiredSpacing:0:5); CurrentZ:=RequiredSpacing/(2 * tan(AngleBetweenRays*PI/180/2)); writeln(OutFile, ';CurrentZ = ',CurrentZ:0:3); end else if (StatorParams.RayShape = 'rect') then begin // writeln(OutFile, ';Rect? '); CreateMotorPhase('Aa'); MoveToFixture(); AttachToFixture(); end; except on E: Exception do begin writeln('Error writing to output file: ', E.Message); Halt(1); end; end; CloseFile(OutFile); EndTime := Now; ExecutionTime := EndTime - StartTime; writeln('G-code generated to: ', OutputFileName, ' in ', FormatFloat('0.000', ExecutionTime * 86400), ' seconds.'); writeln('Press Enter... '); Readln; end.