ระดับกลาง
สร้างจอแสดงผลเรดาร์อัลตราโซนิก
เซ็นเซอร์จอแสดงผลหุ่นยนต์
กวาดเซนเซอร์อัลตราโซนิกไปตามส่วนโค้งกว้างๆ ด้วยเซอร์โว แล้วดูจอแสดงผลแบบเรดาร์กวาดแบบเรียลไทม์ที่สร้างขึ้นบนหน้าจอ ซึ่งเป็นเส้นกวาดสีเขียวแบบคลาสสิก ทำจากชิ้นส่วนที่ทำงานนี้ได้อย่างแม่เจาะจงอยู่แล้ว
รวมชิ้นส่วนจริง 4 รายการ
ราคารวมชุดนี้: 968.00 ฿
ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน
สิ่งที่คุณต้องใช้
เป้าหมายของโครงการ
โครงการนี้เปลี่ยนเซ็นเซอร์ระยะทางตัวเดียวให้เป็นจอแสดงผลเรดาร์กวาดจริง: เซอร์โวจะหมุนเซ็นเซอร์ช้าๆ เป็นวงกว้าง ในขณะที่หน้าจอจะวาดเส้นสำหรับสิ่งที่ตรวจจับได้ในแต่ละมุม ซึ่งเป็นเอฟเฟกต์เส้นกวาดแบบเดียวกับหน้าจอเรดาร์เก่า สร้างขึ้นจากสามส่วนที่ทำงานนี้แยกกันอยู่แล้ว
ตัวควบคุมทำอะไร
ในการวนซ้ำ ตัวควบคุมจะสั่งให้เซอร์โวไปยังมุมใหม่ รอสักครู่เพื่อให้มันเคลื่อนที่ไปถึง สั่งงานเซ็นเซอร์อัลตราโซนิก อ่านค่าระยะทางกลับมา และวาดเส้นใหม่หนึ่งเส้นบนจอแสดงผลก่อนที่จะย้ายไปยังมุมถัดไป กวาด วัด วาด ซ้ำ
เซอร์โวทำอะไร
เซอร์โวจะหมุนเซ็นเซอร์อัลตราโซนิกไปตามแนวโค้งประมาณ 180 องศา ทีละขั้นตอน ทำให้การอ่านค่าระยะทางแต่ละครั้งมีทิศทางทางกายภาพที่แท้จริงที่จะวาด
เซ็นเซอร์อัลตราโซนิกทำอะไร
มันส่งพัลส์อัลตราโซนิกสั้นๆ และจับเวลาว่าเสียงสะท้อนใช้เวลานานแค่ไหนในการกลับมา แปลงเป็นค่าการวัดระยะทาง ซึ่งเป็นหลักการทำงานเดียวกับระบบโซนาร์จริง
จอแสดงผลทำอะไร
OLED จะวาดการอ่านค่าระยะทางใหม่แต่ละครั้งเป็นเส้นที่มุมที่วัดได้ สร้างภาพการกวาดแบบเรดาร์ที่แท้จริงทีละค่า
แนวคิดเกี่ยวกับซอฟต์แวร์และไลบรารี
ให้แต่ละส่วนทำงานแยกกันก่อน: กวาดเซอร์โวตลอดช่วงการเคลื่อนที่ทั้งหมดและยืนยันว่ามันเคลื่อนที่อย่างถูกต้อง, อ่านค่าระยะทางเพียงครั้งเดียวและพิมพ์ออกมา, จากนั้นวาดเส้นทดสอบแบบคงที่หนึ่งเส้นบนจอแสดงผลก่อนที่จะรวมทั้งสามส่วนเข้าด้วยกันในวงวนการกวาด
การทดสอบและการแก้ไขปัญหา
- เซอร์โวกระตุกหรือไม่สามารถรักษามุมที่เสถียรได้ ตรวจสอบแหล่งจ่ายไฟของมัน เซอร์โวใช้กระแสไฟฟ้ามากกว่าที่ขา GPIO เพียงอย่างเดียวจะพยายามจ่ายให้
- ค่าที่อ่านได้จากเซ็นเซอร์ระยะทางไม่สอดคล้องกันอย่างมาก เซ็นเซอร์อัลตราโซนิกไวต่อพื้นผิวที่อ่อนนุ่มหรือเป็นมุมที่ทำให้พัลส์กระจัดกระจายแทนที่จะสะท้อนกลับมาตรงๆ ให้ทดสอบกับผนังแข็งเรียบก่อน
- หน้าจอแสดงผลแสดงเพียงส่วนหนึ่งของการกวาดเท่านั้น ยืนยันว่าเซอร์โวกำลังเคลื่อนที่ครบช่วงการเคลื่อนที่ทั้งหมด และการคำนวณมุมต่อพิกเซลตรงกับช่วงจริงของเซอร์โว
การอัปเกรดเสริม
เพิ่มโหมดการแสดงผลที่สองซึ่งบันทึกเฉพาะวัตถุที่ตรวจพบใกล้ที่สุดต่อการกวาด แทนที่จะวาดส่วนโค้งทั้งหมด ซึ่งเป็นการอ่านค่าการแจ้งเตือนระยะใกล้แบบง่ายๆ ที่สร้างขึ้นจากเซ็นเซอร์สองตัวเดียวกัน
การเดินสายไฟ
- HC-SR04 VCC → ESP32-S3 5V
- HC-SR04 GND → ESP32-S3 GND
- HC-SR04 TRIG → ESP32-S3 GPIO4 (เอาต์พุต)
- HC-SR04 ECHO → ตัวแบ่งแรงดัน 1kΩ/2kΩ → ESP32-S3 GPIO5 (อินพุต) — ECHO เป็นลอจิก 5V ตัวแบ่งจะป้องกันขาอินพุต 3.3V
- SG90 สีแดง → ESP32-S3 5V
- SG90 สีน้ำตาล/ดำ → ESP32-S3 GND
- SG90 สีส้ม/เหลือง (สัญญาณ) → ESP32-S3 GPIO6 (PWM ผ่าน ESP32Servo)
- OLED VCC → ESP32-S3 3.3V
- OLED GND → ESP32-S3 GND
- OLED SDA → ESP32-S3 GPIO8 (I2C เริ่มต้น)
- OLED SCL → ESP32-S3 GPIO9 (I2C เริ่มต้น)
HC-SR04 จะไม่น่าเชื่อถือเมื่อระยะห่างน้อยกว่า ~2 ซม. และเซอร์โวต้องการการหน่วงเวลาสั้นๆ หลังจากการ `write()` แต่ละครั้งก่อนที่การอ่านค่าจะน่าเชื่อถือ ซึ่งเป็นเหตุผลว่าทำไมจึงมีการหยุดชั่วคราว 150 มิลลิวินาทีต่อขั้นตอน สิ่งนี้จะวาดเรดาร์ "กวาด" แบบเส้นเดียวที่เรียบง่าย (วาดใหม่ในแต่ละมุม) แทนที่จะเป็นร่องรอยแบบคงที่ — ใช้งานได้จริง แต่เรียบง่ายกว่าเอฟเฟกต์หน้าจอเรดาร์เต็มรูปแบบ; คุณสามารถเพิ่มจุดร่องรอยที่จางลงได้เมื่อเวอร์ชันพื้นฐานทำงานแล้ว
แผนภาพการต่อสาย
โค้ดเริ่มต้น
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>
// --- Pin definitions: adjust to match your ESP32-S3 board's silkscreen if different ---
#define TRIG_PIN 4 // HC-SR04 trigger (output)
#define ECHO_PIN 5 // HC-SR04 echo (input, through a 1k/2k voltage divider - ECHO is 5V logic)
#define SERVO_PIN 6 // SG90 signal (PWM-capable pin)
#define OLED_SDA 8 // ESP32-S3 default I2C SDA
#define OLED_SCL 9 // ESP32-S3 default I2C SCL
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Servo radarServo;
const int MAX_DISTANCE_CM = 40; // radar range shown on screen
const int CENTER_X = 64;
const int CENTER_Y = 63;
const int RADIUS_PX = 60;
long readDistanceCM() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 25000); // 25ms timeout (~4m max)
if (duration == 0) return -1; // no echo / out of range
return duration * 0.0343 / 2;
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
radarServo.attach(SERVO_PIN);
Wire.begin(OLED_SDA, OLED_SCL);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("OLED init failed");
while (true) delay(1000);
}
display.clearDisplay();
display.display();
}
void sweepAndDraw(int angle) {
radarServo.write(angle);
delay(150); // let the servo settle before reading
long distance = readDistanceCM();
display.clearDisplay();
// Sweep line from center at current angle
float rad = radians(angle);
int lineLen = RADIUS_PX;
if (distance > 0 && distance < MAX_DISTANCE_CM) {
lineLen = map(distance, 0, MAX_DISTANCE_CM, 0, RADIUS_PX);
}
int x = CENTER_X - cos(rad) * lineLen;
int y = CENTER_Y - sin(rad) * lineLen;
display.drawLine(CENTER_X, CENTER_Y, x, y, SSD1306_WHITE);
// Text readout
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Angle: ");
display.print(angle);
display.print((char)247); // degree symbol
display.setCursor(0, 10);
display.print("Dist: ");
if (distance > 0) {
display.print(distance);
display.print(" cm");
} else {
display.print("--");
}
display.display();
}
void loop() {
for (int angle = 0; angle <= 180; angle += 3) {
sweepAndDraw(angle);
}
for (int angle = 180; angle >= 0; angle -= 3) {
sweepAndDraw(angle);
}
}
ไม่แน่ใจขั้นตอนไหน?
ถามเรา