Add project documentation and upload helper
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# Auto_Seat
|
||||
|
||||
## 개요
|
||||
|
||||
차량 시트 자동 제어 프로젝트입니다. EEPROM 설정, 점화/주차 조건, 릴레이 출력, 자동 보정, 시리얼 명령 처리를 포함합니다.
|
||||
|
||||
분류: AutoSeat_UL, Auto_Seat_LL과 같은 자동 시트 제어 계열의 기준 프로젝트입니다.
|
||||
|
||||
## 코드 구성 요약
|
||||
|
||||
- 분석한 파일 수: 3
|
||||
- 사용 라이브러리/include: EEPROM.h
|
||||
- 코드에서 확인되는 주요 모듈: EEPROM, Serial
|
||||
- 코드에서 확인되는 핀/입출력 단서: ignitionPin:INPUT, parkingPin:INPUT, seatRelayD8:OUTPUT, seatRelayD9:OUTPUT
|
||||
|
||||
## 파일별 설명
|
||||
|
||||
### `Auto_Seat.ino`
|
||||
|
||||
- 역할: Arduino의 `setup()`/`loop()`를 포함한 실행 스케치입니다.
|
||||
- include/의존성: EEPROM.h
|
||||
- 주요 함수: applySeatAction, clampPosition, getTargetForConfirmedMode, handleRelativeStep, handleSerial, isSeatCommandBusy, loadSettings, loop, measurement, normalizeMotionState, printIntro, printStatus, processSerialCommand, readUint16, registerIgnitionOffUse, requiresParkingForCommand, saveCurrentPositionCommand, seat, setRelay, setup, startAutoCalibration, startDownEdgeMargin, updateAutoCalibration, updateConfirmedDriveMode, updateDebugOutput, updateManualStepStatus, updateMovement, updateRelayOutput, writeUint16
|
||||
- 주요 전역값/설정값: AUTO_CALIBRATION_DELAY_MS=300000UL, AUTO_CALIBRATION_DOWN_MS=6000UL, AUTO_CALIBRATION_UP_MS=7000UL, DEBUG_INTERVAL_MS=1000UL, DOWN_EDGE_MARGIN_MS=300UL, DOWN_SPEED_DEN=10, DOWN_SPEED_NUM=11, DRIVE_CONFIRM_MS=80UL, EEPROM_MAGIC_ADDR=0, EEPROM_MAGIC_VALUE=0x64, IGNITION_STABILIZE_MS=1000UL, MANUAL_STEP_MS=500, PARK_CONFIRM_MS=250UL, PARKING_OFF_THRESHOLD=940, PARKING_ON_THRESHOLD=950, RELAY_DEADTIME_MS=120UL, SEAT_HARD_LIMIT_UP_MS=6000, USES_BEFORE_AUTO_CALIBRATION=10
|
||||
- 핀/입출력 설정: ignitionPin:INPUT, parkingPin:INPUT, seatRelayD8:OUTPUT, seatRelayD9:OUTPUT
|
||||
- 입출력/통신 호출: analogRead, digitalRead, EEPROM.read, EEPROM.update, Serial.available, Serial.begin, Serial.print, Serial.println
|
||||
|
||||
### `report.html`
|
||||
|
||||
- 역할: 프로젝트 보고서 또는 설명을 담은 HTML 문서입니다.
|
||||
- include/의존성: -
|
||||
- 주요 함수: -
|
||||
- 주요 전역값/설정값: -
|
||||
- 핀/입출력 설정: -
|
||||
- 입출력/통신 호출: EEPROM.update
|
||||
|
||||
### `upload.ps1`
|
||||
|
||||
- 역할: 업로드/자동화에 사용되는 PowerShell 스크립트입니다.
|
||||
- include/의존성: -
|
||||
- 주요 함수: -
|
||||
- 주요 전역값/설정값: -
|
||||
- 핀/입출력 설정: -
|
||||
- 입출력/통신 호출: -
|
||||
|
||||
## 동작 흐름
|
||||
|
||||
1. `setup()`에서 시리얼, 센서, 통신 모듈, LCD/릴레이/핀 모드 등 초기 설정을 수행합니다.
|
||||
2. `loop()`에서 센서 측정, 입력 확인, 상태 계산, 출력 제어, 통신 전송 또는 화면 갱신을 반복합니다.
|
||||
3. 보조 함수들은 측정값 변환, 값 변화 감지, 릴레이/모터 제어, 시간 표시, 네트워크 응답 같은 세부 동작을 나눠 담당합니다.
|
||||
|
||||
## 빌드 및 사용 메모
|
||||
|
||||
- Arduino IDE 또는 PlatformIO에서 폴더명과 같은 대표 스케치를 열어 빌드합니다.
|
||||
- 코드에 포함된 네트워크 주소, Wi-Fi 정보, DB 정보, 장치 핀 번호는 실제 하드웨어 구성에 맞춰 확인해야 합니다.
|
||||
- 공개 저장소에 올릴 때는 비밀번호, 토큰, 차량별 민감 정보가 포함되지 않았는지 확인합니다.
|
||||
+305
@@ -0,0 +1,305 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Auto Seat 동작 시뮬레이션 보고서</title>
|
||||
<style>
|
||||
:root {
|
||||
--ink: #17202a;
|
||||
--muted: #5f6b77;
|
||||
--line: #d8e0e8;
|
||||
--soft: #f5f7fa;
|
||||
--ok: #0b7a3b;
|
||||
--warn: #9a5b00;
|
||||
--bad: #a22020;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, "Noto Sans KR", sans-serif;
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
background: #fff;
|
||||
}
|
||||
header {
|
||||
padding: 28px 36px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--soft);
|
||||
}
|
||||
main {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: 28px 24px 48px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 28px;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 34px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-size: 21px;
|
||||
}
|
||||
h3 {
|
||||
margin-top: 22px;
|
||||
font-size: 17px;
|
||||
}
|
||||
.meta {
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.card {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
background: #fff;
|
||||
}
|
||||
.card strong {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 12px 0 18px;
|
||||
font-size: 14px;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid var(--line);
|
||||
padding: 8px 10px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background: var(--soft);
|
||||
}
|
||||
code, pre {
|
||||
font-family: Consolas, Monaco, "Courier New", monospace;
|
||||
}
|
||||
code {
|
||||
background: #eef2f7;
|
||||
padding: 1px 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
pre {
|
||||
overflow-x: auto;
|
||||
background: #101820;
|
||||
color: #e8eef4;
|
||||
padding: 14px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.ok { color: var(--ok); font-weight: 700; }
|
||||
.warn { color: var(--warn); font-weight: 700; }
|
||||
.bad { color: var(--bad); font-weight: 700; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Auto Seat 동작 시뮬레이션 보고서</h1>
|
||||
<div class="meta">대상 파일: <code>Auto_Seat.ino</code> / 현재 코드 기준</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h2>1. 현재 핵심 설정</h2>
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<strong>최대 상승 가능 위치</strong>
|
||||
<code>SEAT_HARD_LIMIT_UP_MS = 6000</code>
|
||||
<p>모든 자동/수동 위치 목표는 0..6000ms 범위 안에서만 허용됩니다.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>자동 상승 위치</strong>
|
||||
<code>storedSeatPositionMs = EEPROM</code>
|
||||
<p>하드코딩 기본 위치는 사용하지 않고 EEPROM에서 읽습니다. EEPROM 초기화 시 6000ms로 설정됩니다.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>하강 속도 추정</strong>
|
||||
<code>11 / 10</code>
|
||||
<p>일반 자동 하강과 수동 하강 위치 계산은 상승보다 1.1배 빠른 것으로 추정합니다.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>수동 스텝</strong>
|
||||
<code>MANUAL_STEP_MS = 500</code>
|
||||
<p><code>u</code>는 +500ms, <code>d</code>는 -500ms 이동 목표를 설정합니다.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>자동 보정</strong>
|
||||
<code>UP 7000ms -> DOWN 6000ms</code>
|
||||
<p>10회 사용 후 시동 OFF 상태 5분 경과 시 자동 보정합니다. <code>c</code> 명령은 즉시 보정합니다.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>릴레이 보호</strong>
|
||||
<code>RELAY_DEADTIME_MS = 120</code>
|
||||
<p>상승/하강 반전 시 릴레이를 잠깐 OFF로 두어 접점 부담을 줄입니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>2. 입력 신호 판정</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>항목</th><th>조건</th><th>결과</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>P ON</td><td><code>parkingRawValue >= 950</code></td><td><code>parkingState = HIGH</code></td></tr>
|
||||
<tr><td>P OFF</td><td><code>parkingRawValue <= 940</code></td><td><code>parkingState = LOW</code></td></tr>
|
||||
<tr><td>주행 raw</td><td><code>IG1 HIGH && P LOW</code></td><td>시트 상승 목표 상태</td></tr>
|
||||
<tr><td>주행 확정</td><td>주행 raw가 80ms 유지</td><td><code>confirmedDriveMode = HIGH</code></td></tr>
|
||||
<tr><td>P/비주행 확정</td><td>비주행 raw가 250ms 유지</td><td><code>confirmedDriveMode = LOW</code></td></tr>
|
||||
<tr><td>시동 직후 안정화</td><td>IG1 LOW -> HIGH 후 1000ms</td><td>릴레이 OFF, P 신호 튐 무시</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>3. 장시간 주차 후 전원 인가부터 시뮬레이션</h2>
|
||||
<h3>3.1 잠금 해제 직후</h3>
|
||||
<pre>IG1 = LOW
|
||||
P = LOW
|
||||
confirmedDriveMode = LOW
|
||||
targetPosMs = 0
|
||||
relay = OFF</pre>
|
||||
<p>사용자 설명 기준으로 잠금 해제 직후에는 IG1 OFF, P OFF입니다. 코드는 주행 조건을 <code>IG1 HIGH && P LOW</code>로 보므로 상승하지 않습니다.</p>
|
||||
|
||||
<h3>3.2 브레이크 후 시동 ON 직후</h3>
|
||||
<pre>IG1 LOW -> HIGH
|
||||
isStabilizing = true
|
||||
for 1000ms:
|
||||
seat(0)
|
||||
relay = OFF</pre>
|
||||
<p>시동 직후 P가 약 1초 동안 ON/OFF/ON으로 흔들려도 안정화 구간에서 릴레이는 동작하지 않습니다.</p>
|
||||
|
||||
<h3>3.3 P단 유지</h3>
|
||||
<pre>IG1 = HIGH
|
||||
P = HIGH
|
||||
confirmedDriveMode = LOW
|
||||
targetPosMs = 0</pre>
|
||||
<p>P단에서는 목표 위치가 0입니다. 현재 추정 위치가 0보다 높으면 하강합니다.</p>
|
||||
|
||||
<h3>3.4 P단 외 이동</h3>
|
||||
<pre>P = LOW for 80ms
|
||||
confirmedDriveMode = HIGH
|
||||
targetPosMs = storedSeatPositionMs
|
||||
relay = UP until currentPosMs reaches targetPosMs</pre>
|
||||
<p>P단 외 상태가 80ms 유지되면 EEPROM에 저장된 위치까지 상승합니다.</p>
|
||||
|
||||
<h3>3.5 P단 복귀 또는 시동 OFF</h3>
|
||||
<pre>confirmedDriveMode = LOW
|
||||
targetPosMs = 0
|
||||
currentPosMs -= deltaTime * 11 / 10
|
||||
when currentPosMs <= 0:
|
||||
currentPosMs = 0
|
||||
DOWN relay extra 300ms
|
||||
relay = OFF</pre>
|
||||
<p>하강은 1.1배 속도로 위치를 추정하고, 바닥 도달 후 300ms 추가 하강으로 바닥 밀착감을 줍니다.</p>
|
||||
|
||||
<h2>4. 한 글자 시리얼 명령</h2>
|
||||
<p>시리얼 연결 후 처음에는 잠금 상태입니다. 빈 Enter를 한 번 입력하면 도움말과 현재 상태를 출력하고, 그때부터 한 글자 명령을 사용할 수 있습니다. 잠금 해제 후 Enter 단독 입력은 아무 동작도 하지 않습니다. 안전을 위해 <code>p/u/d/a/c/r</code> 명령은 P단에서만 실행됩니다.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>명령</th><th>동작</th><th>응답</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td><code>s</code></td><td>현재 상태 1회 출력</td><td>상태 ACK 출력</td></tr>
|
||||
<tr><td><code>u</code></td><td>현재 추정 위치에서 +500ms 목표 설정</td><td>현재 위치/목표 출력</td></tr>
|
||||
<tr><td><code>d</code></td><td>현재 추정 위치에서 -500ms 목표 설정</td><td>현재 위치/목표 출력</td></tr>
|
||||
<tr><td><code>p</code></td><td>현재 추정 위치를 EEPROM 자동 상승 위치로 저장</td><td>저장된 위치 출력</td></tr>
|
||||
<tr><td><code>g</code></td><td>1초마다 debug 출력 시작</td><td>debug 중에는 <code>x</code>만 작동</td></tr>
|
||||
<tr><td><code>x</code></td><td>debug 모드 종료 전용</td><td>debug 종료 후 상태 출력</td></tr>
|
||||
<tr><td><code>a</code></td><td>수동 모드 해제, 기어 기반 자동 목표로 복귀</td><td>상태 출력</td></tr>
|
||||
<tr><td><code>c</code></td><td>즉시 보정: 상승 7초, 하강 6초, 위치 0 설정</td><td>상태 출력</td></tr>
|
||||
<tr><td><code>r</code></td><td>10회 자동 보정 카운터 초기화</td><td>상태 출력</td></tr>
|
||||
<tr><td><code>h</code></td><td>도움말 출력</td><td>도움말 + 현재 상태 출력</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><span class="warn">주의:</span> 명령은 한 글자만 받습니다. <code>debug</code>, <code>down</code>, <code>position 2000</code>처럼 긴 문자열은 실행하지 않습니다.</p>
|
||||
|
||||
<h2>5. 수동 위치 세팅 시뮬레이션</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>현재 추정 위치</th><th>입력</th><th>계산</th><th>결과</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>2000</td><td><code>u</code></td><td>2000 + 500 = 2500</td><td>목표 2500으로 상승, 상태 출력</td></tr>
|
||||
<tr><td>2500</td><td><code>u</code></td><td>2500 + 500 = 3000</td><td>목표 3000으로 상승, 상태 출력</td></tr>
|
||||
<tr><td>3000</td><td><code>p</code></td><td>현재 위치 3000 저장</td><td>EEPROM 저장 위치가 3000으로 변경</td></tr>
|
||||
<tr><td>3000</td><td>P단 복귀</td><td>목표 0</td><td>하강</td></tr>
|
||||
<tr><td>0</td><td>P단 외 이동</td><td>목표 EEPROM 3000</td><td>3000까지 자동 상승</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>6. 범위 초과 시뮬레이션</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>현재 추정 위치</th><th>입력</th><th>계산</th><th>결과</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>5800</td><td><code>u</code></td><td>6300</td><td>0..6000 범위 초과, 경고 출력, 목표 변경 없음</td></tr>
|
||||
<tr><td>200</td><td><code>d</code></td><td>-300</td><td>0..6000 범위 초과, 경고 출력, 목표 변경 없음</td></tr>
|
||||
<tr><td>임의</td><td><code>abc</code></td><td>한 글자 아님</td><td>실행 거절, ACK 상태 출력</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>7. 10회 사용 후 자동 보정 시뮬레이션</h2>
|
||||
<pre>each IG1 HIGH -> LOW:
|
||||
useCount++
|
||||
EEPROM.update(useCount)
|
||||
|
||||
if useCount >= 10 and IG1 LOW for 5 minutes:
|
||||
UP relay ON for 7000ms
|
||||
DOWN relay ON for 6000ms
|
||||
relay OFF
|
||||
currentPosMs = 0
|
||||
targetPosMs = 0
|
||||
useCount = 0</pre>
|
||||
<p>자동 보정 중 시동이 켜지면 중단합니다. 단, <code>c</code>로 시작한 강제 보정은 IG1 ON 상태에서도 끝까지 진행합니다.</p>
|
||||
|
||||
<h2>8. 현재 주의 사항</h2>
|
||||
<ul>
|
||||
<li>시트 위치는 실제 센서가 아니라 시간 기반 추정값입니다.</li>
|
||||
<li>전원 차단 후 재부팅하면 <code>currentPosMs</code>는 0에서 시작합니다.</li>
|
||||
<li><code>u</code>/<code>d</code>는 위치 조절만 하고 EEPROM 저장은 하지 않습니다. 저장은 반드시 <code>p</code>로 합니다.</li>
|
||||
<li><code>d</code>는 하강, <code>g</code>는 debug입니다. debug 충돌을 피하기 위해 <code>d</code>를 debug로 쓰지 않습니다.</li>
|
||||
<li>debug 상태에서는 <code>x</code>만 작동하며, <code>r</code>, <code>a</code>, <code>s</code>, <code>u</code>, <code>d</code>, <code>p</code>, <code>c</code>는 모두 무시됩니다.</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. 추가 예외처리 기준</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>예외 상황</th><th>처리</th><th>목적</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>시트 이동 중 키 입력</td>
|
||||
<td><code>ERR: busy</code> 출력 후 명령 무시</td>
|
||||
<td>연속 입력으로 500ms 단위가 흐트러지는 문제 방지</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>P단이 아닌 상태에서 <code>p/u/d/a/c/r</code> 입력</td>
|
||||
<td><code>ERR: check gear state. Command requires P.</code> 출력</td>
|
||||
<td>수동 이동, 저장, 보정, EEPROM 변경이 P단 외 상태에서 실행되는 문제 방지</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>수동 이동 완료 전 기어 상태 변경</td>
|
||||
<td>수동 완료 대기 플래그 해제</td>
|
||||
<td>자동 제어로 넘어간 뒤 잘못된 <code>MANUAL_STEP_DONE</code> 출력 방지</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>내부 위치값 범위 이탈</td>
|
||||
<td><code>currentMs</code>, <code>targetMs</code>를 0..6000으로 보정</td>
|
||||
<td>시간 계산 오차나 상태 꼬임으로 인한 비정상 목표 방지</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>보정 시작/중단</td>
|
||||
<td>수동 이동 플래그, 하강 잔여값, 하단 추가 하강 상태 초기화</td>
|
||||
<td>보정과 일반 이동 상태가 섞이는 문제 방지</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
param(
|
||||
[string]$Port = "COM3",
|
||||
[string]$Fqbn = "arduino:avr:nano:cpu=atmega328"
|
||||
)
|
||||
|
||||
$ArduinoCli = "arduino-cli"
|
||||
$InstalledCli = "C:\Program Files\Arduino CLI\arduino-cli.exe"
|
||||
|
||||
if (Test-Path $InstalledCli) {
|
||||
$ArduinoCli = $InstalledCli
|
||||
}
|
||||
|
||||
& $ArduinoCli upload --fqbn $Fqbn --port $Port .
|
||||
Reference in New Issue
Block a user