Compare commits

..

9 commits

Author SHA1 Message Date
aa5693dd09 Just commit 2025-02-26 21:50:32 +03:00
62a95eddde Just commit 2025-02-26 21:48:59 +03:00
fab7e2e593 gitignore update 2025-01-22 13:00:45 +03:00
cd0292f19a rm exe & old versions of gcodegenerator 2025-01-17 20:13:12 +03:00
b8561888fa remove old marlin 2025-01-17 19:42:32 +03:00
815ee1fb17 remove old marlin 2025-01-17 19:41:36 +03:00
ae07549e1b v5-rc2
Все изменения в CHANGELOG.md
2025-01-12 23:00:23 +03:00
766bb1a985 Some changes 2025-01-10 12:27:32 +03:00
57455b84ab Система натяжения и множество изменений. 2024-12-25 19:14:10 +03:00
41 changed files with 1094 additions and 38 deletions

7
.gitignore vendored
View file

@ -1,13 +1,8 @@
# Pascal & err out logs, binaries
# Pascal err out logs
*.exe
*.o
*.compiled
*.err
*.out
# Solidworks
~$*.SLDPRT
~$*.SLDASM

View file

@ -1,51 +1,43 @@
# Намотчик Робосборщика
![](img/winder-5-rc2.jpg)
![](img/2024-08-20_22-46-04.png)
Станок предназначен для автоматической намотки катушек индуктивности статоров/роторов. На данный момент станок поддерживает намотку статоров сервоприводов Robossembler Servo ([gitlab](https://gitlab.com/robossembler/servo), [radicle](https://git.robossembler.org/nodes/seed.robossembler.org/rad:z2kN57BanxaiTZq3dWZ1Ej3oT8eD5)) диаметром 50 и 70 мм., однако, благодаря генератору gcode, станок может быть адаптирован для намотки более широкой номенклатуры статоров/роторов диаметром от 30 до 100 мм.
Станок предназначен для автоматической намотки катушек индуктивности статоров [outrunner-сервоприводов](https://gitlab.com/robossembler/servo) робота-манипулятора [Robossembler Arm](https://gitlab.com/robossembler/roboarm-diy-version) и других агрегатов экосистемы Робосборщика.
## Текущее состояние разработки
Первая работоспособная версия v4 в состоянии публичной альфы. Работоспособность зафиксирована в видео - [VK](https://vk.com/video717161_456239257), [Youtube](https://youtu.be/5glGYkbpT6w). Пока нет документации по сборке, возможны незначительные недочёты в конструкции. Предельный ресурс 3D-печатной версии станка пока неизвестен. В настоящее время проходит испытания 5-я версия станка. Подробная информация о дате выпуска новых версий и содержании изменений приведена в файле `CHANGELOG.md`. Информация о ходе разработки также публикуется в Telegram-канале [@robossembler_ru](https://t.me/robossembler_ru).
Первая работоспособная версия v4 в состоянии публичной альфы. Работоспособность зафиксирована в видео - [VK](https://vk.com/video717161_456239257), [Youtube](https://youtu.be/5glGYkbpT6w). Пока нет документации по сборке, возможны незначительные недочёты в конструкции. Промышленная эксплуатация не производилась, поэтому предельный ресурс 3D-печатной версии станка неизвестен.
## Особенности
1. Управление с помощью G-Code. Загрузка программы осуществляется по USB с помощью [OctoPrint](https://github.com/OctoPrint/OctoPrint) или другой подобной программы.
2. На данный момент поддерживаются два типа контроллеров: RAMPS (Arduino Mega) и Creality 4.2.7. В качестве встроенного ПО контроллера используется [Marlin](https://github.com/MarlinFirmware/Marlin). Чтобы избежать возможных расхождений в версиях, исходные файлы Marlin размещены в директории `firmware`; собрать прошивку можно, используя [официальную документацию](https://marlinfw.org/docs/basics/install_platformio.html) Marlin.
3. Перечень комплектующих станка для закупки приведён в BoM-листе `bom.xlsx`. Некоторые ссылки с маркетплейсов могут быть недоступны.
## Генератор gcode
Управляющая программа для станка представляет собой `gcode` (применяется для управления ЧПУ-станками или 3D-принтерами), который генерируется с помощью разработанной в рамках проекта утилиты `gcodegenerator`. Исходный код утилиты на написан на языке Pascal с использованием открытой среды разработки [Lazarus IDE](https://www.lazarus-ide.org) и размещён в директории `gcodegenerator`. Для сборки утилиты из исходных файлов необходимо установить Lazarus IDE и запустить команду `lazbuild gcodegenerator.lpi` (в случае с Windows - `lazbuild.exe gcodegenerator.lpi`).
Утилита не имеет графического интерфейса и запускается в командной строке следующей командой:
```bash
gcodegenerator stator_input.txt output.gcode coils_input.txt
```
где
- `stator_input.txt` - файл, содержащий, параметры статора; описание параметров см. в файле `gcodegenerator/input.txt`
- `output.gcode` - наименование генерируемого файла gcode;
- `coils_input.txt` - файл, содержащий параметры катушек: количество слоёв намотки на каждый луч статора и количество витков на каждом слое. Если в конфигурационном файле `stator_input.txt` задан автоматический режим работы (`Operation_Mode=auto`, рекомендуется), то данный файл формируется автоматически или перезаписывает имеющийся файл. В ручном режиме для более тонкой настройки и отладки файл `stator_coil.txt` не перезаписывается.
1. Управление с помощью G-Code (см. директорию `gcode`). Загрузка программы осуществляется по USB с персонального компьютера с помощью [OctoPrint](https://github.com/OctoPrint/OctoPrint).
2. В качестве платы управления используется недорогой одноплатный контроллер от 3D-принтера Creality 4.2.7. Планируется переход на Open Source версии контроллеров - RAMPS и т.п. В качестве встроенного ПО контроллера используется [Marlin](https://github.com/MarlinFirmware/Marlin). Чтобы избежать возможных расхождений в версиях, исходные файлы Marlin размещены в директории `firmware`; собрать прошивку можно, используя [официальную документацию](https://marlinfw.org/docs/basics/install_platformio.html) Marlin.
3. В базовом варианте станок умеет мотать только статоры из сервоприводов Robossembler Servo (зеркала: [Gitlab](https://gitlab.com/robossembler/servo), [Radicle](https://git.robossembler.org/nodes/seed.robossembler.org/rad:z2kN57BanxaiTZq3dWZ1Ej3oT8eD5)) - диаметром 50 и 70 мм. Планируется реализовать генератор GCode под более широкую номенклатуру статоров.
4. Перечень комплектующих станка для закупки приведён в BoM-листе `bom.xlsx`. Некоторые ссылки с маркетплейсов могут быть недоступны.
## Конструкция
Исходные файлы модели размещены в директории `src` в формате Solidworks. Для просмотра моделей в любом CAD подготовлены файлы в формате STEP в директории `step`.
Исходные файлы модели размещены в директории `src` в формате Solidworks. Активно ищутся желающие перечертить всё в FreeCAD. Для просмотра моделей в любом CAD подготовлены файлы в формате STEP в директории `step`. Последняя версия станка - `step/_main_asm_config_3.STEP`.
![](img/2024-08-24_19-58-01.png)
| Вид сбоку | Вид снизу |
| ----------- | ----------- |
| ![](img/2024-08-20_22-46-38.png) | ![](img/2024-08-20_22-45-36.png) |
| Держатель статора | Держатель в сборе со статором |
| ----------- | ----------- |
| ![](img/2024-08-18_17-57-20.png) | ![](img/2024-08-20_22-47-22.png) |
## Фото испытательных образцов
| Версия №4 | |
| ----------- | ----------- |
| ![](img/msk_1.jpg) | ![](img/msk_2.jpg) |
| ![](img/robonomics_1.jpg) | ![](img/robonomics_2.jpg) |
| Версия №5 | |
| ----------- | ----------- |
| ![](img/winder-5-rc2-1.jpg) | ![](img/winder-5-rc2-2.jpg) |
![](img/msk_1.jpg)
![](img/msk_2.jpg)
![](img/robonomics_1.jpg)
![](img/robonomics_2.jpg)
## Сотрудничество
Станок разрабатывается силами энтузиастов из числа команды Robossembler при поддержке [Robonomics](https://robonomics.network). Спасибо вам всем!
Станок разрабатывается силами энтузиастов из числа команды Robossembler при поддержке [robonomics.network](https://robonomics.network). Спасибо вам всем!
Мы будем рады любой форме участия в проекте: делитесь своими идеями, пожеланиями и предложениями в [issues](https://gitlab.com/robossembler/cnc/motor-wire-winder/-/issues) и комментариях канала [robossembler_ru](https://t.me/robossembler_ru) в Telegram.
По вопросам дальнейшего развития проекта и иным формам сотрудничества пишите в Telegram по адресу [@brylev](https://t.me/brylev).
Мы будем рады любой форме участия в проекте: делитесь своими идеями, пожеланиями и предложениями в [issues](https://gitlab.com/robossembler/cnc/motor-wire-winder/-/issues) и комментариях канала [robossembler_ru](https://t.me/robossembler_ru) в Telegram.

View file

@ -0,0 +1,13 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## 2025-01-05
### Добавлено
### Изменено
### Исправлено

16
gcodegenerator/TODO.md Normal file
View file

@ -0,0 +1,16 @@
This file contains a list of tasks that need to be completed.
# TODO
## CRITICAL
## HIGH
## MEDIUM
## LOW
1. Íàïèñàòü ïîäðîáíûé àëãîðèòì ðàáîòû ñòàíêà.
2. Íàïèñàòü ïîäðîáíóþ èíñòðóêöèþ ïî ðàáîòå.
# IN PROGRESS
# DONE

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="gcodegenerator_v5"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<Units>
<Unit>
<Filename Value="gcodegenerator_v5.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="gcodegenerator_v5"/>
</Target>
<SearchPaths>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf3"/>
</Debugging>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<PathDelim Value="\"/>
<Version Value="12"/>
<BuildModes Active="Default"/>
<Units>
<Unit>
<Filename Value="gcodegenerator_v5.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<TopLine Value="648"/>
<CursorPos X="25" Y="668"/>
<FoldState Value=" TC6B22 PPTB T3iV2{#5 piZmf2L1123]Rl3pQ2 T0yU4U0"/>
<UsageCount Value="220"/>
<Loaded Value="True"/>
</Unit>
</Units>
<JumpHistory HistoryIndex="19">
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="191" Column="51" TopLine="158"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="351" Column="28" TopLine="333"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="518" Column="74" TopLine="496"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="524" Column="47" TopLine="504"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="181" Column="56" TopLine="166"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="651" Column="71" TopLine="625"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="604" Column="42" TopLine="587"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="612" Column="91" TopLine="590"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="506" Column="32" TopLine="245"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="657" Column="139" TopLine="621"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="630" Column="26" TopLine="246"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="632" TopLine="610"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="671" Column="7" TopLine="615"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="532" Column="51" TopLine="493"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="542" Column="49" TopLine="515"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="580" Column="67" TopLine="313"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="507" Column="66" TopLine="72"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="222" Column="64" TopLine="198"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Column="11"/>
</Position>
<Position>
<Filename Value="gcodegenerator_v5.pas"/>
<Caret Line="668" Column="25" TopLine="636"/>
</Position>
</JumpHistory>
<RunParams>
<FormatVersion Value="2"/>
<Modes ActiveMode="default">
<Mode Name="default">
<local>
<CommandLineParams Value="input.txt output.gcode"/>
</local>
</Mode>
</Modes>
</RunParams>
<HistoryLists>
<List Name="LaunchingApplication" Type="File" Count="1">
<Item1 Value="C:\Windows\system32\cmd.exe /C ${TargetCmdLine}"/>
</List>
<List Name="CommandLineParameters" Count="1">
<Item1 Value="input.txt output.gcode"/>
</List>
</HistoryLists>
</ProjectSession>
</CONFIG>

Binary file not shown.

View file

@ -0,0 +1,816 @@
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 <input_file.txt> <output_file.gcode> <coil_geometry.txt>');
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.

36
gcodegenerator/input.txt Normal file
View file

@ -0,0 +1,36 @@
# диаметр основания статора
base_dia=37,8
# количество лучей статора
num_rays=1
# форма луча статора (circle, rect, superellipse)
ray_shape=rect
# диаметр луча статора
# ray_dia=5,0
# ширина луча статора
ray_w=2,4
# высота луча статора
ray_h=5
# длина луча статора
ray_len=9,0
# форма вершины луча
raytop_shape=circle
# диаметр вершины луча
raytop_dia=8,9
# ширина вершины луча
raytop_w=5,6
# высота вершины луча
raytop_h=14,0
# смещение центра луча
ray_offset=14,7
# диаметр провода
wire_diameter=0,25
# диаметр иглы
needle_diameter=1,25
# зазор пути
path_clearance=0,2
# скорость намотки
work_speed=2000

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<Compiler Value="C:\lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.exe" Date="1497193866"/>
<Params Value=" -MObjFPC -Scghi -O1 -gw3 -gl -l -vewnhibq -FuD:\Documents\GitHub\motor-wire-winder\gcodegenerator\ -FUD:\Documents\GitHub\motor-wire-winder\gcodegenerator\lib\x86_64-win64\ -FED:\Documents\GitHub\motor-wire-winder\gcodegenerator\ -oD:\Documents\GitHub\motor-wire-winder\gcodegenerator\gcodegenerator.exe gcodegenerator.pas"/>
</CONFIG>

Binary file not shown.

View file

@ -0,0 +1 @@
gcodegenerator_v4.exe trident_input.txt trident_output.gcode trident_coil.txt

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.