Đo mức nước, mức nhiên liệu đang có trong bồn, bể chứa sử dụng cảm biến siêu âm SR04 và Arduino
Mục Lục
Đo mức nước, mức nhiên liệu đang có trong bồn, bể chứa sử dụng cảm biến siêu âm SR04 và Arduino
Nếu bạn có 1 bồn chứa nước hoặc nguyên vật liệu đóng kín, bạn sẽ gặp phải yếu tố giống như tôi :
Làm sao để biết lượng nước (nhiện liệu) đang có trong bồn mà không cần mở bồn ra kiểm tra?
Xem thêm :
Đương nhiên là lắp đồng hồ đo rồi!
Bạn đang đọc: Đo mức nước, mức nhiên liệu đang có trong bồn, bể chứa sử dụng cảm biến siêu âm SR04 và Arduino
Dạo quanh chợ 1 vòng thì than ôi, đủ những loại hàng từ cơ đến điện tử, Ngân sách chi tiêu đắt đỏ và hiệu suất cao chưa được kiểm chứng .
Vậy là Quyết Định tự làm 1 bộ đo cho riêng mình – Tiêu chí : Ngon – Bổ – Rẻ .
Bộ đo này sử dụng những module siêu âm có sẵn trên thị trường .
Các bạn có thể sử dụng Module siêu âm chống nước JSN-SR04T hoặc Module siêu âm KHÔNG chống nước HC-SR04.
Code hoạt động giải trí trên cả 2 loại và không cần chỉnh sửa gì cả, ráp đúng chân là chạy .
Module JSN-SR04T – Chống nước
Module HC-SR04 – Không chống nước
Trong bài viết này, mình sẽ lập trình bằng Arduino để đo mức ( level ) nước, nguyên vật liệu :
- Đơn vị đo “cm”
- Hiển thị đồng thời qua màn LCD 16×2 dưới dạng thanh báo “%” còn lại và Serial qua máy tính dưới dạng “cm” và có cảnh báo.
- Hiển thị LCD 16×2 dùng cách mắc trực tiếp – Hơi tốn chân GPIO của board Arduino nhưng đỡ tiền mua module I2C (Nếu không muốn dùng cách này có thể tham khảo bài sau để sử dụng cách module I2C cho tiết kiệm chân)
- Đo môi trường ngoài không khí. Trong điều kiện khắc nghiệt, độ ẩm cao.
NGUYÊN LÝ HOẠT ĐỘNG
Cảm biến khoảng cách siêu âm SR04 được sử dụng rất phổ cập để xác lập khoảng cách vì RẺ và CHÍNH XÁC .
Cảm biến sử dụng sóng siêu âm và hoàn toàn có thể đo khoảng cách trong khoảng chừng từ 2 -> 300 cm, với độ đúng chuẩn gần như chỉ phụ thuộc vào vào cách lập trình .
- Cảm biến SR04 có 4 chân là: Vcc, Trig, Echo, GND.
- Để đo khoảng cách, ta sẽ phát 1 xung rất ngắn (5 microSeconds – us) từ chân Trig. Sau đó, cảm biến sẽ tạo ra 1 xung HIGH ở chân Echo cho đến khi nhận lại được sóng phản xạ ở pin này. Chiều rộng của xung sẽ bằng với thời gian sóng siêu âm được phát từ cảm biển và quay trở lại.
Tốc độ của âm thanh trong không khí là 340 m / s ( hằng số vật lý ), tương tự với 29,412 microSeconds / cm ( 106 / ( 340 * 100 ) ) .
Khi đã tính được thời hạn, ta sẽ chia cho 29,412 để nhận được khoảng cách .
Các bước thống kê giám sát như sau :
- Đặt chân TRIG của module lên mức Cao (5V) trong ít nhất 10 μs (microseconds)
- Sau đó module siêu âm ghi lại thời gian và gửi ra sóng âm tần số 40Khz
- Sóng siêu âm truyền xuống bề mặt chất lỏng trong bể và phản xạ lại
- Sóng phản xạ sau đó truyền ngược về đầu dò
- Module siêu âm nhận được sóng phản xạ và đánh dấu thời gian nhận được sóng phản hồi
- Cuối cùng, module siêu âm đưa chân ECHO lên mức cao trong khoảng thời gian (microseconds ) phản hồi sóng âm (Gửi đi – nhận về) và tính toán ra khoảng cách.
Kết quả trên chân ECHO có thể được chuyển đổi khá đơn giản về: 58 μs/cm
Vì vậy, nếu chân ECHO lên mức cao trong thời hạn 5800 μs ( 5.8 ms ), thì tất cả chúng ta tính được khoảng cách giữa cảm biến và mức chất lỏng trong bể là :
5800μs / 58μs/cm = 100cm = 1m
Mô phỏng bồn chứa và cách đo
VẬT TƯ CẦN THIẾT
Arduino Uno
Module JSN-SR04T hoặc HC-SR04
Đầu dò siêu âm chống nước của module JSN-SR04T
Module siêu âm chống nước JSN-SR04T rất tiện lợi cho những ứng dụng ngoài trời như cảm biến đỗ xe ; đo khoảng cách ngoài trời ; đo mức nước bể cá, bể nước, đo mức nguyên vật liệu xăng, dầu, …
Bảng thông số của module JSN-SR04T mình trích ra từ tài liệu nhà sản xuất: Download
Giải thích :
Điện áp hoạt động | DC 3 – 5.5V |
Dòng tiêu thụ | Khoảng 8mA |
Tần số đầu dò | 40KHz |
Dải đo | 20cm – 600cm |
Sai số | +- 1cm |
Độ phân giải | 1mm |
Góc mở đầu dò | 75 độ |
Chú ý:
Vì cảm biến JSN-SR04T có góc mở rất lớn ( >= 75 độ) nên KHÔNG phù hợp đo khoảng cách trong không gian chật hẹp.
Chỉ nên dùng trong không gian mở như ngoài trời hoặc bể chứa kích thước lớn- không vật cản.
Nếu đo trong không gian chật hẹp thì sai số rất lớn do sóng phản xạ lại bị va đập vào vật cản hoặc thành bể – bình chứa.
Ảnh dưới miêu tả góc quét và phản xạ của 1 loại cảm biến siêu âm trên thị trường, tùy loại sẽ có góc khác nhau :
Góc quét và phản xạ của 1 loại cảm biến siêu âm
LCD 16×2
Biến trở
SƠ ĐỒ NGUYÊN LÝ
Sơ đồ chân liên kết
MODULE PIN | ARDUINO PIN |
Trigger pin (Module SR04) | Pin 8 |
Echo Pin (Module SR04) | Pin 9 |
RS Pin (LCD) | Pin A4 |
EN Pin (LCD) | Pin A5 |
D4 Pin (LCD) | Pin 5 |
D5 Pin (LCD) | Pin 4 |
D6 Pin (LCD) | Pin 3 |
D7 Pin (LCD) | Pin 2 |
Những chân còn lại của LCD | Nối theo sơ đồ (hĩnh vẽ) |
LED xanh | Pin 6 |
LED đỏ | Pin 7 |
5V | 5V |
GND | GND |
THƯ VIỆN CHO CẢM BIẾN SIÊU ÂM
- Thư viện NewLiquidCrystal : Download here
- Thư viện LiquidCrystal : Download here
Hướng dẫn: Tải thư viện về và copy vào thư mục library của Arduino trong Documents
CODE
Code Arduino sử dụng thư viện LiquidCrystal, hiển thị đồng thời LCD dạng “%” và Serial đợn vị đo “cm”
Môi trường đo trong không khí, có điều chỉnh mức cảnh báo “dưới ngưỡng” hoặc “vượt ngưỡng” cho phép, tín hiệu cảnh báo “dưới ngưỡng” hoặc “vượt ngưỡng” đưa ra 2 đèn LED (dễ dàng thay bằng còi hú, relay.. tùy bạn chỉnh) và cảnh báo cả trên Serial:
/* Arduino Uno Ultrasonic Fuel Gauge / Liquid Level Sensor System by Scott Ogrin MIT License */ // include the library code: #include#include #define G_LED 6 // Onboard Green LED #define R_LED 7 // Onboard Red LED // Init vars // ************** // CHANGE ME! // ************** const int tankEmptyDepth = 200; // This MUST be no greater than 450 cm (500cm for the HC-SR04)! const int tankFullDepth = 25; // This should be at least 25 cm, if possible (2cm for the HC-SR04) // Change the above tankEmptyDepth and tankFullDepth constants to be the distance (in centimeters): // - tankEmptyDepth = between the ultrasonic sensor and the empty level (i.e. bottom of tank) // - tankFullDepth = between the sensor and the liquid when the tank is full (MINIMUM 25cm) // Note that the ultrasonic sensor works only between 25cm and 450cm, so the min tankFullDepth = 25. // For my tank, the tankFullDepth = 15, which is okay... BUT it means that when the tank is full, // I will probably get incorrect readings until the level drops 10cm. This isn't a problem in my case // since I I don't care about accurate level readings when the fuel tank is full! But it means that // after getting the tank filled, the level will read near-empty or "Error: Timeout". // // You could also use the HC-SR04, which is larger but has a min depth of 2cm and max of 500cm. // Note however that it's not waterproof! I chose the JSN-SR04T-2.0 for that reason. // // Note also that you might want to set tankEmptyDepth to be less than the bottom of your tank, // esp if you have a vertical feed sucking liquid from, say, 5cm above the bottom of the tank. // For example, my tank is 163cm deep from the sensor, so I set tankEmptyDepth to 153. This ensures // that when my LevelMatic reads 0%, I should have 10cm of fuel left in the tank. // // If measuring in inches: 1 inch = 2.54 cm // These vars hold the current and last-measured level from the sensor int currentLevel = 0; int lastLevel = 0; int maximumRange = 190; // Maximum range needed int minimumRange = 30; // Minimum range needed // These vars are for showPartialBarChar() and showCurrentLevel() int done = 0; char levelTxt[] = "Current level:"; // Var for showError // This error means the ultrasound unit couldn't do a measurement, and timed out // Usually that means the sensor is at a weird angle, too close to the liquid, or // the ultrasound waves are bouncing off the walls of the tank. char timeoutErrorTxt[] = "ERROR: Timeout"; // Var for echo response from ultrasonic sensor board unsigned long timeHigh; // Custom chars for LCD byte barEmpty[8] = { B11111, B00000, B00000, B00000, B00000, B00000, B00000, B11111, }; byte barOne[8] = { B11111, B10000, B10000, B10000, B10000, B10000, B10000, B11111, }; byte barTwo[8] = { B11111, B11000, B11000, B11000, B11000, B11000, B11000, B11111, }; byte barThree[8] = { B11111, B11100, B11100, B11100, B11100, B11100, B11100, B11111, }; byte barFour[8] = { B11111, B11110, B11110, B11110, B11110, B11110, B11110, B11111, }; // constants for ultrasonic sensor board IO pins const int trigPin = 8, echoPin = 9; // constants for LCD IO pins const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; // initialize the library by associating any needed LCD interface pin // with the arduino pin number it is connected to LiquidCrystal lcd(rs, en, d4, d5, d6, d7); void setup() { // Set up IO pins for ultrasonic sensor board pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); // Set trigger pin for sensor to 0 (aka "do nothing yet") digitalWrite(trigPin, LOW); pinMode(G_LED, OUTPUT); // Use LED indicator (if required) pinMode(R_LED, OUTPUT); // Use LED indicator (if required) Serial.begin(9600); // Serial monitoring // set up the LCD's number of columns and rows: lcd.begin(16, 2); // Set custom chars 0-7 lcd.createChar(0, barEmpty); lcd.createChar(1, barOne); lcd.createChar(2, barTwo); lcd.createChar(3, barThree); lcd.createChar(4, barFour); lcd.clear(); } void loop() { // Do level scan with ultrasonic board // Start a scan - trigger pin must be high for at least 10us digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Get time echo pin is high using pulseIn, which returns value in microseconds // Default timeout of 1s is more than enough for 8 pulses, and we're not in a hurry timeHigh = pulseIn(echoPin, HIGH); if (timeHigh == 0) { // Oops! Timeout... showError(); } else { // Calculate level // Assume 343 m/s for the speed of the 40kHz sound waves in air at standard temperature and pressure // It's 58 us/cm, which we get from: // (343 m/s * (1s / 1000000 us) * (100cm / 1m)) / 2 = 0.01715 cm / us // Must divide by 2 because sound wave travels to liquid, and back // Invert that to get: // 1 / 0.01715 cm/us = 58.309038 us/cm // Note resolution of ultrasonic sensor is +/- 0.5cm currentLevel = round(timeHigh / 58); if (currentLevel > tankEmptyDepth) { // If level is lower than empty, show 0% // This is useful if you want to have "empty" be "still 10cm of liquid left in tank" currentLevel = tankEmptyDepth; } else if (currentLevel < tankFullDepth) { // If level is higher than full, show 100% // This is useful since "full" level may vary when tank is refilled currentLevel = tankFullDepth; } // Don't redraw screen if level is the same as last time if (currentLevel != lastLevel) { lastLevel = currentLevel; showCurrentLevel(); } } if (currentLevel <= minimumRange){ /* Send a negative number to computer and Turn LED ON to indicate "out of range" */ Serial.println("SAFE"); digitalWrite(R_LED, LOW); digitalWrite(G_LED, HIGH); } else if (currentLevel >= maximumRange){ /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */ Serial.println("DANGER"); digitalWrite(R_LED, HIGH); digitalWrite(G_LED, LOW); } else { /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */ Serial.println("NORMAL"); digitalWrite(R_LED, LOW); digitalWrite(G_LED, LOW); } // Delay 2s between scans delay(2000); } void showError() { lcd.clear(); lcd.setCursor(0, 0); lcd.print(timeoutErrorTxt); } void showPartialBarChar(int val) { switch (val) { case 0: lcd.write(byte(0)); // barEmpty ++done; break; case 1: lcd.write(byte(1)); // one bar ++done; break; case 2: lcd.write(byte(2)); // two bars ++done; break; case 3: lcd.write(byte(3)); // three bars ++done; break; case 4: lcd.write(byte(4)); // four bars ++done; break; } } void showCurrentLevel() { // Get integer between 0 and 50 for bar graph // We have 10 progress bar characters, and each character can have 0-5 vertical columns of pixels // Subtracting tankFullDepth gives us a precise ratio between full/empty, as if the ultrasonic sensor // would be 0 cm away from the liquid level when the tank is full. // Also, currentLevel contains height of "emptiness" above the liquid, so to get liquid level we do: // abs(1 - currentLevel/tankEmptyDepth). float ratio = 1 - ((float)currentLevel - (float)tankFullDepth) / ((float)tankEmptyDepth - (float)tankFullDepth); ratio = abs(ratio); int textLevelInt = round(ratio * 100.0); int levelInt = round(ratio * 50.0); int fulls = 0; // Reset done done = 0; // Display text above progress bar lcd.clear(); lcd.setCursor(0, 0); lcd.print(levelTxt); // Display progress bar based on levelInt lcd.setCursor(0, 1); // Draw progress bar for XX% fulls = levelInt / 5; if (fulls == 0) { // First char on bar is a partial char with 0-4 vertical columns of pixels showPartialBarChar(levelInt); } else { for (int i = 0; i < fulls; ++i) { lcd.write(255); // full ++done; } } if (done < 10) { if (fulls > 0) { // Here we may have a partial char with 0-4 vertical columns of pixels showPartialBarChar(levelInt - (fulls * 5)); } // Here we may have blank boxes left if (done < 10) { // We have empty boxes to draw for (int i = 0; i < 10 - done; ++i) { lcd.write(byte(0)); // barEmpty } } } // Lastly, print percentage: if (textLevelInt == 100) { lcd.setCursor(12, 1); lcd.print("100%"); } else if (textLevelInt < 10) { lcd.setCursor(14, 1); lcd.print(textLevelInt); lcd.print("%"); } else { lcd.setCursor(13, 1); lcd.print(textLevelInt); lcd.print("%"); } Serial.print("Distance "); Serial.print(currentLevel); Serial.println("cm"); delay(100); }
- Điều chỉnh “%” lượng nước hiển thị trên LCD thông qua 2 dòng này trong code (Các bạn tự điều chỉnh phù hợp với thực tế bể chứa nhà bạn – Nên tính toán sao cho vẫn còn dư 10cm so với ngưỡng cảnh báo để dự phòng khẩn cấp):
—- Khoảng cách từ cảm biến đến mặt nước 200cm- Bể hết-> Hiển thị 0% (Tối đa 600cm – Khuyến nghị dùng trong 250cm)
const int tankEmptyDepth = 200;
—- Khoảng cách từ cảm biến đến mặt nước còn 25cm- Bể đầy-> Hiển thị 100% (Tối thiểu 20cm)
const int tankFullDepth = 25;
- Điều chỉnh thông số cảnh báo “dưới ngưỡng” hoặc “vượt ngưỡng” ở 2 dòng dưới đây (Các bạn tự điều chỉnh phù hợp với thực tế bể chứa nhà bạn – Nên tính toán sao cho vẫn còn dư 10cm so với ngưỡng cảnh báo để dự phòng khẩn cấp ) :
— – Khoảng cách từ cảm biến đến mặt nước 190 cm – Bể sắp hết -> cảnh báo nhắc nhở ( Tối đa 600 cm – Khuyến nghị dùng tối đa trong khoảng chừng 250 – 450 cm )
int maximumRange = 190;
— – Khoảng cách từ cảm biến đến mặt nước còn 30 cm – Bể sắp đầy -> cảnh báo nhắc nhở ( Tối thiểu 20 cm )
int minimumRange = 30;
- Chân kết nối 2 LED cảnh báo: Pin 6 và Pin 7 của Arduino nối với Anot (+) của mỗi LED (Có thể nối Loa báo động hoặc Relay vào 2 chân này thay cho LED) :
define G_LED 6 // Onboard Green LED – Pin 6
define R_LED 7 // Onboard Red LED – Pin 7
TEST
Mạch hoạt động giải trí khá tốt, khoảng cách đo mức nước, mức nguyên vật liệu tối thiểu 20 cm và tối đa 6 m ( khuyến nghị đo tối đa trong khoảng chừng 2.5 – 4 m ) .
- Nếu muốn đo mức nhiên liệu chính xác hơn và dùng trong không gian nhỏ, chật hẹp thì nên dùng module HC-SR04
- Nếu muốn đo trong không gian rộng rãi + yêu cầu chống nước, đo dưới nước, đo trong môi trường khắc nghiệt thì nên dùng module JSC-SR04T
Nguồn: scottiestech.info
5/5 – ( 1 bầu chọn )
Source: https://dvn.com.vn
Category: Phụ Kiện