feat: MOTF(Mark On The Fly) 구현 준비 - ACS Stage X 연동
- WeldingCommon/Devices/ACS/ ScannerACS 독립 구현 (Gun 참조 제거) - Scanner EquipmentSetup.RegisterDevices()에 ScannerACS + 모터 등록 - EquipDef.cs MotorIds 추가 - UCScannerMotionViewModel Stage X 조그 필드/커맨드/모니터링 추가 - UCScannerMotion.xaml Stage X Motion 섹션 추가 - SeqComponentTeachingRun MOTF 자리 확보 (_ACS 필드 선언, InitDev() 취득, MOTFStart/CheckMOTFComp 주석 준비) - AuroraEx Device 네임스페이스 충돌 수정 TODO: 이정인 선임 ACS 변수 맵 수신 후 - ScannerACS.Parameter.cs 변수명/버퍼 번호 교체 - MOTFStart() / CheckMOTFComp() 주석 해제 - 축 번호 검증
This commit is contained in:
parent
1915724771
commit
e309230949
1
Doc/ToNDH/.~lock.개발사항 전달.pptx#
Normal file
1
Doc/ToNDH/.~lock.개발사항 전달.pptx#
Normal file
@ -0,0 +1 @@
|
||||
,DESKTOP-CN4O63O/User,DESKTOP-CN4O63O,06.04.2026 14:05,file:///C:/Users/User/AppData/Roaming/LibreOffice/4;
|
||||
156
Doc/ToNDH/MOTF_구현가이드_26.04.06.md
Normal file
156
Doc/ToNDH/MOTF_구현가이드_26.04.06.md
Normal file
@ -0,0 +1,156 @@
|
||||
# ILSOS PrismaticScanner - MOTF 구현 가이드
|
||||
> 작성일: 2026-04-06 | 작성자: NDY
|
||||
|
||||
---
|
||||
|
||||
## 목차
|
||||
1. [MOTF 개념](#1-motf-개념)
|
||||
2. [변경된 파일 목록](#2-변경된-파일-목록)
|
||||
3. [흐름 정리](#3-흐름-정리)
|
||||
4. [변수 맵 수신 후 작업](#4-변수-맵-수신-후-작업)
|
||||
5. [TODO 체크리스트](#5-todo-체크리스트)
|
||||
|
||||
---
|
||||
|
||||
## 1. MOTF 개념
|
||||
|
||||
```
|
||||
MOTF (Mark On The Fly)
|
||||
= Stage X(ACS)가 이동하는 동안 갈바노 스캐너가 레이저 마킹
|
||||
|
||||
트리거: Stage X 엔코더 위치 기반
|
||||
→ WaitForEncoderX 조건 도달 시 갈바노 마킹 시작
|
||||
```
|
||||
|
||||
### 기존 방식 vs MOTF 방식
|
||||
|
||||
| 항목 | 기존 (갈바노 단독) | MOTF |
|
||||
|---|---|---|
|
||||
| Stage X | 정지 상태 | 이동 중 |
|
||||
| 마킹 트리거 | 즉시 실행 | 엔코더 위치 트리거 |
|
||||
| 처리량 | 낮음 | 높음 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 변경된 파일 목록
|
||||
|
||||
### WeldingCommon/Devices/ACS/
|
||||
- `ScannerACS.cs` - Scanner 전용 ACS 디바이스 (Gun과 독립)
|
||||
- `ScannerACS.Parameter.cs` - ACS 변수명 상수 **(TODO: 변수 맵 교체 필요)**
|
||||
- `MotionVariable.cs` - 모터 상태값
|
||||
|
||||
### WeldingCommon/Views/
|
||||
- `UCScannerMotionViewModel.cs` - Stage X 조그 UI 연동
|
||||
- `UCScannerMotion.xaml` - Stage X Motion 섹션 추가
|
||||
|
||||
### ILSOS_PrismaticScanner/
|
||||
- `EquipmentSetup.cs` - ScannerACS + 모터 등록
|
||||
- `EquipDef.cs` - MotorIds 추가
|
||||
- `Sequences/SeqComponentTeachingRun.cs` - MOTF 자리 확보 (주석)
|
||||
|
||||
---
|
||||
|
||||
## 3. 흐름 정리
|
||||
|
||||
### SeqComponentTeachingRun 흐름
|
||||
|
||||
```
|
||||
CheckEndList
|
||||
↓
|
||||
UpdateComponentWeldingParameters (레이저 파라미터 설정)
|
||||
↓
|
||||
SetUploadWeldingList_SeqParams
|
||||
↓
|
||||
SeqUploadWeldingList (Scanner List 채우기 + MOTF ON/OFF)
|
||||
↓ Scanner.Config.UseMarkingOnTheFly = true 이면
|
||||
↓ SetFlyX() + WaitForEncoderX() 자동 실행
|
||||
GetUploadWeldingList_SeqResult
|
||||
↓
|
||||
DoComponentWelding
|
||||
├── _Scanner.ExecuteList() (Scanner List 실행)
|
||||
├── _ACS?.MOTFStart() ← TODO: 변수 맵 수신 후 주석 해제
|
||||
├── _Scanner.WaitForListTaskCompleted()
|
||||
└── CheckMOTFComp() ← TODO: 변수 맵 수신 후 주석 해제
|
||||
↓
|
||||
CheckEndList (반복)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 변수 맵 수신 후 작업
|
||||
|
||||
### 4-1. ScannerACS.Parameter.cs - 변수명 교체
|
||||
|
||||
```csharp
|
||||
// 현재 placeholder → 실제 변수명으로 교체
|
||||
const string iMOTFStart = "iPCset_SCANNER_MOTF_START"; // TODO
|
||||
const string iMOTFComplete = "iPCget_SCANNER_MOTF_COMP"; // TODO
|
||||
const string rMOTFVelocity = "rPCset_SCANNER_MOTF_VEL"; // TODO
|
||||
const string rMOTFAcc = "rPCset_SCANNER_MOTF_ACC"; // TODO
|
||||
const string iAllAxisHomeComplete = "iPCget_ALLAXIS_HOMECOMP"; // TODO
|
||||
const string AlarmReset = "iAlarmreset"; // TODO
|
||||
const string HeavyAlarm = "iAlarm"; // TODO
|
||||
const string LightAlarm = "iLightAlarm"; // TODO
|
||||
|
||||
private enum eBuffer
|
||||
{
|
||||
All_Axis_Home = 0, // TODO: 실제 버퍼 번호로 교체
|
||||
MOTF_Start = 11, // TODO: 실제 버퍼 번호로 교체
|
||||
}
|
||||
```
|
||||
|
||||
### 4-2. EquipDef.cs - MotorIds 축 번호 검증
|
||||
|
||||
```csharp
|
||||
public enum eMotorIdx
|
||||
{
|
||||
AxisX2 = 1, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisY1 = 3, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisY2 = 4, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisZ = 5, // TODO: 실제 ACS 채널 번호 확인
|
||||
}
|
||||
```
|
||||
|
||||
### 4-3. SeqComponentTeachingRun.cs - 주석 해제 3곳
|
||||
|
||||
```csharp
|
||||
// [1] CheckDeviceReady() - ACS 활성화 확인 추가
|
||||
// DeviceIds.ACS ← 주석 해제
|
||||
|
||||
// [2] DoComponentWelding() - Stage X 이동 시작
|
||||
// _ACS?.MOTFStart(); ← 주석 해제
|
||||
|
||||
// [3] DoComponentWelding() - MOTF 완료 대기
|
||||
// while (!_ACS.CheckMOTFComp()) { Thread.Sleep(10); } ← 주석 해제
|
||||
```
|
||||
|
||||
### 4-4. Scanner Config 설정 확인
|
||||
|
||||
```
|
||||
Scanner.Config.UseMarkingOnTheFly = true ← 반드시 확인
|
||||
Scanner.Config.OnTheFlyCoordinate = eOntheFlyCoordinate.XY ← Linear Track 방식
|
||||
Scanner.Config.MarkingOnTheFlyEncoderResolutionX ← 엔코더 분해능
|
||||
Scanner.Config.MarkingStartEncoderPositionX ← 마킹 시작 엔코더 위치
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. TODO 체크리스트
|
||||
|
||||
### 이정인 선임 변수 맵 수신 전 (완료)
|
||||
- [x] WeldingCommon에 ScannerACS 독립 구현
|
||||
- [x] Scanner RegisterDevices()에 ACS + 모터 등록
|
||||
- [x] UCScannerMotion Stage X 조그 UI 추가
|
||||
- [x] SeqComponentTeachingRun MOTF 자리 확보 (주석)
|
||||
- [x] _ACS 필드 선언 및 InitDev()에서 null-safe 취득
|
||||
- [x] CheckDeviceReady()에 ACS 주석으로 준비
|
||||
|
||||
### 이정인 선임 변수 맵 수신 후
|
||||
- [ ] ScannerACS.Parameter.cs 변수명 교체
|
||||
- [ ] eBuffer 번호 교체
|
||||
- [ ] MotorIds.eMotorIdx 축 번호 검증
|
||||
- [ ] CheckDeviceReady() DeviceIds.ACS 주석 해제
|
||||
- [ ] DoComponentWelding() MOTFStart() 주석 해제
|
||||
- [ ] DoComponentWelding() CheckMOTFComp() 주석 해제
|
||||
- [ ] Scanner Config UseMarkingOnTheFly 설정 확인
|
||||
- [ ] 실제 장비에서 동작 확인
|
||||
347
Doc/ToNDH/ScannerACS_작업가이드_26.04.06.md
Normal file
347
Doc/ToNDH/ScannerACS_작업가이드_26.04.06.md
Normal file
@ -0,0 +1,347 @@
|
||||
# ILSOS PrismaticScanner - ACS 작업 가이드
|
||||
> 작성일: 2026-04-06 | 작성자: NDY
|
||||
|
||||
---
|
||||
|
||||
## 목차
|
||||
1. [현재까지 완료된 작업](#1-현재까지-완료된-작업)
|
||||
2. [변수 맵 수신 후 교체할 곳](#2-변수-맵-수신-후-교체할-곳)
|
||||
3. [홈/서보/알람 버튼 추가 작업](#3-홈서보알람-버튼-추가-작업)
|
||||
4. [MOTF 시퀀스 흐름](#4-motf-시퀀스-흐름)
|
||||
5. [캘리브레이션](#5-캘리브레이션)
|
||||
6. [TODO 체크리스트](#6-todo-체크리스트)
|
||||
|
||||
---
|
||||
|
||||
## 1. 현재까지 완료된 작업
|
||||
|
||||
### 1-1. 프로젝트 구조
|
||||
```
|
||||
WeldingCommon
|
||||
└── Devices/ACS/
|
||||
├── ScannerACS.cs ← Gun과 독립된 Scanner 전용 ACS
|
||||
├── ScannerACS.Parameter.cs ← ACS 변수명 상수 (TODO: 변수 맵 교체 필요)
|
||||
└── MotionVariable.cs ← 모터 상태값
|
||||
|
||||
ILSOS_PrismaticScanner
|
||||
└── EquipmentSetup.RegisterDevices()
|
||||
├── ScannerACS 등록
|
||||
├── MotorX2 등록 (Stage X)
|
||||
├── MotorY1, Y2, Z 등록 (TODO: 축 번호 검증 필요)
|
||||
└── EquipDef.cs에 MotorIds 추가
|
||||
```
|
||||
|
||||
### 1-2. WeldingCommon - UCScannerMotionViewModel.cs 수정 완료
|
||||
- `_MotorX` (ACSMotor) 필드 추가 및 연결
|
||||
- `StageXPos`, `IsStageXActivated` 프로퍼티 추가
|
||||
- `CMD_JogMove`에 `Stage_X_Left`, `Stage_X_Right` 케이스 추가
|
||||
- `MoveStageX()` 메서드 추가 (현재: 직접 모터 명령 방식)
|
||||
- `OnMonitoring()`에 Stage X 위치 갱신 추가
|
||||
|
||||
### 1-3. WeldingCommon - UCScannerMotion.xaml 수정 완료
|
||||
- `Stage X Motion (ACS)` GroupBox 추가 (Grid.Row="2")
|
||||
- Stage X[mm] 위치 표시
|
||||
- ◀ − / + ▶ 조그 버튼
|
||||
|
||||
---
|
||||
|
||||
## 2. 변수 맵 수신 후 교체할 곳
|
||||
|
||||
### 2-1. ScannerACS.Parameter.cs
|
||||
```csharp
|
||||
// 현재 placeholder → 실제 변수명으로 교체
|
||||
const string iMOTFStart = "iPCset_SCANNER_MOTF_START"; // TODO
|
||||
const string iMOTFComplete = "iPCget_SCANNER_MOTF_COMP"; // TODO
|
||||
const string rMOTFVelocity = "rPCset_SCANNER_MOTF_VEL"; // TODO
|
||||
const string rMOTFAcc = "rPCset_SCANNER_MOTF_ACC"; // TODO
|
||||
const string iAllAxisHomeComplete = "iPCget_ALLAXIS_HOMECOMP"; // TODO
|
||||
const string AlarmReset = "iAlarmreset"; // TODO
|
||||
const string HeavyAlarm = "iAlarm"; // TODO
|
||||
const string LightAlarm = "iLightAlarm"; // TODO
|
||||
|
||||
private enum eBuffer
|
||||
{
|
||||
All_Axis_Home = 0, // TODO: 실제 버퍼 번호로 교체
|
||||
MOTF_Start = 11, // TODO: 실제 버퍼 번호로 교체
|
||||
}
|
||||
```
|
||||
|
||||
### 2-2. EquipDef.cs - MotorIds 축 번호 검증
|
||||
```csharp
|
||||
public enum eMotorIdx
|
||||
{
|
||||
AxisX2 = 1, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisY1 = 3, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisY2 = 4, // TODO: 실제 ACS 채널 번호 확인
|
||||
AxisZ = 5, // TODO: 실제 ACS 채널 번호 확인
|
||||
}
|
||||
```
|
||||
|
||||
### 2-3. UCScannerMotionViewModel.cs - MoveStageX() 교체
|
||||
```csharp
|
||||
// 현재 (직접 모터 명령)
|
||||
private void MoveStageX(eJogDirection direction)
|
||||
{
|
||||
if (_MotorX == null || !_MotorX.IsActivated) return;
|
||||
double step = direction == eJogDirection.PLUS ? -StepValue : +StepValue;
|
||||
_MotorX.SetTargetPos(step, TargetPosType.REL);
|
||||
_MotorX.Move();
|
||||
}
|
||||
|
||||
// TODO: 변수 맵 수신 후 ACS 버퍼 방식으로 교체
|
||||
// private void MoveStageX(eJogDirection direction)
|
||||
// {
|
||||
// double velocity = GetStageXVelocity(); // Setting에서 가져오기
|
||||
// double acc = GetStageXAcc();
|
||||
// _acs?.StageXJogStart(velocity, acc);
|
||||
// }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 홈/서보/알람 버튼 추가 작업
|
||||
|
||||
### 3-1. IScannerACS 인터페이스 추가 항목
|
||||
```csharp
|
||||
// WeldingCommon/Devices/ACS/ScannerACS.cs
|
||||
public interface IScannerACS
|
||||
{
|
||||
bool IsActivated();
|
||||
|
||||
// 홈
|
||||
bool AllAxisHomeStart();
|
||||
bool AllAxisHomeStop();
|
||||
bool CheckAllAxisHome();
|
||||
|
||||
// Stage X 조그 (ACS 버퍼 방식) - TODO: 변수 맵 수신 후 구현
|
||||
bool StageXJogStart(double velocity, double acc);
|
||||
bool StageXJogStop();
|
||||
|
||||
// MOTF
|
||||
bool MOTFStart();
|
||||
bool MOTFStop();
|
||||
bool CheckMOTFComp();
|
||||
|
||||
// 레이저
|
||||
bool SetLaserIOUse(bool on);
|
||||
bool IsLaserOn();
|
||||
|
||||
// 알람
|
||||
bool ResetAlarm();
|
||||
void AllAxisServoOff();
|
||||
}
|
||||
```
|
||||
|
||||
### 3-2. UCScannerMotionViewModel.cs - 추가할 코드
|
||||
```csharp
|
||||
// 필드 추가
|
||||
private ScannerACS _acs;
|
||||
|
||||
// 커맨드 추가
|
||||
public ICommand CMD_HomeStart { get; }
|
||||
public ICommand CMD_HomeStop { get; }
|
||||
public ICommand CMD_AlarmReset { get; }
|
||||
public ICommand CMD_ServoOff { get; }
|
||||
|
||||
// 생성자에서 추가
|
||||
try { _acs = _Aurora.DeviceManager["ACS"] as ScannerACS; }
|
||||
catch { _acs = null; }
|
||||
|
||||
CMD_HomeStart = new DelegateCommand(_ => _acs?.AllAxisHomeStart());
|
||||
CMD_HomeStop = new DelegateCommand(_ => _acs?.AllAxisHomeStop());
|
||||
CMD_AlarmReset = new DelegateCommand(_ => _acs?.ResetAlarm());
|
||||
CMD_ServoOff = new DelegateCommand(_ => _acs?.AllAxisServoOff());
|
||||
```
|
||||
|
||||
### 3-3. UCScannerMotion.xaml - Stage X GroupBox 교체
|
||||
```xml
|
||||
<!-- 26.04.06 NDY Stage X Motion 섹션 -->
|
||||
<GroupBox Grid.Row="2" Header="Stage X Motion (ACS)" Margin="0 3 3 0"
|
||||
IsEnabled="{Binding IsStageXActivated}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Row 0: 위치 표시 + 조그 버튼 -->
|
||||
<GroupBox Grid.Row="0" Grid.Column="0" Header="Stage X[mm]"
|
||||
Style="{StaticResource StGBMonitor}" Margin="0 0 5 0" MinWidth="120">
|
||||
<TextBlock FontSize="18" FontWeight="Bold"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="{Binding StageXPos, StringFormat={}{0:0.000}}"/>
|
||||
</GroupBox>
|
||||
<Button Grid.Row="0" Grid.Column="1" FontWeight="Bold" Margin="3"
|
||||
Command="{Binding CMD_JogMove}"
|
||||
CommandParameter="Stage_X_Left">◀ −</Button>
|
||||
<Button Grid.Row="0" Grid.Column="2" FontWeight="Bold" Margin="3"
|
||||
Command="{Binding CMD_JogMove}"
|
||||
CommandParameter="Stage_X_Right">+ ▶</Button>
|
||||
<TextBlock Grid.Row="0" Grid.Column="3" FontSize="10" Foreground="Gray"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Text="* 이미지 방향 반전 적용"/>
|
||||
|
||||
<!-- Row 1: 홈/서보/알람 버튼 (TODO: 변수 맵 수신 후 활성화) -->
|
||||
<UniformGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4"
|
||||
Rows="1" Margin="3">
|
||||
<Button Margin="3" Content="Home Start"
|
||||
Command="{Binding CMD_HomeStart}"
|
||||
Style="{StaticResource StButtonAccentBlue}"/>
|
||||
<Button Margin="3" Content="Home Stop"
|
||||
Command="{Binding CMD_HomeStop}"
|
||||
Background="DarkSlateGray"/>
|
||||
<Button Margin="3" Content="Servo Off"
|
||||
Command="{Binding CMD_ServoOff}"
|
||||
Background="DarkOrange"/>
|
||||
<Button Margin="3" Content="Alarm Reset"
|
||||
Command="{Binding CMD_AlarmReset}"
|
||||
Background="DarkRed"/>
|
||||
</UniformGrid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. MOTF 시퀀스 흐름
|
||||
|
||||
### 4-1. 개념
|
||||
```
|
||||
MOTF (Mark On The Fly)
|
||||
= Stage X가 이동하는 동안 갈바노 스캐너가 레이저 마킹
|
||||
|
||||
트리거: Stage X 엔코더 위치 기반
|
||||
→ 특정 위치 도달 시 갈바노가 마킹 시작
|
||||
```
|
||||
|
||||
### 4-2. 시퀀스 흐름 (사수 피드백 기준)
|
||||
```
|
||||
[Step 1] Scanner List 채우기
|
||||
LASA 레시피 기반으로 마킹 좌표 목록 생성
|
||||
→ ScannerList에 마킹할 X, Y 좌표 순서대로 입력
|
||||
|
||||
[Step 2] ACS에 파라미터 전송
|
||||
→ 시작 위치, 속도, 가속도 설정
|
||||
→ 레이저 ON/OFF 위치 설정
|
||||
→ MOTF 트리거 조건 설정
|
||||
|
||||
[Step 3] ACS MOTF 시작
|
||||
→ RunBuffer(eBuffer.MOTF_Start)
|
||||
→ Stage X 이동 시작
|
||||
→ 엔코더 트리거로 갈바노 동기화
|
||||
|
||||
[Step 4] 완료 확인
|
||||
→ ReadVariableInt(iMOTFComplete) > 0
|
||||
```
|
||||
|
||||
### 4-3. 참조할 기존 소스
|
||||
```
|
||||
CCW 웰더 프로젝트
|
||||
└── SeqAutoRunCCWH52A.cs ← MOTF 시퀀스 구현 참조
|
||||
```
|
||||
|
||||
### 4-4. 구현 예정 시퀀스 클래스 구조
|
||||
```csharp
|
||||
// ILSOS_PrismaticScanner/Sequences/SeqAutoRunPrismaticScanner.cs
|
||||
public class SeqAutoRunPrismaticScanner : ISequence
|
||||
{
|
||||
private ScannerACS _acs;
|
||||
private Scanner _scanner;
|
||||
|
||||
protected override void DoProcess()
|
||||
{
|
||||
// Step 1. Scanner List 채우기 (LASA 레시피 기반)
|
||||
FillScannerList();
|
||||
|
||||
// Step 2. ACS 파라미터 전송
|
||||
SetMOTFParameters();
|
||||
|
||||
// Step 3. MOTF 시작
|
||||
_acs.MOTFStart();
|
||||
|
||||
// Step 4. 완료 대기
|
||||
WaitForComplete();
|
||||
}
|
||||
|
||||
private void FillScannerList()
|
||||
{
|
||||
// TODO: LASA 레시피에서 마킹 좌표 가져오기
|
||||
// var recipe = ... (MainRecipe)
|
||||
// scanner.SetMarkList(recipe.MarkPoints);
|
||||
}
|
||||
|
||||
private void SetMOTFParameters()
|
||||
{
|
||||
// TODO: 변수 맵 수신 후 실제 변수명으로 구현
|
||||
// _acs.SetMOTFVelocity(velocity);
|
||||
// _acs.SetMOTFAcc(acc);
|
||||
// _acs.SetLaserOnOffPosition(onPos, offPos);
|
||||
}
|
||||
|
||||
private void WaitForComplete()
|
||||
{
|
||||
// TODO: Timeout 처리 포함
|
||||
// while (!_acs.CheckMOTFComp()) { Thread.Sleep(10); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4-5. MOTF 좌표 오류 주의사항
|
||||
```
|
||||
주의: MOTF 트리거는 Stage X 엔코더만 기준
|
||||
→ 헤드 유닛 Y축 이동은 미반영
|
||||
→ R-section(라운드 코너)에서 위치 오차 발생 가능
|
||||
|
||||
원인:
|
||||
Stage X + 갈바노 X + 갈바노 Y 조합으로 실제 마킹 위치 결정
|
||||
→ Stage X 엔코더 트리거만으로는 Y 성분 누락
|
||||
|
||||
해결: 이정인 선임과 R-section 처리 방법 협의 필요
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 캘리브레이션
|
||||
|
||||
### 5-1. 방향
|
||||
```
|
||||
기존 소스와 동일하게 진행 (사수 피드백)
|
||||
→ WeldingCommon의 LaserPowerCalParam 그대로 사용
|
||||
→ ScannerACS.DoActivate()에서 이미 참조 구조 잡혀있음
|
||||
```
|
||||
|
||||
### 5-2. 현재 ScannerACS.cs 상태
|
||||
```csharp
|
||||
// DoActivate()에서 캘리브레이션 참조 준비됨
|
||||
// TODO: Scanner용 SettingIds 확정 후 연결
|
||||
// _calibration = env.SettingEntry[CommonSettingIds.LaserPowerCalParam]
|
||||
// as LaserPowerCalParam;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. TODO 체크리스트
|
||||
|
||||
### 이정인 선임 변수 맵 수신 전
|
||||
- [ ] 홈/서보/알람 버튼 XAML 추가
|
||||
- [ ] UCScannerMotionViewModel에 CMD_HomeStart 등 커맨드 추가
|
||||
- [ ] SeqAutoRunPrismaticScanner 클래스 골격 작성
|
||||
|
||||
### 이정인 선임 변수 맵 수신 후
|
||||
- [ ] ScannerACS.Parameter.cs 변수명 교체
|
||||
- [ ] eBuffer 번호 교체
|
||||
- [ ] MotorIds.eMotorIdx 축 번호 검증
|
||||
- [ ] MoveStageX() → ACS 버퍼 방식으로 교체
|
||||
- [ ] MOTF 파라미터 전송 구현
|
||||
- [ ] 실제 장비에서 동작 확인
|
||||
|
||||
### 장기 과제
|
||||
- [ ] R-section 위치 오차 처리 방법 협의
|
||||
- [ ] 캘리브레이션 연결
|
||||
- [ ] Scanner + ACS 통합 컨트롤러 클래스 설계
|
||||
@ -305,6 +305,9 @@ namespace ILSOS_PrismaticScanner
|
||||
//manual.AddSubMenu(CommonViewIds.LBAD, new UCLBADDevice(AuroraEnv, CommonDeviceIds.LBAD, CommonDeviceIds.IODevice));
|
||||
//manual.AddSubMenu(CommonViewIds.ConvEdgeObject, new UCConvEdgeObject(AuroraEnv));
|
||||
manual.AddSubMenu(CommonViewIds.ModelFinder, new UCManualModelFinder(new UCManualModelFinderViewModel(AuroraEnv)));
|
||||
#region 26.04.06 ACS 모션 스테이지 메뉴얼 추가 - 진행 예정이였으나, Gun 에 속해서 사용 애매함. View 자체를 전부 가져오지는 못함.
|
||||
#endregion
|
||||
|
||||
|
||||
// Manual - For Test
|
||||
//manual.AddSubMenu(CommonViewIds.TestDevice, new UCTestDevice(new UCTestDeviceViewModel(AuroraEnv)));
|
||||
|
||||
@ -33,6 +33,7 @@ using VisionCommon;
|
||||
using WeldingCommon;
|
||||
using WeldingCommon.Alarm;
|
||||
using WeldingCommon.Data;
|
||||
using WeldingCommon.Devices.ACS; // 26.04.06
|
||||
using WeldingCommon.Sequences;
|
||||
using WeldingCommon.Settings;
|
||||
using WeldingCommon.Utils;
|
||||
@ -78,6 +79,10 @@ namespace ILSOS_PrismaticScanner.Sequences
|
||||
|
||||
private static Scanner _Scanner;
|
||||
private static PAIX_PrismaticScanner _IO;
|
||||
|
||||
// 필드 선언 추가 (다른 필드들 옆에)
|
||||
private ScannerACS _ACS; // 26.04.06 NDY - MOTF용 ACS Stage X 제어
|
||||
|
||||
private Laser _Laser;
|
||||
private ILaser _LaserDevice;
|
||||
private LaserTruFiber _LaserTruFiber;
|
||||
@ -194,11 +199,15 @@ namespace ILSOS_PrismaticScanner.Sequences
|
||||
_Scanner = context.GetLaserScanner();
|
||||
_IO = context.Devices[CommonDeviceIds.IODevice] as PAIX_PrismaticScanner;
|
||||
|
||||
// 26.04.06 NDY 추가: ACS 디바이스 취득 (null-safe)
|
||||
// 변수 맵 수신 후 MOTFStart() 호출에 사용
|
||||
try { _ACS = context.Devices["ACS"] as ScannerACS; }
|
||||
catch { _ACS = null; Log.W("ACS 디바이스 취득 실패 (null 처리)"); }
|
||||
}
|
||||
private bool CheckDeviceReady(SequenceContext context)
|
||||
{
|
||||
List<string> deviceListToCheck = new List<string>() { CommonDeviceIds.Scanner, CommonDeviceIds.IODevice };
|
||||
|
||||
//List<string> deviceListToCheck = new List<string>() { CommonDeviceIds.Scanner, CommonDeviceIds.IODevice,DeviceIds.ACS }; 변수 맵 수신 후 ACS 주석 해제 위에 주석 처리
|
||||
bool isAllDeviceActivated = true;
|
||||
foreach (string item in deviceListToCheck) {
|
||||
if (!context.Devices[item].IsActivated) {
|
||||
@ -505,7 +514,24 @@ namespace ILSOS_PrismaticScanner.Sequences
|
||||
Log.I($"Welding List Space : {_Scanner.GetListSpace()}");
|
||||
DateTime weldingTime = DateTime.Now;
|
||||
_Scanner.ExecuteList(_WeldingScannerListNo);
|
||||
|
||||
|
||||
// ── 26.04.06 NDY 추가: ACS Stage X 이동 ──────────────
|
||||
// MOTF: Scanner List 실행과 동시에 Stage X 이동 시작
|
||||
// Stage X 엔코더가 트리거 → WaitForEncoderX 조건 도달 시 갈바노 마킹
|
||||
// TODO: 변수 맵 수신 후 _ACS.MOTFStart()로 교체
|
||||
// _ACS?.MOTFStart();
|
||||
// ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
_Scanner.WaitForListTaskCompleted(_SystemParameter.WeldLinesTaskTimeOut);
|
||||
|
||||
// ── 26.04.06 NDY 추가: ACS 완료 대기 ─────────────────
|
||||
// TODO: 변수 맵 수신 후 활성화
|
||||
// while (!_ACS.CheckMOTFComp()) { Thread.Sleep(10); }
|
||||
// ────────────────────────────────────────────────────
|
||||
|
||||
_MeasurementSpanTime = DateTime.Now.Subtract(weldingTime);
|
||||
Log.D(string.Format($"[ComponentTeachingRun] Component Welding Complete Time : {_MeasurementSpanTime.TotalMilliseconds}"));
|
||||
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
// WeldingCommon/Devices/ACS/ScannerACS.Parameter.cs
|
||||
using AuroraACS;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
namespace WeldingCommon.Devices.ACS
|
||||
{
|
||||
public partial class ScannerACS
|
||||
@ -19,6 +22,19 @@ namespace WeldingCommon.Devices.ACS
|
||||
const string rMOTFVelocity = "rPCset_SCANNER_MOTF_VEL"; // placeholder
|
||||
const string rMOTFAcc = "rPCset_SCANNER_MOTF_ACC"; // placeholder
|
||||
|
||||
#region 변수 맵 받으면 작업 순서
|
||||
//1. ScannerACS.Parameter.cs
|
||||
// → placeholder 변수명을 실제 변수명으로 교체
|
||||
|
||||
//2. ScannerACS.cs
|
||||
// → 축 번호 검증(ACSMotor 생성 시 넣은 번호)
|
||||
|
||||
//3. EquipDef.cs
|
||||
// → MotorIds의 eMotorIdx 번호 검증
|
||||
|
||||
//4. 빌드 후 실제 장비에서 동작 확인
|
||||
#endregion
|
||||
|
||||
// ── 레이저 ───────────────────────────────────────
|
||||
const string IsLaserOn = "LCI_DEVICE.LaserEnabled";
|
||||
const string iLaserUse = "iPCset_LASER_USE";
|
||||
|
||||
@ -65,6 +65,7 @@
|
||||
|
||||
public const string TestDevice = "TestDevice"; // For Test Device
|
||||
public const string TestSequence = "TestSequence"; // For Test Sequence
|
||||
public const string StageManual = "StageManual"; // 26.04.06
|
||||
|
||||
// Monitoring
|
||||
public const string PLCBitMonitoring = "PLCBitMonitoring";
|
||||
|
||||
@ -87,7 +87,7 @@ namespace WeldingCommon.Sequences
|
||||
sb.AddAction(SEQ_ENTER, Sequence_Enter);
|
||||
sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기
|
||||
|
||||
sb.AddAction(SEQ_MARKING_ON_THE_FLY_ON, MarkingOnTheFlyOn);
|
||||
sb.AddAction(SEQ_MARKING_ON_THE_FLY_ON, MarkingOnTheFlyOn);
|
||||
sb.AddAction(SEQ_RECORD_SIGNAL_ON, RecordSignalOn);
|
||||
sb.AddAction(SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM, LoadDrawObjectScannerParam);
|
||||
sb.AddAction(SEQ_MARKING_ON_THE_FLY_OFF, MarkingOnTheFlyOff);
|
||||
@ -225,6 +225,7 @@ namespace WeldingCommon.Sequences
|
||||
return SEQ_MARKING_ON_THE_FLY_ON;
|
||||
}
|
||||
|
||||
// MOTF 지원 중
|
||||
private SequenceActionResult MarkingOnTheFlyOn(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
if (_Scanner.Config.UseMarkingOnTheFly) {
|
||||
|
||||
@ -24,38 +24,47 @@
|
||||
</behavior:Interaction.Triggers>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Scanner 위치 표시 -->
|
||||
<Grid Grid.Row="0" Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox Header="X[mm]" Style="{StaticResource StGBMonitor}" Margin="0 0 3 3">
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ScannerXPos, StringFormat={}{0:0.000000}}"/>
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="{Binding ScannerXPos, StringFormat={}{0:0.000000}}"/>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Column="1" Header="Y[mm]" Style="{StaticResource StGBMonitor}" Margin="3 0 3 3" >
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ScannerYPos, StringFormat={}{0:0.000000}}"/>
|
||||
<GroupBox Grid.Column="1" Header="Y[mm]" Style="{StaticResource StGBMonitor}" Margin="3 0 3 3">
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="{Binding ScannerYPos, StringFormat={}{0:0.000000}}"/>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Column="2" Header="Status" Style="{StaticResource StGBMonitor}" Margin="3 0 3 3" >
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding IsScannerBusy, Converter={StaticResource convWorkConverter}}"/>
|
||||
<GroupBox Grid.Column="2" Header="Status" Style="{StaticResource StGBMonitor}" Margin="3 0 3 3">
|
||||
<TextBlock FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="{Binding IsScannerBusy, Converter={StaticResource convWorkConverter}}"/>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<!-- Scanner Motion -->
|
||||
<GroupBox Grid.Row="1" Header="Scanner Motion" Margin="0 3 3 0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="230"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="230"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="230"></RowDefinition>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="230"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Grid.Column="0" Margin="5">
|
||||
<usercontrols:UCKeyValue KeyText="Step Value" Value="{Binding StepValue}" DecimalPlaces="3" Unit="mm" KeyHorizontalAlignment="Right" KeyTextWidth="0.9*" />
|
||||
<usercontrols:UCKeyValue KeyText="Step Value" Value="{Binding StepValue}"
|
||||
DecimalPlaces="3" Unit="mm"
|
||||
KeyHorizontalAlignment="Right" KeyTextWidth="0.9*"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" Grid.Column="0" Margin="20 5 15 5">
|
||||
<Grid.ColumnDefinitions>
|
||||
@ -68,84 +77,116 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Button Grid.Row="0" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e" Command="{Binding CMD_JogMove}" CommandParameter="Up">▲</Button>
|
||||
<Button Grid.Row="1" Grid.Column="0" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e" Command="{Binding CMD_JogMove}" CommandParameter="Left">◀</Button>
|
||||
<Button Grid.Row="1" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e" Command="{Binding CMD_JogMove}" CommandParameter="Home">⌂</Button>
|
||||
<Button Grid.Row="1" Grid.Column="2" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e" Command="{Binding CMD_JogMove}" CommandParameter="Right">▶</Button>
|
||||
<Button Grid.Row="2" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e" Command="{Binding CMD_JogMove}" CommandParameter="Down">▼</Button>
|
||||
<Button Grid.Row="0" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Up">▲</Button>
|
||||
<Button Grid.Row="1" Grid.Column="0" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Left">◀</Button>
|
||||
<Button Grid.Row="1" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Home">⌂</Button>
|
||||
<Button Grid.Row="1" Grid.Column="2" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Right">▶</Button>
|
||||
<Button Grid.Row="2" Grid.Column="1" FontWeight="Bold" Margin="2" BorderBrush="#1e1e1e"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Down">▼</Button>
|
||||
</Grid>
|
||||
<Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="3*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="3*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"></RowDefinition>
|
||||
<RowDefinition Height="1*"></RowDefinition>
|
||||
<RowDefinition Height="0.3*"></RowDefinition>
|
||||
<RowDefinition Height="2*"></RowDefinition>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="0.3*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource StGuideTB}" VerticalAlignment="Center">Motion Speed</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource StGuideTB}" VerticalAlignment="Center">Motion Mode</TextBlock>
|
||||
<Grid Grid.Row="0" Grid.Column="1" Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0" Command="{Binding CMD_SpeedChanged}" CommandParameter="Low"
|
||||
Style="{StaticResource stRadio}" Content="LOW" Margin="3"/>
|
||||
Style="{StaticResource stRadio}" Content="LOW" Margin="3"/>
|
||||
<RadioButton Grid.Column="1" Command="{Binding CMD_SpeedChanged}" CommandParameter="Mid"
|
||||
Style="{StaticResource stRadio}" Content="MID" IsChecked="True" Margin="3"/>
|
||||
Style="{StaticResource stRadio}" Content="MID" IsChecked="True" Margin="3"/>
|
||||
<RadioButton Grid.Column="2" Command="{Binding CMD_SpeedChanged}" CommandParameter="High"
|
||||
Style="{StaticResource stRadio}" Content="HIGH" Margin="3"/>
|
||||
Style="{StaticResource stRadio}" Content="HIGH" Margin="3"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" Grid.Column="1" Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0" Command="{Binding CMD_MotionModeChanged}" CommandParameter="ABS"
|
||||
Style="{StaticResource stRadio}" Content="ABS" Margin="3" IsChecked="True"/>
|
||||
Style="{StaticResource stRadio}" Content="ABS" Margin="3" IsChecked="True"/>
|
||||
<RadioButton Grid.Column="1" Command="{Binding CMD_MotionModeChanged}" CommandParameter="REL"
|
||||
Style="{StaticResource stRadio}" Content="REL" Margin="3"/>
|
||||
Style="{StaticResource stRadio}" Content="REL" Margin="3"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="0.8*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="0.2*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="0.8*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="2*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="0.8*"/>
|
||||
<ColumnDefinition Width="0.2*"/>
|
||||
<ColumnDefinition Width="0.8*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"></RowDefinition>
|
||||
<RowDefinition Height="1.5*"></RowDefinition>
|
||||
<RowDefinition Height="1.5*"></RowDefinition>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1.5*"/>
|
||||
<RowDefinition Height="1.5*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Foreground="White" TextAlignment="Center" FontSize="8" >MinLimit</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" FontSize="8" Text="{Binding CommandPosLimitMinX, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"></TextBlock>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" FontSize="8" Text="{Binding CommandPosLimitMinY, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"></TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="3" Foreground="White" TextAlignment="Center" FontSize="8" >MaxLimit</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="3" FontSize="8" Text="{Binding CommandPosLimitMaxX, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"></TextBlock>
|
||||
<TextBlock Grid.Row="2" Grid.Column="3" FontSize="8" Text="{Binding CommandPosLimitMaxY, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"></TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Foreground="White" TextAlignment="Center" VerticalAlignment="Center" FontSize="10" Text="~"></TextBlock>
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" Foreground="White" TextAlignment="Center" VerticalAlignment="Center" FontSize="10" Text="~"></TextBlock>
|
||||
|
||||
<usercontrols:UCKeyValue Grid.Row="1" Grid.Column="0" KeyText="Axis X" Value="{Binding CommandPosX}" DecimalPlaces="3" Unit="mm" KeyHorizontalAlignment="Right" KeyTextWidth="0.6*" />
|
||||
<usercontrols:UCKeyValue Grid.Row="2" Grid.Column="0" KeyText="Axis Y" Value="{Binding CommandPosY}" DecimalPlaces="3" Unit="mm" KeyHorizontalAlignment="Right" KeyTextWidth="0.6*" />
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Foreground="White" TextAlignment="Center" FontSize="8">MinLimit</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" FontSize="8" Text="{Binding CommandPosLimitMinX, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" FontSize="8" Text="{Binding CommandPosLimitMinY, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="3" Foreground="White" TextAlignment="Center" FontSize="8">MaxLimit</TextBlock>
|
||||
<TextBlock Grid.Row="1" Grid.Column="3" FontSize="8" Text="{Binding CommandPosLimitMaxX, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="3" FontSize="8" Text="{Binding CommandPosLimitMaxY, StringFormat={}{0:0.000}}" Foreground="Gray" HorizontalAlignment="Center" TextAlignment="Center"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Foreground="White" TextAlignment="Center" VerticalAlignment="Center" FontSize="10" Text="~"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" Foreground="White" TextAlignment="Center" VerticalAlignment="Center" FontSize="10" Text="~"/>
|
||||
<usercontrols:UCKeyValue Grid.Row="1" Grid.Column="0" KeyText="Axis X" Value="{Binding CommandPosX}"
|
||||
DecimalPlaces="3" Unit="mm" KeyHorizontalAlignment="Right" KeyTextWidth="0.6*"/>
|
||||
<usercontrols:UCKeyValue Grid.Row="2" Grid.Column="0" KeyText="Axis Y" Value="{Binding CommandPosY}"
|
||||
DecimalPlaces="3" Unit="mm" KeyHorizontalAlignment="Right" KeyTextWidth="0.6*"/>
|
||||
<UniformGrid Grid.Row="1" Grid.Column="4" Grid.RowSpan="2" Columns="2">
|
||||
<Button Margin="3" Command="{Binding CMD_CommandPosMove}" CommandParameter="X" Content="Move X" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto" Style="{StaticResource StButtonAccentBlue}" />
|
||||
<Button Margin="3" Command="{Binding CMD_CommandPosMove}" CommandParameter="Y" Content="Move Y" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto" Style="{StaticResource StButtonAccentBlue}" />
|
||||
<Button Margin="3" Command="{Binding CMD_CommandPosMove}" CommandParameter="X"
|
||||
Content="Move X" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Height="auto" Style="{StaticResource StButtonAccentBlue}"/>
|
||||
<Button Margin="3" Command="{Binding CMD_CommandPosMove}" CommandParameter="Y"
|
||||
Content="Move Y" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Height="auto" Style="{StaticResource StButtonAccentBlue}"/>
|
||||
</UniformGrid>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 26.04.06 NDY Stage X Motion 섹션 추가 -->
|
||||
<GroupBox Grid.Row="2" Header="Stage X Motion (ACS)" Margin="0 3 3 0"
|
||||
IsEnabled="{Binding IsStageXActivated}">
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox Grid.Column="0" Header="Stage X[mm]"
|
||||
Style="{StaticResource StGBMonitor}" Margin="0 0 5 0" MinWidth="120">
|
||||
<TextBlock FontSize="18" FontWeight="Bold"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Text="{Binding StageXPos, StringFormat={}{0:0.000}}"/>
|
||||
</GroupBox>
|
||||
<Button Grid.Column="1" FontWeight="Bold" Margin="3"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Stage_X_Left">◀ −</Button>
|
||||
<Button Grid.Column="2" FontWeight="Bold" Margin="3"
|
||||
Command="{Binding CMD_JogMove}" CommandParameter="Stage_X_Right">+ ▶</Button>
|
||||
<TextBlock Grid.Column="3" FontSize="10" Foreground="Gray"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
Text="* 이미지 방향 반전 적용"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
@ -1,7 +1,9 @@
|
||||
using Aurora;
|
||||
using Aurora.Api;
|
||||
using Aurora.Api.Devices;
|
||||
using Aurora.Api.Manager;
|
||||
using Aurora.View;
|
||||
using AuroraACS; // 26.04.06 NDY 추가
|
||||
using AuroraLaser;
|
||||
using AuroraLaserScanner;
|
||||
using HarfBuzzSharp;
|
||||
@ -41,13 +43,10 @@ namespace WeldingCommon.Views
|
||||
public ICommand CMD_VisibleChanged { get; }
|
||||
public ICommand CMD_SpeedChanged { get; }
|
||||
public ICommand CMD_MotionModeChanged { get; }
|
||||
|
||||
public ICommand CMD_JogMove { get; }
|
||||
public ICommand CMD_CommandPosMove { get; }
|
||||
|
||||
|
||||
private readonly IAuroraEnvironment _Aurora;
|
||||
|
||||
private readonly Scanner _Scanner;
|
||||
private readonly Laser _Laser;
|
||||
private readonly ScannerConfig _ScannerConfig;
|
||||
@ -82,6 +81,16 @@ namespace WeldingCommon.Views
|
||||
|
||||
private readonly DispatcherTimer _MonitorTimer;
|
||||
|
||||
// 26.04.06 NDY Stage X 관련 필드 추가 ==================
|
||||
private ACSMotor _MotorX;
|
||||
|
||||
private double _StageXPos;
|
||||
public double StageXPos { get => _StageXPos; set => SetProperty(ref _StageXPos, value); }
|
||||
|
||||
private bool _IsStageXActivated;
|
||||
public bool IsStageXActivated { get => _IsStageXActivated; set => SetProperty(ref _IsStageXActivated, value); }
|
||||
// ========================================================
|
||||
|
||||
// PAM, RUW 처럼 2개 이상의 scanner 를 사용하는 경우가 있어, scannerId 를 받는 형태로 생성
|
||||
public UCScannerMotionViewModel(IAuroraEnvironment aurora, string scannerId)
|
||||
{
|
||||
@ -91,6 +100,11 @@ namespace WeldingCommon.Views
|
||||
_Laser = _Aurora.DeviceManager[CommonDeviceIds.Laser] as Laser;
|
||||
_ScannerConfig = _Aurora.DeviceManager.GetDeviceConfig(scannerId) as ScannerConfig;
|
||||
|
||||
// 26.04.06 NDY Stage X 모터 연결 추가 ===============
|
||||
try { _MotorX = _Aurora.DeviceManager["AxisX2"] as ACSMotor; }
|
||||
catch { _MotorX = null; }
|
||||
// ====================================================
|
||||
|
||||
InitVariable();
|
||||
|
||||
CMD_VisibleChanged = new DelegateCommand(VisibleChanged);
|
||||
@ -113,157 +127,139 @@ namespace WeldingCommon.Views
|
||||
private void VisibleChanged(object obj)
|
||||
{
|
||||
bool visible = (bool)obj;
|
||||
if (visible) {
|
||||
if (visible)
|
||||
{
|
||||
Init_XYLimitPos();
|
||||
_MonitorTimer.Start();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_MonitorTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void Init_XYLimitPos()
|
||||
{
|
||||
// TODO: Limit 값을 Min, Max 로 따로 Setting 입력값으로 가져와야 할 수도 있음. 우선 현상태 유지
|
||||
CommandPosLimitMinX = -1 * _ScannerConfig.ScanXSize / 2;
|
||||
CommandPosLimitMaxX = _ScannerConfig.ScanXSize / 2;
|
||||
|
||||
CommandPosLimitMinY = -1 * _ScannerConfig.ScanYSize / 2;
|
||||
CommandPosLimitMaxY = _ScannerConfig.ScanYSize / 2;
|
||||
|
||||
//CommandPosXLimit = string.Format($"{-1 * _ScannerConfig.ScanXSize / 2} ~ {_ScannerConfig.ScanXSize / 2}");
|
||||
//CommandPosYLimit = string.Format($"{-1 * _ScannerConfig.ScanYSize / 2} ~ {_ScannerConfig.ScanYSize / 2}");
|
||||
}
|
||||
|
||||
private void OnMonitoring(object sender, EventArgs e)
|
||||
{
|
||||
// 기존 Scanner 모니터링
|
||||
double xPos, yPos;
|
||||
if (_Scanner != null && _Scanner.IsActivated) {
|
||||
if (_Scanner != null && _Scanner.IsActivated)
|
||||
{
|
||||
_Scanner.GetXYPos(out xPos, out yPos);
|
||||
ScannerXPos = xPos;
|
||||
ScannerYPos = yPos;
|
||||
|
||||
IsScannerBusy = _Scanner.GetBusyStatus();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ScannerXPos = 0;
|
||||
ScannerYPos = 0;
|
||||
IsScannerBusy = false;
|
||||
}
|
||||
|
||||
// 26.04.06 NDY Stage X 모니터링 추가 ================
|
||||
if (_MotorX != null && _MotorX.IsActivated)
|
||||
{
|
||||
StageXPos = _MotorX.GetActualPos();
|
||||
IsStageXActivated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsStageXActivated = false;
|
||||
}
|
||||
// ====================================================
|
||||
}
|
||||
|
||||
private void PerformCmdSpeedChanged(object commandParameter)
|
||||
{
|
||||
switch ((string)commandParameter) {
|
||||
case "Low": {
|
||||
_VelocityRate = 0.5;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Mid": {
|
||||
_VelocityRate = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "High": {
|
||||
_VelocityRate = 1.5;
|
||||
}
|
||||
break;
|
||||
switch ((string)commandParameter)
|
||||
{
|
||||
case "Low": _VelocityRate = 0.5; break;
|
||||
case "Mid": _VelocityRate = 1; break;
|
||||
case "High": _VelocityRate = 1.5; break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformCmdMotionModeChanged(object commandParameter)
|
||||
{
|
||||
switch ((string)commandParameter) {
|
||||
case "ABS": {
|
||||
_MotionMode = eMotionMode.ABS;
|
||||
}
|
||||
break;
|
||||
|
||||
case "REL": {
|
||||
_MotionMode = eMotionMode.REL;
|
||||
}
|
||||
break;
|
||||
switch ((string)commandParameter)
|
||||
{
|
||||
case "ABS": _MotionMode = eMotionMode.ABS; break;
|
||||
case "REL": _MotionMode = eMotionMode.REL; break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformCmdJogMove(object commandParameter)
|
||||
{
|
||||
// TODO: Left, Right, Up, Down 은 장비 Scanner 의 방향에 따라 달라질 수 있다
|
||||
// 양산중에는 동작 하면 안됨
|
||||
var MainSequence = _Aurora.SequenceEntry[CommonSequenceIds.SeqAutoRun].RunState;
|
||||
if(MainSequence == SequenceRunState.Running)
|
||||
if (MainSequence == SequenceRunState.Running)
|
||||
return;
|
||||
|
||||
switch ((string)commandParameter) {
|
||||
case "Left": {
|
||||
MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.MINUS);
|
||||
}
|
||||
break;
|
||||
switch ((string)commandParameter)
|
||||
{
|
||||
case "Left": MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.MINUS); break;
|
||||
case "Right": MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.PLUS); break;
|
||||
case "Up": MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.PLUS); break;
|
||||
case "Down": MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.MINUS); break;
|
||||
case "Home": MoveJogHome(); break;
|
||||
|
||||
case "Right": {
|
||||
MoveJogXYPos(eAxisType.AXIS_X, eJogDirection.PLUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Up": {
|
||||
MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.PLUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Down": {
|
||||
MoveJogXYPos(eAxisType.AXIS_Y, eJogDirection.MINUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Home": {
|
||||
MoveJogHome();
|
||||
}
|
||||
break;
|
||||
// 26.04.06 NDY Stage X 버튼 추가 =================
|
||||
case "Stage_X_Left": MoveStageX(eJogDirection.MINUS); break;
|
||||
case "Stage_X_Right": MoveStageX(eJogDirection.PLUS); break;
|
||||
// =================================================
|
||||
}
|
||||
}
|
||||
|
||||
// 26.04.06 NDY Stage X 이동 메서드 추가 ==================
|
||||
private void MoveStageX(eJogDirection direction)
|
||||
{
|
||||
if (_MotorX == null || !_MotorX.IsActivated) return;
|
||||
|
||||
// 이미지 기준 방향 반전 적용
|
||||
double step = direction == eJogDirection.PLUS ? -StepValue : +StepValue;
|
||||
Log.I($"Stage X Move : {step}mm");
|
||||
|
||||
_MotorX.SetTargetPos(step, TargetPosType.REL);
|
||||
_MotorX.Move();
|
||||
}
|
||||
// =========================================================
|
||||
|
||||
private void MoveJogXYPos(eAxisType axisType, eJogDirection direction)
|
||||
{
|
||||
double xPos = 0.0;
|
||||
double yPos = 0.0;
|
||||
switch (axisType) {
|
||||
case eAxisType.AXIS_X: {
|
||||
if (direction == eJogDirection.MINUS) {
|
||||
xPos = StepValue * -1;
|
||||
yPos = 0;
|
||||
} else if (direction == eJogDirection.PLUS) {
|
||||
xPos = StepValue;
|
||||
yPos = 0;
|
||||
}
|
||||
switch (axisType)
|
||||
{
|
||||
case eAxisType.AXIS_X:
|
||||
{
|
||||
if (direction == eJogDirection.MINUS) { xPos = StepValue * -1; yPos = 0; }
|
||||
else if (direction == eJogDirection.PLUS) { xPos = StepValue; yPos = 0; }
|
||||
}
|
||||
break;
|
||||
|
||||
case eAxisType.AXIS_Y: {
|
||||
if (direction == eJogDirection.MINUS) {
|
||||
xPos = 0;
|
||||
yPos = StepValue * -1;
|
||||
} else if (direction == eJogDirection.PLUS) {
|
||||
xPos = 0;
|
||||
yPos = StepValue;
|
||||
}
|
||||
case eAxisType.AXIS_Y:
|
||||
{
|
||||
if (direction == eJogDirection.MINUS) { xPos = 0; yPos = StepValue * -1; }
|
||||
else if (direction == eJogDirection.PLUS) { xPos = 0; yPos = StepValue; }
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 현재 Curruent Pos 기준으로, 입력방향으로 입력값이 Limit 를 넘어 서는지 확인 (Rel 임)
|
||||
if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) {
|
||||
Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다."));
|
||||
if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos))
|
||||
{
|
||||
Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate;
|
||||
_Scanner.SetJumpSpeedCtrl(finalVelocity);
|
||||
_Scanner.JumpRel(xPos, yPos);
|
||||
|
||||
//Jump 후 Speed 원복
|
||||
_Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed);
|
||||
}
|
||||
|
||||
@ -272,23 +268,15 @@ namespace WeldingCommon.Views
|
||||
double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate;
|
||||
_Scanner.SetJumpSpeedCtrl(finalVelocity);
|
||||
_Scanner.JumpAbs(0, 0);
|
||||
|
||||
//Jump 후 Speed 원복
|
||||
_Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed);
|
||||
}
|
||||
|
||||
private void PerformCmdCommandPosMove(object commandParameter)
|
||||
{
|
||||
switch ((string)commandParameter) {
|
||||
case "X": {
|
||||
MoveCommandXYPos(eAxisType.AXIS_X);
|
||||
}
|
||||
break;
|
||||
|
||||
case "Y": {
|
||||
MoveCommandXYPos(eAxisType.AXIS_Y);
|
||||
}
|
||||
break;
|
||||
switch ((string)commandParameter)
|
||||
{
|
||||
case "X": MoveCommandXYPos(eAxisType.AXIS_X); break;
|
||||
case "Y": MoveCommandXYPos(eAxisType.AXIS_Y); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,42 +284,35 @@ namespace WeldingCommon.Views
|
||||
{
|
||||
double xPos = 0.0;
|
||||
double yPos = 0.0;
|
||||
switch (axisType) {
|
||||
case eAxisType.AXIS_X: {
|
||||
switch (axisType)
|
||||
{
|
||||
case eAxisType.AXIS_X:
|
||||
{
|
||||
xPos = CommandPosX;
|
||||
|
||||
if (_MotionMode == eMotionMode.ABS) {
|
||||
yPos = _Scanner.GetCommandPosY();
|
||||
} else {
|
||||
yPos = 0.0;
|
||||
}
|
||||
yPos = _MotionMode == eMotionMode.ABS ? _Scanner.GetCommandPosY() : 0.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case eAxisType.AXIS_Y: {
|
||||
if (_MotionMode == eMotionMode.ABS) {
|
||||
xPos = _Scanner.GetCommandPosX();
|
||||
} else {
|
||||
xPos = 0.0;
|
||||
}
|
||||
|
||||
case eAxisType.AXIS_Y:
|
||||
{
|
||||
xPos = _MotionMode == eMotionMode.ABS ? _Scanner.GetCommandPosX() : 0.0;
|
||||
yPos = CommandPosY;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 현재 Curruent Pos 기준으로, 입력방향으로 입력값이 Limit 를 넘어 서는지 확인
|
||||
if (_MotionMode == eMotionMode.ABS) {
|
||||
if (CheckOverLimitPos(xPos, yPos)) {
|
||||
Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다."));
|
||||
if (_MotionMode == eMotionMode.ABS)
|
||||
{
|
||||
if (CheckOverLimitPos(xPos, yPos))
|
||||
{
|
||||
Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos)) {
|
||||
Log.E(string.Format("움직이려는 범위가 스캐너 범위를 초과하였습니다."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CheckOverLimitPos(ScannerXPos + xPos, ScannerYPos + yPos))
|
||||
{
|
||||
Log.E("움직이려는 범위가 스캐너 범위를 초과하였습니다.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -339,25 +320,19 @@ namespace WeldingCommon.Views
|
||||
double finalVelocity = _ScannerConfig.JumpSpeed * _VelocityRate;
|
||||
_Scanner.SetJumpSpeedCtrl(finalVelocity);
|
||||
|
||||
if (_MotionMode == eMotionMode.ABS) {
|
||||
if (_MotionMode == eMotionMode.ABS)
|
||||
_Scanner.JumpAbs(xPos, yPos);
|
||||
} else {
|
||||
else
|
||||
_Scanner.JumpRel(xPos, yPos);
|
||||
}
|
||||
|
||||
//Jump 후 Speed 원복
|
||||
_Scanner.SetJumpSpeedCtrl(_ScannerConfig.JumpSpeed);
|
||||
}
|
||||
|
||||
private bool CheckOverLimitPos(double calcPosX, double calcPosY)
|
||||
{
|
||||
if (calcPosX < CommandPosLimitMinX || calcPosX > CommandPosLimitMaxX) {
|
||||
return true;
|
||||
} else if (calcPosY < CommandPosLimitMinY || calcPosY > CommandPosLimitMaxY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (calcPosX < CommandPosLimitMinX || calcPosX > CommandPosLimitMaxX) return true;
|
||||
if (calcPosY < CommandPosLimitMinY || calcPosY > CommandPosLimitMaxY) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user