// --- MiniExam Starter Code ---
//
// คำชี้แจงสำหรับนักเรียน:
// 1. กำหนดค่า Pin ที่ถูกต้องให้กับตัวแปรด้านล่างตามการต่อวงจรของคุณ
// 2. เติมโค้ดในส่วนที่มีเครื่องหมาย "TODO" ให้สมบูรณ์เพื่อให้อุปกรณ์ทำงานตามโจทย์
// 3. สามารถสร้างตัวแปรหรือฟังก์ชันเพิ่มเติมได้ตามความเหมาะสม
#include <ESP32Servo.h>
// --- 1. กำหนด Pin ของอุปกรณ์ (TODO) ---
// ให้นักเรียนกำหนดหมายเลข Pin ที่ถูกต้องตามที่ต่อวงจรไว้
const int potenPin = 14; // Pin สำหรับอ่านค่า Slide Potentiometer (Analog)
const int servoPin = 26; // Pin สำหรับควบคุม Servo (PWM)
const int btnPin = 27; // Pin สำหรับปุ่มกด (Digital)
const int ledPin = 12; // Pin สำหรับ LED ไฟเบรค (Digital)
const int trigPin = 32; // Pin สำหรับ Trig ของ Ultrasonic Sensor
const int echoPin = 33; // Pin สำหรับ Echo ของ Ultrasonic Sensor
// --- Global Variables ---
Servo servo; // สร้าง Object สำหรับ Servo
int currentSpeed = 0; // ตัวแปรเก็บความเร็วปัจจุบัน
int lastSpeed = -1; // ตัวแปรเก็บความเร็วล่าสุดเพื่อใช้เปรียบเทียบ (ตั้งค่าเริ่มต้นไม่ให้ซ้ำกับ 0)
// ตัวแปรสำหรับจัดการสถานะการเบรค
bool isBraking = false;
unsigned long brakeStartTime = 0;
void setup() {
Serial.begin(115200);
Serial.println("MiniExam: Speed Control System Initializing...");
// --- กำหนดโหมดการทำงานของ Pin ---
pinMode(potenPin, INPUT);
pinMode(btnPin, INPUT_PULLUP); // ใช้ Pull-up ภายใน ไม่ต้องต่อ Resistor
pinMode(ledPin, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// --- เริ่มต้นการทำงานของ Servo ---
servo.attach(servoPin);
// --- ตั้งค่าสถานะเริ่มต้น ---
servo.write(0); // ให้หน้าปัด Servo เริ่มที่ 0
digitalWrite(ledPin, LOW); // ปิดไฟเบรค
}
void loop() {
// --- ส่วนจัดการสถานะการเบรค ---
if (isBraking) {
unsigned long elapsedTime = millis() - brakeStartTime;
if (elapsedTime < 5000) { // 5000 ms = 5 วินาที
// TODO: เขียนอัลกอริทึมเพื่อ "ค่อยๆ ลดความเร็ว" ลงจนเหลือ 0 ก่อนจะหมด 5 วิ
int initialSpeed = currentSpeed;
int brakingSpeed = initialSpeed * (5000 - elapsedTime) / 5000; // <--- แก้ไขตรงนี้
// อัปเดตหน้าปัด Servo และ Serial Monitor
updateSpeedometer(brakingSpeed);
} else {
// เมื่อครบ 5 วินาทีแล้ว ให้ยกเลิกสถานะการเบรค
isBraking = false;
digitalWrite(ledPin, LOW); // ปิดไฟเบรค
Serial.println("Braking complete. Resuming normal operation.");
}
return; // ออกจากการทำงานใน loop นี้ไปก่อนเพื่อรอให้การเบรคเสร็จสิ้น
}
// --- ส่วนตรวจสอบเงื่อนไขการเบรค ---
float distance = readUltrasonicDistance();
bool brakeButtonPressed = (digitalRead(btnPin) == LOW);
if (distance <= 100 || brakeButtonPressed) {
if (!isBraking) { // เริ่มเบรคเมื่อยังไม่ได้อยู่ในสถานะเบรคเท่านั้น
isBraking = true;
brakeStartTime = millis();
digitalWrite(ledPin, HIGH); // เปิดไฟเบรค
Serial.printf("BRAKE TRIGGERED! Obstacle at %.2f cm or Button Pressed.\n", distance);
}
return; // เมื่อเงื่อนไขเบรคทำงาน ให้ข้ามไปรอบถัดไป
}
// --- ส่วนควบคุมความเร็วปกติ (คันเร่ง) ---
int potenValue = analogRead(potenPin); // อ่านค่าจาก Potentiometer (0-4095)
// TODO: แปลงค่าที่อ่านได้จาก Poten (0-4095) ให้เป็นความเร็ว (0-200 km/hr)
// คำใบ้: ใช้ฟังก์ชัน map()
currentSpeed = map(potenValue, 0, 4095, 0, 200); ; // <--- แก้ไขตรงนี้
// --- ส่วนแสดงผล ---
// TODO: ตรวจสอบว่าความเร็วมีการเปลี่ยนแปลงหรือไม่ ก่อนที่จะแสดงผล
// คำใบ้: เปรียบเทียบ currentSpeed กับ lastSpeed
if (currentSpeed != lastSpeed) { // <--- แก้ไขเงื่อนไขตรงนี้
updateSpeedometer(currentSpeed);
lastSpeed = currentSpeed; // อัปเดตความเร็วล่าสุด
}
delay(50); // หน่วงเวลาเล็กน้อยเพื่อความเสถียร
}
/**
* @brief ฟังก์ชันสำหรับอัปเดตการแสดงผลทั้ง Servo และ Serial Monitor
* @param speed ความเร็วที่ต้องการแสดงผล (0-200)
*/
void updateSpeedometer(int speed) {
// TODO: แปลงความเร็ว (0-200 km/hr) เป็นองศาของ Servo (0-180 องศา)
// และสั่งให้ Servo หมุนไปตามองศาที่คำนวณได้
int servoAngle = map(speed, 0, 200, 0, 180); // <--- แก้ไขตรงนี้
servo.write(servoAngle);
// แสดงผลความเร็วออกทาง Serial Monitor
Serial.printf("Speed: %d km/hr.\n", speed);
}
/**
* @brief ฟังก์ชันสำหรับวัดระยะทางด้วย Ultrasonic Sensor
* @return ระยะทางที่วัดได้ในหน่วยเซนติเมตร (cm)
*/
float readUltrasonicDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
return duration / 58.2;
}