Code Download
GetLiveData.ino, ECU Simulator.inoIntroduction
ก่อนที่จะเกิดโปรเจคนี้ขึ้นมา การเข้าถึง ECU จริงเพื่อการเรียนรู้มีค่าใช้จ่ายสูงและไม่สะดวกนัก โดยเฉพาะเมื่อต้องการทดลองส่งคำสั่งที่อาจเกิดข้อผิดพลาด เราจึงมองหาทางเลือกที่ประหยัดและยืดหยุ่นกว่า แนวคิดในการใช้ไมโครคอนโทรลเลอร์ ESP32 ที่มีประสิทธิภาพสูงและเชื่อมต่อ Wi-Fi ได้ เพื่อสร้างเป็น ECU Simulator ต้นแบบ (Prototype) จึงเป็นคำตอบที่ลงตัวที่สุดสำหรับโปรเจกต์นี้
Objective
- เพื่อพัฒนาเครื่องมือจำลอง (Simulator) ที่มีความเสถียร สำหรับใช้เป็น Test Bench ในการทดสอบและดีบักซอฟต์แวร์หรือฮาร์ดแวร์วินิจฉัย (Diagnostic Tools)
- จำลองการตอบสนองต่อคำสั่ง KWP2000 อย่างน้อย 5 คำสั่งที่แตกต่างกัน เช่น Read Data
- จำลองสภาวะที่ผิดปกติ Error Conditions เช่น การส่ง Negative Response (NACK) หรือการตอบสนองช้า (Timeout)
Implementation Notes: ESP32 K-Line Simulator (ตามโค้ดที่ใช้งานจริง)
1) ฮาร์ดแวร์ที่ใช้ (Hardware Stack)
ไมโครคอนโทรลเลอร์ (MCU)
- ESP32 ใช้ UART ฮาร์ดแวร์ที่
10400baud - พอร์ตตัวอย่าง: RX=GPIO16, TX=GPIO17
-
การตั้งค่า Serial ทำผ่านเมธอดรวม
setSerial()ลดขั้นตอน
K-Line Transceiver
- 4N25 Optocouper (ใช้แยกสัญญาน 5 V, 12 V)
- การต่อ: ESP32 TX→TXD, ESP32 RX←RXD, ขา K ของชิป ไปที่ 4N25 Optocouper
แหล่งจ่ายไฟ
- อินพุต 12 V จากรถ, ควบคุมเป็น 5 V ด้วยเรกูเลเตอร์ที่เหมาะสม
คอนเนคเตอร์
หัว OBD-II แบบตัวผู้
2) การตั้งค่า Baud และ Initialization (สอดคล้องกับโค้ด)
A) 5-Baud Initialization (ISO 9141 / ISO14230_Slow)
- ปิด UART ชั่วคราวด้วย
setSerial(false)เพื่อควบคุมขา GPIO โดยตรง ลดขั้นตอน - ส่ง 5-baud address 0x33 ด้วย
send5baud(0x33)(สตาร์ทบิต + 7 บิต + parity + stop, คาบ ~200 ms/บิต) - เปิด UART กลับเป็น 10400 baud ด้วย
setSerial(true), ตั้ง inter-byte timeout เริ่มต้น 30–60 ms - ตรวจซิงก์ 0x55 และ key bytes; ตอบกลับเขียน inverted KW2 แล้วรอ 0xCC เพื่อยืนยันเชื่อมต่อ
B) Fast Initialization (ISO14230_Fast)
- สร้าง wake pulse: K-Line LOW ~25 ms แล้ว HIGH ~25 ms ด้วยการดึง TX โดยตรง
- ส่งเฟรมเริ่มต้น
[ C1 33 F1 81 | CS ]แล้วรอรับ โดยตรวจresultBuffer[3] == 0xC1เพื่อฟันธงโปรโตคอล - ลอจิกเปิด/ปิด UART รวมที่
setSerial()และส่งด้วยwriteRawData()ลดขั้นตอน
C) Honda Initialization (ISO14230_Honda)
- ลำดับปลุก: LOW ~70 ms → HIGH ~120 ms → LOW (ตามที่โค้ดกำหนด)
- ส่งสองเฟส:
wakeupHondaMsg = [ FE 04 72 ]แล้วตามด้วยinitHondaMsg = [ 72 05 00 F0 ] - ตรวจผลตอบกลับ เช่น
resultBuffer[3] == 0xFAหรือresultBuffer[0] == 0x02เพื่อยืนยัน - ทุกอย่างถูกห่อด้วย
tryHondaInit()ลดขั้นตอน
หมายเหตุ: เลือกโปรโตคอลได้ทั้ง Automatic / ISO9141 / ISO14230_Slow / ISO14230_Fast / ISO14230_Honda ผ่าน
setProtocol() และวนลอง trySlowInit(), tryFastInit(),
tryHondaInit() ตามลำดับที่ตั้งค่าไว้
ลดขั้นตอน
3) โครงสร้างเฟรม และตัวอย่าง PDU (ตามเฮดเดอร์ที่โค้ดใช้)
ISO9141 / ISO14230 (โหมดทั่วไป)
โค้ดกำหนดส่วนหัวต่างกันตามโปรโตคอลใน writeData():
- ISO9141:
[ 68/69 6A F1 MODE (PID?) ... | CS ] - ISO14230_Fast/Slow:
[ C1/C2/C3 33 F1 MODE (PID?) ... | CS ]
การเติม Checksum ทำอัตโนมัติใน writeRawData() และ writeData()
ลดขั้นตอน
Honda (Live Data)
เมื่อเชื่อมต่อแบบ Honda โค้ดส่งเฟรมอ่าน Live Data ด้วยส่วนหัวคงที่:
[ 72 05 71 PID | CS ]
การประกอบเฟรมและเช็กซัมถูกห่อใน writeData() (รวม Honda mode)
ลดขั้นตอน
4) Checksum
- ทั่วไป: ผลรวมแบบ 8-bit (
sum % 256) - Honda: ใช้ค่ากลับส่วนเติมเต็ม (
0x100 - (sum % 256)) ภายในcalculateChecksum()ลดขั้นตอน
5) Timing & I/O Handling
- เว้นระยะส่งต่อไบต์: ค่าเริ่มต้น ~
_byteWriteInterval = 5 msปรับได้ด้วยsetByteWriteInterval() - Inter-byte timeout: ค่าเริ่มต้น ~
_interByteTimeout = 60 msปรับได้ด้วยsetInterByteTimeout() - Read timeout รวม: ~
_readTimeout = 1000 msปรับได้ด้วยsetReadTimeout() - ทุกการอ่านเรียก
readData()ซึ่งจะรอจนไม่มีไบต์ใหม่ภายในช่วง inter-byte แล้วค่อยสรุปแพ็กเก็ต -
เคลียร์ Echo อัตโนมัติหลังส่งด้วย
clearEcho()ลดขั้นตอน
6) การแมป Live Data (Honda Table 0x17)
| ฟิลด์ | สูตร/ที่มา |
|---|---|
| Engine Speed (rpm) | payload[0..1] เป็น 16-bit big-endian |
| Throttle Position (%) | payload[3] × 5 / 256 |
| Ignition Timing (°) | payload[4] / 2 − 64 |
| IAT / ECT (°C) | IAT: payload[5] − 40, ECT: payload[7] − 40 |
| MAP (mbar) | payload[9] × 10 |
| Battery (V) | payload[10] / 10 |
| Vehicle Speed (km/h) | payload[16] |
ฟังก์ชันรวมสำหรับอ่าน/แปลง: getHondaLiveData() → parseHondaTable17()
ลดขั้นตอน
7) ยูทิลิตี้ที่ใช้ลดขั้นตอน
writeRawData(): เติม checksum อัตโนมัติ + เคลียร์ echo หลังส่ง ลดขั้นตอนwriteData(): เลือกฟอร์แมตเฮดเดอร์ให้ตามโปรโตคอลที่ต่ออยู่ ลดขั้นตอนreadData(): รวมลูปรอข้อมูล + inter-byte window + อัปเดตสถานะการเชื่อมต่อ ลดขั้นตอนreadSupportedData(): วนอ่านบล็อก Supported PIDs แบบไดนามิก (หยุดเมื่อไม่มีบล็อกต่อ) ลดขั้นตอนcalculateChecksum(): สวิตช์อัตโนมัติระหว่างแบบปกติและแบบ Honda ลดขั้นตอน
Methodology
Block Diagram / Flowchart
ภาพวงจร/ไดอะแกรม
Results / Findings
ตัวอย่างตารางสรุปผลการทดลอง:
| Metric | Value | Notes |
|---|---|---|
| Init Success Rate | 99 % | ปรับตามผลจริง |
| Response Latency | 25ms | เฉลี่ยจาก N ครั้ง |
| Packet Error | 0 % | ขึ้นกับสภาพสัญญาณ |
Analysis
จากการทดลองสื่อสารระหว่าง ESP32 กับ ECU ผ่าน K-Line (ISO 9141-2 / KWP2000) พบว่าสามารถทำการ Fast Initialization ได้สำเร็จภายใต้เงื่อนไขเวลามาตรฐาน (70 ms low, 120 ms high) และสามารถรับ–ส่งเฟรมข้อมูลด้วย baud rate 10400 bps ได้อย่างเสถียร การตอบสนองของ ECU แสดงให้เห็นถึงการ handshake ที่ถูกต้อง เช่น การตอบกลับด้วย header [0x0e, 0x04, 0x72] หรือรหัสสถานะจาก ECU หลังจากคำสั่ง “Start Communication”.
Conclusion & Recommendations
Conclusion:
- ระบบสามารถสื่อสารกับ ECU ผ่าน K-Line ได้อย่างถูกต้อง
- การทำ fast-init ตาม timing มาตรฐานช่วยให้ ECU เริ่มต้น session ได้เสถียร
- เฟรมข้อมูลที่มี checksum ถูกต้องทุกครั้งจะทำให้ ECU ตอบสนองตามที่คาดหมาย
- การใช้วงจร transceiver ที่เหมาะสมช่วยลดปัญหา noise และปกป้องวงจร ESP32
Recommendations:
- พัฒนาโมดูล Auto-detect Protocol: เพื่อให้ระบบสามารถตรวจจับประเภทโปรโตคอล (ISO 9141-2, KWP2000, CAN) ได้อัตโนมัติ
- เพิ่มระบบ Logging: เก็บข้อมูลเฟรมที่ส่ง–รับในรูปแบบ CSV หรือ JSON สำหรับการวิเคราะห์ย้อนหลัง
- ออกแบบ Dashboard แบบ Real-time: แสดงค่าพารามิเตอร์ เช่น RPM, TPS, IAT, ECT, Voltage แบบกราฟเพื่อใช้ในการวิเคราะห์สมรรถนะเครื่องยนต์
- ทดสอบภาคสนามกับ ECU หลายรุ่น: เพื่อประเมินความเข้ากันได้ (Compatibility) ระหว่างยี่ห้อรถยนต์และปีผลิตต่างๆ